Skip to content

Commit 037e21d

Browse files
committed
use delegating shard tasks for connectedCheck
These shard tasks which collectively depend upon all Android `connectedCheck` tasks in the entire project. Each shard depends upon the `connectedCheck` tasks of some subset of Android projects. Projects are assigned to a shard by counting the number of `@Test` annotations within their `androidTest` directory, then associating those projects to a shard in a round-robin fashion. These shards are invoked in CI using a GitHub Actions matrix. If the number of shards changes, the `connectedCheckShardMatrixYamlUpdate` task can automatically update the workflow file so that they're all invoked. The shard tasks are invoked as: ```shell # roughly 1/3 of the tests ./gradlew connectedCheckShard1 # the second third ./gradlew connectedCheckShard2 # the last third ./gradlew connectedCheckShard3 ``` The task filtering we currently use in CI (`./gradlew fooShard1 -x :my-project:foo`) will still work here, however the "cost" of the excluded task's tests is still accounted for when the sharding is performed.
1 parent 0ddc861 commit 037e21d

File tree

9 files changed

+472
-131
lines changed

9 files changed

+472
-131
lines changed

.github/actions/gradle-task/action.yml

Lines changed: 12 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -26,8 +26,8 @@ runs :
2626
- name : Set up JDK
2727
uses : actions/setup-java@v3
2828
with :
29-
distribution : ${{ inputs.distribution }}
30-
java-version : ${{ inputs.java-version }}
29+
distribution : ${{inputs.distribution}}
30+
java-version : ${{inputs.java-version}}
3131

3232
- name : Set Gradle Args for runner OS
3333
id : gradle-args
@@ -44,42 +44,41 @@ runs :
4444
# This step's "cache_hit" output will only be true if an exact match was found.
4545
- name: restore cache for ${{inputs.write-cache-key}}
4646
id: restore-write-cache
47-
if: ${{inputs.write-cache-key}} != ''
47+
if: ${{inputs.write-cache-key}}
4848
uses: actions/cache/restore@v3
4949
with:
5050
path: |
5151
~/.gradle/caches/build-cache-1
5252
~/.gradle/wrapper
53-
key: ${{inputs.write-cache-key}}-${{ hashFiles('**/*.gradle.kt*') }}-${{ hashFiles('**/libs.versions.toml') }}-${{ hashFiles('**/gradle.properties') }}
53+
key: ${{inputs.write-cache-key}}-${{hashFiles('**/*.gradle.kt*')}}-${{hashFiles('**/libs.versions.toml')}}-${{hashFiles('**/gradle.properties')}}
5454
restore-keys: ${{inputs.write-cache-key}}
5555
enableCrossOsArchive: true
56-
lookup-only: true
5756

5857
# Attempt to restore from the restore-cache-key, or fall back to a partial match for the restore key.
5958
# Skipped if the restore-cache-key wasn't set, or if the write-cache-key restore had an exact match.
6059
- name: restore cache for ${{inputs.restore-cache-key}}
61-
if: ${{inputs.restore-cache-key}} != '' && steps.restore-write-cache.outputs.cache-hit != 'true'
60+
if: ${{inputs.restore-cache-key}} && steps.restore-write-cache.outputs.cache-hit != 'true'
6261
uses: actions/cache/restore@v3
6362
with:
6463
path: |
6564
~/.gradle/caches/build-cache-1
6665
~/.gradle/wrapper
67-
key: ${{inputs.restore-cache-key}}-${{ hashFiles('**/*.gradle.kt*') }}-${{ hashFiles('**/libs.versions.toml') }}-${{ hashFiles('**/gradle.properties') }}
66+
key: ${{inputs.restore-cache-key}}-${{hashFiles('**/*.gradle.kt*')}}-${{hashFiles('**/libs.versions.toml')}}-${{hashFiles('**/gradle.properties')}}
6867
restore-keys: ${{inputs.restore-cache-key}}
6968
enableCrossOsArchive: true
7069

7170
- uses: gradle/wrapper-validation-action@v1
7271

