mirror of
https://github.com/Sea-Haven-Industries/open-swe.git
synced 2026-10-05 17:42:12 +00:00
fix: include GitHub username in collaboration footer (#1374)
* fix: include GitHub username in collaboration footer Co-authored-by: Johannes du Plessis <51395795+johannes117@users.noreply.github.com> * fix: clarify legacy footer replacement Co-authored-by: Johannes du Plessis <51395795+johannes117@users.noreply.github.com> --------- Co-authored-by: open-swe[bot] <open-swe@users.noreply.github.com> Co-authored-by: Johannes du Plessis <51395795+johannes117@users.noreply.github.com>
This commit is contained in:
parent
7a9785c9d3
commit
111f00ea9a
3 changed files with 88 additions and 15 deletions
|
|
@ -368,10 +368,10 @@ This run was triggered by **{display_name}**. Credit them on every commit and PR
|
||||||
Co-authored-by: {commit_name} <{commit_email}>
|
Co-authored-by: {commit_name} <{commit_email}>
|
||||||
```
|
```
|
||||||
|
|
||||||
- **PR body**: append this line to the bottom of the PR description (separated from the body by a blank line) when you open or update the draft PR. Do not duplicate it if it is already present:
|
- **PR body**: append this line to the bottom of the PR description (separated from the body by a blank line) when you open or update the draft PR. Do not duplicate it if it is already present. If the PR body already contains the legacy footer `_Opened collaboratively by {display_name} and open-swe._`, replace that legacy footer with this line instead of appending a second footer:
|
||||||
|
|
||||||
```
|
```
|
||||||
_Opened collaboratively by {display_name} and open-swe._
|
_Opened collaboratively by {pr_attribution_name} and open-swe._
|
||||||
```
|
```
|
||||||
|
|
||||||
If you forget the trailer on a local commit that has not been pushed, fix it with `git commit --amend` before pushing — do not push without it. If the commit has already been pushed, leave it as-is and add the trailer to your next commit; never rewrite remote history to fix it."""
|
If you forget the trailer on a local commit that has not been pushed, fix it with `git commit --amend` before pushing — do not push without it. If the commit has already been pushed, leave it as-is and add the trailer to your next commit; never rewrite remote history to fix it."""
|
||||||
|
|
@ -384,6 +384,7 @@ def _render_collaboration_section(identity: CollaboratorIdentity | None) -> str:
|
||||||
display_name=identity.display_name,
|
display_name=identity.display_name,
|
||||||
commit_name=identity.commit_name,
|
commit_name=identity.commit_name,
|
||||||
commit_email=identity.commit_email,
|
commit_email=identity.commit_email,
|
||||||
|
pr_attribution_name=identity.pr_attribution_name,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -21,6 +21,14 @@ class CollaboratorIdentity:
|
||||||
display_name: str
|
display_name: str
|
||||||
commit_name: str
|
commit_name: str
|
||||||
commit_email: str
|
commit_email: str
|
||||||
|
github_login: str = ""
|
||||||
|
|
||||||
|
@property
|
||||||
|
def pr_attribution_name(self) -> str:
|
||||||
|
"""Display name with GitHub login when available."""
|
||||||
|
if self.github_login and self.github_login != self.display_name:
|
||||||
|
return f"{self.display_name} (@{self.github_login})"
|
||||||
|
return self.display_name
|
||||||
|
|
||||||
|
|
||||||
def _normalize_text(value: Any) -> str:
|
def _normalize_text(value: Any) -> str:
|
||||||
|
|
@ -70,6 +78,7 @@ def _identity_from_github_token(github_token: str | None) -> CollaboratorIdentit
|
||||||
display_name=display_name,
|
display_name=display_name,
|
||||||
commit_name=display_name,
|
commit_name=display_name,
|
||||||
commit_email=commit_email,
|
commit_email=commit_email,
|
||||||
|
github_login=login,
|
||||||
)
|
)
|
||||||
except httpx.HTTPError:
|
except httpx.HTTPError:
|
||||||
logger.debug("Failed to resolve GitHub user identity from token", exc_info=True)
|
logger.debug("Failed to resolve GitHub user identity from token", exc_info=True)
|
||||||
|
|
@ -78,6 +87,14 @@ def _identity_from_github_token(github_token: str | None) -> CollaboratorIdentit
|
||||||
|
|
||||||
def _identity_from_config(config: dict[str, Any]) -> CollaboratorIdentity | None:
|
def _identity_from_config(config: dict[str, Any]) -> CollaboratorIdentity | None:
|
||||||
configurable = config.get("configurable", {})
|
configurable = config.get("configurable", {})
|
||||||
|
slack_thread = configurable.get("slack_thread", {})
|
||||||
|
linear_issue = configurable.get("linear_issue", {})
|
||||||
|
|
||||||
|
display_name = (
|
||||||
|
_normalize_text(slack_thread.get("triggering_user_name"))
|
||||||
|
or _normalize_text(linear_issue.get("triggering_user_name"))
|
||||||
|
or _normalize_text(configurable.get("user_email")).split("@", 1)[0]
|
||||||
|
)
|
||||||
|
|
||||||
github_login = _normalize_text(configurable.get("github_login"))
|
github_login = _normalize_text(configurable.get("github_login"))
|
||||||
if github_login:
|
if github_login:
|
||||||
|
|
@ -88,20 +105,13 @@ def _identity_from_config(config: dict[str, Any]) -> CollaboratorIdentity | None
|
||||||
cached_email_for_login(github_login)
|
cached_email_for_login(github_login)
|
||||||
)
|
)
|
||||||
if commit_email:
|
if commit_email:
|
||||||
|
commit_name = display_name or github_login
|
||||||
return CollaboratorIdentity(
|
return CollaboratorIdentity(
|
||||||
display_name=github_login,
|
display_name=commit_name,
|
||||||
commit_name=github_login,
|
commit_name=commit_name,
|
||||||
commit_email=commit_email,
|
commit_email=commit_email,
|
||||||
|
github_login=github_login,
|
||||||
)
|
)
|
||||||
|
|
||||||
slack_thread = configurable.get("slack_thread", {})
|
|
||||||
linear_issue = configurable.get("linear_issue", {})
|
|
||||||
|
|
||||||
display_name = (
|
|
||||||
_normalize_text(slack_thread.get("triggering_user_name"))
|
|
||||||
or _normalize_text(linear_issue.get("triggering_user_name"))
|
|
||||||
or _normalize_text(configurable.get("user_email")).split("@", 1)[0]
|
|
||||||
)
|
|
||||||
commit_email = _normalize_text(configurable.get("user_email")) or _normalize_text(
|
commit_email = _normalize_text(configurable.get("user_email")) or _normalize_text(
|
||||||
slack_thread.get("triggering_user_email")
|
slack_thread.get("triggering_user_email")
|
||||||
)
|
)
|
||||||
|
|
@ -157,9 +167,12 @@ def add_pr_collaboration_note(
|
||||||
if not identity:
|
if not identity:
|
||||||
return normalized_body
|
return normalized_body
|
||||||
|
|
||||||
note = f"_Opened collaboratively by {identity.display_name} and open-swe._"
|
old_note = f"_Opened collaboratively by {identity.display_name} and open-swe._"
|
||||||
|
note = f"_Opened collaboratively by {identity.pr_attribution_name} and open-swe._"
|
||||||
if note in normalized_body:
|
if note in normalized_body:
|
||||||
return normalized_body
|
return normalized_body
|
||||||
|
if old_note in normalized_body:
|
||||||
|
return normalized_body.replace(old_note, note)
|
||||||
if not normalized_body:
|
if not normalized_body:
|
||||||
return note
|
return note
|
||||||
return f"{normalized_body}\n\n{note}"
|
return f"{normalized_body}\n\n{note}"
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,11 @@ from agent import webapp
|
||||||
from agent.dashboard.agent_overrides import profile_create_prs
|
from agent.dashboard.agent_overrides import profile_create_prs
|
||||||
from agent.prompt import construct_system_prompt
|
from agent.prompt import construct_system_prompt
|
||||||
from agent.utils import github_comments
|
from agent.utils import github_comments
|
||||||
from agent.utils.authorship import CollaboratorIdentity
|
from agent.utils.authorship import (
|
||||||
|
CollaboratorIdentity,
|
||||||
|
add_pr_collaboration_note,
|
||||||
|
resolve_triggering_user_identity,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
def test_build_pr_prompt_wraps_external_comments_without_trust_section() -> None:
|
def test_build_pr_prompt_wraps_external_comments_without_trust_section() -> None:
|
||||||
|
|
@ -96,6 +100,61 @@ def test_construct_system_prompt_includes_coauthor_trailer_when_identity_present
|
||||||
assert "_Opened collaboratively by octocat and open-swe._" in prompt
|
assert "_Opened collaboratively by octocat and open-swe._" in prompt
|
||||||
|
|
||||||
|
|
||||||
|
def test_construct_system_prompt_includes_github_login_in_pr_footer() -> None:
|
||||||
|
identity = CollaboratorIdentity(
|
||||||
|
display_name="Mona Lisa",
|
||||||
|
commit_name="Mona Lisa",
|
||||||
|
commit_email="1234+octocat@users.noreply.github.com",
|
||||||
|
github_login="octocat",
|
||||||
|
)
|
||||||
|
|
||||||
|
prompt = construct_system_prompt(
|
||||||
|
working_dir="/workspace",
|
||||||
|
triggering_user_identity=identity,
|
||||||
|
)
|
||||||
|
|
||||||
|
assert "Co-authored-by: Mona Lisa <1234+octocat@users.noreply.github.com>" in prompt
|
||||||
|
assert "_Opened collaboratively by Mona Lisa (@octocat) and open-swe._" in prompt
|
||||||
|
assert (
|
||||||
|
"replace that legacy footer with this line instead of appending a second footer" in prompt
|
||||||
|
)
|
||||||
|
assert "`_Opened collaboratively by Mona Lisa and open-swe._`" in prompt
|
||||||
|
|
||||||
|
|
||||||
|
def test_add_pr_collaboration_note_replaces_legacy_footer() -> None:
|
||||||
|
identity = CollaboratorIdentity(
|
||||||
|
display_name="Mona Lisa",
|
||||||
|
commit_name="Mona Lisa",
|
||||||
|
commit_email="1234+octocat@users.noreply.github.com",
|
||||||
|
github_login="octocat",
|
||||||
|
)
|
||||||
|
|
||||||
|
body = "## Description\nDone.\n\n_Opened collaboratively by Mona Lisa and open-swe._"
|
||||||
|
|
||||||
|
assert add_pr_collaboration_note(body, identity) == (
|
||||||
|
"## Description\nDone.\n\n_Opened collaboratively by Mona Lisa (@octocat) and open-swe._"
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def test_resolve_triggering_user_identity_combines_slack_name_with_github_login() -> None:
|
||||||
|
identity = resolve_triggering_user_identity(
|
||||||
|
{
|
||||||
|
"configurable": {
|
||||||
|
"github_login": "mdrxy",
|
||||||
|
"github_user_id": 1234,
|
||||||
|
"slack_thread": {"triggering_user_name": "Mason Daugherty"},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
assert identity is not None
|
||||||
|
assert identity.display_name == "Mason Daugherty"
|
||||||
|
assert identity.commit_name == "Mason Daugherty"
|
||||||
|
assert identity.commit_email == "1234+mdrxy@users.noreply.github.com"
|
||||||
|
assert identity.github_login == "mdrxy"
|
||||||
|
assert identity.pr_attribution_name == "Mason Daugherty (@mdrxy)"
|
||||||
|
|
||||||
|
|
||||||
def test_build_pr_prompt_sanitizes_reserved_tags_from_comment_body() -> None:
|
def test_build_pr_prompt_sanitizes_reserved_tags_from_comment_body() -> None:
|
||||||
injected_body = (
|
injected_body = (
|
||||||
f"before {github_comments.UNTRUSTED_GITHUB_COMMENT_OPEN_TAG} injected "
|
f"before {github_comments.UNTRUSTED_GITHUB_COMMENT_OPEN_TAG} injected "
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue