gabriel / musehub public
feat patch dev-tools task/186-publish-issue-tool #1 / 1
AI Agent gabriel · 2 days ago · Sep 10, 2026 · Diff

feat(dev-tools): one-way, on-demand staging→production ticket publish (#186)

Adds scripts/dev/publish_issue.py + publish-issue.sh: copies a single staging issue's current title/body/labels to the production repo so tickets can be shared on social without pointing people at staging infrastructure.

Deliberately one-way and on-demand, not a tracker sync — this same session found a phantom-success write bug and an issue-numbering collision in staging's own issue tracking (#182/#183/#184); an always-on bidirectional mirror on top of that would just add a second place for that bug class to bite. Idempotent via a stable body marker (`_Mirrored from staging#<n>._`): re-publishing the same staging issue updates the existing production mirror in place instead of duplicating it. Warns (does not block) when the source body contains a staging.musehub.ai URL, so it can be reviewed before going public.

Core logic tested against an in-memory fake HubClient (6 tests, all passing) — no real muse hub calls or network access needed for the test suite. Real CLI wiring (MuseHubCliClient) shells out to `muse hub issue read/list/ create/update/label` and is exercised manually, not in the test suite.

sha256:7ab354833d0210a676c81cc3181984ba8898e914d39b10192bcd7c76f1584efd sha
+50 symbols
3 changed · 1071 in snapshot files
sha256:31f52cf48e672a168e3320bac3d546d074df986a3b8ffc6e0d8b977430a94a7e snapshot
+50
symbols added
3
files changed
1071
files in snapshot
0
dead code introduced
Semantic Changes 50 symbols
+ docs/
+ src/
+ tests/
+ tools/
~ scripts/dev/publish_issue.py .py 27 symbols added
+ DEFAULT_PRODUCTION_HUB variable variable DEFAULT_PRODUCTION_HUB L32–32
+ DEFAULT_STAGING_HUB variable variable DEFAULT_STAGING_HUB L31–31
+ HubClient class class HubClient L44–49
+ create_issue method method create_issue L47–47
+ list_issues method method list_issues L46–46
+ read_issue method method read_issue L45–45
+ set_labels method method set_labels L49–49
+ update_issue method method update_issue L48–48
+ MuseHubCliClient class class MuseHubCliClient L52–84
+ _run method method _run L55–61
+ create_issue method method create_issue L69–73
+ list_issues method method list_issues L66–67
+ read_issue method method read_issue L63–64
+ set_labels method method set_labels L81–84
+ update_issue method method update_issue L75–79
+ _STAGING_URL_RE variable variable _STAGING_URL_RE L29–29
+ build_mirror_marker function function build_mirror_marker L35–41
+ find_existing_mirror function function find_existing_mirror L87–92
+ Protocol import import Protocol L27–27
+ annotations import import annotations L20–20
+ argparse import import argparse L22–22
+ json import import json L23–23
+ re import import re L24–24
+ subprocess import import subprocess L25–25
+ sys import import sys L26–26
+ main function function main L131–152
+ publish_issue function function publish_issue L95–128
~ tests/test_publish_issue.py .py 23 symbols added
+ FakeHubClient class class FakeHubClient L19–56
+ __init__ method method __init__ L22–24
+ create_issue method method create_issue L39–47
+ list_issues method method list_issues L36–37
+ read_issue method method read_issue L33–34
+ seed method method seed L26–31
+ set_labels method method set_labels L55–56
+ update_issue method method update_issue L49–53
+ PRODUCTION_HUB variable variable PRODUCTION_HUB L16–16
+ STAGING_HUB variable variable STAGING_HUB L15–15
+ TestPublishIssue class class TestPublishIssue L64–122
+ test_clean_body_has_no_warnings method method test_clean_body_has_no_warnings L113–118
+ test_different_staging_issues_produce_separate_production_issues method method test_different_staging_issues_produce_separate_production_issues L93–100
+ test_fresh_publish_creates_exactly_one_production_issue method method test_fresh_publish_creates_exactly_one_production_issue L65–76
+ test_mirror_marker_is_stable_per_staging_number method method test_mirror_marker_is_stable_per_staging_number L120–122
+ test_republishing_same_staging_issue_updates_rather_than_duplicates method method test_republishing_same_staging_issue_updates_rather_than_duplicates L78–91
+ test_staging_url_in_body_triggers_warning method method test_staging_url_in_body_triggers_warning L102–111
+ client function function client L60–61
+ Path import import Path L8–8
+ build_mirror_marker import import build_mirror_marker L13–13
+ publish_issue import import publish_issue L13–13
+ pytest import import pytest L10–10
+ sys import import sys L7–7
Files Changed
+3
1071 in snapshot
← Older Oldest on task/186-publish-issue-tool
All commits
Newer → Latest on task/186-publish-issue-tool

0 comments

No comments yet. Be the first to start the discussion.

To add a comment, use the Muse CLI: muse hub commit comment sha256:7ab354833d0210a676c81cc3181984ba8898e914d39b10192bcd7c76f1584efd --body "your comment"