7372
# Run the actual task. Note that this still uses gradle-build-action for more fine-grained caching.
74-
- name : Run ${{ inputs.task }}
73+
- name : Run ${{inputs.task}}
7574
uses : gradle/gradle-build-action@v2
7675
with :
7776
# These arguments need to be on a single line. If they're defined with wrapping (using `|`),
7877
# something along the way to the actual CLI invocation gets confused and the jvmargs list
7978
# winds up getting parsed as a single argument.
80-
arguments : ${{ steps.gradle-args.outputs.gradle-property-args }} ${{ inputs.task }} '-Dorg.gradle.jvmargs=${{ steps.gradle-args.outputs.gradle-jvm-args }}'
79+
arguments : ${{steps.gradle-args.outputs.gradle-property-args}} ${{inputs.task}} '-Dorg.gradle.jvmargs=${{steps.gradle-args.outputs.gradle-jvm-args}}'
8180
cache-read-only : false
82-
build-root-directory : ${{ inputs.build-root-directory }}
81+
build-root-directory : ${{inputs.build-root-directory}}
8382
gradle-home-cache-cleanup : true
8483

8584
# Save the build cache to `write-cache-key`.
@@ -89,16 +88,16 @@ runs :
8988
- name: save the '${{inputs.write-cache-key}}' cache
9089
uses: actions/cache/save@v3
9190
id: save-write-cache-key
92-
if: ${{inputs.write-cache-key}} != '' && steps.restore-write-cache.outputs.cache-hit != 'true' && runner.os != 'Windows'
91+
if: ${{inputs.write-cache-key}} && steps.restore-write-cache.outputs.cache-hit != 'true' && runner.os != 'Windows'
9392
with:
9493
path: |
9594
~/.gradle/caches/build-cache-1
9695
~/.gradle/wrapper
97-
key: ${{inputs.write-cache-key}}-${{ hashFiles('**/*.gradle.kt*') }}-${{ hashFiles('**/libs.versions.toml') }}-${{ hashFiles('**/gradle.properties') }}
96+
key: ${{inputs.write-cache-key}}-${{hashFiles('**/*.gradle.kt*')}}-${{hashFiles('**/libs.versions.toml')}}-${{hashFiles('**/gradle.properties')}}
9897

9998
- name : Upload heap dump
10099
if : failure()
101100
uses : actions/upload-artifact@v3
102101
with :
103102
name : heap-dump
104-
path : ${{ github.workspace }}/**/*{.hprof,.log}
103+
path : ${{github.workspace}}/**/*{.hprof,.log}

.github/workflows/kotlin.yml

Lines changed: 58 additions & 118 deletions
Original file line numberDiff line numberDiff line change
@@ -14,22 +14,22 @@ concurrency :
1414

1515
jobs :
1616

17-
build-all:
18-
name: Build all
19-
runs-on: macos-latest
20-
steps:
21-
- uses: actions/checkout@v3
22-
23-
- name: main build
24-
uses: ./.github/actions/gradle-task
25-
with:
26-
task: compileKotlin compileDebugKotlin
27-
write-cache-key: main-build-artifacts
17+
build-all :
18+
name : Build all
19+
runs-on : macos-latest
20+
steps :
21+
- uses : actions/checkout@v3
22+
23+
- name : main build
24+
uses : ./.github/actions/gradle-task
25+
with :
26+
task : compileKotlin compileDebugKotlin
27+
write-cache-key : main-build-artifacts
2828

2929
dokka :
3030
name : Assemble & Dokka
3131
runs-on : ubuntu-latest
32-
needs: build-all
32+
needs : build-all
3333
steps :
3434
- uses : actions/checkout@v3
3535

@@ -39,6 +39,19 @@ jobs :
3939
task : siteDokka
4040
write-cache-key : main-build-artifacts
4141

