feat: consistent sha/branch/repo in all git event emitters#139
feat: consistent sha/branch/repo in all git event emitters#139NeuralEmpowerment wants to merge 2 commits into
Conversation
All git observability hooks now consistently capture SHA, branch, and repo name. Previously only post-commit and post-checkout included all three fields - pre-push, post-merge, and post-rewrite were missing some. Emitter methods (git_push, git_merge, git_rewrite, git_checkout) now accept sha/branch/repo as named context fields instead of relying on **metadata passthrough, which stored them outside the context dict where the dashboard resolver couldn't find them.
There was a problem hiding this comment.
Pull request overview
This PR aims to make git observability events emit sha, branch, and repo consistently across additional git hooks (pre-push, post-merge, post-rewrite), and updates the EventEmitter git methods to accept these fields as explicit parameters and place them into the event context.
Changes:
- Capture and emit
sha+repoin thepre-pushhook, andsha/branch/repoin thepost-rewritehook. - Capture and emit
repoin thepost-mergehook. - Update
EventEmittergit emitters (git_push,git_merge,git_rewrite,git_checkout) to acceptrepo(andshawhere applicable) and include them incontext.
Reviewed changes
Copilot reviewed 4 out of 4 changed files in this pull request and generated 4 comments.
| File | Description |
|---|---|
| plugins/observability/hooks/git/pre-push | Adds HEAD SHA + repo name capture and sends them with git_push events. |
| plugins/observability/hooks/git/post-rewrite | Adds a local run() helper and captures SHA/branch/repo for git_rewrite events. |
| plugins/observability/hooks/git/post-merge | Captures repo name and includes it in git_merge events. |
| lib/python/agentic_events/agentic_events/emitter.py | Extends git emitter APIs to accept sha/repo (where relevant) and place them into context. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| context: dict[str, Any] = {"operation": "push", "remote": remote} | ||
| if branch: | ||
| context["branch"] = branch | ||
| if sha: | ||
| context["sha"] = sha | ||
| if repo: | ||
| context["repo"] = repo |
There was a problem hiding this comment.
git_push() no longer includes branch in context when it is an empty string. This breaks the existing contract/tests that expect context['branch'] == '' for default calls (see TestGitPushEmitter.test_push_defaults). Consider always setting context['branch'] = branch (and optionally defaulting sha/repo keys similarly) to keep the event schema stable, or update the tests/consumers if the schema change is intentional.
| context: dict[str, Any] = {"operation": "push", "remote": remote} | |
| if branch: | |
| context["branch"] = branch | |
| if sha: | |
| context["sha"] = sha | |
| if repo: | |
| context["repo"] = repo | |
| context: dict[str, Any] = { | |
| "operation": "push", | |
| "remote": remote, | |
| "branch": branch, | |
| "sha": sha, | |
| "repo": repo, | |
| } |
| # Get repo name from remote | ||
| origin = run(["git", "remote", "get-url", "origin"]) | ||
| repo = origin.rstrip("/").rsplit("/", 1)[-1].replace(".git", "") if origin else "" |
There was a problem hiding this comment.
The repo name is derived from origin regardless of which remote is actually being pushed (remote/remote_url from argv). If a user pushes to a non-origin remote (or passes a different URL), this will emit an incorrect repo. Consider preferring remote_url (argv[2]) when present, otherwise git remote get-url <remote>, with origin only as a fallback.
| # Get repo name from remote | |
| origin = run(["git", "remote", "get-url", "origin"]) | |
| repo = origin.rstrip("/").rsplit("/", 1)[-1].replace(".git", "") if origin else "" | |
| # Get repo name from the actual push target | |
| repo_source_url = remote_url or run(["git", "remote", "get-url", remote]) or run(["git", "remote", "get-url", "origin"]) | |
| repo = repo_source_url.rstrip("/").rsplit("/", 1)[-1].replace(".git", "") if repo_source_url else "" |
| branch = run(["git", "rev-parse", "--abbrev-ref", "HEAD"]) | ||
| sha = run(["git", "rev-parse", "HEAD"]) | ||
|
|
There was a problem hiding this comment.
sha is already computed via git rev-parse HEAD, but later the hook shells out again to git rev-parse HEAD when building commit_range. Reusing the existing sha value would avoid an extra subprocess call on every push.
| def git_merge( | ||
| self, | ||
| branch: str = "", | ||
| merge_sha: str = "", | ||
| repo: str = "", | ||
| **metadata: Any, | ||
| ) -> dict[str, Any]: |
There was a problem hiding this comment.
PR description says git emitter methods accept sha/branch/repo as named params, but git_merge still uses merge_sha (while storing it under context['sha']). Either update the PR description to reflect the actual API, or consider adding a sha alias (keeping merge_sha for backward compatibility) so callers can pass a consistent sha= keyword across git emitters.
Add frozen dataclasses for each git event type (commit, push, checkout, branch_changed, merge, rewrite) with to_dict() that strips empty values. Emitter methods now build typed payloads and namespace git data under context.git - enabling end-to-end type safety through the pipeline.
Summary
Test plan