Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
44e1708
Load & merge global and per-project user configsbefore CLI overrides
MariosLiapis Sep 18, 2025
6fb5ace
Add 'briefcase config' command for per-user configs
MariosLiapis Sep 23, 2025
726bc54
support ? to force interactive selection across iOS, Android and macO…
MariosLiapis Sep 24, 2025
babbfa4
Add new config command in cmdline, __init__ (commands) and .gitignore
MariosLiapis Sep 24, 2025
d0bcc88
Add config command to command options in cmdline.py
MariosLiapis Sep 24, 2025
038ede3
Use per-user default android device in run command, respecting preced…
MariosLiapis Sep 25, 2025
ae54669
Fix copy config method in merged_global
MariosLiapis Sep 25, 2025
c98e8ae
Small fixes in commands/config.py helper functions; added abstract me…
MariosLiapis Sep 25, 2025
911b8bf
Add config.toml to .gitignore
MariosLiapis Sep 25, 2025
aa14648
Use per-user default iOS device in respecting precedence
MariosLiapis Sep 25, 2025
a9a52b1
Implement new helper function in commands\config.py that validates th…
MariosLiapis Sep 29, 2025
ad1941d
Update allowed keys in config.py
MariosLiapis Sep 29, 2025
43e746e
Add global user config for author name and email as default (if exist…
MariosLiapis Sep 29, 2025
77afd5a
Add functions that resolves identity for macOS platform from config.toml
MariosLiapis Sep 29, 2025
ea93862
Replace allowed_keys list; implement key normalizer function to avoid…
MariosLiapis Sep 29, 2025
97654f2
Update .gitignore file and the function that creates it
MariosLiapis Sep 29, 2025
96bcf36
Implement test suits to honor test coverage
MariosLiapis Sep 29, 2025
e2aee51
Fix failed tests from config command test suite; implement test for s…
MariosLiapis Sep 30, 2025
7715aaf
Remove failing tests
MariosLiapis Sep 30, 2025
93c2617
Remove macOS identity handler from config command and its tests
MariosLiapis Sep 30, 2025
cd7972b
Replace old config command test suite
MariosLiapis Sep 30, 2025
5572a28
Implement additional tests for commands [base, config, convert, new] …
MariosLiapis Sep 30, 2025
4f83434
Add final tests for complete test coverage
MariosLiapis Oct 1, 2025
ca67ab5
Add towncrier fragment and documentation for the new config command f…
MariosLiapis Oct 1, 2025
57e144c
Remove unneccesary tests
MariosLiapis Oct 1, 2025
e54e389
Append keywords in docs
MariosLiapis Oct 1, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -37,3 +37,4 @@ coverage.xml

tests/apps/verify-*/
logs/
.briefcase/
1 change: 1 addition & 0 deletions changes/2279.feature.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Briefcase can now store per-project and per-user defaults for some options, such as author details, preferred simulators, and signing identities.
93 changes: 93 additions & 0 deletions docs/reference/commands/config.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
======
config
======

Manage user-level defaults without editing ``pyproject.toml``. Defaults can be
stored per project (in ``.briefcase/``) or globally for your user account.

Usage
=====

Set a value (project scope):

.. code-block:: console
$ briefcase config android.device "@Pixel_5"
$ briefcase config iOS.device "iPhone 15"
Set a value (global scope):

.. code-block:: console
$ briefcase config --global android.device "emulator-5554"
$ briefcase config --global iOS.device "?"
Get a value:

.. code-block:: console
$ briefcase config --get android.device
$ briefcase config --global --get iOS.device
List the current file:
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
List the current file:
List the current configuration:


.. code-block:: console
$ briefcase config --list
$ briefcase config --global --list
Unset a value:

.. code-block:: console
$ briefcase config --unset android.device
$ briefcase config --global --unset iOS.device
Where settings are stored
-------------------------

- Project user config: ``<project>/.briefcase/config.toml``
- Global user config: platform user config directory, e.g.:

- macOS: ``~/Library/Application Support/org.beeware.briefcase/config.toml``
- Linux: ``~/.config/org.beeware.briefcase/config.toml``
- Windows: ``%LOCALAPPDATA%\\BeeWare\\org.beeware.briefcase\\config.toml``

Format
------

On read, both a **root** TOML shape and a ``[tool.briefcase]`` block are accepted.
On write, Briefcase uses the **root** shape.

Example (project):

.. code-block:: toml
[android]
device = "@Pixel_5"
[iOS]
device = "iPhone 15"
Supported keys
--------------

- ``android.device`` — AVD name (``@Name``) or emulator id (e.g., ``emulator-5554``)
- ``iOS.device`` — UDID (``xxxxxxxx-…-xxxxxxxxxxxx``), device name (e.g., ``"iPhone 15"``),
or ``"Device Name::iOS X[.Y]"``

Validation & special values
---------------------------

- ``?`` is allowed for both device keys to **force** interactive selection next run.
- Invalid formats are rejected with a helpful error; no file is written.

Precedence
----------

**CLI overrides > ``pyproject.toml`` > project user config > global user config**

Notes
-----

- Keys are case-sensitive (use ``iOS.device``, not ``ios.device``).
1 change: 1 addition & 0 deletions docs/reference/commands/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ Command reference
package
publish
upgrade
config

Common options
==============
Expand Down
5 changes: 5 additions & 0 deletions docs/spelling_wordlist
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ appimage
artefact
artefacts
autodetect
AVD
backend
backends
backported
Expand All @@ -17,6 +18,7 @@ Chaquopy
checkmarks
cibuildwheel
codebase
config
Cookiecutter
cryptographic
customizations
Expand Down Expand Up @@ -63,6 +65,7 @@ OSX
passthrough
Passthrough
phablet
PlatformDirs
pre
precompiled
proxied
Expand All @@ -72,6 +75,7 @@ px
pygame
Pygame
Pyodide
pyproject.toml
PyScript
PySide
pytest
Expand Down Expand Up @@ -102,6 +106,7 @@ triaged
Triaging
TTY
tvOS
UDID
unallocated
untrusted
vendored
Expand Down
4 changes: 4 additions & 0 deletions src/briefcase/cmdline.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
from briefcase import __version__
from briefcase.commands import (
BuildCommand,
ConfigCommand,
ConvertCommand,
CreateCommand,
DevCommand,
Expand All @@ -32,6 +33,7 @@
COMMANDS = [
NewCommand,
DevCommand,
ConfigCommand,
ConvertCommand,
CreateCommand,
OpenCommand,
Expand Down Expand Up @@ -133,6 +135,8 @@ def parse_known_args(args):
Command = NewCommand
elif options.command == "upgrade":
Command = UpgradeCommand
elif options.command == "config":
Command = ConfigCommand
else:
# Commands dependent on the platform and format. The general form of such a
# command is `briefcase <cmd> <platform> <format>`; but the format will be
Expand Down
1 change: 1 addition & 0 deletions src/briefcase/commands/__init__.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
from .build import BuildCommand # noqa: F401
from .config import ConfigCommand # noqa: F401
from .convert import ConvertCommand # noqa: F401
from .create import CreateCommand # noqa: F401
from .dev import DevCommand # noqa: F401
Expand Down
29 changes: 25 additions & 4 deletions src/briefcase/commands/base.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
from __future__ import annotations

import argparse
import copy
import importlib
import importlib.metadata
import inspect
Expand Down Expand Up @@ -28,7 +29,13 @@

import briefcase
from briefcase import __version__
from briefcase.config import AppConfig, GlobalConfig, parse_config
from briefcase.config import (
AppConfig,
GlobalConfig,
deep_merge,
load_user_config_files,
parse_config,
)
from briefcase.console import MAX_TEXT_WIDTH, Console
from briefcase.exceptions import (
BriefcaseCommandError,
Expand Down Expand Up @@ -1007,15 +1014,29 @@ def parse_config(self, filename, overrides):
console=self.console,
)

# Merge user-level config (global and per-project) before CLI overrides
project_root = Path(filename).resolve().parent
global_user_cfg, project_user_cfg = load_user_config_files(project_root)

# precedence within user-level config: global < project
user_merged = deep_merge(global_user_cfg, project_user_cfg)

# apply to global and each app (user config < pyproject)
merged_global = deep_merge(copy.deepcopy(user_merged), global_config)
merged_app_configs = {
name: deep_merge(copy.deepcopy(user_merged), cfg)
for name, cfg in app_configs.items()
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The general approach you've taken here looks about right; however, it concerns me the extent to which the config handling is completely dissociated from the rest of the pyproject.toml config handling.


# Create the global config
global_config.update(overrides)
merged_global.update(overrides)
self.global_config = create_config(
klass=GlobalConfig,
config=global_config,
config=merged_global,
msg="Global configuration",
)

for app_name, app_config in app_configs.items():
for app_name, app_config in merged_app_configs.items():
# Construct an AppConfig object with the final set of
# configuration options for the app.
app_config.update(overrides)
Expand Down
Loading