---
title: "Source Code Management Platform"
url: https://develop.sentry.dev/backend/source-code-management-platform/
---

# Source Code Management Platform

## [Introduction](https://develop.sentry.dev/backend/source-code-management-platform.md#introduction)

The SCM (Source Code Management) platform is a vendor-agnostic abstraction layer for interacting with source code management providers such as GitHub, GitLab, and Bitbucket. It decouples Sentry's product features from provider-specific APIs by presenting a single, declarative interface for both reading and writing SCM resources and for reacting to SCM webhook events.

### [Goals](https://develop.sentry.dev/backend/source-code-management-platform.md#goals)

1. **Provider independence.** Product code should never import a provider's client or parse a provider's response format directly. All interaction flows through a common type system so that adding a new provider does not require changes to callers.
2. **Declarative usage.** Callers describe *what* they want (e.g. "create a pull request") not *how* to accomplish it. Initialization, authentication, rate limiting, and response mapping are handled internally.
3. **Observability by default.** Every outbound action and every inbound webhook listener automatically records success/failure metrics, emits traces, and reports errors to Sentry. Callers do not need to instrument their own usage.
4. **Fair access.** Referrer-based rate limiting with allocation policies prevents any single caller from exhausting a provider's API budget. Shared and caller-specific quotas are enforced transparently.
5. **Centrally enforced access controls.** Access controls must be strictly and consistently enforced across all SCM providers to prevent unprivileged access to sensitive customer data, ensuring the security model is implemented once and applied universally.

### [Features](https://develop.sentry.dev/backend/source-code-management-platform.md#features)

The platform exposes two subsystems:

* **Actions** — outbound operations initiated by Sentry code. The `SourceCodeManager` class provides 70+ methods covering comments, reactions, pull requests, branches, git objects, reviews, and check runs.
* **Event Stream** — inbound webhook processing. SCM providers push events which are deserialized into typed, provider-neutral dataclasses (`CheckRunEvent`, `CommentEvent`, `PullRequestEvent`) and dispatched to registered listener functions.

## [Quick Start](https://develop.sentry.dev/backend/source-code-management-platform.md#quick-start)

### [Source Code Manager](https://develop.sentry.dev/backend/source-code-management-platform.md#source-code-manager)

To use the Source Code Manager interfaces first import the SourceCodeManager class from the scm module and initialize it with your repository id.

```python
from sentry.scm.actions import SourceCodeManager

scm = SourceCodeManager.make_from_repository_id(organization_id=1, repository_id=2)
```

This will initialize a new SCM class with its capabilities scoped to what the repository's service-provider can offer.

Now import the actions your use case requires.

```python
from sentry.scm.actions import SourceCodeManager, create_issue_reaction, create_issue_comment
```

By default the SourceCodeManager class can not execute any methods without the type checker complaining. To smooth over service-provider variations, the SCM ships a capability system. You must statically assert that your "scm" instance is capable of executing a particular action or set of actions prior to calling an action function.

```python
from sentry.scm.types import CreateIssueReactionProtocol, CreateIssueCommentProtocol


if isinstance(scm, CreateIssueReactionProtocol):
    create_issue_reaction(scm, issue_id="1", reaction="eyes")
elif isinstance(scm, CreateIssueCommentProtocol):
    create_issue_comment(scm, issue_id="1", body="We've seen your request.")
else:
    return None # Unsupported providers do nothing.
```

Capabilities may be composed when granularity is not required.

```python
class GitInteractionProtocol(
    GetTreeProtocol,
    GetGitCommitProtocol,
    CreateGitBlobProtocol,
    CreateGitTreeProtocol,
    CreateGitCommitProtocol,
):
    ...


if isinstance(scm, GitInteractionProtocol):
    # do work
    ...
```

Alternatively if you want to target a specific platform you may.

```python
from sentry.scm.private.providers.github import GitHubProvider

if isinstance(scm, GitHubProvider):
    # do github specific work.
    ...
```

This pattern is discouraged, however, and is hidden within the `private` module. It is preferred that you interact with service-providers on a capability basis so that your feature is automatically enabled for new service-providers but we understand that this is not always desired.

