fix(wall): every entry carries an https permalink — the product engine links its public package page; null refused, an unknown product refuses by name
This commit is contained in:
parent
adcb883e67
commit
97b5ea2d5d
2 changed files with 29 additions and 14 deletions
|
|
@ -73,13 +73,14 @@ const ENTRY_OPTIONAL_KEYS = ['thumb']
|
|||
const ENTRY_ALLOWED_KEYS = [...ENTRY_REQUIRED_KEYS, ...ENTRY_OPTIONAL_KEYS]
|
||||
const FILE_KEYS = ['product', 'entries']
|
||||
|
||||
// The public release-page URL pattern, by product — only products with a
|
||||
// PUBLIC forge repo get a derived link. A product without an entry here
|
||||
// (e.g. "brainy", whose repo is private) gets url: null, matching every
|
||||
// entry the fleet has shipped for it so far — a private link would 404 for
|
||||
// anyone reading the public HQ page.
|
||||
// The public permalink pattern, by product. Every entry MUST carry an https
|
||||
// permalink: HQ's parser rejects a wall whose entries carry url: null (the
|
||||
// whole feed became unreadable on 2026-09-02). A product whose forge repo is
|
||||
// private links its PUBLIC package page on The Source instead of a release
|
||||
// page that would 404 for HQ's readers.
|
||||
const RELEASE_URL_PATTERNS = {
|
||||
'open-brainy': (version) => `https://source.soulcraft.com/soulcraftlabs/open-brainy/releases/tag/v${version}`,
|
||||
'brainy': (version) => `https://source.soulcraft.com/soulcraft/-/packages/npm/@soulcraft%2Fbrainy/${version}`,
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -203,8 +204,8 @@ function validateShape(data) {
|
|||
if (!Array.isArray(entry.items) || entry.items.length === 0 || entry.items.some((it) => typeof it !== 'string' || it.trim() === '')) {
|
||||
errors.push(`${label}: "items" must be a non-empty array of non-empty strings`)
|
||||
}
|
||||
if (!(entry.url === null || typeof entry.url === 'string')) {
|
||||
errors.push(`${label}: "url" must be a string or null`)
|
||||
if (typeof entry.url !== 'string' || !/^https:\/\/\S+$/.test(entry.url)) {
|
||||
errors.push(`${label}: "url" must be an https permalink — never null; HQ's parser rejects the whole feed`)
|
||||
}
|
||||
if ('thumb' in entry && !(entry.thumb === null || typeof entry.thumb === 'string')) {
|
||||
errors.push(`${label}: "thumb" must be a string or null when present`)
|
||||
|
|
@ -274,8 +275,8 @@ function extractChangelogBullets(changelog, version) {
|
|||
|
||||
/**
|
||||
* Derive a wall entry from a CHANGELOG.md.
|
||||
* @param {{product: string, version: string, date: string, changelogPath: string, url?: string | null, thumb?: string | null}} opts
|
||||
* @returns {{version: string, date: string, headline: string, items: string[], url: string | null, thumb: string | null}}
|
||||
* @param {{product: string, version: string, date: string, changelogPath: string, url?: string, thumb?: string | null}} opts
|
||||
* @returns {{version: string, date: string, headline: string, items: string[], url: string, thumb: string | null}}
|
||||
*/
|
||||
function deriveEntry({ product, version, date, changelogPath, url, thumb }) {
|
||||
if (!parseSemver(version)) fail(`--version "${version}" is not a semver string`)
|
||||
|
|
@ -288,7 +289,11 @@ function deriveEntry({ product, version, date, changelogPath, url, thumb }) {
|
|||
const items = extractChangelogBullets(changelog, version)
|
||||
const headline = items[0]
|
||||
|
||||
const resolvedUrl = url !== undefined ? url : (RELEASE_URL_PATTERNS[product]?.(version) ?? null)
|
||||
const pattern = RELEASE_URL_PATTERNS[product]
|
||||
if (url === undefined && pattern === undefined) {
|
||||
throw new Error(`wall-entry: no permalink pattern for product "${product}" — add one to RELEASE_URL_PATTERNS or pass --url; entries never carry url: null`)
|
||||
}
|
||||
const resolvedUrl = url !== undefined ? url : pattern(version)
|
||||
const resolvedThumb = thumb !== undefined ? thumb : null
|
||||
|
||||
return { version, date, headline, items, url: resolvedUrl, thumb: resolvedThumb }
|
||||
|
|
@ -382,7 +387,7 @@ function ensureReleasesClone(remote, cacheDir) {
|
|||
* existing entry for the same version (idempotent re-runs), validating
|
||||
* before and after, committing, and pushing — or refusing loudly, naming
|
||||
* the cure, at whichever step fails.
|
||||
* @param {{version: string, date: string, headline: string, items: string[], url: string | null, thumb: string | null}} entry
|
||||
* @param {{version: string, date: string, headline: string, items: string[], url: string, thumb: string | null}} entry
|
||||
* @param {string} product
|
||||
* @param {string} remote
|
||||
* @param {string} cacheDir
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue