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.RegistryConfigurationType
RegistryConfiguration

Shared configuration fields used by both PR checking and merging functionality.

RegistryConfiguration(; kwargs...)
RegistryConfiguration(config::RegistryConfiguration; kwargs...)  # Override constructor

The second form creates a config with specified fields overridden, e.g., RegistryConfiguration(config; read_only=true).

Note

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.g String["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 to new_jll_*_waiting_minutess instead of new_*_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 of master_branch, e.g you may want to specify this to "main" for new GitHub repositories.
  • error_exit_if_automerge_not_applicable::Bool = false: if false, AutoMerge will not error on PRs made by non-AutoMerge-authorized users
  • api_url::String = "https://api.github.com": the registry host API URL.
  • read_only::Bool = false: run in read only mode.
source
AutoMerge.CheckPRConfigurationType
CheckPRConfiguration

Configuration struct for checking PR registration validity (security-isolated functionality).

CheckPRConfiguration(; kwargs...)
CheckPRConfiguration(config::CheckPRConfiguration; kwargs...)  # Override constructor

The second form creates a config with specified fields overridden, e.g., CheckPRConfiguration(config; check_license=false).

Note

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: if master_branch specified 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-registration Julia-Slack channel when auto-merging is not possible.
  • registry_deps::Vector{String} = String[]: list of registry dependencies, e.g your packages may depend on General.
  • 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 does Pkg.add("Foo") and import Foo
  • commit_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 needs repo:status permission to set commit statuses and read access to PRs, but does not need write access to the repository.
source
AutoMerge.MergePRsConfigurationType
MergePRsConfiguration

Configuration struct for merging approved PRs (requires merge permissions).

MergePRsConfiguration(; kwargs...)
MergePRsConfiguration(config::MergePRsConfiguration; kwargs...)  # Override constructor

The second form creates a config with specified fields overridden, e.g., MergePRsConfiguration(config; merge_new_packages=false).

Note

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 packages
  • merge_new_versions::Bool = true: should AutoMerge merge registration PRs for new versions of packages
  • additional_statuses::Vector{String} = String[]: list of additional commit statuses that must pass before AutoMerge will merge a PR
  • additional_check_runs::Vector{String} = String[]: list of additional check runs that must pass before AutoMerge will merge a PR
  • merge_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.
source

The AutoMerge.AutoMergeConfiguration combines all 3 into one object:

AutoMerge.AutoMergeConfigurationType
AutoMergeConfiguration

Combined configuration object containing registry, PR checking, and PR merging settings.

AutoMergeConfiguration(; registry_config, check_pr_config, merge_prs_config)
AutoMergeConfiguration(config::AutoMergeConfiguration; kwargs...)  # Override constructor

The second form creates a config with specified sub-configs overridden, e.g., AutoMergeConfiguration(config; registry_config=new_reg_config).

Note

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 settings
  • check_pr_config::CheckPRConfiguration: PR validation settings
  • merge_prs_config::MergePRsConfiguration: PR merging settings
source

General Registry Configuration

The General registry provides a pre-configured setup that can be used as a reference:

AutoMerge.general_registry_configFunction
AutoMerge.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.

Warning

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"`
source

Configuration Management

AutoMerge.write_configFunction
write_config(path, config::AbstractConfiguration) -> Nothing

Write an AutoMerge configuration to a TOML file. Automatically handles serialization of Dates.Minute fields to integer values.

source

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:

TokenScopes RequiredUsed ByPurpose
commit_status_token_namerepo:status, read PRscheck_prSet commit statuses during PR validation
merge_token_namepull_request:write, contents:writemerge_prsMerge 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.

Token Security

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:

  1. PR checking (check_pr) runs untrusted package code during validation but only has minimal GitHub permissions
  2. 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}