Probe tagged-union ListTags shape + surface raw bodies on miss
read/ListTags with an empty body was returning something we couldn't
parse, so every tag lookup silently missed and the CreateTag duplicate
fallback dead-ended with no diagnostic.
Now the tag lookup tries two request styles in order — the per-endpoint
`read/ListTags {}` used by the rest of this file, then the tagged-union
`read {type: "ListTags", params: {}}` used by mbecker20/komodo's
canonical API. If both fail to yield a match, both raw response bodies
get logged so the actual Komodo shape is diagnosable on the next run
without another commit-and-deploy cycle.
This commit is contained in:
@@ -548,27 +548,55 @@ function unwrapTagList(body: unknown): unknown[] {
|
||||
return [];
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetch the tag list from Komodo. Two request styles are attempted in order:
|
||||
*
|
||||
* 1. `POST /read/ListTags` with an empty body — the per-endpoint style
|
||||
* already used by the rest of this file (see execute/RestartDeployment).
|
||||
* 2. `POST /read` with `{type: "ListTags", params: {}}` — the tagged-union
|
||||
* style used by mbecker20/komodo's canonical API. If your Komodo build
|
||||
* wires up only the tagged-union path, style #1 returns something we
|
||||
* can't parse (empty array or non-tag payload) and we fall through.
|
||||
*
|
||||
* The winning parsed list is returned. The raw response bodies get logged
|
||||
* only when both attempts fail to yield a match, so a fresh Komodo API shape
|
||||
* is diagnosable without spamming stderr on the happy path.
|
||||
*/
|
||||
async function fetchTagsWithFallback(): Promise<{ tags: unknown[]; rawBodies: string[] }> {
|
||||
const attempts: Array<{ path: string; body: unknown }> = [
|
||||
{ path: 'read/ListTags', body: {} },
|
||||
{ path: 'read', body: { type: 'ListTags', params: {} } }
|
||||
];
|
||||
const rawBodies: string[] = [];
|
||||
for (const attempt of attempts) {
|
||||
let res: Response;
|
||||
try {
|
||||
res = await komodoCall(attempt.path, attempt.body);
|
||||
} catch (err) {
|
||||
rawBodies.push(`${attempt.path}: network error — ${(err as Error).message}`);
|
||||
continue;
|
||||
}
|
||||
if (!res.ok) {
|
||||
const snippet = await res.text().catch(() => '');
|
||||
rawBodies.push(`${attempt.path}: HTTP ${res.status}${snippet ? ` — ${truncate(snippet)}` : ''}`);
|
||||
continue;
|
||||
}
|
||||
const raw = await res.text().catch(() => '');
|
||||
rawBodies.push(`${attempt.path}: ${truncate(raw)}`);
|
||||
let parsed: unknown;
|
||||
try {
|
||||
parsed = JSON.parse(raw);
|
||||
} catch {
|
||||
continue;
|
||||
}
|
||||
const tags = unwrapTagList(parsed);
|
||||
if (tags.length > 0) return { tags, rawBodies };
|
||||
}
|
||||
return { tags: [], rawBodies };
|
||||
}
|
||||
|
||||
async function findTagByName(name: string): Promise<KomodoTagResult | null> {
|
||||
let listRes: Response;
|
||||
try {
|
||||
listRes = await komodoCall('read/ListTags', {});
|
||||
} catch (err) {
|
||||
console.warn(`[komodoEnsureTag] ListTags network failure for "${name}":`, (err as Error).message);
|
||||
return null;
|
||||
}
|
||||
if (!listRes.ok) {
|
||||
const snippet = await listRes.text().catch(() => '');
|
||||
console.warn(`[komodoEnsureTag] ListTags HTTP ${listRes.status} for "${name}"${snippet ? `: ${truncate(snippet)}` : ''}`);
|
||||
return null;
|
||||
}
|
||||
let body: unknown;
|
||||
try {
|
||||
body = await listRes.json();
|
||||
} catch (err) {
|
||||
console.warn(`[komodoEnsureTag] ListTags non-JSON body for "${name}":`, (err as Error).message);
|
||||
return null;
|
||||
}
|
||||
const tags = unwrapTagList(body);
|
||||
const { tags, rawBodies } = await fetchTagsWithFallback();
|
||||
for (const t of tags) {
|
||||
if (!t || typeof t !== 'object') continue;
|
||||
const tagName = (t as { name?: unknown }).name;
|
||||
@@ -576,6 +604,11 @@ async function findTagByName(name: string): Promise<KomodoTagResult | null> {
|
||||
const id = extractTagId(t);
|
||||
if (id) return { ok: true, id };
|
||||
}
|
||||
// Miss — dump the raw bodies so the next iteration knows the real shape.
|
||||
console.warn(
|
||||
`[komodoEnsureTag] no matchable tag "${name}" in any ListTags variant. Bodies:\n ` +
|
||||
rawBodies.join('\n ')
|
||||
);
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user