Push auto-release tags as renovate-bot so release.yml fires, and give the Docker Hub page its short description
CI / full-gate (push) Successful in 3m20s
CI / full-gate (push) Successful in 3m20s
This commit is contained in:
@@ -0,0 +1,10 @@
|
||||
import assert from "node:assert/strict";
|
||||
import { readFileSync } from "node:fs";
|
||||
import { test } from "node:test";
|
||||
|
||||
test("auto-release's checkout persists no credentials, so the tag push authenticates as renovate-bot", () => {
|
||||
const workflow = readFileSync(".gitea/workflows/renovate.yml", "utf8");
|
||||
const job = workflow.slice(workflow.indexOf("\n auto-release:"));
|
||||
const checkout = job.slice(job.indexOf("actions/checkout@"), job.indexOf("\n - name:"));
|
||||
assert.match(checkout, /^\s+persist-credentials: false$/m);
|
||||
});
|
||||
@@ -1,7 +1,7 @@
|
||||
import assert from "node:assert/strict";
|
||||
import { readFileSync } from "node:fs";
|
||||
import { test } from "node:test";
|
||||
import { jwtFrom, leftoverPlaceholders, renderOverview } from "./dockerhub-overview.ts";
|
||||
import { DESCRIPTION, jwtFrom, leftoverPlaceholders, renderOverview } from "./dockerhub-overview.ts";
|
||||
|
||||
const TEMPLATE = "release-tooling/dockerhub-overview.md.tmpl";
|
||||
const template = () => readFileSync(TEMPLATE, "utf8");
|
||||
@@ -46,3 +46,24 @@ test("jwtFrom accepts only a non-empty string token, never throwing on a hostile
|
||||
assert.equal(jwtFrom({ token: "" }), null);
|
||||
assert.equal(jwtFrom({ token: 42 }), null);
|
||||
});
|
||||
|
||||
test("the short description opens a README sentence and fits Docker Hub's 100 characters", () => {
|
||||
const readme = readFileSync("README.md", "utf8").replaceAll("**", "");
|
||||
assert.ok(DESCRIPTION.length <= 100, `${DESCRIPTION.length} characters`);
|
||||
const escaped = DESCRIPTION.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
||||
assert.match(readme, new RegExp(`^${escaped}(?=[\\s.:,])`, "m"));
|
||||
});
|
||||
|
||||
test("every command the overview shows, the README shows too", () => {
|
||||
const commands = (source: string) =>
|
||||
[...source.matchAll(/```bash\n(.*?)```/gs)].flatMap((block) =>
|
||||
(block[1] ?? "")
|
||||
.split("\n")
|
||||
.map((line) => (line.split(" #")[0] ?? "").trim().replace(/larvit\/plainpages:\S+/g, "larvit/plainpages:X.Y.Z"))
|
||||
.filter((line) => line !== ""),
|
||||
);
|
||||
const shown = new Set(commands(readFileSync("README.md", "utf8")));
|
||||
const published = commands(template());
|
||||
assert.ok(published.length > 0, `${TEMPLATE} should show commands`);
|
||||
for (const command of published) assert.ok(shown.has(command), `${TEMPLATE} runs ${command}, which README.md doesn't show`);
|
||||
});
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
// Publishes the Docker Hub repository overview from dockerhub-overview.md.tmpl, rendering
|
||||
// `{{VERSION}}` to the release being published.
|
||||
// `{{VERSION}}` to the release being published, and the short description.
|
||||
|
||||
import { readFileSync } from "node:fs";
|
||||
import { join } from "node:path";
|
||||
@@ -8,6 +8,8 @@ const HUB = "https://hub.docker.com/v2";
|
||||
const TIMEOUT_MS = 30_000;
|
||||
const VERSION = /^\d+\.\d+\.\d+$/;
|
||||
|
||||
export const DESCRIPTION = "A self-hostable foundation for server-rendered web applications";
|
||||
|
||||
export function renderOverview(source: string, version: string): string {
|
||||
return source.replaceAll("{{VERSION}}", version);
|
||||
}
|
||||
@@ -81,21 +83,21 @@ async function main(): Promise<number> {
|
||||
if (!jwt) return fail("Docker Hub login returned no token");
|
||||
|
||||
const res = await post(`${HUB}/repositories/${repo}/`, {
|
||||
body: JSON.stringify({ full_description: body }),
|
||||
body: JSON.stringify({ description: DESCRIPTION, full_description: body }),
|
||||
headers: { authorization: `Bearer ${jwt}`, "content-type": "application/json" },
|
||||
method: "PATCH",
|
||||
});
|
||||
if ("error" in res) return fail(`Docker Hub unreachable: ${res.error}`);
|
||||
if (!res.ok) {
|
||||
return fail(
|
||||
`Docker Hub overview PATCH failed: ${res.status} ${res.text}` +
|
||||
`Docker Hub description and overview PATCH failed: ${res.status} ${res.text}` +
|
||||
(res.status === 403
|
||||
? "\n403 means DOCKERHUB_TOKEN lacks the delete scope — editing the overview needs " +
|
||||
"read/write/delete, which pushing images alone does not (README -> CI/CD)."
|
||||
: ""),
|
||||
);
|
||||
}
|
||||
process.stdout.write(`Docker Hub overview updated for ${repo} at ${version}\n`);
|
||||
process.stdout.write(`Docker Hub description and overview updated for ${repo} at ${version}\n`);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user