Skip to content

[Bugfix #749][Bugfix #750] Fix Gitea forge crash and field normalization#768

Merged
waleedkadous merged 5 commits into
mainfrom
builder/bugfix-749
May 19, 2026
Merged

[Bugfix #749][Bugfix #750] Fix Gitea forge crash and field normalization#768
waleedkadous merged 5 commits into
mainfrom
builder/bugfix-749

Conversation

@waleedkadous
Copy link
Copy Markdown
Contributor

Summary

Two tightly-coupled Gitea-forge regressions reported in v3.0.3 against a Forgejo instance, fixed together since the second was masked by the first (Tower 500'd before the rendering bug was visible).

#749labels.map is not a function 500 on Tower overview

Forgejo/Gitea returns labels: "" (or null) for unlabeled issues, where GitHub always returns []. parseLabelDefaults() in lib/github.ts called .map() unconditionally and crashed.

  • Coerce non-array inputs to [] before mapping: Array.isArray(labels) ? labels.map(...) : []
  • Widen the parameter type to Array<{name}> | null | undefined | string to reflect the actual cross-forge runtime shape (the project's forge-contracts already document presets as "best-effort" with non-conforming shapes treated as nulls; this lifts the contract into the type system at one call site)
  • Regression tests for empty-string, null, and undefined paths alongside the existing array (GitHub) path

#750#undefined / NaNd in Tower overview for Gitea

Once the 500 was patched, every backlog row rendered #undefined and ages showed NaNd because the Gitea preset scripts piped raw tea --output json straight to the overview, which expects the GitHub-compatible shape declared in forge-contracts.ts.

Each of the four affected scripts now requests an explicit --fields list and normalizes via jq:

tea field normalized to
index (string) number (int)
created createdAt
author (flat string) author.login
labels (CSV string or "") labels[].name
assignees (CSV string or "") assignees[].login
description body
  • recently-closed.sh: maps updatedclosedAt (Gitea has no closed_at field on list output; for issues edited after close this overestimates, acceptable for the 24h overview window)
  • recently-merged.sh: filters select(.merged == true) (same predicate scripts/forge/gitea/pr-exists.sh already uses) and maps updatedmergedAt, head.refheadRefName

jq is already a runtime dependency of the gitea preset (pr-exists.sh, user-identity.sh both use it) so this introduces no new tooling requirement.

Test plan

  • Run unit tests — pnpm exec vitest run src/__tests__/github.test.ts → 55/55 pass (4 new regression cases)
  • Typecheck — pnpm exec tsc --noEmit clean
  • Validate jq filters offline with synthetic tea-shaped fixtures (empty-string labels, CSV labels, merged-vs-closed PRs) — output matches IssueListItem / PrListItem shapes in forge-contracts.ts
  • Forgejo round-trip — verified by report reproducer; requires the original reporter or a Gitea instance for end-to-end Tower overview check
  • CMAP review (will run next)

Fixes #749
Fixes #750

Two tightly-coupled Gitea-forge regressions reported in v3.0.3:

#749 — parseLabelDefaults() crashed with `labels.map is not a function`,
500ing the Tower overview when Forgejo returned `labels: ""` (or null) for
unlabeled issues. Coerce non-array inputs to [] so the array methods can't
throw. Added regression tests exercising the empty-string, null, and
undefined paths alongside the existing array (GitHub) path.

#750 — Tower showed `#undefined` / `NaNd` because the Gitea preset scripts
piped raw `tea` JSON straight to the overview, which expects the
GitHub-compatible shape declared in forge-contracts.ts. Each script now
requests an explicit `--fields` list and normalizes via jq:
  index (string)   -> number (int)
  created          -> createdAt
  author (string)  -> author.login
  labels    (CSV)  -> labels[].name
  assignees (CSV)  -> assignees[].login
  description      -> body
recently-closed maps `updated` -> `closedAt`; recently-merged filters by
`.merged == true` (same predicate gitea/pr-exists.sh already uses) and
maps `updated` -> `mergedAt`, `head.ref` -> `headRefName`.

Fixes #749
Fixes #750
The labels parameter type in parseLabelDefaults() was widened to accept
`string | null | undefined` as part of the #749 fix, so the @ts-expect-error
directives in the new regression tests no longer have anything to suppress.
Per Gemini CMAP cosmetic note.
@waleedkadous waleedkadous merged commit f644e7d into main May 19, 2026
6 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Gitea forge: issue/PR field names not normalized - Tower shows #undefined, NaNd Gitea Forge 500 Error Bug With Forgejo Instance

1 participant