Skip to content

Feedback Workflows

Feedback workflows react to events in a repository (like PRs being merged or issues being created) and perform actions in response.

Unlike core.workflow which synchronizes code, core.feedback triggers actions based on repository events.

core.feedback(
name = "notify-on-merge",
origin = git.github_trigger(...),
destination = git.github_api(...),
actions = [...],
)
  • Notify internal systems when external PRs are merged
  • Create tracking issues when code is synced
  • Update labels or milestones automatically
  • Post comments on related PRs/issues
  • Trigger downstream workflows

Listen to GitHub events:

origin = git.github_trigger(
url = "https://github.com/org/repo",
events = ["pull_request", "push"],
)
EventTrigger
pull_requestPR opened, closed, merged, etc.
pushCommits pushed to a branch
issueIssue opened, closed, etc.
issue_commentComment on issue or PR

Perform actions via the GitHub API:

destination = git.github_api(
url = "https://github.com/org/internal-repo",
)

Define actions using Starlark functions:

def _notify_internal(ctx):
"""Notify internal team when external PR is merged."""
for change in ctx.origin.get_changes():
if change.labels.get("merged"):
ctx.destination.create_issue(
title = "External contribution merged: " + change.ref,
body = "PR " + change.ref + " was merged. Please sync.",
)
return ctx.success()
core.action(
impl = _notify_internal,
params = {},
)
copy.bara.sky
# Workflow to notify when external PRs are merged
core.feedback(
name = "notify-on-external-merge",
origin = git.github_trigger(
url = "https://github.com/myorg/public-repo",
events = ["pull_request"],
),
destination = git.github_api(
url = "https://github.com/myorg/internal-repo",
),
actions = [
core.action(
impl = _handle_pr_event,
params = {},
),
],
)
def _handle_pr_event(ctx):
for pr in ctx.origin.get_pull_requests():
if pr.merged:
# Create an issue in the internal repo
ctx.destination.create_issue(
title = "[External] PR merged: " + pr.title,
body = """\
An external contribution was merged.
**PR**: """ + pr.url + """
**Author**: """ + pr.author + """
**Description**: """ + pr.body + """
Please run Copybara to import these changes.
""",
labels = ["external-contribution", "needs-import"],
)
ctx.console.info("Created issue for PR: " + pr.number)
return ctx.success()

The ctx object provides:

PropertyDescription
ctx.originAccess to origin events/data
ctx.destinationAPI to perform actions
ctx.consoleLogging methods (info, warn, error)
ctx.success()Return successful result
ctx.noop(msg)Return no-op result
ctx.error(msg)Return error result
# Get all changes/events
changes = ctx.origin.get_changes()
# Get pull requests
prs = ctx.origin.get_pull_requests()
# Access event data
for change in changes:
ref = change.ref
labels = change.labels
author = change.author
# Create an issue
ctx.destination.create_issue(
title = "Issue title",
body = "Issue body",
labels = ["label1", "label2"],
assignees = ["user1"],
)
# Add a comment
ctx.destination.add_comment(
number = 123, # Issue or PR number
body = "Comment text",
)
# Update labels
ctx.destination.add_labels(
number = 123,
labels = ["reviewed"],
)
Terminal window
# Validate
java -jar copybara.jar validate copy.bara.sky notify-on-external-merge
# Run (typically triggered by webhooks in CI)
java -jar copybara.jar feedback copy.bara.sky notify-on-external-merge

Set up a GitHub webhook to trigger the feedback workflow:

  1. Go to repo Settings → Webhooks
  2. Add webhook URL pointing to your CI
  3. Select events (e.g., “Pull requests”)
  4. CI runs Copybara feedback workflow on webhook

A common pattern:

  1. External contributor opens PR on public repo
  2. PR gets merged
  3. Feedback workflow creates internal issue
  4. Team reviews and approves import
  5. Sync workflow (import) runs to bring changes internal
# Feedback: notify on merge
core.feedback(
name = "notify-on-merge",
origin = git.github_trigger(url = public_url, events = ["pull_request"]),
...
)
# Sync: import external contributions
core.workflow(
name = "import",
origin = git.github_pr_origin(url = public_url, branch = "main"),
destination = git.gerrit_destination(url = internal_url, ...),
mode = "CHANGE_REQUEST_FROM_SOT",
...
)