From 4486c05b49aec6dcd7bc1ece93ca752d57b5405d Mon Sep 17 00:00:00 2001 From: Francisco Solla Date: Sun, 23 Aug 2026 15:13:48 -0300 Subject: [PATCH] =?UTF-8?q?fix(api):=20removeLabels=20idempotente=20?= =?UTF-8?q?=E2=80=94=20404=20em=20label=20ausente=20n=C3=A3o=20derruba=20o?= =?UTF-8?q?=20flip=20(dispatch=20re-run=20404'd=20no=20in-progress=20j?= =?UTF-8?q?=C3=A1=20removido)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- scripts/lib/github-api.mjs | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/scripts/lib/github-api.mjs b/scripts/lib/github-api.mjs index 2ae14a50..7be10d1e 100644 --- a/scripts/lib/github-api.mjs +++ b/scripts/lib/github-api.mjs @@ -88,7 +88,7 @@ export const createApi = ({ } } - const request = async (path, { method = 'GET', body, query } = {}) => { + const request = async (path, { method = 'GET', body, query, ignoreNotFound = false } = {}) => { const qs = query ? '?' + Object.entries(query) @@ -131,6 +131,7 @@ export const createApi = ({ } if (response.status === 404 && method === 'GET') return null if (!response.ok) { + if (ignoreNotFound && response.status === 404) return null throw new Error(`GitHub API ${method} ${path} → ${response.status}: ${text.slice(0, 400)}`) } if (!text) return null @@ -237,13 +238,19 @@ export const createApi = ({ body: { labels }, }), - /** Removes labels by NAME (GitHub DELETE is by label name). */ + /** + * Removes labels by NAME (GitHub DELETE is by label name). Idempotent: + * removing an already-absent label (404) is the desired end state — a + * re-run of the flip/recovery path must not fail (live finding OPS46-S1, + * dispatch re-run after a manual flip 404'd on `in-progress`). + */ removeLabels: async (number, labels) => { for (const label of labels) { await request( `/repos/${owner}/${name}/issues/${number}/labels/${encodeURIComponent(label)}`, { method: 'DELETE', + ignoreNotFound: true, }, ) }