b967d82d724e
delete a repo's kept tarballs from the bucket on its admin page (v3.0.146)
- time
- 2026-09-30 13:54 UTC · 1 week ago
- machine
- Junes-MacBook-Pro.local
- agent
- claude-opus-5-5
- session
- admin repo settings
- parent
- 02702253e7ae
↓ kepr-b967d82d.tar.gzatlas at this save
files changed3 files
package.json+1 −1src/admin/repos.ts+19 −0tests/repoworkspace.test.ts+16 −0package.json+1 −1
@@ -1,6 +1,6 @@11 {22 "name": "kepr",3- "version": "3.0.145",3+ "version": "3.0.146",44 "private": true,55 "type": "module",66 "scripts": {src/admin/repos.ts+19 −0
@@ -15,6 +15,7 @@1515 visibleReleases,1616 } from "../releases/releases.ts";1717 import { type RepoText, repoText, setRepoText } from "../server/db.ts";18+import { dropTarballs } from "../tarball/cache.ts";1819 import { type AdminContext, adminPage, formField, notice, textFields } from "./console.ts";1920 import { type AdminRepo, allRepos, findRepo, type RepoEdit, updateRepo } from "./store.ts";2021 import { LIMITS } from "./text.ts";@@ -105,6 +106,18 @@105106 );106107 });107108 109+ app.post("/admin/repos/:repo/tarballs/delete", async (c) => {110+ const repo = findRepo(ctx.kepr, c.req.param("repo"));111+ if (!repo) return c.notFound();112+ try {113+ await dropTarballs(ctx.sync.bucket, repo.name);114+ } catch (error) {115+ if (!(error instanceof BucketWriteError)) throw error;116+ return c.html(reposPage(c, ctx, `${repo.name}: ${error.message}`, repo.name), 503);117+ }118+ return c.redirect(`/admin/repos?repo=${repo.name}&saved=1#repo-editor`, 303);119+ });120+108121 app.post("/admin/releases/:repo/:version/delete", async (c) => {109122 const found = findRelease(ctx, c.req.param("repo"), c.req.param("version"));110123 if (!found) return c.notFound();@@ -227,6 +240,12 @@227240 html`<section class="repo-section" id="builds"><h2 class="section-label mono">builds</h2>228241 ${releases.map((release) => releaseForm(c, repo.name, release))}</section>`229242 }243+<section class="repo-section"><h2 class="section-label mono">archives</h2>244+<form class="issues-form" method="post" action="/admin/repos/${repo.name}/tarballs/delete">245+${formField(c)}246+<p class="issue-meta mono">Tarballs are kept in the bucket once downloaded, and rebuilt on the next download.</p>247+<button class="issues-submit" type="submit">delete kept tarballs</button>248+</form></section>230249 </article>`;231250 }232251 tests/repoworkspace.test.ts+16 −0
@@ -13,6 +13,7 @@1313 describe("the selected repo's workspace (§24)", () => {1414 let inst: Instance;1515 let browser: Browser;16+ let bucketDir: string;1617 const workspace = async () => (await browser.get("/admin/repos?repo=app")).text();1718 const save = (fields: Record<string, string>) =>1819 browser.post("/admin/repos/app", { public: "1", ...fields });@@ -32,6 +33,7 @@3233 files: [{ platform: "linux-x86_64", name: "app", bytes: new Uint8Array([1]) }],3334 });3435 }36+ bucketDir = repos.bucketDir;3537 inst = await instance(repos.bucketDir);3638 inst.kepr.run(3739 `INSERT INTO issues (repo, number, title, body, type, filed_at)@@ -117,6 +119,20 @@117119 expect(await response.text()).toContain(error);118120 }119121 expect(await workspace()).not.toContain('value="Zig');122+ });123+124+ test("deletes the repo's kept tarballs from the bucket", async () => {125+ await save({});126+ const head = (await inst.app.request("/app/archive/HEAD.tar.gz")).headers.get("location");127+ expect((await inst.app.request(head ?? "")).status).toBe(200);128+ const kept = new Bun.Glob("**/*.tar.gz");129+ const keptIn = () => Array.fromAsync(kept.scan(join(bucketDir, ".kepr", "tarballs", "app")));130+ expect(await keptIn()).toHaveLength(1);131+ expect(await workspace()).toContain('action="/admin/repos/app/tarballs/delete"');132+ const deleted = await browser.post("/admin/repos/app/tarballs/delete", {});133+ expect(deleted.headers.get("location")).toBe("/admin/repos?repo=app&saved=1#repo-editor");134+ expect(await keptIn()).toEqual([]);135+ expect((await inst.app.request(head ?? "")).status).toBe(200);120136 });121137 });122138