Archilyzer · Source

archilyzer

Archilyzer
git clone https://archilyzer.pages.dev/source/archilyzer.git
Log | Files | Refs | README | LICENSE

commit fa5e654fb90ee44ad213c11827a4017d6a50ead1
parent e897dff42c538f11c469bc0169a65935d78c0a04
Author: I Mean I'm Just Saying <imeanimjustsaying@kiwifarms.st>
Date:   Sun, 24 May 2026 02:26:05 -0400

Update release cut

Diffstat:
Mcommon/lib/changelog.ts | 2+-
Meditor/CHANGELOG.md | 1+
Meditor/app/deploy/page.tsx | 3+--
Aeditor/e2e/cut-release.spec.ts | 93+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Mexport/CHANGELOG.md | 2--
5 files changed, 96 insertions(+), 5 deletions(-)

diff --git a/common/lib/changelog.ts b/common/lib/changelog.ts @@ -82,6 +82,6 @@ export function cutRelease( const headingEnd = headingStart + match[0].length; const before = source.slice(0, headingStart); const after = source.slice(headingEnd); - const replacement = `## [Unreleased]\n\n## [${version}] - ${dateISO}`; + const replacement = `## [${version}] - ${dateISO}`; return `${before}${replacement}${after}`; } diff --git a/editor/CHANGELOG.md b/editor/CHANGELOG.md @@ -1,6 +1,7 @@ # Changelog ## [Unreleased] +- **Cutting a release now clears `## [Unreleased]` entirely** instead of leaving an empty heading sitting above the new dated section. The `/changelog` and `/deploy` pages stop showing a blank Unreleased block after a release; the heading reappears the next time somebody hand-adds a pending bullet to the file. ## [0.2.0] - 2026-05-22 - **`/actionable` page** aggregating pending work across all channels — three sections (channels with undownloaded videos, channels with downloaded videos awaiting transcription, and channels with stale or missing reports), each row linking to the channel with inline "Download missing" / "Transcribe pending" / "Refresh report" buttons. An "Update all reports" button queues a refresh per channel. A "Needs attention" card on the dashboard links here whenever either of the first two lists has anything in it. diff --git a/editor/app/deploy/page.tsx b/editor/app/deploy/page.tsx @@ -71,8 +71,7 @@ export default function DeployPage() { <h2 className="text-lg font-semibold">Cut release</h2> <p className="text-sm text-zinc-500"> Turns the current <code>## [Unreleased]</code> heading into a - dated semver heading and inserts a fresh empty{" "} - <code>## [Unreleased]</code> above it. + dated semver heading. </p> </div> <CutReleaseForm diff --git a/editor/e2e/cut-release.spec.ts b/editor/e2e/cut-release.spec.ts @@ -0,0 +1,93 @@ +import { readFile, writeFile } from "node:fs/promises"; +import { test, expect } from "@playwright/test"; +import { resolvePath } from "./helpers"; + +const CHANGELOG_PATH = resolvePath("CHANGELOG.md"); + +const WITH_UNRELEASED = + "# Changelog\n" + + "\n" + + "## [Unreleased]\n" + + "- test bullet for cut-release spec\n" + + "\n" + + "## [9.9.9] - 2024-01-01\n" + + "- old released bullet\n"; + +const WITHOUT_UNRELEASED = + "# Changelog\n" + + "\n" + + "## [9.9.9] - 2024-01-01\n" + + "- old released bullet\n"; + +function todayISO(): string { + const now = new Date(); + const y = now.getFullYear().toString().padStart(4, "0"); + const m = (now.getMonth() + 1).toString().padStart(2, "0"); + const d = now.getDate().toString().padStart(2, "0"); + return `${y}-${m}-${d}`; +} + +let original: string; + +test.beforeEach(async () => { + original = await readFile(CHANGELOG_PATH, "utf8"); +}); + +test.afterEach(async () => { + await writeFile(CHANGELOG_PATH, original); +}); + +test("cutting a release removes the Unreleased heading from the file", async ({ + page, +}) => { + await writeFile(CHANGELOG_PATH, WITH_UNRELEASED); + + await page.goto("/changelog"); + await page.locator("#version-editor").fill("9.9.10"); + await page.getByRole("button", { name: /^cut release$/i }).click(); + + await expect( + page.getByRole("status").filter({ hasText: "Cut release 9.9.10." }), + ).toBeVisible(); + + const after = await readFile(CHANGELOG_PATH, "utf8"); + expect(after).toContain(`## [9.9.10] - ${todayISO()}`); + expect(after).not.toMatch(/^##\s+\[Unreleased\]/im); + expect(after).toContain("## [9.9.9] - 2024-01-01"); + expect(after).toContain("- test bullet for cut-release spec"); +}); + +test("form disables after a successful cut on reload", async ({ page }) => { + await writeFile(CHANGELOG_PATH, WITH_UNRELEASED); + + await page.goto("/changelog"); + await page.locator("#version-editor").fill("9.9.10"); + await page.getByRole("button", { name: /^cut release$/i }).click(); + await expect( + page.getByRole("status").filter({ hasText: "Cut release 9.9.10." }), + ).toBeVisible(); + + await page.goto("/changelog"); + await expect(page.locator("#version-editor")).toBeDisabled(); + await expect( + page.getByRole("button", { name: /^cut release$/i }), + ).toBeDisabled(); + await expect( + page.getByText("Nothing pending under [Unreleased] yet."), + ).toBeVisible(); +}); + +test("form is disabled when the file has no Unreleased heading", async ({ + page, +}) => { + await writeFile(CHANGELOG_PATH, WITHOUT_UNRELEASED); + + await page.goto("/changelog"); + await expect(page.locator("#version-editor")).toBeDisabled(); + await expect( + page.getByRole("button", { name: /^cut release$/i }), + ).toBeDisabled(); + await expect( + page.getByText("Nothing pending under [Unreleased] yet."), + ).toBeVisible(); +}); diff --git a/export/CHANGELOG.md b/export/CHANGELOG.md @@ -1,7 +1,5 @@ # Changelog -## [Unreleased] - ## [0.2.0] - 2026-05-22 - **Composable layered search.** The single search bar is now a query builder: combine any number of layers with AND / OR / NOT and arbitrary nesting, each layer scoped to transcripts, live chat, or title/channel. Matches from every layer surface in the result list with a per-layer colour swatch. Editing one layer doesn't re-run the others, so deep nests stay fast. Simple one-keyword search still looks like a single input — the builder collapses to compact mode when there's only one layer. Legacy `?q=&m=&re=` share-links auto-migrate to a one-layer tree. - **Query-builder controls.** A "Reset layers" button collapses the builder back to one empty transcripts leaf. An "Unwrap" button on every non-root group flattens its children into the parent; if the group had NOT set, the promoted children inherit a flipped NOT so the meaning of the subtree doesn't silently change. The "slow / medium / fast" cost badges next to each scope dropdown have been removed — they read as a warning on the primary mode (transcripts) without giving you anything to do about it.