The mono-repository is split into multiple ‘Domains’ (like ‘Compiler’, ‘AnalysisApi’, ...). The CI can verify commits into such Domains independently. ‘Plain old tests’ of ‘unaffected Domains’ are not required to be executed on CI.
Domains are defined in the domains.yaml file e.g. the Native domain could be defined as:
Native: home: "kotlin-native" include: - "native/**" - "kotlin-native/**" fullyAffectedBy: - Compiler
where it gets assigned the ‘kotlin-native’ directory as its home. Files belonging to this ‘Native’ domain are included using the native/** and kotlin-native/** globs. A domain is always marked as ‘affected’ if any file, belonging to the domain, is changed.
Some domains might form a ‘Domain/Subdomain’ relationship which can be expressed using ‘fullyAffectedBy.’ A domain, which is fully affected by another domain, will always be marked as ‘affected’ by a set of changes if any of the (transitive) dependencies are marked affected. In the example above:
A change which marks the ‘larger Compiler domain’ as affected will also mark the ‘Native’ domain as affected, while a change isolated within the ‘Native’ domain will not affect the ‘Compiler’ domain.
The declared domains will be ‘expanded’ into the actual files belonging to each domain. The dump file will be verified on CI.
./gradlew :gradle-build-conventions:test-federation-convention:test --tests "org.jetbrains.kotlin.testFederation.DomainsDumpTest" --rerun
Changes to the domain.yaml file might require an update of the dump file. This can be done by executing the ‘update-domains’ script:
cd .. ./scripts/update-domains.sh
All tests of affected ‘Domains’ will be executed on CI. Running tests of a domain, which is not affected can be done by marking a test as ‘SmokeTest’. Using junit5 (or higher) allows using the @SmokeTest annotation
@SmokeTest @Test fun `my important test`() { // ... }
@SmokeTest class MyImportantTest { @Test fun `my important test`() { // ... } }
@SmokeTest abstract class AbstractImportantTests { // ... }
@SmokeTest annotation class MyImportantTest @MyImportantTest fun `my important test`() { // ... }
Smoke tests are always executed on CI, no matter the affected domains. Checking in a smoke test requires the test to fulfill the following criteria:
As unstable/flaky smoke tests affect the entire team, fixing them is a high priority.
It is possible to check in an entire test task as ‘smoke test’. This can be done by using the isSmokeTest extension property on the Test task. E.g.
tasks.withType<Test>().configureEach { isSmokeTest = true }
Some Domains might rely on the behavior or API of another Domain. Such requirements can be expressed as ‘Contract’ between two Domains. Any test can be promoted to a ‘Contract Test’ using the relevant @AffectedByXYZ annotation. e.g., a test that defines a contract to the ‘Js’ compiler might be marked as @AffectedByJs.
A set of well-maintained contracts is always more preferable than marking a domain as ‘fullyAffectedBy’ another domain, as ‘ContractTests’ will enable actually building efficient pipelines for verifying commits, whereas ‘fullyAffectedBy’ will require a full build of the affected domains.
@AffectedByJs class MyImportantJsTests { // ... }
any commit to the Js domain will verify all contracts.
Declaring a contract is transactional between at least two teams (owning their domains). Defining and changing a contract requires the explicit approval of both teams.