Add Prettier and ESLint tooling (Refs #77)

This commit is contained in:
2026-10-09 15:56:13 -04:00
parent 8ed059b8d3
commit 16469e2d43
711 changed files with 99737 additions and 28286 deletions
+100 -34
View File
@@ -1,16 +1,33 @@
import { describe, expect, it } from 'vitest';
import { groupMaintenanceScanErrors, groupMaintenanceVersions } from '../../src/lib/ui/maintenance-presentation.js';
import {
groupMaintenanceScanErrors,
groupMaintenanceVersions
} from '../../src/lib/ui/maintenance-presentation.js';
import type { MaintenanceJob, PlutoniumVersion } from '../../src/lib/plutonium.js';
const theater = 't5_zombie_theater_1';
const moon = 't5_zombie_moon_1';
const version = (server: string, changes: Partial<PlutoniumVersion> = {}): PlutoniumVersion => ({
server, revision: 4878, checked_at: '2026-10-07T12:00:00Z', error: null, update_status: 'unknown', ...changes
server,
revision: 4878,
checked_at: '2026-10-07T12:00:00Z',
error: null,
update_status: 'unknown',
...changes
});
const job = (server: string, changes: Partial<MaintenanceJob> = {}): MaintenanceJob => ({
id: 1, server, state: 'queued', target_revision: 4878, requested_at: '2026-10-07T12:00:00Z',
restarted_at: null, provisioning_id: 'restart-1', finished_at: null, detail: null,
kind: 'update', origin: 'manual', ...changes
id: 1,
server,
state: 'queued',
target_revision: 4878,
requested_at: '2026-10-07T12:00:00Z',
restarted_at: null,
provisioning_id: 'restart-1',
finished_at: null,
detail: null,
kind: 'update',
origin: 'manual',
...changes
});
describe('maintenance scan summaries', () => {
@@ -18,7 +35,11 @@ describe('maintenance scan summaries', () => {
const errors = `${theater}: Host agent is offline; /srv/private-one unavailable\n${moon}: Host agent is offline; /srv/private-two unavailable`;
const groups = groupMaintenanceScanErrors(errors, [theater, moon]);
expect(groups).toHaveLength(1);
expect(groups[0]).toMatchObject({ key: 'host', title: 'Host agent unavailable', servers: [theater, moon] });
expect(groups[0]).toMatchObject({
key: 'host',
title: 'Host agent unavailable',
servers: [theater, moon]
});
expect(groups[0].details).toHaveLength(2);
expect(groups[0].description).not.toContain('/srv/');
expect(groups[0].description).not.toContain(theater);
@@ -26,21 +47,34 @@ describe('maintenance scan summaries', () => {
});
it('separates file, permission, timeout and unknown causes without exposing raw messages as headings', () => {
const groups = groupMaintenanceScanErrors([
`${theater}: ENOENT: no such file /srv/missing`,
`${moon}: EACCES: permission denied /srv/private`,
`${theater}: timeout: no reply`,
`${moon}: Unrecognized diagnostic code 123`
].join('\n'), [theater, moon]);
expect(groups.map(group => group.key)).toEqual(['files', 'permissions', 'timeout', 'other']);
expect(groups.every(group => !/ENOENT|EACCES|123/.test(group.title))).toBe(true);
const groups = groupMaintenanceScanErrors(
[
`${theater}: ENOENT: no such file /srv/missing`,
`${moon}: EACCES: permission denied /srv/private`,
`${theater}: timeout: no reply`,
`${moon}: Unrecognized diagnostic code 123`
].join('\n'),
[theater, moon]
);
expect(groups.map((group) => group.key)).toEqual([
'files',
'permissions',
'timeout',
'other'
]);
expect(groups.every((group) => !/ENOENT|EACCES|123/.test(group.title))).toBe(true);
});
it('supports custom names containing colons, avoids linking unknown identifiers and deduplicates identical failures', () => {
const message = 'Weekend: west: timeout: No reply';
const groups = groupMaintenanceScanErrors(`${message}\n${message}\nretired_server: Agent unavailable`, ['Weekend', 'Weekend: west']);
const groups = groupMaintenanceScanErrors(
`${message}\n${message}\nretired_server: Agent unavailable`,
['Weekend', 'Weekend: west']
);
expect(groups[0].servers).toEqual(['Weekend: west']);
expect(groups[0].details).toEqual([{ server: 'Weekend: west', message: 'timeout: No reply' }]);
expect(groups[0].details).toEqual([
{ server: 'Weekend: west', message: 'timeout: No reply' }
]);
expect(groups[1].servers).toEqual([]);
expect(groups[1].details[0].server).toBeNull();
});
@@ -48,46 +82,78 @@ describe('maintenance scan summaries', () => {
it('handles setup messages and empty scans without inventing an affected server', () => {
expect(groupMaintenanceScanErrors(null, [])).toEqual([]);
expect(groupMaintenanceScanErrors(' \n ', [])).toEqual([]);
expect(groupMaintenanceScanErrors('Register a native host instance before automatic recovery.', []))
.toEqual([expect.objectContaining({ key: 'setup', servers: [] })]);
expect(
groupMaintenanceScanErrors(
'Register a native host instance before automatic recovery.',
[]
)
).toEqual([expect.objectContaining({ key: 'setup', servers: [] })]);
});
});
describe('maintenance revision groups', () => {
it('collapses identical revisions and verification states without claiming that unknown versions are current', () => {
const versions = Array.from({ length: 12 }, (_, index) => version(`t5_zombie_theater_${index + 1}`));
const versions = Array.from({ length: 12 }, (_, index) =>
version(`t5_zombie_theater_${index + 1}`)
);
const groups = groupMaintenanceVersions(versions, []);
expect(groups).toHaveLength(1);
expect(groups[0]).toMatchObject({ revision: 4878, label: 'Unverified', tone: 'warning', updatable: [] });
expect(groups[0]).toMatchObject({
revision: 4878,
label: 'Unverified',
tone: 'warning',
updatable: []
});
expect(groups[0].versions).toHaveLength(12);
});
it('retains separate verification states and puts failures and available updates first', () => {
const groups = groupMaintenanceVersions([
version('current', { update_status: 'current' }), version('unknown'),
version('outdated', { revision: 4800, update_status: 'outdated' }),
version('ahead', { revision: 5000, update_status: 'ahead' })
], []);
expect(groups.map(group => group.status)).toEqual(['unknown', 'outdated', 'current', 'ahead']);
const groups = groupMaintenanceVersions(
[
version('current', { update_status: 'current' }),
version('unknown'),
version('outdated', { revision: 4800, update_status: 'outdated' }),
version('ahead', { revision: 5000, update_status: 'ahead' })
],
[]
);
expect(groups.map((group) => group.status)).toEqual([
'unknown',
'outdated',
'current',
'ahead'
]);
expect(groups[0].revision).toBe(groups[2].revision);
});
it('excludes pending restarts from group update actions while preserving the pending operation links', () => {
const pending = job(theater, { state: 'restarting' });
const [group] = groupMaintenanceVersions([
version(theater, { update_status: 'outdated' }), version(moon, { update_status: 'outdated' })
], [pending, job(moon, { id: 2, state: 'done' })]);
const [group] = groupMaintenanceVersions(
[
version(theater, { update_status: 'outdated' }),
version(moon, { update_status: 'outdated' })
],
[pending, job(moon, { id: 2, state: 'done' })]
);
expect(group.updatable).toEqual([moon]);
expect(group.pending).toEqual([pending]);
});
it('does not let deleted-server jobs suppress a current server update and preserves stopped legacy evidence', () => {
const groups = groupMaintenanceVersions([
version(theater, { update_status: 'outdated' }),
version(moon, { update_status: undefined, stopped: true, revision: null })
], [job(theater, { server_deleted_at: '2026-10-06' })]);
const groups = groupMaintenanceVersions(
[
version(theater, { update_status: 'outdated' }),
version(moon, { update_status: undefined, stopped: true, revision: null })
],
[job(theater, { server_deleted_at: '2026-10-06' })]
);
expect(groups[0].updatable).toEqual([theater]);
expect(groups[0].pending).toEqual([]);
expect(groups[1]).toMatchObject({ status: 'stopped', label: 'Intentionally stopped', revision: null, updatable: [] });
expect(groups[1]).toMatchObject({
status: 'stopped',
label: 'Intentionally stopped',
revision: null,
updatable: []
});
});
});