@@ -95,6 +95,11 @@ def api_post(
9595 params : dict [str , Any ] | None = None ,
9696 ) -> Any :
9797 if url .endswith ("/pulls" ):
98+ head_user , head_ref = (
99+ json ["head" ].split (":" , 1 )
100+ if ":" in json ["head" ]
101+ else ("toktok-releaser" , json ["head" ])
102+ )
98103 pr = {
99104 "title" : json ["title" ],
100105 "body" : json ["body" ],
@@ -104,7 +109,11 @@ def api_post(
104109 "node_id" : f"node{ len (self ._prs )} " ,
105110 "html_url" : f"url{ len (self ._prs )} " ,
106111 "state" : "open" ,
107- "head" : {"sha" : "sha123" , "ref" : json ["head" ]},
112+ "head" : {
113+ "sha" : "sha123" ,
114+ "ref" : head_ref ,
115+ "user" : {"login" : head_user },
116+ },
108117 "milestone" : None ,
109118 "draft" : json .get ("draft" , False ),
110119 "merged_at" : None ,
@@ -123,6 +132,7 @@ def api_post(
123132 "prerelease" : json ["prerelease" ],
124133 "draft" : json ["draft" ],
125134 "published_at" : None ,
135+ "html_url" : f"https://github.com/TokTok/ci-tools/releases/edit/{ json ['tag_name' ]} " ,
126136 }
127137 self ._releases .append (release )
128138 return release
@@ -217,7 +227,8 @@ def find_pr_for_branch(
217227 ) -> github .PullRequest | None :
218228 for pr_data in self ._prs :
219229 if pr_data ["state" ] == state or state == "all" :
220- if pr_data ["head" ]["ref" ] == head .split (":" )[- 1 ]:
230+ pr_head = f"{ pr_data ['head' ]['user' ]['login' ]} :{ pr_data ['head' ]['ref' ]} "
231+ if pr_head == head :
221232 return github .PullRequest .fromJSON (pr_data )
222233 return None
223234
@@ -312,7 +323,7 @@ def checkout(self, name: str) -> None:
312323 self ._current_branch = name
313324
314325 def owner (self , remote : str ) -> str :
315- return "bot "
326+ return "human "
316327
317328 def last_commit_message (self , branch : str ) -> str :
318329 return self ._log [- 1 ] if self ._log else ""
@@ -415,6 +426,7 @@ def test_full_release_lifecycle(self) -> None:
415426 "tag_name" : "v1.0.0" ,
416427 "published_at" : None ,
417428 "body" : "Existing draft notes" ,
429+ "html_url" : "https://github.com/TokTok/ci-tools/releases/edit/v1.0.0" ,
418430 }
419431 )
420432
@@ -487,11 +499,16 @@ def mock_action_runs(branch: str, sha: str) -> list[github.ActionRun]:
487499 pass
488500
489501 # Verify intermediate dashboard state
502+ self .assertIn ("[x] Create release branch and PR" , gh ._issues [1 ]["body" ])
490503 self .assertIn ("**Current Step: Finalize release**" , gh ._issues [1 ]["body" ])
491504 self .assertIn (
492505 "Action Required:** All checks passed and assets signed" ,
493506 gh ._issues [1 ]["body" ],
494507 )
508+ self .assertIn (
509+ "https://github.com/TokTok/ci-tools/releases/edit/v1.0.0" ,
510+ gh ._issues [1 ]["body" ],
511+ )
495512
496513 # Simulate user published release, re-assign bot, and re-run
497514 gh ._releases [0 ]["published_at" ] = "2026-02-06T00:00:00Z"
@@ -503,6 +520,41 @@ def mock_action_runs(branch: str, sha: str) -> list[github.ActionRun]:
503520 self .assertEqual (gh ._issues [1 ]["state" ], "closed" )
504521 self .assertIn ("[x] Finalize release" , gh ._issues [1 ]["body" ])
505522
523+ def test_mismatched_actor_and_owner (self ) -> None :
524+ """Verify that the dashboard works when actor and owner are different."""
525+ config = self .make_config ()
526+ gh = FakeGitHub ()
527+ gh ._user = {"login" : "releaser-bot" }
528+ gh .add_issue (
529+ 1 ,
530+ "Release tracking issue" ,
531+ "### Release notes\n Cool notes\n Production release" ,
532+ )
533+ gh .add_milestone (1 , "v1.0.0" )
534+
535+ gt = FakeGit ()
536+
537+ # Simulate owner being different from actor
538+ def mock_owner (remote : str ) -> str :
539+ return "TokTok"
540+
541+ setattr (gt , "owner" , mock_owner )
542+
543+ releaser = Releaser (config , gt , gh )
544+
545+ with self .release_mocks (gh , gt ):
546+ # We only care about the preparation stage for this test
547+ releaser .stage_init ()
548+ version = releaser .stage_version ()
549+ releaser .stage_branch (version )
550+ releaser .stage_pull_request (version )
551+ releaser .update_dashboard (version )
552+
553+ # Check that the checkbox is marked
554+ self .assertIn ("[x] Create release branch and PR" , gh ._issues [1 ]["body" ])
555+ # Verify the PR head in our fake storage
556+ self .assertEqual (gh ._prs [0 ]["head" ]["user" ]["login" ], "TokTok" )
557+
506558 def test_invalid_issue_title (self ) -> None :
507559 config = self .make_config ()
508560 gh = FakeGitHub ()
@@ -528,6 +580,7 @@ def test_prerelease_lifecycle(self) -> None:
528580 "published_at" : "2026-02-06T00:00:00Z" ,
529581 "prerelease" : True ,
530582 "draft" : False ,
583+ "html_url" : "https://github.com/TokTok/ci-tools/releases/edit/v1.0.0-rc.1" ,
531584 }
532585 )
533586
@@ -578,7 +631,11 @@ def test_existing_pr_update(self) -> None:
578631 "node_id" : "node555" ,
579632 "html_url" : "url555" ,
580633 "state" : "open" ,
581- "head" : {"sha" : "sha123" , "ref" : "release/v1.0.0" },
634+ "head" : {
635+ "sha" : "sha123" ,
636+ "ref" : "release/v1.0.0" ,
637+ "user" : {"login" : "human" },
638+ },
582639 "milestone" : {"number" : 1 },
583640 "draft" : True ,
584641 "merged_at" : None ,
@@ -660,6 +717,7 @@ def test_release_ci_failure(self) -> None:
660717 "tag_name" : "v1.0.0" ,
661718 "published_at" : None ,
662719 "body" : "Existing draft notes" ,
720+ "html_url" : "https://github.com/TokTok/ci-tools/releases/edit/v1.0.0" ,
663721 }
664722 )
665723
@@ -698,6 +756,7 @@ def test_release_ci_timeout(self) -> None:
698756 "tag_name" : "v1.0.0" ,
699757 "published_at" : None ,
700758 "body" : "Existing draft notes" ,
759+ "html_url" : "https://github.com/TokTok/ci-tools/releases/edit/v1.0.0" ,
701760 }
702761 )
703762
0 commit comments