This monorepo hosts client-side code for Proton applications (e.g. Mail, Calendar), shared SDKs, and supporting tools.
project/
<project>/
<platform>/ # android, apple, rust
<module>/ # e.g. mail-composer, calendar-api
build/ # scripts and tools
doc/ # versioned ADRs, RFCs, guidelines
Each project is self-contained, and code is grouped by product first, then platform.
To create a new project with the proper structure and GitLab CI configuration,
use the create_project.sh script:
./create_project.sh <ProjectName>This script will:
- Create the project directory structure (
project/<project>/android/,project/<project>/apple/,project/<project>/rust/) - Generate appropriate
.gitignorefiles for each platform - Create placeholder
README.mdfiles - Set up the GitLab CI configuration file (
.gitlab-ci.yml) for the project - Automatically update the main
.gitlab-ci.ymlto include the new project
Example:
./create_project.sh Pass
# Creates project/pass/ with all necessary files and configurationThe monorepo is formatted by a Bazel target. Run it from the root before pushing:
bazel run //:formatSetup and troubleshooting: tools/dprint/README.md.
Rationale:
doc/000004-monorepo-wide-formatting.md.
You SHOULD use Conventional Commits.
Your commit SHOULD:
- Use a proper sentence as a description — start with an Uppercase letter, end with a dot.
- Use the common commit types.
- Whenever possible use a project as a scope (e.g.
fix(mail,apple): Fixed schedule send delay.). - Remember: the commits will be used to generate changelog.
ci: CI configuration.chore: No source or test files modified (e.g. tooling, script, dependency updates, maintenance).doc: Documentation changes.feat: A new feature.fix: Bug fixes.i18n: Internationalization and translations.refactor: A change in the source code that neither fixes a bug nor adds a feature.revert: Reverting a commit.style: Code style changes, not affecting code meaning (formatting).test: Adding new tests or improving existing ones.perf: Performance improvements, changes that make the code run faster, use less memory, etc. No functionality change.
| Branch name | Pattern | Remarks |
|---|---|---|
| main | main |
Main line branch, where we merge back, should always be production ready. |
| feature | <project>/feature/... |
|
| fix | <project>/fix/... |
|
| refactor | <project>/refactor/... |
|
| release | <project>/release/... |
See Releasing section below. |
When merging into main branch:
- You MUST rebase and fast-forward in order to keep the history linear.
- You MUST NOT use merge commits.
- You MUST only merge if the pipeline is successful, passing all minimal tests (described in the containing folder changes).
- You SHOULD run enough tests to be sure the MR is not breaking any tests in the monorepo.
When a merged commit break a test/project/platform/app, by default:
- The affected team SHOULD ask for a revert/rollback.
- The team owner of the breaking commit SHOULD take care of the revert process (e.g. MR, review, conflict, git revert).
You MUST create a release branch from the main branch, following this pattern:
<project>/release/<platform>/.../<version>
You MAY work on this branch for final release touch-ups. If you do, you SHOULD cherry-pick back to main.
Note: The preferred process is to fix the main branch, and then cherry-pick the commit in your release branch.
You MAY tag by project and module:
Example: @mail/android/mail-composer-1.0.2
There SHOULD be a CODEOWNERS file per directory that scopes the CODEOWNERS independently of the file structure. That has the effect that CODEOWNERS will be enforced even if the directory is moved.
- CI/CD triggers MUST be scoped per project with independent pipelines.
- Main branch changes trigger all minimal tests execution.
- Nightly tests might execute more than all minimal tests.
- The CI system MUST utilize the same commands employed by developers for building and testing purpose.
- Each project SHOULD provide a Gitlab CI pipeline yml file (.gitlab-ci.yml)
with:
- Minimal tests: Any change in a specific project will run at least this set of tests.
- Manual tests: Any team should be able to manually run any tests.
ci/Dockerfile: Main Dockerfile.ci/docker.gitlab-ci.yml: Image jobs.
- Update the
ci/Dockerfile(e.g.ENV,RUN, ...). - Update image version in
ci/docker.gitlab-ci.yml(e.g.1.0.10->1.0.11). - Update image version in
ci/base.gitlab-ci.yml(e.g.1.0.11). - Open an MR.
Gradle is cached and shared between jobs. To update the verstion of Gradle:
- Change the version of gradle in
gradle/wrapper/gradle-wrapper.properties. - Change the cache key used by the template
.build_android_templateinci/base.gitlab-ci.ymlappropriately. - Change the cache key used by the job
dowload:gradleinci/project.gitlab-ci.ymlappropriately.
The Android projects use Gradle composite builds to manage dependencies
between modules across different projects. This enables sharing common modules
(like core/design-system) across multiple Android applications while
maintaining project separation.
project/
core/android/ # Shared modules
design-system/ # UI components, themes, utilities
account/android/ # Account-specific modules
account-manager-ui/ # Account UI components
app/ # Account demo/test application
<other-projects>/android/ # Additional Android projects
Run Gradle commands from the monorepo root using the -p flag to specify the
project directory:
# Build a specific module
./gradlew -p project/account/android :app:assembleDebug
# Run tests
./gradlew -p project/account/android :account-manager-ui:testDebugUnitTestAndroid projects that depend on core modules use composite builds:
// Include the core Android project as a composite build
includeBuild("../../core/android")Note: Make sure all dependencies module follow group:artefact[:version] (e.g.
module: "core-design-system" + group = "me.proton.android.core" ->
me.proton.android.core:core-design-system).
Reference core modules in your build.gradle.kts:
dependencies {
implementation(libs.proton.monorepo.core.design.system) // From version catalog
}Shared dependencies are managed through a centralized version catalog
(gradle/libs.versions.toml):
The project uses JUnit5 for parameterized unit tests.
The project uses JUnit4 with TestParameterInjector for parameterized snapshot tests.
Generate and record visual snapshot tests:
# Record golden snapshots (update baseline images)
./gradlew -p project/account/android :account-manager-ui:recordPaparazziDebugNote: Snapshot PNG files are tracked with Git LFS to avoid repository bloat.
A sanitized mirror will be published to:
https://github.com/ProtonMail/clients