42+
shards-and-version :
43+
name : Shard Matrix Yaml
44+
runs-on : ubuntu-latest
45+
steps :
46+
- uses : actions/checkout@v3
47+
48+
- name : check published artifacts
49+
uses : ./.github/actions/gradle-task-with-commit
50+
with :
51+
check-task : connectedCheckShardMatrixYamlCheck checkVersionIsSnapshot
52+
fix-task : connectedCheckShardMatrixYamlUpdate checkVersionIsSnapshot
53+
write-cache-key : build-logic
54+
4255
artifacts-check :
4356
name : ArtifactsCheck
4457
# the `artifactsCheck` task has to run on macOS in order to see the iOS KMP artifacts
@@ -101,7 +114,7 @@ jobs :
101114
android-lint :
102115
name : Android Lint
103116
runs-on : ubuntu-latest
104-
needs: build-all
117+
needs : build-all
105118
timeout-minutes : 20
106119
steps :
107120
- uses : actions/checkout@v3
@@ -114,17 +127,16 @@ jobs :
114127
check :
115128
name : Check
116129
runs-on : ubuntu-latest
117-
needs: build-all
130+
needs : build-all
118131
timeout-minutes : 20
119132
steps :
120133
- uses : actions/checkout@v3
121134
- name : Check with Gradle
122135
uses : ./.github/actions/gradle-task
123136
with :
124137
task : |
125-
checkVersionIsSnapshot
126138
allTests
127-
test
139+
test
128140
--continue
129141
restore-cache-key : build-logic
130142
write-cache-key : main-build-artifacts
@@ -289,7 +301,7 @@ jobs :
289301
build-instrumentation-tests :
290302
name : Build Instrumentation tests
291303
runs-on : macos-latest
292-
needs: build-all
304+
needs : build-all
293305
timeout-minutes : 45
294306
steps :
295307
- uses : actions/checkout@v3
@@ -303,21 +315,24 @@ jobs :
303315

304316
instrumentation-tests :
305317
name : Instrumentation tests
306-
needs: build-instrumentation-tests
318+
needs : build-instrumentation-tests
307319
runs-on : macos-latest
308320
timeout-minutes : 45
309321
strategy :
310322
# Allow tests to continue on other devices if they fail on one device.
311323
fail-fast : false
312324
matrix :
325+
# Unclear that older versions actually honor command to disable animation.
326+
# Newer versions are reputed to be too slow: https://github.com/ReactiveCircus/android-emulator-runner/issues/222
313327
api-level :
314328
- 29
315-
# Unclear that older versions actually honor command to disable animation.
316-
# Newer versions are reputed to be too slow: https://github.com/ReactiveCircus/android-emulator-runner/issues/222
329+
### <start-connected-check-shards>
330+
shardNum : [ 1, 2, 3 ]
331+
### <end-connected-check-shards>
317332
steps :
318333
- uses : actions/checkout@v3
319334

