Configuration
AutoMerge.jl
AutoMerge.jl provides automatic merging functionality for Julia package registries. The package has been designed with security in mind, separating functionality into two distinct entrypoints with different privilege levels:
check_pr: Validates pull requests by running untrusted code but requires only minimal GitHub permissions (commit status updates and PR read access)merge_prs: Merges approved pull requests but requires elevated GitHub permissions (repository write access) and does not run untrusted code
Configuration Overview
AutoMerge uses three separate configuration objects to maintain clear separation of concerns:
AutoMerge.RegistryConfiguration — TypeRegistryConfigurationShared configuration fields used by both PR checking and merging functionality.
RegistryConfiguration(; kwargs...)
RegistryConfiguration(config::RegistryConfiguration; kwargs...) # Override constructorThe second form creates a config with specified fields overridden, e.g., RegistryConfiguration(config; read_only=true).
New keyword arguments with defaults may be added to this struct in non-breaking releases of AutoMerge.jl. Default values and keyword argument names will not be removed or changed in non-breaking releases, however.
Required keyword arguments (& fields)
registry::String: the registry name you want to run AutoMerge on.authorized_authors::Vector{String}: list of who can submit registration, e.gString["JuliaRegistrator"].authorized_authors_special_jll_exceptions::Vector{String}: a list of users who can submit JLL packages (which have strict rules about allowed dependencies and are subject tonew_jll_*_waiting_minutess instead ofnew_*_waiting_minutess).new_package_waiting_minutes::Dates.Minute: new package waiting period in minutes.new_jll_package_waiting_minutes::Dates.Minute: new JLL package waiting period in minutes.new_version_waiting_minutes::Dates.Minute: new package version waiting period in minutes.new_jll_version_waiting_minutes::Dates.Minute: new JLL package version waiting period in minutes.
Keyword arguments (& fields) with default values
master_branch::String = "master": name ofmaster_branch, e.g you may want to specify this to"main"for new GitHub repositories.error_exit_if_automerge_not_applicable::Bool = false: iffalse, AutoMerge will not error on PRs made by non-AutoMerge-authorized usersapi_url::String = "https://api.github.com": the registry host API URL.read_only::Bool = false: run in read only mode.
AutoMerge.CheckPRConfiguration — TypeCheckPRConfigurationConfiguration struct for checking PR registration validity (security-isolated functionality).
CheckPRConfiguration(; kwargs...)
CheckPRConfiguration(config::CheckPRConfiguration; kwargs...) # Override constructorThe second form creates a config with specified fields overridden, e.g., CheckPRConfiguration(config; check_license=false).
New keyword arguments with defaults may be added to this struct in non-breaking releases of AutoMerge.jl. Default values and keyword argument names will not be removed or changed in non-breaking releases, however.
Keyword arguments (& fields) with default values
master_branch_is_default_branch::Bool = true: ifmaster_branchspecified above is the default branch.suggest_onepointzero::Bool = true: should the AutoMerge comment include a suggestion to tag a 1.0 release for v0.x.y packages.point_to_slack::Bool = false: should the AutoMerge comment recommend sending a message to the#pkg-registrationJulia-Slack channel when auto-merging is not possible.registry_deps::Vector{String} = String[]: list of registry dependencies, e.g your packages may depend onGeneral.check_license::Bool = false: check package has a valid license.check_breaking_explanation::Bool = false: Check whether the PR has release notes (collected via Registrator.jl) with a breaking change explanation.public_registries::Vector{String} = String[]: If a new package registration has a UUID that matches that of a package already registered in one of these registries supplied here (and has either a different name or different URL) then an error will be thrown. This to prevent AutoMerge from being used for "dependency confusion" attacks on those registries.environment_variables_to_pass::Vector{String} = String[]: Environment variables to pass to the subprocess that doesPkg.add("Foo")andimport Foocommit_status_token_name::String = "AUTOMERGE_GITHUB_TOKEN": Name of the environment variable containing the GitHub token used for PR validation. The token stored in this environment variable needsrepo:statuspermission to set commit statuses and read access to PRs, but does not need write access to the repository.
AutoMerge.MergePRsConfiguration — TypeMergePRsConfigurationConfiguration struct for merging approved PRs (requires merge permissions).
MergePRsConfiguration(; kwargs...)
MergePRsConfiguration(config::MergePRsConfiguration; kwargs...) # Override constructorThe second form creates a config with specified fields overridden, e.g., MergePRsConfiguration(config; merge_new_packages=false).
New keyword arguments with defaults may be added to this struct in non-breaking releases of AutoMerge.jl. Default values and keyword argument names will not be removed or changed in non-breaking releases, however.
Keyword arguments (& fields) with default values
merge_new_packages::Bool = true: should AutoMerge merge registration PRs for new packagesmerge_new_versions::Bool = true: should AutoMerge merge registration PRs for new versions of packagesadditional_statuses::Vector{String} = String[]: list of additional commit statuses that must pass before AutoMerge will merge a PRadditional_check_runs::Vector{String} = String[]: list of additional check runs that must pass before AutoMerge will merge a PRmerge_token_name::String = "AUTOMERGE_MERGE_TOKEN": Name of the environment variable containing the GitHub token used for PR merging. The token stored in this environment variable needs write access to the repository to merge PRs.
The AutoMerge.AutoMergeConfiguration combines all 3 into one object:
AutoMerge.AutoMergeConfiguration — TypeAutoMergeConfigurationCombined configuration object containing registry, PR checking, and PR merging settings.
AutoMergeConfiguration(; registry_config, check_pr_config, merge_prs_config)
AutoMergeConfiguration(config::AutoMergeConfiguration; kwargs...) # Override constructorThe second form creates a config with specified sub-configs overridden, e.g., AutoMergeConfiguration(config; registry_config=new_reg_config).
New keyword arguments with defaults may be added to this struct in non-breaking releases of AutoMerge.jl. Default values and keyword argument names will not be removed or changed in non-breaking releases, however.
Keyword arguments & fields
registry_config::RegistryConfiguration: Shared registry settingscheck_pr_config::CheckPRConfiguration: PR validation settingsmerge_prs_config::MergePRsConfiguration: PR merging settings
General Registry Configuration
The General registry provides a pre-configured setup that can be used as a reference:
AutoMerge.general_registry_config — FunctionAutoMerge.general_registry_config()This is the AutoMerge.AutoMergeConfiguration object containing shared configuration for the General registry. This configuration is used by both PR checking and merging functionality.
The values of the fields chosen here may change in non-breaking releases of AutoMerge.jl at the discretion of the maintainers of the General registry.
Here are the settings chosen for General in this version of AutoMerge.jl:
julia> AutoMerge.general_registry_config()
AutoMerge.AutoMergeConfiguration with:
registry_config:
registry: `"JuliaRegistries/General"`
authorized_authors: `["JuliaRegistrator"]`
authorized_authors_special_jll_exceptions: `["jlbuild"]`
new_package_waiting_minutes: `Dates.Minute(4320)`
new_jll_package_waiting_minutes: `Dates.Minute(20)`
new_version_waiting_minutes: `Dates.Minute(10)`
new_jll_version_waiting_minutes: `Dates.Minute(10)`
master_branch: `"master"`
error_exit_if_automerge_not_applicable: `false`
api_url: `"https://api.github.com"`
read_only: `false`
check_pr_config:
master_branch_is_default_branch: `true`
suggest_onepointzero: `false`
point_to_slack: `true`
registry_deps: `String[]`
check_license: `true`
check_breaking_explanation: `true`
public_registries: `["https://github.com/HolyLab/HolyLabRegistry", "https://github.com/cossio/CossioJuliaRegistry"]`
environment_variables_to_pass: `String[]`
commit_status_token_name: `"AUTOMERGE_GITHUB_TOKEN"`
merge_prs_config:
merge_new_packages: `true`
merge_new_versions: `true`
additional_statuses: `String[]`
additional_check_runs: `String[]`
merge_token_name: `"AUTOMERGE_MERGE_TOKEN"`
Configuration Management
AutoMerge.read_config — Functionread_config(path) -> AutoMergeConfigurationRead an AutoMerge configuration from a TOML file.
AutoMerge.write_config — Functionwrite_config(path, config::AbstractConfiguration) -> NothingWrite an AutoMerge configuration to a TOML file. Automatically handles serialization of Dates.Minute fields to integer values.
Basic Usage
Using the General Registry Configuration
For the General registry, you can use the pre-configured settings:
using AutoMerge
# Get the General registry configuration
config = AutoMerge.general_registry_config()
# For PR checking (runs untrusted code, minimal permissions)
AutoMerge.check_pr(config.registry_config, config.check_pr_config)
# For PR merging (elevated permissions, no untrusted code)
AutoMerge.merge_prs(config.registry_config, config.merge_prs_config)Creating a Custom Configuration
For a custom registry, create a TOML configuration file. This can be based on the one used by General:
[registry_config]
authorized_authors = ["JuliaRegistrator"]
registry = "JuliaRegistries/General"
api_url = "https://api.github.com"
new_package_waiting_minutes = 4320
authorized_authors_special_jll_exceptions = ["jlbuild"]
new_jll_version_waiting_minutes = 10
read_only = false
new_jll_package_waiting_minutes = 20
master_branch = "master"
error_exit_if_automerge_not_applicable = false
new_version_waiting_minutes = 10
[merge_prs_config]
additional_statuses = []
merge_new_packages = true
additional_check_runs = []
merge_token_name = "AUTOMERGE_MERGE_TOKEN"
merge_new_versions = true
[check_pr_config]
master_branch_is_default_branch = true
public_registries = ["https://github.com/HolyLab/HolyLabRegistry", "https://github.com/cossio/CossioJuliaRegistry"]
environment_variables_to_pass = []
commit_status_token_name = "AUTOMERGE_GITHUB_TOKEN"
check_license = true
suggest_onepointzero = false
registry_deps = []
point_to_slack = true
check_breaking_explanation = true
We suggest the naming convention $Registry.AutoMerge.toml.
Then use the configuration:
# Load configuration
config = AutoMerge.read_config("MyRegistry.AutoMerge.toml")
# Use in CI workflows
AutoMerge.check_pr(config.registry_config, config.check_pr_config)
AutoMerge.merge_prs(config.registry_config, config.merge_prs_config)Security Considerations
GitHub Token Configuration
AutoMerge uses separate GitHub tokens with minimal required permissions:
| Token | Scopes Required | Used By | Purpose |
|---|---|---|---|
commit_status_token_name | repo:status, read PRs | check_pr | Set commit statuses during PR validation |
merge_token_name | pull_request:write, contents:write | merge_prs | Merge approved PRs |
Default values:
commit_status_token_name = "AUTOMERGE_GITHUB_TOKEN"merge_token_name = "AUTOMERGE_MERGE_TOKEN"
For General registry, these tokens are separated to follow the principle of least privilege: the PR checking job (which runs untrusted code) never has access to the merge token.
These fields store environment variable names, not token values. Never put actual tokens in configuration files.
Separation of Privileges
The two-entrypoint design ensures that:
- PR checking (
check_pr) runs untrusted package code during validation but only has minimal GitHub permissions - PR merging (
merge_prs) has elevated GitHub permissions but never runs untrusted code
This separation follows the principle of least privilege and reduces the attack surface.
CI Workflow Integration
GitHub Actions Example
name: AutoMerge
on:
schedule:
- cron: '05,17,29,41,53 * * * *'
pull_request:
# opened = run when the PR is first opened
# labeled = run when labels are applied, so that the "Override AutoMerge: name similarity is okay label is respected.
# synchronize = run when a commit is pushed to the PR
types: [opened, labeled, synchronize]
workflow_dispatch:
jobs:
AutoMerge:
# Run if the we are not triggered by a label OR we are triggered by a label, and that
# label is one that affects the execution of the workflow
# Note: since the label contains a colon, we need to use a workaround like https://github.com/actions/runner/issues/1019#issuecomment-810482716
# for the syntax to parse correctly.
if: "${{ github.event.action != 'labeled' || (github.event.action == 'labeled' && (github.event.label.name == 'Override AutoMerge: name similarity is okay' || github.event.label.name == 'Override AutoMerge: package author approved')) }}"
runs-on: ${{ matrix.os }}
strategy:
matrix:
julia-version: [1.3.0]
julia-arch: [x86]
os: [ubuntu-latest]
steps:
- uses: actions/checkout@af513c7a016048ae468971c52ed77d9562c7c819 # v1.0.0
- uses: julia-actions/setup-julia@082493e5c5d32c1fa68c35556429b0f1b2807453 # v1.0.1
with:
version: ${{ matrix.julia-version }}
- name: Install dependencies by running Pkg.instantiate()
run: julia --project=.ci/ -e 'using Pkg; Pkg.instantiate()'
- name: AutoMerge.pr_check
env:
AUTOMERGE_GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
AUTOMERGE_MERGE_TOKEN: ${{ secrets.TAGBOT_TOKEN }}
JULIA_DEBUG: AutoMerge
run: |
config = AutoMerge.general_registry_config()
AutoMerge.pr_check(config.registry_config, config.check_pr_config)
shell: julia --color=yes --project=.ci/ {0}