Using locally published components in Fenix
It's often important to test work-in-progress changes to Application Services components against a real-world consumer project. The most reliable method of performing such testing is to publish your components to a local Maven repository, and adjust the consuming project to install them from there.
With support from the upstream project, it's possible to do this in a single step using our auto-publishing workflow.
rust.targets
Both the auto-publishing and manual workflows can be sped up significantly by
using the rust.targets
property which limits which architectures the Rust
code gets build against. You can set this property by creating/editing the
local.properties
file in the repository root and adding a line like
rust.targets=x86,linux-x86-64
. The trick is knowing which targets to put in
that comma separated list:
- Use
x86
for running the app on most emulators (in rare cases, when you have a 64-bit emulator, you'll wantx86_64
) - If you're running the
android-components
orfenix
unit tests, then you'll need the architecture of your machine:- OSX running Intel chips:
darwin-x86-64
- OSX running M1 chips:
darwin-aarch64
- Linux:
linux-x86-64
- OSX running Intel chips:
Using the auto-publishing workflow
Some consumers (notably Fenix) have support for automatically publishing and including a local development version of application-services in their build. The workflow is:
-
Check out the consuming project.
-
Edit (or create) the file
local.properties
in the consuming project and tell it where to find your local checkout of application-services, by adding a line like:autoPublish.application-services.dir=relative/path/to/your/checkout/of/application-services
Note that the path should be relative from the root of the consumer's directory. For example, if
application-services
andfenix
are at the same level, the relative path would be../application-services
-
Build the consuming project following its usual build procedure, e.g. via
./gradlew assembleDebug
or./gradlew test
.
If all goes well, this should automatically build your checkout of application-services
, publish it
to a local maven repository, and configure the consuming project to install it from there instead of
from our published releases.
Using a manual workflow
Note: This is a bit tedious, and you should first try the auto-publishing workflow described
above. But if the auto-publishing workflow fails then it's important to know how to do the publishing process manually. Since most consuming apps get their copy of application-services
via a dependency
on android-components
, this procedure involves three separate repos:
-
Inside the
application-services
repository root:-
In
.buildconfig-android.yml
, changelibraryVersion
to end in-TESTING$N
1, where$N
is some number that you haven't used for this before.Example:
libraryVersion: 0.27.0-TESTING3
-
Run
./gradlew publishToMavenLocal
. This may take between 5 and 10 minutes.
-
-
Inside the
android-components
repository root:-
In
.buildconfig.yml
, changecomponentsVersion
to end in-TESTING$N
1, where$N
is some number that you haven't used for this before.Example:
componentsVersion: 0.51.0-TESTING3
-
Inside
buildSrc/src/main/java/Dependencies.kt
, changemozilla_appservices
to reference thelibraryVersion
you published in step 1 part 1.Example:
const val mozilla_appservices = "0.27.0-TESTING3"
-
Inside
build.gradle
, addmavenLocal()
insideallprojects { repositories { <here> } }
. -
Inside the android-components
local.properties
file, ensureautoPublish.application-services.dir
is NOT set. -
Run
./gradlew publishToMavenLocal
.
-
-
Inside the consuming project repository root:
-
Inside
build.gradle
, addmavenLocal()
insideallprojects { repositories { <here> } }
. -
Ensure that
local.properties
does not contain any configuration to related to auto-publishing the application-services repo. -
Inside
buildSrc/src/main/java/AndroidComponents.kt
, change the version numbers for android-components to match the new versions you defined above.Example:
const val VERSION = "0.51.0-TESTING3"
-
You should now be able to build and run the consuming application (assuming you could do so before all this).
Caveats
- This assumes you have followed the build instructions for Fenix
- Make sure you're fully up to date in all repos, unless you know you need to not be.
- This omits the steps if changes needed because, e.g.
application-services
made a breaking change to an API used inandroid-components
. These should be understandable to fix, you usually should be able to find a PR with the fixes somewhere in the android-component's list of pending PRs (or, failing that, a description of what to do in the application-services changelog). - Contact us if you get stuck.
Adding support for the auto-publish workflow
If you had to use the manual workflow above and found it incredibly tedious, you might like to try adding support for the auto-publish workflow to the consuming project! The details will differ depending on the specifics of the project's build setup, but at a high level you will need to:
-
In your settings.gradle, locate (or add) the code for parsing the
local.properties
file, and add support for loading a directory path from the propertyautoPublish.application-services.dir
.If this property is present, spawn a subprocess to run
./gradlew autoPublishForLocalDevelopment
in the specified directory. This automates step (1) of the manual workflow above, publishing your changes toapplication-services
into a local maven repository under a unique version number. -
In your build.gradle, if the
autoPublish.application-services.dir
property is present, have each project apply the build script from./build-scripts/substitute-local-appservices.gradle
in the specified directory.This automates steps (2) and (3) of the manual workflow above, using gradle's dependency substitution capabilities to override the verion requirements for application-services components. It may be necessary to experiment with the ordering of this relative to other build configuration steps, in order for the dependency substitution to work correctly.
For a single-project build this would look something like:
if (gradle.hasProperty('localProperties.autoPublish.application-services.dir')) { ext.appServicesSrcDir = gradle."localProperties.autoPublish.application-services.dir" apply from: "${appServicesSrcDir}/build-scripts/substitute-local-appservices.gradle" }
For a multi-project build it should be applied to all subprojects, like:
subprojects { if (gradle.hasProperty('localProperties.autoPublish.application-services.dir')) { ext.appServicesSrcDir = gradle."localProperties.autoPublish.application-services.dir" apply from: "${rootProject.projectDir}/${appServicesSrcDir}/build-scripts/substitute-local-appservices.gradle" } }
-
Confirm that the setup is working, by adding
autoPublish.application-services.dir
to yourlocal.properties
file and running./gradlew dependencies
for the project.You should be able to see gradle checking the build status of the various application-services dependencies as part of its setup phase. When the command completes, it should print the resolved versions of all dependencies, and you should see that application-services components have a version number in the format
0.0.1-SNAPSHOT-{TIMESTAMP}
.
[1]: It doesn't have to start with -TESTING
, it only needs
to have the format -someidentifier
. -SNAPSHOT$N
is also very common to use,
however without the numeric suffix, this has specific meaning to gradle, so we
avoid it. Additionally, while the $N
we have used in our running example has
matched (e.g. all of the identifiers ended in -TESTING3
, this is not required,
so long as you match everything up correctly at the end. This can be tricky, so
I always try to use the same number).