Skip to content

Configuration File Structure

Copybara uses Starlark configuration files, typically named copy.bara.sky.

copy.bara.sky
# Variables (optional)
internal_url = "https://github.com/org/internal"
external_url = "https://github.com/org/external"
# Workflow definitions
core.workflow(
name = "export",
origin = git.origin(url = internal_url, ref = "main"),
destination = git.destination(url = external_url, push = "main"),
authoring = authoring.pass_thru("Bot <bot@example.com>"),
transformations = [...],
)
# Additional workflows
core.workflow(
name = "import",
...
)
FilePurpose
copy.bara.skyStandard configuration file
*.bara.skyAny .bara.sky extension works

Define reusable values at the top:

# Repository URLs
internal_repo = "https://github.com/myorg/internal"
public_repo = "https://github.com/myorg/public"
# Common patterns
internal_globs = glob(["**/internal/**"])
public_files = glob(["src/**", "docs/**"])
# Author info
default_author = "Sync Bot <sync@example.com>"

Define reusable transformation functions:

def common_transforms():
"""Transformations used in multiple workflows."""
return [
core.replace("internal.corp", "example.com"),
core.verify_match(
regex = "SECRET",
verify_no_match = True,
),
]
core.workflow(
name = "export",
transformations = common_transforms() + [
core.move("src/", ""),
],
...
)

One file can contain multiple workflows:

# Export: internal → external
core.workflow(
name = "export",
origin = git.origin(url = internal_url, ref = "main"),
destination = git.github_destination(url = external_url, push = "main"),
...
)
# Import: external PRs → internal
core.workflow(
name = "import",
origin = git.github_pr_origin(url = external_url, branch = "main"),
destination = git.gerrit_destination(url = internal_url, ...),
...
)
# Validate: dry run
core.workflow(
name = "validate",
origin = git.origin(url = internal_url, ref = "main"),
destination = folder.destination(),
...
)

Run specific workflow:

Terminal window
java -jar copybara.jar migrate copy.bara.sky export
java -jar copybara.jar migrate copy.bara.sky import

Use Starlark conditionals:

# Environment-based configuration
is_production = True
transforms = [
core.move("src/", "lib/"),
]
if is_production:
transforms.append(
core.verify_match(regex = "DEBUG", verify_no_match = True)
)
core.workflow(
name = "export",
transformations = transforms,
...
)

Split configuration across files:

common.bara.sky
def standard_transforms():
return [
core.replace("internal", "external"),
]
INTERNAL_URL = "https://github.com/org/internal"
copy.bara.sky
load("common.bara.sky", "standard_transforms", "INTERNAL_URL")
core.workflow(
name = "export",
origin = git.origin(url = INTERNAL_URL, ref = "main"),
transformations = standard_transforms(),
...
)

Use # for comments:

# Main export workflow
# Syncs internal code to public GitHub repository
core.workflow(
name = "export", # Unique identifier
origin = git.origin(
url = "https://github.com/org/internal",
ref = "main", # Track main branch
),
...
)
copybara/
├── export.bara.sky # Internal → External
├── import.bara.sky # External → Internal
└── common.bara.sky # Shared definitions
copybara/
├── github.bara.sky # Sync to GitHub
├── gerrit.bara.sky # Sync to Gerrit
└── common.bara.sky # Shared definitions
copy.bara.sky # All workflows in one file
copy.bara.sky
# Configuration for syncing between internal and public repositories
# ==== Variables ====
INTERNAL = "https://github.com/myorg/internal"
PUBLIC = "https://github.com/myorg/public"
BOT = "Sync Bot <sync@myorg.com>"
# ==== Shared Transforms ====
def security_checks():
"""Verify no secrets are exposed."""
return [
core.verify_match(
regex = "API_KEY|SECRET|PASSWORD",
verify_no_match = True,
),
]
def url_transforms():
"""Replace internal URLs."""
return [
core.replace("internal.myorg.com", "api.myorg.io"),
]
# ==== Workflows ====
# Export internal code to public repository
core.workflow(
name = "export",
origin = git.github_origin(
url = INTERNAL,
ref = "main",
),
destination = git.github_pr_destination(
url = PUBLIC,
destination_ref = "main",
pr_branch = "sync/${CONTEXT_REFERENCE}",
),
origin_files = glob(
include = ["src/**", "docs/**"],
exclude = ["**/internal/**"],
),
authoring = authoring.pass_thru(BOT),
transformations = security_checks() + url_transforms() + [
core.move("src/public/", "src/"),
metadata.add_header("Synced-From: internal"),
],
mode = "SQUASH",
)
# Import external contributions
core.workflow(
name = "import",
origin = git.github_pr_origin(
url = PUBLIC,
branch = "main",
required_labels = ["ready-to-import"],
),
destination = git.gerrit_destination(
url = INTERNAL,
fetch = "main",
push_to_refs_for = "main",
),
authoring = authoring.pass_thru(BOT),
transformations = [
core.move("src/", "src/public/"),
],
mode = "CHANGE_REQUEST_FROM_SOT",
)