320-
# This really just pulls the cache from the dependency job
335+
## Build before running tests, using cache.
321336
- name : Build instrumented tests
322337
uses : ./.github/actions/gradle-task
323338
with :
@@ -333,104 +348,34 @@ jobs :
333348
api-level : ${{ matrix.api-level }}
334349
arch : x86_64
335350
# Skip the benchmarks as this is running on emulators
336-
script : ./gradlew connectedCheck -x :benchmarks:dungeon-benchmark:connectedCheck -x :benchmarks:performance-poetry:complex-benchmark:connectedCheck -x :benchmarks:performance-poetry:complex-poetry:connectedCheck
337-
338-
- name : Upload results
339-
if : ${{ always() }}
340-
uses : actions/upload-artifact@v3
341-
with :
342-
name : instrumentation-test-results-${{ matrix.api-level }}
343-
path : ./**/build/reports/androidTests/connected/**
344-
345-
conflate-renderings-instrumentation-tests :
346-
name : Conflate Stale Renderings Instrumentation tests
347-
runs-on : macos-latest
348-
timeout-minutes : 45
349-
strategy :
350-
# Allow tests to continue on other devices if they fail on one device.
351-
fail-fast : false
352-
matrix :
353-
api-level :
354-
- 29
355-
# Unclear that older versions actually honor command to disable animation.
356-
# Newer versions are reputed to be too slow: https://github.com/ReactiveCircus/android-emulator-runner/issues/222
357-
steps :
358-
- uses : actions/checkout@v3
359-
360-
## Build before running tests, using cache.
361-
- name : Build instrumented tests
362-
uses : ./.github/actions/gradle-task
363-
with :
364-
# Unfortunately I don't think we can key this cache based on our project property so
365-
# we clean and rebuild.
366-
task : clean assembleDebugAndroidTest -Pworkflow.runtime=conflate
367-
368-
## Actual task
369-
- name : Instrumentation Tests
370-
uses : reactivecircus/android-emulator-runner@v2
371-
with :
372-
# @ychescale9 suspects Galaxy Nexus is the fastest one
373-
profile : Galaxy Nexus
374-
api-level : ${{ matrix.api-level }}
375-
arch : x86_64
376-
# Skip the benchmarks as this is running on emulators
377-
script : ./gradlew connectedCheck -x :benchmarks:dungeon-benchmark:connectedCheck -x :benchmarks:performance-poetry:complex-benchmark:connectedCheck -x :benchmarks:performance-poetry:complex-poetry:connectedCheck -Pworkflow.runtime=conflate
351+
script : ./gradlew connectedCheckShard${{ matrix.shardNum }} -x :benchmarks:dungeon-benchmark:connectedCheck -x :benchmarks:performance-poetry:complex-benchmark:connectedCheck -x :benchmarks:performance-poetry:complex-poetry:connectedCheck
378352

379353
- name : Upload results
380354
if : ${{ always() }}
381355
uses : actions/upload-artifact@v3
382356
with :
383-
name : instrumentation-test-results-${{ matrix.api-level }}
357+
name : instrumentation-test-results-${{ matrix.api-level }}-shard_${{ matrix.shardNum }}
384358
path : ./**/build/reports/androidTests/connected/**
385359

386-
stateChange-runtime-instrumentation-tests :
387-
name : Render on State Change Only Instrumentation tests
360+
build-runtime-instrumentation-tests :
361+
name : Build Instrumented tests for ${{ matrix.runtime }}
388362
runs-on : macos-latest
389-
timeout-minutes : 45
363+
timeout-minutes : 35
390364
strategy :
391-
# Allow tests to continue on other devices if they fail on one device.
392-
fail-fast : false
393365
matrix :
394-
api-level :
395-
- 29
396-
# Unclear that older versions actually honor command to disable animation.
397-
# Newer versions are reputed to be too slow: https://github.com/ReactiveCircus/android-emulator-runner/issues/222
366+
runtime : [ conflate, baseline-stateChange, conflate-stateChange ]
398367
steps :
399368
- uses : actions/checkout@v3
400-
- name : set up JDK 11
401-
uses : actions/setup-java@v3
402-
with :
403-
distribution : 'zulu'
404-
java-version : 11
405369

406-
## Build before running tests, using cache.
407370
- name : Build instrumented tests
408371
uses : ./.github/actions/gradle-task
409372
with :
410-
# Unfortunately I don't think we can key this cache based on our project property so
411-
# we clean and rebuild.
412-
task : clean assembleDebugAndroidTest -Pworkflow.runtime=baseline-stateChange
373+
task : assembleDebugAndroidTest -Pworkflow.runtime=${{matrix.runtime}}
374+
write-cache-key : androidTest-build-artifacts-${{matrix.runtime}}
413375

414-
## Actual task
415-
- name : Instrumentation Tests
416-
uses : reactivecircus/android-emulator-runner@v2
417-
with :
418-
# @ychescale9 suspects Galaxy Nexus is the fastest one
419-
profile : Galaxy Nexus
420-
api-level : ${{ matrix.api-level }}
421-
arch : x86_64
422-
# Skip the benchmarks as this is running on emulators
423-
script : ./gradlew connectedCheck -x :benchmarks:dungeon-benchmark:connectedCheck -x :benchmarks:performance-poetry:complex-benchmark:connectedCheck -x :benchmarks:performance-poetry:complex-poetry:connectedCheck -Pworkflow.runtime=baseline-stateChange
424-
425-
- name : Upload results
426-
if : ${{ always() }}
427-
uses : actions/upload-artifact@v3
428-
with :
429-
name : stateChange-instrumentation-test-results-${{ matrix.api-level }}
430-
path : ./**/build/reports/androidTests/connected/**
431-
432-
conflate-stateChange-runtime-instrumentation-tests :
433-
name : Render on State Change Only and Conflate Stale Renderings Instrumentation tests
376+
runtime-instrumentation-tests :
377+
name : Conflate Stale Renderings Instrumentation tests
378+
needs : build-runtime-instrumentation-tests
434379
runs-on : macos-latest
435380
timeout-minutes : 45
436381
strategy :
@@ -439,23 +384,19 @@ jobs :
439384
matrix :
440385
api-level :
441386
- 29
442-
# Unclear that older versions actually honor command to disable animation.
443-
# Newer versions are reputed to be too slow: https://github.com/ReactiveCircus/android-emulator-runner/issues/222
387+
### <start-connected-check-shards>
388+
shardNum : [ 1, 2, 3 ]
389+
### <end-connected-check-shards>
390+
runtime : [ conflate, baseline-stateChange, conflate-stateChange ]
444391
steps :
445392
- uses : actions/checkout@v3
446-
- name : set up JDK 11
447-
uses : actions/setup-java@v3
448-
with :
449-
distribution : 'zulu'
450-
java-version : 11
451393

452-
## Build before running tests, using cache.
394+
# This really just pulls the cache from the dependency job
453395
- name : Build instrumented tests
454396
uses : ./.github/actions/gradle-task
455397
with :
456-
# Unfortunately I don't think we can key this cache based on our project property so
457-
# we clean and rebuild.
458-
task : clean assembleDebugAndroidTest -Pworkflow.runtime=conflate-stateChange
398+
task : assembleDebugAndroidTest -Pworkflow.runtime=${{matrix.runtime}}
399+
read-cache-key : androidTest-build-artifacts-${{matrix.runtime}}
459400

460401
## Actual task
461402
- name : Instrumentation Tests
@@ -466,13 +407,13 @@ jobs :
466407
api-level : ${{ matrix.api-level }}
467408
arch : x86_64
468409
# Skip the benchmarks as this is running on emulators
469-
script : ./gradlew connectedCheck -x :benchmarks:dungeon-benchmark:connectedCheck -x :benchmarks:performance-poetry:complex-benchmark:connectedCheck -x :benchmarks:performance-poetry:complex-poetry:connectedCheck -Pworkflow.runtime=conflate-stateChange
410+
script : ./gradlew connectedCheckShard${{ matrix.shardNum }} -Pworkflow.runtime=${{matrix.runtime}} -x :benchmarks:dungeon-benchmark:connectedCheck -x :benchmarks:performance-poetry:complex-benchmark:connectedCheck -x :benchmarks:performance-poetry:complex-poetry:connectedCheck
470411

471412
- name : Upload results
472413
if : ${{ always() }}
473414
uses : actions/upload-artifact@v3
474415
with :
475-
name : conflate-stateChange-instrumentation-test-results-${{ matrix.api-level }}
416+
name : conflate-instrumentation-test-results-${{ matrix.api-level }}-shard_${{ matrix.shardNum }}
476417
path : ./**/build/reports/androidTests/connected/**
477418

478419
all-green :
@@ -483,8 +424,6 @@ jobs :
483424
- api-check
484425
- artifacts-check
485426
- check
486-
- conflate-renderings-instrumentation-tests
487-
- conflate-stateChange-runtime-instrumentation-tests
488427
- dependency-guard
489428
- dokka
490429
- instrumentation-tests
@@ -495,7 +434,8 @@ jobs :
495434
- jvm-stateChange-runtime-test
496435
- ktlint
497436
- performance-tests
498-
- stateChange-runtime-instrumentation-tests
437+
- runtime-instrumentation-tests
438+
- shards-and-version
499439
- tutorials
500440

501441
steps :

build-logic/build.gradle.kts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ dependencies {
2323
implementation(libs.squareup.moshi)
2424
implementation(libs.squareup.moshi.adapters)
2525
implementation(libs.vanniktech.publish)
26+
implementation(libs.java.diff.utils)
2627

2728
ksp(libs.squareup.moshi.codegen)
2829
}

0 commit comments

Comments
 (0)