Files
maxinflection 16b1dd0a71 feat(gitlab): sync issue dependency links on push (#4294)
* feat(gitlab): sync issue dependency links on push

After issue content syncs, mirror local beads dependency edges as GitLab
issue links: blocks -> GitLab blocks/is_blocked_by (direction-normalized),
related/relates-to -> a single relates_to link per unordered pair (deduped).
Children of synced epics also keep the epic's milestone during a
dependency-only sync. Reports links_pushed in --json.

Additive only (never deletes remote links). License-aware: blocks/
is_blocked_by needs GitLab Premium/Ultimate; on instances without it the
link is reported as a single curated, non-fatal message (links_license_skipped
in JSON) while relates_to and milestones still apply. Genuine (non-license)
link failures remain real warnings, kept distinct from the license case.

Feature: max-efe

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* refactor(gitlab): address review — drop dead RelationMap, add push link parity

Follow-up to maphew's review on #4294.

- Delete the dead GitLab RelationMap: issueLinksToDependencies maps link
  types via hardcoded constants and ignores MappingConfig, so the field, its
  default, and the test assertion were dead config surface implying a
  configurability that does not exist. (Linear's RelationMap is untouched.)

- Give `bd gitlab push` dependency-link + epic-milestone parity with
  `bd gitlab sync`: extract the shared pushGitLabDependencyLinks helper from
  runGitLabSync's inline block and call it from runGitLabPush, scoped to the
  requested IssueIDs. Render push output natively so the link pass runs
  before the summary, dry-run ordering is correct, and the --json payload
  carries links_pushed / links_license_skipped / milestones_updated, matching
  sync in all output modes; also guard OnMessage under !jsonOutput.

Reviewed with /code-review + /codex (dry-run "Synced" line, output ordering,
and --json link-stat omission all caught and fixed here).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* fix(gitlab): check outputJSON error in runGitLabSync (errcheck)

CI lint (first run on this branch, only-new-issues=false) flagged the
unchecked outputJSON return in the sync --json path. Return it, matching
runGitLabPush. Fixes the Lint / Build Artifacts / PR Lint failures.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* fix(gitlab): carry closed state on push; surface failed-close in sync result

GitLab's POST /issues (and milestone/work-item creation) cannot set state,
so closed beads were pushed as opened issues and closed epics as active
milestones — milestone progress read 0/X even when all children were done.

- Close after create on all three paths (CreateIssue, createMilestone,
  createTaskWorkItem) via a best-effort follow-up state_event=close.
- BeadsIssueToGitLabFields emits state_event close/reopen so the update path
  flips both directions (reopening a bead reopens the GitLab issue). deferred
  stays open — only "done" work counts toward milestone completion.
- A failed best-effort close now records a warning on TrackerIssue.Warnings,
  which the engine drains into the sync result (visible in --json) instead of
  a bare stderr print that left --json reporting errors:0 while the issue was
  left open.

On close failure the created issue and its external_ref are still returned so
the next push doesn't create a duplicate (the push skip-guard means it won't
retry the close until the bead is next modified — hence the surfaced warning).

Reviewed via /code-review + Codex.

bd: max-9t6

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-08 08:00:41 -07:00
..