SCM actions will raise exceptions on failure. All exceptions are subclassed by `SCMError`. It is recommended that you catch these failures and handle them in some way.

```python
from sentry.scm.errors import SCMError

try:
    create_issue_reaction(scm, issue_id="1", reaction="+1")
except SCMError:
    retry_this_action(...)
```

The SCM exposes the following actions. For more information (and more up to date information) browse the `/src/sentry/scm/actions.py` file in the `getsentry/sentry` repository.

* `compare_commits`
* `create_branch`
* `create_check_run`
* `create_git_blob`
* `create_git_commit`
* `create_git_tree`
* `create_issue_comment`
* `create_issue_comment_reaction`
* `create_issue_reaction`
* `create_pull_request`
* `create_pull_request_comment`
* `create_pull_request_comment_reaction`
* `create_pull_request_draft`
* `create_pull_request_reaction`
* `create_review`
* `create_review_comment_file`
* `create_review_comment_reply`
* `delete_issue_comment`
* `delete_issue_comment_reaction`
* `delete_issue_reaction`
* `delete_pull_request_comment`
* `delete_pull_request_comment_reaction`
* `delete_pull_request_reaction`
* `get_archive_link`
* `get_branch`
* `get_check_run`
* `get_commit`
* `get_commits`
* `get_commits_by_path`
* `get_file_content`
* `get_git_commit`
* `get_issue_comment_reactions`
* `get_issue_comments`
* `get_issue_reactions`
* `get_pull_request`
* `get_pull_request_comment_reactions`
* `get_pull_request_comments`
* `get_pull_request_commits`
* `get_pull_request_diff`
* `get_pull_request_files`
* `get_pull_request_reactions`
* `get_pull_requests`
* `get_tree`
* `minimize_comment`
* `request_review`
* `update_branch`
* `update_check_run`
* `update_pull_request`

### [Source Code Manager RPC](https://develop.sentry.dev/backend/source-code-management-platform.md#source-code-manager-rpc)

The Source Code Manager is exposed over RPC and may be accessed with the client library in your microservice.

```python
scm = SourceCodeManagerRpcClient.make_from_repository_id(organization_id=1, repository_id=1)

if isinstance(scm, CreateIssueReactionProtocol):
    try:
        create_issue_reaction(scm, issue_id="1", reaction="+1")
    except SCMError:
        retry_this_action(...)
```

### [Event Stream](https://develop.sentry.dev/backend/source-code-management-platform.md#event-stream)

Source code management service providers will push events to Sentry. The Source Code Management Platform exposes a typed, event-stream interface which may be listened to by interested implementers.

```python
from sentry.scm.stream import CheckRunEvent, scm_event_stream

@scm_event_stream.listen_for(event_type="check_run")
def listen_for_check_run(event: CheckRunEvent):
    # do work
    return None
```

Event stream listeners are isolated. They run asynchronously in their own worker process.

The event stream supports the following event types.

* `CheckRunEvent`
* `CommentEvent`
* `PullRequestEvent`

### [Observability](https://develop.sentry.dev/backend/source-code-management-platform.md#observability)

Both subsystems emit metrics under the `sentry.scm` namespace:

| Metric                                           | Source                                                             |
| ------------------------------------------------ | ------------------------------------------------------------------ |
| `sentry.scm.actions.success`                     | Every successful outbound action (tagged by provider and referrer) |
| `sentry.scm.actions.failed`                      | Unhandled exception during an outbound action                      |
| `sentry.scm.produce_event_to_scm_stream.success` | Event successfully dispatched to listeners                         |
| `sentry.scm.produce_event_to_scm_stream.failed`  | Dispatch failure (tagged by reason)                                |
| `sentry.scm.run_listener.success`                | Listener executed successfully (tagged by listener name)           |
| `sentry.scm.run_listener.failed`                 | Listener failed (tagged by reason and listener name)               |
| `sentry.scm.run_listener.message.size`           | Serialized event size in bytes                                     |
| `sentry.scm.run_listener.queue_time`             | Time from webhook receipt to task start                            |
| `sentry.scm.run_listener.task_time`              | Time to execute the listener                                       |
| `sentry.scm.run_listener.real_time`              | End-to-end time from webhook receipt to listener completion        |
