Devlog #3

06 June 2022

This development log (devlog) includes work done since the last devlog which mostly focus on iOS support.

Xcode Build Adapter

Building Xcode Scheme

Xcode schemes are the glue that ties actions (i.e. build, test, archive, etc.) and targets together. We map the scheme in two ways: globally, using the workspace, or locally, per project. The difference is subtle, but we will favour the local mapping over time as it should be more performant. The global mapping is a simple substitute for invoking the xcodebuild command line directly, as shown in the following cast:

We can build any shared scheme from Gradle’s root project.

Execution Avoidance for Xcode Targets

We are investigating how Gradle can provide execution avoidance directly out-of-the-box. Execution avoidance includes up-to-date detection (e.g. inputs/outputs snapshotting) and build cache (local or remote). Xcode is significantly lacking in the up-to-date detection capability. From our research, it seems Xcode heavily relies on modification time. In scenarios where only the modification time changes (not the content), i.e. on fresh GitHub clone or on pod install, xcodebuild will perform a full rebuild. The following demonstrates this behaviour:

However, with Gradle, we can detect the inputs and outputs of a target through analytics, allowing for some execution avoidance:

In this scenario, we used the HackerNews repository, a trivial application. The important takeaway here is the ability to split an Xcode workspace into multiple target clusters where we can cache each one individually. Some targets cluster can execute for as long as 7 minutes! It should be possible to avoid those lengthy executions using Gradle/Nokee.

Xcode error out on the side of rebuilding a target; hence proper inputs/outputs declaration isn’t as important. We will most likely need user intervention to identify the inputs/outputs of target clusters correctly.

Nokee Version Management plugin

To provide a first-class integration between Nokee and Gradle, we are developing a settings plugin to manage Nokee versions and repositories. We initially intended for the plugin to have a narrow scope for the first version. Still, we decided to include more features for those odd projects (i.e. air-gapped, firewalled, source dependencies, etc.). Nokee configuration will simplify to a single plugin apply instead of the current complicated pluginManagement block:

settings.gradle[.kts]
plugins {
    id("dev.nokee.nokee-version-management") version("<version>")
}