From fdbfd9e5c2c5e35c618e8cf82e247122fe0df49c Mon Sep 17 00:00:00 2001 From: Titouan Thibaud Date: Fri, 13 Mar 2026 13:53:08 +0100 Subject: [PATCH] Handle `tryfox://` deeplinks. Closes Issue #26 --- README.md | 5 +- .../artifacts_MtjLasg-Q5Kfvxqbke7VRA.json | 46 + .../artifacts_WDJb1HJaTr-dfSkshBxw4w.json | 46 + .../artifacts_aYE-3Nm5RH-fkycUNlPFuw.json | 52 + .../artifacts_cnZtdaVgTpeS3Vk4FtvYhA.json | 52 + .../assets/job_for_push_1711351.json | 3667 +++++++++++++++++ .../assets/job_for_push_1712468.json | 3607 ++++++++++++++++ .../assets/profile-pushes-for-npoon.json | 61 + .../tryfox/MainActivityDeeplinkTest.kt | 36 + app/src/main/AndroidManifest.xml | 11 +- app/src/main/assets/kotzilla.key | 1 + .../org/mozilla/tryfox/AppDeepLinkParser.kt | 125 + .../java/org/mozilla/tryfox/MainActivity.kt | 49 +- .../mozilla/tryfox/AppDeepLinkParserTest.kt | 89 + metro.txt | 669 +++ tracebox | 286 ++ 16 files changed, 8782 insertions(+), 20 deletions(-) create mode 100644 app/src/androidTest/assets/artifacts_MtjLasg-Q5Kfvxqbke7VRA.json create mode 100644 app/src/androidTest/assets/artifacts_WDJb1HJaTr-dfSkshBxw4w.json create mode 100644 app/src/androidTest/assets/artifacts_aYE-3Nm5RH-fkycUNlPFuw.json create mode 100644 app/src/androidTest/assets/artifacts_cnZtdaVgTpeS3Vk4FtvYhA.json create mode 100644 app/src/androidTest/assets/job_for_push_1711351.json create mode 100644 app/src/androidTest/assets/job_for_push_1712468.json create mode 100644 app/src/androidTest/assets/profile-pushes-for-npoon.json create mode 100644 app/src/main/assets/kotzilla.key create mode 100644 app/src/main/java/org/mozilla/tryfox/AppDeepLinkParser.kt create mode 100644 app/src/test/java/org/mozilla/tryfox/AppDeepLinkParserTest.kt create mode 100644 metro.txt create mode 100755 tracebox diff --git a/README.md b/README.md index 18df854..4e399b9 100644 --- a/README.md +++ b/README.md @@ -30,6 +30,9 @@ A simple Android app to search, download, and install Fenix (Firefox for Android `https://treeherder.mozilla.org/jobs?repo=&revision=` (e.g., `https://treeherder.mozilla.org/jobs?repo=try&revision=c2f3f652a3a063cb7933c2781038a25974cd09ec`) The app will select the correct project and load the revision. + - Open the app directly with the custom TryFox scheme using the same query parameters: + `tryfox://jobs?repo=&revision=` + `tryfox://jobs?author=` ## Usage @@ -43,7 +46,7 @@ A simple Android app to search, download, and install Fenix (Firefox for Android - Tap "Download" to fetch an APK. Progress will be shown on the button. - Once downloaded, the button changes to "Install". Tap it to install the APK. - Unsupported APKs can be viewed by expanding their section. -7. Alternatively, click a Treeherder link (formatted as described in Deep Link Integration) to open the app directly to that build. +7. Alternatively, click a Treeherder link or a `tryfox://jobs?...` link to open the app directly to that build or profile view. ## API Endpoints Used diff --git a/app/src/androidTest/assets/artifacts_MtjLasg-Q5Kfvxqbke7VRA.json b/app/src/androidTest/assets/artifacts_MtjLasg-Q5Kfvxqbke7VRA.json new file mode 100644 index 0000000..f3a902b --- /dev/null +++ b/app/src/androidTest/assets/artifacts_MtjLasg-Q5Kfvxqbke7VRA.json @@ -0,0 +1,46 @@ +{ + "artifacts": [ + { + "storageType": "s3", + "name": "public/build/target.arm64-v8a.apk", + "expires": "2025-09-23T16:57:07.283Z", + "contentType": "application/vnd.android.package-archive" + }, + { + "storageType": "s3", + "name": "public/build/target.armeabi-v7a.apk", + "expires": "2025-09-23T16:57:07.283Z", + "contentType": "application/vnd.android.package-archive" + }, + { + "storageType": "s3", + "name": "public/build/target.x86_64.apk", + "expires": "2025-09-23T16:57:07.283Z", + "contentType": "application/vnd.android.package-archive" + }, + { + "storageType": "s3", + "name": "public/build/target.x86.apk", + "expires": "2025-09-23T16:57:07.283Z", + "contentType": "application/vnd.android.package-archive" + }, + { + "storageType": "s3", + "name": "public/chain-of-trust.json", + "expires": "2025-09-23T16:57:07.283Z", + "contentType": "application/json" + }, + { + "storageType": "s3", + "name": "public/logs/chain_of_trust.log", + "expires": "2025-09-23T16:57:07.283Z", + "contentType": "text/plain" + }, + { + "storageType": "s3", + "name": "public/logs/live_backing.log", + "expires": "2025-09-23T16:57:07.283Z", + "contentType": "text/plain" + } + ] +} \ No newline at end of file diff --git a/app/src/androidTest/assets/artifacts_WDJb1HJaTr-dfSkshBxw4w.json b/app/src/androidTest/assets/artifacts_WDJb1HJaTr-dfSkshBxw4w.json new file mode 100644 index 0000000..d029a15 --- /dev/null +++ b/app/src/androidTest/assets/artifacts_WDJb1HJaTr-dfSkshBxw4w.json @@ -0,0 +1,46 @@ +{ + "artifacts": [ + { + "storageType": "s3", + "name": "public/build/target.arm64-v8a.apk", + "expires": "2025-09-24T13:53:58.443Z", + "contentType": "application/vnd.android.package-archive" + }, + { + "storageType": "s3", + "name": "public/build/target.armeabi-v7a.apk", + "expires": "2025-09-24T13:53:58.443Z", + "contentType": "application/vnd.android.package-archive" + }, + { + "storageType": "s3", + "name": "public/build/target.x86_64.apk", + "expires": "2025-09-24T13:53:58.443Z", + "contentType": "application/vnd.android.package-archive" + }, + { + "storageType": "s3", + "name": "public/build/target.x86.apk", + "expires": "2025-09-24T13:53:58.443Z", + "contentType": "application/vnd.android.package-archive" + }, + { + "storageType": "s3", + "name": "public/chain-of-trust.json", + "expires": "2025-09-24T13:53:58.443Z", + "contentType": "application/json" + }, + { + "storageType": "s3", + "name": "public/logs/chain_of_trust.log", + "expires": "2025-09-24T13:53:58.443Z", + "contentType": "text/plain" + }, + { + "storageType": "s3", + "name": "public/logs/live_backing.log", + "expires": "2025-09-24T13:53:58.443Z", + "contentType": "text/plain" + } + ] +} \ No newline at end of file diff --git a/app/src/androidTest/assets/artifacts_aYE-3Nm5RH-fkycUNlPFuw.json b/app/src/androidTest/assets/artifacts_aYE-3Nm5RH-fkycUNlPFuw.json new file mode 100644 index 0000000..298a1e7 --- /dev/null +++ b/app/src/androidTest/assets/artifacts_aYE-3Nm5RH-fkycUNlPFuw.json @@ -0,0 +1,52 @@ +{ + "artifacts": [ + { + "storageType": "s3", + "name": "public/build/target.arm64-v8a.apk", + "expires": "2025-09-23T16:57:07.497Z", + "contentType": "application/vnd.android.package-archive" + }, + { + "storageType": "s3", + "name": "public/build/target.armeabi-v7a.apk", + "expires": "2025-09-23T16:57:07.497Z", + "contentType": "application/vnd.android.package-archive" + }, + { + "storageType": "s3", + "name": "public/build/target.universal.apk", + "expires": "2025-09-23T16:57:07.497Z", + "contentType": "application/vnd.android.package-archive" + }, + { + "storageType": "s3", + "name": "public/build/target.x86_64.apk", + "expires": "2025-09-23T16:57:07.497Z", + "contentType": "application/vnd.android.package-archive" + }, + { + "storageType": "s3", + "name": "public/build/target.x86.apk", + "expires": "2025-09-23T16:57:07.497Z", + "contentType": "application/vnd.android.package-archive" + }, + { + "storageType": "s3", + "name": "public/chain-of-trust.json", + "expires": "2025-09-23T16:57:07.497Z", + "contentType": "application/json" + }, + { + "storageType": "s3", + "name": "public/logs/chain_of_trust.log", + "expires": "2025-09-23T16:57:07.497Z", + "contentType": "text/plain" + }, + { + "storageType": "s3", + "name": "public/logs/live_backing.log", + "expires": "2025-09-23T16:57:07.497Z", + "contentType": "text/plain" + } + ] +} \ No newline at end of file diff --git a/app/src/androidTest/assets/artifacts_cnZtdaVgTpeS3Vk4FtvYhA.json b/app/src/androidTest/assets/artifacts_cnZtdaVgTpeS3Vk4FtvYhA.json new file mode 100644 index 0000000..909262d --- /dev/null +++ b/app/src/androidTest/assets/artifacts_cnZtdaVgTpeS3Vk4FtvYhA.json @@ -0,0 +1,52 @@ +{ + "artifacts": [ + { + "storageType": "s3", + "name": "public/build/target.arm64-v8a.apk", + "expires": "2025-09-24T13:53:58.646Z", + "contentType": "application/vnd.android.package-archive" + }, + { + "storageType": "s3", + "name": "public/build/target.armeabi-v7a.apk", + "expires": "2025-09-24T13:53:58.646Z", + "contentType": "application/vnd.android.package-archive" + }, + { + "storageType": "s3", + "name": "public/build/target.universal.apk", + "expires": "2025-09-24T13:53:58.646Z", + "contentType": "application/vnd.android.package-archive" + }, + { + "storageType": "s3", + "name": "public/build/target.x86_64.apk", + "expires": "2025-09-24T13:53:58.646Z", + "contentType": "application/vnd.android.package-archive" + }, + { + "storageType": "s3", + "name": "public/build/target.x86.apk", + "expires": "2025-09-24T13:53:58.646Z", + "contentType": "application/vnd.android.package-archive" + }, + { + "storageType": "s3", + "name": "public/chain-of-trust.json", + "expires": "2025-09-24T13:53:58.646Z", + "contentType": "application/json" + }, + { + "storageType": "s3", + "name": "public/logs/chain_of_trust.log", + "expires": "2025-09-24T13:53:58.646Z", + "contentType": "text/plain" + }, + { + "storageType": "s3", + "name": "public/logs/live_backing.log", + "expires": "2025-09-24T13:53:58.646Z", + "contentType": "text/plain" + } + ] +} \ No newline at end of file diff --git a/app/src/androidTest/assets/job_for_push_1711351.json b/app/src/androidTest/assets/job_for_push_1711351.json new file mode 100644 index 0000000..fc2aba6 --- /dev/null +++ b/app/src/androidTest/assets/job_for_push_1711351.json @@ -0,0 +1,3667 @@ +{ + "count": 182, + "next": null, + "previous": null, + "results": [ + [ + 1, + 524257822, + "unknown", + "?", + "Gecko Decision Task", + "D", + "2025-08-26T16:57:34.247858", + "gecko-decision", + 1711578, + "47e31ea0adff5b3270d76c73aa66f3eafde85316", + "success", + "2aa083621bb989d6acf1151667288d5fe9616178", + "completed", + 1, + "KbMWJYQfQvyleW1PebgQZQ", + 0, + 4, + "opt" + ], + [ + 1, + 524259486, + "ktlint linter", + "ktlint", + "source-test-ktlint-android-components", + "AC", + "2025-08-26T17:08:25.742165", + "lint", + 1711578, + "47e31ea0adff5b3270d76c73aa66f3eafde85316", + "success", + "19b2dbb17d2317489961d59d56a20b8c822a6425", + "completed", + 1, + "bnvF0RftR82vPFooduODTA", + 0, + 4, + "opt" + ], + [ + 1, + 524259487, + "Make sure the content of .buildconfig.yml matches what gradle knows about its projects", + "buildconfig", + "source-test-buildconfig-buildconfig-android-components", + "AC", + "2025-08-26T17:05:29.554327", + "lint", + 1711578, + "47e31ea0adff5b3270d76c73aa66f3eafde85316", + "success", + "7188e619c71cb2ff52e45c4c8efa961a70d5ee6d", + "completed", + 2, + "BzA051PPQFCU8HJkYrLiKQ", + 0, + 6, + "opt" + ], + [ + 1, + 524259488, + "pedantic checks", + "pedantic", + "source-test-mozlint-file-whitespace", + "file-whitespace", + "2025-08-26T17:01:42.863107", + "lint", + 1711578, + "47e31ea0adff5b3270d76c73aa66f3eafde85316", + "success", + "8762ce85f312620a908db2d256608d1c8c23fffa", + "completed", + 2, + "CceQCKbKRVKPgk_qxlLomQ", + 0, + 2, + "opt" + ], + [ + 1, + 524259489, + "Make sure the content of .buildconfig.yml matches what gradle knows about its projects", + "buildconfig", + "source-test-buildconfig-buildconfig-focus", + "focus", + "2025-08-26T17:05:15.988241", + "lint", + 1711578, + "47e31ea0adff5b3270d76c73aa66f3eafde85316", + "success", + "ccae5ecbd29e2ae9f2e2adc1ab359243f215d8f5", + "completed", + 2, + "cPT2xRKnQly66yyNI20m6A", + 0, + 6, + "opt" + ], + [ + 1, + 524259490, + "Android Gradle tests", + "A", + "source-test-mozlint-android-focus", + "focus-lints", + "2025-08-26T17:16:42.793481", + "lint", + 1711578, + "47e31ea0adff5b3270d76c73aa66f3eafde85316", + "success", + "ec71355f9f1dd054c2d09f84e32c5cf65004d6e1", + "completed", + 1, + "cFYriYERS4a9UQAOGzTtoQ", + 0, + 17, + "opt" + ], + [ + 1, + 524259491, + "Android Gradle tests", + "A", + "source-test-mozlint-android-lints", + "lints", + "2025-08-26T17:13:39.503539", + "lint", + 1711578, + "47e31ea0adff5b3270d76c73aa66f3eafde85316", + "success", + "6135ddac32ce2bce207c33c98a57ec3ee27f1c66", + "completed", + 1, + "DhAKkJ4UT0atYDjJSWncMg", + 0, + 14, + "opt" + ], + [ + 1, + 524259492, + "Check on texts", + "text", + "source-test-mozlint-dot-mozilla-reference", + "dot-mozilla-reference", + "2025-08-26T17:01:22.194299", + "lint", + 1711578, + "47e31ea0adff5b3270d76c73aa66f3eafde85316", + "retry", + "ad31a3742ce4afc54ac78bdcc6f2b6f891c47559", + "completed", + 2, + "Dy4gR0qpSs2AY7rCP2kh9g", + 0, + 2, + "opt" + ], + [ + 1, + 524259493, + "JavaScript checks", + "js", + "source-test-mozlint-eslint", + "ES", + "2025-08-26T17:08:59.755619", + "lint", + 1711578, + "47e31ea0adff5b3270d76c73aa66f3eafde85316", + "success", + "01b2f1ca1f5d11dc77d82097b26ec9549d71f1e8", + "completed", + 1, + "eHLRgIg0TVCrIw21PcY7VQ", + 0, + 10, + "opt" + ], + [ + 1, + 524259494, + "ktlint linter", + "ktlint", + "source-test-ktlint-focus", + "focus", + "2025-08-26T17:08:42.889629", + "lint", + 1711578, + "47e31ea0adff5b3270d76c73aa66f3eafde85316", + "success", + "043aa07c36173f1633e2ce2eb0d5164ea208a110", + "completed", + 1, + "E_eA2vbSTIKEmqNRMTmWZQ", + 0, + 4, + "opt" + ], + [ + 1, + 524259495, + "unknown", + "?", + "build-android-arm/opt", + "Ba", + "2025-08-26T17:06:36.519846", + "android-5-0-armv7", + 1711578, + "47e31ea0adff5b3270d76c73aa66f3eafde85316", + "success", + "77ffc689165cfb0c63d389e188e797410af8c447", + "completed", + 1, + "elFpOn19RsGbmPlr4q7-bg", + 0, + 9, + "opt" + ], + [ + 1, + 524259496, + "pedantic checks", + "pedantic", + "source-test-mozlint-license", + "license", + "2025-08-26T17:01:54.695299", + "lint", + 1711578, + "47e31ea0adff5b3270d76c73aa66f3eafde85316", + "success", + "6b73bd01b6cf9a0b87c15c032e2da81bedddd157", + "completed", + 1, + "fs9-ugdtSOes2y9HZVHuUg", + 0, + 2, + "opt" + ], + [ + 1, + 524259497, + "detekt linter", + "detekt", + "source-test-android-detekt-detekt-android-components", + "AC", + "2025-08-26T17:08:59.614118", + "lint", + 1711578, + "47e31ea0adff5b3270d76c73aa66f3eafde85316", + "success", + "7c07e5ff57d9261e7cc6a27ffb70aea702f239f9", + "completed", + 1, + "ftbWal1gTDe1osGqCoAuKg", + 0, + 4, + "opt" + ], + [ + 1, + 524259498, + "Android Gradle tests", + "A", + "source-test-mozlint-android-android-components", + "ac-lints", + "2025-08-26T17:21:27.941553", + "lint", + 1711578, + "47e31ea0adff5b3270d76c73aa66f3eafde85316", + "success", + "e84cfc17c87572d08d28f46a6501711edd5beee1", + "completed", + 1, + "fuDLaRq9Rl2J_nnirMHqCg", + 0, + 22, + "opt" + ], + [ + 1, + 524259499, + "Python 3 unit tests", + "py3", + "source-test-python-android-android-gradle-build-linux2404-64/opt", + "agb", + "2025-08-26T17:21:47.103813", + "linux2404-64", + 1711578, + "47e31ea0adff5b3270d76c73aa66f3eafde85316", + "success", + "a793986369ed470436e94ab73c751ac42763e125", + "completed", + 2, + "G_nCrYjESc6l0yF9DVRDiw", + 0, + 22, + "opt" + ], + [ + 1, + 524259500, + "Validate strings.xml with compare-locales", + "compare-locales", + "source-test-android-compare-locales-compare-locales-android-components", + "AC", + "2025-08-26T17:00:54.225320", + "lint", + 1711578, + "47e31ea0adff5b3270d76c73aa66f3eafde85316", + "success", + "b70d6b81fcb498ffcf522a9429565733b15464c8", + "completed", + 2, + "Jf8jNJvGRPqAINKnuOTgZQ", + 0, + 1, + "opt" + ], + [ + 1, + 524259501, + "detekt linter", + "detekt", + "source-test-android-detekt-detekt-fenix", + "fenix", + "2025-08-26T17:09:32.944445", + "lint", + 1711578, + "47e31ea0adff5b3270d76c73aa66f3eafde85316", + "success", + "9cf9e3292e270afd08c18d91ee3605b0a5df9049", + "completed", + 1, + "P17WgDvyQjyUU2J1SnNn9g", + 0, + 4, + "opt" + ], + [ + 1, + 524259502, + "pedantic checks", + "pedantic", + "source-test-mozlint-file-perm", + "file-perm", + "2025-08-26T17:03:23.601478", + "lint", + 1711578, + "47e31ea0adff5b3270d76c73aa66f3eafde85316", + "success", + "58b1d7accdebfa1395ee38cf4e1181c36555c4a1", + "completed", + 2, + "PCXIy5cGR1SpngCYEgYRNQ", + 0, + 4, + "opt" + ], + [ + 1, + 524259503, + "Make sure the content of .buildconfig.yml matches what gradle knows about its projects", + "buildconfig", + "source-test-buildconfig-buildconfig-fenix", + "fenix", + "2025-08-26T17:06:08.625987", + "lint", + 1711578, + "47e31ea0adff5b3270d76c73aa66f3eafde85316", + "success", + "21b7b90f765bec57c7e991e0d8085fc1a7fd982f", + "completed", + 2, + "PmvKBURzRrKC2o3l8Vs4CQ", + 0, + 7, + "opt" + ], + [ + 1, + 524259504, + "ktlint linter", + "ktlint", + "source-test-ktlint-fenix", + "fenix", + "2025-08-26T17:09:09.275968", + "lint", + 1711578, + "47e31ea0adff5b3270d76c73aa66f3eafde85316", + "success", + "6f89ad8095150763ffe8d190146d0bce3cb83599", + "completed", + 1, + "Q0U_WL3_RQCkYsAcm_5nJQ", + 0, + 4, + "opt" + ], + [ + 1, + 524259505, + "Android Gradle tests", + "A", + "source-test-mozlint-android-fenix", + "fenix-lints", + "2025-08-26T17:27:45.384997", + "lint", + 1711578, + "47e31ea0adff5b3270d76c73aa66f3eafde85316", + "success", + "1326e00ec86829fcbbca62688d7d0ffa06b30c0a", + "completed", + 1, + "QouB4EZoR9yIsw3b15jaRA", + 0, + 28, + "opt" + ], + [ + 1, + 524259506, + "detekt linter", + "detekt", + "source-test-android-detekt-detekt-focus", + "focus", + "2025-08-26T17:09:14.722500", + "lint", + 1711578, + "47e31ea0adff5b3270d76c73aa66f3eafde85316", + "success", + "7ee68125000cfe80ac5f2ac8d122e733147269d0", + "completed", + 1, + "Qup_vfK2SnuzDI8BD5Ga9A", + 0, + 4, + "opt" + ], + [ + 1, + 524259507, + "Validate strings.xml with compare-locales", + "compare-locales", + "source-test-android-compare-locales-compare-locales-fenix", + "fenix", + "2025-08-26T17:00:49.571167", + "lint", + 1711578, + "47e31ea0adff5b3270d76c73aa66f3eafde85316", + "success", + "fedce0f857e8cfff0af4a592e29843a71cd034b7", + "completed", + 2, + "Tc428l20RSygFkKoPFdQxA", + 0, + 1, + "opt" + ], + [ + 1, + 524259508, + "Validate strings.xml with compare-locales", + "compare-locales", + "source-test-android-compare-locales-compare-locales-focus", + "focus", + "2025-08-26T17:00:59.407762", + "lint", + 1711578, + "47e31ea0adff5b3270d76c73aa66f3eafde85316", + "success", + "0373f095aacb94058314765f40bad4d8041f93cf", + "completed", + 2, + "WrcloVMQTHOUqLxkY1rMzg", + 0, + 1, + "opt" + ], + [ + 1, + 524259509, + "unknown", + "?", + "build-android-x86/opt", + "Ba", + "2025-08-26T17:03:30.217210", + "android-5-0-x86", + 1711578, + "47e31ea0adff5b3270d76c73aa66f3eafde85316", + "success", + "76d2f0885564b84df6b664274360a49253d5c248", + "completed", + 1, + "VVPOY29fQ3Kc9bQH6Oky9Q", + 0, + 6, + "opt" + ], + [ + 1, + 524259510, + "unknown", + "?", + "build-android-x86_64/opt", + "Ba", + "2025-08-26T17:03:44.312856", + "android-5-0-x86_64", + 1711578, + "47e31ea0adff5b3270d76c73aa66f3eafde85316", + "success", + "403283030fcbd7c79a0fa1973708af105c983218", + "completed", + 1, + "X6InI4FqQ9muWRad3tbs8A", + 0, + 6, + "opt" + ], + [ + 1, + 524259511, + "unknown", + "?", + "build-android-aarch64/opt", + "Ba", + "2025-08-26T17:04:06.085800", + "android-5-0-aarch64", + 1711578, + "47e31ea0adff5b3270d76c73aa66f3eafde85316", + "success", + "dfa39c8d92b68e4e1307814a6e161c4524b579c1", + "completed", + 1, + "WwOoRVE0SxqV1XFeBz8Frw", + 0, + 7, + "opt" + ], + [ + 1, + 524259512, + "Check on texts", + "text", + "source-test-mozlint-rejected-words", + "rejected-words", + "2025-08-26T17:06:41.628882", + "lint", + 1711578, + "47e31ea0adff5b3270d76c73aa66f3eafde85316", + "success", + "f22644154e5ef26d261fa39ac64de643582d66b5", + "completed", + 2, + "ZKWlgPphSIGI4jIJRtJJJA", + 0, + 7, + "opt" + ], + [ + 1, + 524260389, + "Check on texts", + "text", + "source-test-mozlint-dot-mozilla-reference", + "dot-mozilla-reference", + "2025-08-26T17:04:28.961356", + "lint", + 1711578, + "47e31ea0adff5b3270d76c73aa66f3eafde85316", + "success", + "ad31a3742ce4afc54ac78bdcc6f2b6f891c47559", + "completed", + 2, + "Dy4gR0qpSs2AY7rCP2kh9g", + 1, + 3, + "opt" + ], + [ + 1, + 524261159, + "unknown", + "?", + "build-fat-aar-android-geckoview-fat-aar/opt", + "B", + "2025-08-26T17:13:24.554036", + "android-5-0-geckoview-fat-aar", + 1711578, + "47e31ea0adff5b3270d76c73aa66f3eafde85316", + "success", + "b18b9a54b1ed572910bd7fc677feb1be6fe69175", + "completed", + 1, + "OseZnvT_Q6yug-MSDgroOQ", + 0, + 7, + "opt" + ], + [ + 1, + 524262155, + "feature-addons", + "feature-addons", + "build-components-feature-addons", + "B", + "2025-08-26T17:31:18.138934", + "AC-android-all", + 1711578, + "47e31ea0adff5b3270d76c73aa66f3eafde85316", + "success", + "ab25215247c585400cd3e450a7d8135abb21d4be", + "completed", + 1, + "Af7NaGD2QH6jqq1AElWuoQ", + 0, + 9, + "opt" + ], + [ + 1, + 524262158, + "samples-dataprotect", + "samples-dataprotect", + "build-components-samples-dataprotect", + "B", + "2025-08-26T17:29:34.173060", + "AC-android-all", + 1711578, + "47e31ea0adff5b3270d76c73aa66f3eafde85316", + "success", + "b9236328559eb94a6829bd0baebde64b5d3707d9", + "completed", + 1, + "aH67ivINR4GJaBTHK5FIUw", + 0, + 7, + "opt" + ], + [ + 1, + 524262160, + "concept-awesomebar", + "concept-awesomebar", + "build-components-concept-awesomebar", + "B", + "2025-08-26T17:28:57.694647", + "AC-android-all", + 1711578, + "47e31ea0adff5b3270d76c73aa66f3eafde85316", + "success", + "c364766b1201a44805804289be4f5c7e87a66165", + "completed", + 1, + "AR8uA267Qv2WOmvSsd0sjQ", + 0, + 7, + "opt" + ], + [ + 1, + 524262162, + "lib-state", + "lib-state", + "build-components-lib-state", + "B", + "2025-08-26T17:29:56.603515", + "AC-android-all", + 1711578, + "47e31ea0adff5b3270d76c73aa66f3eafde85316", + "success", + "4f2d44a3f116359cbe875d59cd11e8c2b361d4bd", + "completed", + 1, + "AssKGeyHSHuQtIKZ59O9AA", + 0, + 7, + "opt" + ], + [ + 1, + 524262164, + "tooling-lint", + "tooling-lint", + "build-components-tooling-lint", + "B", + "2025-08-26T17:29:04.038278", + "AC-android-all", + 1711578, + "47e31ea0adff5b3270d76c73aa66f3eafde85316", + "success", + "fea54c65d9e1aa9f1c37b497769749af648f6bc8", + "completed", + 1, + "auPtlK-OSo-FggmeboGXoQ", + 0, + 6, + "opt" + ], + [ + 1, + 524262166, + "support-ktx", + "support-ktx", + "test-components-android-support-ktx", + "unit", + "2025-08-26T17:40:13.338333", + "AC-ui-test", + 1711578, + "47e31ea0adff5b3270d76c73aa66f3eafde85316", + "success", + "a84579a328de7428d278134d257fb8cdde2f055a", + "completed", + 2, + "avfvx0VRTE-mYG1CWjGnFA", + 0, + 18, + "opt" + ], + [ + 1, + 524262168, + "samples-crash", + "samples-crash", + "build-components-samples-crash", + "B", + "2025-08-26T17:30:15.395566", + "AC-android-all", + 1711578, + "47e31ea0adff5b3270d76c73aa66f3eafde85316", + "success", + "36bd21032d5e98b3c7cd4547a02727bef81f60bb", + "completed", + 1, + "AVoIpERsQ1Gkd0S3SyjnDg", + 0, + 8, + "opt" + ], + [ + 1, + 524262170, + "browser-engine-gecko", + "browser-engine-gecko", + "build-components-browser-engine-gecko", + "B", + "2025-08-26T17:33:28.205358", + "AC-android-all", + 1711578, + "47e31ea0adff5b3270d76c73aa66f3eafde85316", + "success", + "af71760b61bccf9d0879f06bef863b053dcfc4ba", + "completed", + 1, + "AxmBZnjmTLKw0VPDqd6Oug", + 0, + 11, + "opt" + ], + [ + 1, + 524262172, + "feature-customtabs", + "feature-customtabs", + "build-components-feature-customtabs", + "B", + "2025-08-26T17:32:52.691238", + "AC-android-all", + 1711578, + "47e31ea0adff5b3270d76c73aa66f3eafde85316", + "success", + "94f247243038cc8b364cab4978e6701fc8828f27", + "completed", + 1, + "B6CDILJITnOGnrnUCwYTjg", + 0, + 10, + "opt" + ], + [ + 1, + 524262174, + "feature-media", + "feature-media", + "build-components-feature-media", + "B", + "2025-08-26T17:30:52.181936", + "AC-android-all", + 1711578, + "47e31ea0adff5b3270d76c73aa66f3eafde85316", + "success", + "02985175132ccb9621f21a68bb3a8a325c87e4aa", + "completed", + 1, + "BaMEpF_hSB20sEAwyxT1AA", + 0, + 8, + "opt" + ], + [ + 1, + 524262176, + "browser-icons", + "browser-icons", + "build-components-browser-icons", + "B", + "2025-08-26T17:30:43.081791", + "AC-android-all", + 1711578, + "47e31ea0adff5b3270d76c73aa66f3eafde85316", + "success", + "0cc479368fa28a226328226e294cfe2f2fc920c3", + "completed", + 1, + "BFRUQ_YjQ9uOD5NGKXXvvQ", + 0, + 8, + "opt" + ], + [ + 1, + 524262178, + "awesomebar-browser-toolbar", + "compose-browser-toolbar", + "build-components-compose-browser-toolbar", + "B", + "2025-08-26T17:31:51.485132", + "AC-android-all", + 1711578, + "47e31ea0adff5b3270d76c73aa66f3eafde85316", + "success", + "51a19a587475ec7585bea456e2a22e20c63488cf", + "completed", + 1, + "b_GMvxOTSKeI7YiVkiy-XQ", + 0, + 9, + "opt" + ], + [ + 1, + 524262179, + "gradle lint linter", + "lint", + "source-test-android-lint-fenix", + "fenix", + "2025-08-26T17:24:26.232162", + "lint", + 1711578, + "47e31ea0adff5b3270d76c73aa66f3eafde85316", + "success", + "2e3f6994fb7910c850881b5ec54cd004d76abce9", + "completed", + 1, + "BhKcZD9MRTy1_wMqa3xTXw", + 0, + 11, + "opt" + ], + [ + 1, + 524262182, + "gradle lint linter", + "lint", + "source-test-android-lint-android-components", + "AC", + "2025-08-26T17:21:27.811901", + "lint", + 1711578, + "47e31ea0adff5b3270d76c73aa66f3eafde85316", + "success", + "b7f083eebe051945503cdaefc5af10852ac99140", + "completed", + 1, + "bIonlyjIT_2RgZ_Xuig5tQ", + 0, + 8, + "opt" + ], + [ + 1, + 524262185, + "tooling-detekt", + "tooling-detekt", + "build-components-tooling-detekt", + "B", + "2025-08-26T17:27:26.511721", + "AC-android-all", + 1711578, + "47e31ea0adff5b3270d76c73aa66f3eafde85316", + "success", + "842236e43d9cb875e9972906653877336d88933e", + "completed", + 1, + "BL-jvrFeQ2mVrMHqoDnzHQ", + 0, + 4, + "opt" + ], + [ + 1, + 524262186, + "concept-storage", + "concept-storage", + "build-components-concept-storage", + "B", + "2025-08-26T17:29:32.292113", + "AC-android-all", + 1711578, + "47e31ea0adff5b3270d76c73aa66f3eafde85316", + "success", + "77935e78010ae63a17318815ed1ac45e738bd142", + "completed", + 1, + "BoowA3KVQIuFU27OtcGX2A", + 0, + 6, + "opt" + ], + [ + 1, + 524262188, + "service-nimbus", + "service-nimbus", + "build-components-service-nimbus", + "B", + "2025-08-26T17:34:44.584291", + "AC-android-all", + 1711578, + "47e31ea0adff5b3270d76c73aa66f3eafde85316", + "success", + "109765a04fffe435d7c9e0986eb030d46de19304", + "completed", + 1, + "C1vdropoQTWSspRGyr9EUA", + 0, + 12, + "opt" + ], + [ + 1, + 524262190, + "feature-recentlyclosed", + "feature-recentlyclosed", + "test-components-android-feature-recentlyclosed", + "unit", + "2025-08-26T17:42:48.340101", + "AC-ui-test", + 1711578, + "47e31ea0adff5b3270d76c73aa66f3eafde85316", + "success", + "652897acedd7f5af3749520368d82b32f889d566", + "completed", + 2, + "c5qGAXLxRR2WHpg81rdMHw", + 0, + 20, + "opt" + ], + [ + 1, + 524262192, + "unknown", + "?", + "test-components-unit-browser-engine-gecko-nightly", + "ui-components", + "2025-08-26T17:47:14.894144", + "AC-ui-test", + 1711578, + "47e31ea0adff5b3270d76c73aa66f3eafde85316", + "success", + "a8e77a818241350ec8337d716c524b27a13ddd09", + "completed", + 2, + "C75reAaiSNiwTyQYNJFWJg", + 0, + 24, + "opt" + ], + [ + 1, + 524262194, + "Fenix builds made for testing", + "fenix-debug", + "test-apk-fenix-debug", + "T", + "2025-08-26T17:47:36.633683", + "fenix-android-all", + 1711578, + "47e31ea0adff5b3270d76c73aa66f3eafde85316", + "success", + "6ed819cd63350d33f3ee4365e286ac8716cb5018", + "completed", + 1, + "C7__LB5KTy6NxcNRGSqZvQ", + 0, + 24, + "opt" + ], + [ + 1, + 524262196, + "compose-base", + "compose-base", + "build-components-compose-base", + "B", + "2025-08-26T17:34:03.999715", + "AC-android-all", + 1711578, + "47e31ea0adff5b3270d76c73aa66f3eafde85316", + "success", + "ebdfb6933136d86aecc2ca567512d74db5783957", + "completed", + 1, + "cBKJmKA7QWmhkJze_2_q3Q", + 0, + 11, + "opt" + ], + [ + 1, + 524262198, + "browser-tabstray", + "browser-tabstray", + "build-components-browser-tabstray", + "B", + "2025-08-26T17:34:32.938411", + "AC-android-all", + 1711578, + "47e31ea0adff5b3270d76c73aa66f3eafde85316", + "success", + "0c5184c356f159ed5e48be84046112a02d21d33c", + "completed", + 1, + "CKJZznepTJCvVxekirfqqg", + 0, + 11, + "opt" + ], + [ + 1, + 524262200, + "ui-widgets", + "ui-widgets", + "build-components-ui-widgets", + "B", + "2025-08-26T17:34:13.056959", + "AC-android-all", + 1711578, + "47e31ea0adff5b3270d76c73aa66f3eafde85316", + "success", + "c0f834b9f673616f074a9494c0ddc3f8f5032584", + "completed", + 1, + "CLq5ZJscSOW10pLUOq81aA", + 0, + 11, + "opt" + ], + [ + 1, + 524262202, + "service-mars", + "service-mars", + "build-components-service-mars", + "B", + "2025-08-26T17:33:51.067173", + "AC-android-all", + 1711578, + "47e31ea0adff5b3270d76c73aa66f3eafde85316", + "success", + "19019a93f7b944dab18889fe4c2873de69c7a243", + "completed", + 1, + "CtSkyougSpK8sbRJZaNw0w", + 0, + 10, + "opt" + ], + [ + 1, + 524262205, + "feature-share", + "feature-share", + "build-components-feature-share", + "B", + "2025-08-26T17:29:56.826230", + "AC-android-all", + 1711578, + "47e31ea0adff5b3270d76c73aa66f3eafde85316", + "success", + "935e75e1a528d8cd16da68382945e74a760e1ef7", + "completed", + 1, + "cZFlP8zwRX6GAqgfuBd_hg", + 0, + 6, + "opt" + ], + [ + 1, + 524262207, + "feature-sitepermissions", + "feature-sitepermissions", + "build-components-feature-sitepermissions", + "B", + "2025-08-26T17:32:30.160422", + "AC-android-all", + 1711578, + "47e31ea0adff5b3270d76c73aa66f3eafde85316", + "retry", + "ef791ef06c59c78efccf81efc3298b0e4083d0b6", + "completed", + 1, + "d42cmsAySa2UWLfNyj1O-g", + 0, + 9, + "opt" + ], + [ + 1, + 524262209, + "browser-menu2", + "browser-menu2", + "build-components-browser-menu2", + "B", + "2025-08-26T17:34:22.893618", + "AC-android-all", + 1711578, + "47e31ea0adff5b3270d76c73aa66f3eafde85316", + "success", + "4ca831afebe68ba442f70b4c6c5c6309dde614f2", + "completed", + 1, + "dAITJTXAR8aL92k0P0AQ2w", + 0, + 11, + "opt" + ], + [ + 1, + 524262212, + "samples-sync", + "samples-sync", + "build-components-samples-sync", + "B", + "2025-08-26T17:34:26.031165", + "AC-android-all", + 1711578, + "47e31ea0adff5b3270d76c73aa66f3eafde85316", + "success", + "b415b3a78b84f086a6f7758dbce1656aaf606761", + "completed", + 1, + "dBxTbWiMQlGlBTXPKX9B9Q", + 0, + 11, + "opt" + ], + [ + 1, + 524262213, + "ui-fonts", + "ui-fonts", + "build-components-ui-fonts", + "B", + "2025-08-26T17:28:17.972637", + "AC-android-all", + 1711578, + "47e31ea0adff5b3270d76c73aa66f3eafde85316", + "success", + "6b02bb8304f40d4f22d0855b199060adfd85cc11", + "completed", + 1, + "DCiLAf4GR2S0CM0rIFZhgQ", + 0, + 5, + "opt" + ], + [ + 1, + 524262215, + "feature-session", + "feature-session", + "build-components-feature-session", + "B", + "2025-08-26T17:31:30.566128", + "AC-android-all", + 1711578, + "47e31ea0adff5b3270d76c73aa66f3eafde85316", + "success", + "2979e768e0f0d25e504a1f9de8cc20c15de478e5", + "completed", + 1, + "dIfYLJLBQl6w99TJ0pCygQ", + 0, + 8, + "opt" + ], + [ + 1, + 524262217, + "browser-errorpages", + "browser-errorpages", + "build-components-browser-errorpages", + "B", + "2025-08-26T17:34:27.044938", + "AC-android-all", + 1711578, + "47e31ea0adff5b3270d76c73aa66f3eafde85316", + "success", + "3339983746effb0d4a1f019ce4a68cfa96d10d47", + "completed", + 1, + "dj5uMFOzRXeQ5P8iV8HDnQ", + 0, + 11, + "opt" + ], + [ + 1, + 524262219, + "feature-serviceworker", + "feature-serviceworker", + "build-components-feature-serviceworker", + "B", + "2025-08-26T17:32:56.263749", + "AC-android-all", + 1711578, + "47e31ea0adff5b3270d76c73aa66f3eafde85316", + "success", + "b7270e43c080390f34f45784fc158a13fb37c784", + "completed", + 1, + "dKRIBzjbTo2MxFDDTAwIhw", + 0, + 9, + "opt" + ], + [ + 1, + 524262221, + "feature-sitepermissions", + "feature-sitepermissions", + "test-components-android-feature-sitepermissions", + "unit", + "2025-08-26T17:46:21.497233", + "AC-ui-test", + 1711578, + "47e31ea0adff5b3270d76c73aa66f3eafde85316", + "success", + "6886a25fc95030657f8f5f5d97fec004d6a58714", + "completed", + 2, + "DnCvpbLkS9-0-dWMh6bdEA", + 0, + 23, + "opt" + ], + [ + 1, + 524262223, + "Focus builds made for testing", + "focus-debug", + "build-apk-focus-debug", + "Bf", + "2025-08-26T17:20:42.052414", + "focus-android-all", + 1711578, + "47e31ea0adff5b3270d76c73aa66f3eafde85316", + "success", + "fb6dc5399cf01ed282699758c95e77695743f8d2", + "completed", + 1, + "dOHdg8FpTFiwMdK4ccVSrw", + 0, + 7, + "opt" + ], + [ + 1, + 524262225, + "service-location", + "service-location", + "build-components-service-location", + "B", + "2025-08-26T17:33:55.555898", + "AC-android-all", + 1711578, + "47e31ea0adff5b3270d76c73aa66f3eafde85316", + "success", + "9d17731772a3e6372245c4a3b931b59127058eca", + "completed", + 1, + "dsoTwkkSSJ6BSmdKhOMW9w", + 0, + 10, + "opt" + ], + [ + 1, + 524262227, + "support-utils", + "support-utils", + "build-components-support-utils", + "B", + "2025-08-26T17:30:15.539474", + "AC-android-all", + 1711578, + "47e31ea0adff5b3270d76c73aa66f3eafde85316", + "success", + "6520c0e8af9838655007c68076ae57e5490584b5", + "completed", + 1, + "dtz49eXHQTyzBaHjb1UHCQ", + 0, + 6, + "opt" + ], + [ + 1, + 524262230, + "feature-fxsuggest", + "feature-fxsuggest", + "build-components-feature-fxsuggest", + "B", + "2025-08-26T17:31:32.863860", + "AC-android-all", + 1711578, + "47e31ea0adff5b3270d76c73aa66f3eafde85316", + "success", + "59e9d1d46af7f3ed675bfb0d0ecba8d9bcb59ab6", + "completed", + 1, + "ebAg_PhjSuGpt84c78fnZw", + 0, + 8, + "opt" + ], + [ + 1, + 524262231, + "feature-autofill", + "feature-autofill", + "build-components-feature-autofill", + "B", + "2025-08-26T17:34:30.593253", + "AC-android-all", + 1711578, + "47e31ea0adff5b3270d76c73aa66f3eafde85316", + "success", + "e57236bf594b6fd4b648764d9d5039e810025fc7", + "completed", + 1, + "EDRHHQrMRXGMwfwyHEHbPQ", + 0, + 11, + "opt" + ], + [ + 1, + 524262233, + "Fenix builds made for testing", + "fenix-debug", + "build-apk-fenix-debug", + "Bf", + "2025-08-26T17:22:34.069738", + "fenix-android-all", + 1711578, + "47e31ea0adff5b3270d76c73aa66f3eafde85316", + "success", + "8030e9dba410550485d5d81975321812bdb092c7", + "completed", + 1, + "ekvdPOr9SyqwpBUHGbCd9g", + 0, + 9, + "opt" + ], + [ + 1, + 524262235, + "browser-domains", + "browser-domains", + "build-components-browser-domains", + "B", + "2025-08-26T17:33:49.601851", + "AC-android-all", + 1711578, + "47e31ea0adff5b3270d76c73aa66f3eafde85316", + "success", + "342aacc8cb0eb357ab8361aa8861e445a90f87c9", + "completed", + 1, + "enCfCwWKT-OLTjAlqWH43w", + 0, + 10, + "opt" + ], + [ + 1, + 524262237, + "lib-publicsuffixlist", + "lib-publicsuffixlist", + "build-components-lib-publicsuffixlist", + "B", + "2025-08-26T17:32:38.326237", + "AC-android-all", + 1711578, + "47e31ea0adff5b3270d76c73aa66f3eafde85316", + "success", + "8cd4f2430dc181c38e58179a340e3e5e9d4ce2d9", + "completed", + 1, + "F1VF3ye5Qn6XVTbeDUQDuQ", + 0, + 9, + "opt" + ], + [ + 1, + 524262239, + "gradle lint linter", + "lint", + "source-test-android-lint-focus", + "focus", + "2025-08-26T17:21:44.491205", + "lint", + 1711578, + "47e31ea0adff5b3270d76c73aa66f3eafde85316", + "success", + "5b9de7abd8a1c4ed42d1f8b2ce818438d11a68c8", + "completed", + 1, + "FdHBlsOOQKGZfFV62_LdWw", + 0, + 8, + "opt" + ], + [ + 1, + 524262240, + "ui-icons", + "ui-icons", + "build-components-ui-icons", + "B", + "2025-08-26T17:28:33.313710", + "AC-android-all", + 1711578, + "47e31ea0adff5b3270d76c73aa66f3eafde85316", + "success", + "08d9ea158bda0016e745a27673749724aca404a0", + "completed", + 1, + "fKQXL3C7TKq6OMHsrpDkfw", + 0, + 5, + "opt" + ], + [ + 1, + 524262243, + "support-images", + "support-images", + "build-components-support-images", + "B", + "2025-08-26T17:34:31.345792", + "AC-android-all", + 1711578, + "47e31ea0adff5b3270d76c73aa66f3eafde85316", + "success", + "42809d52ec24f3c6d13b22679c33a823889e4e04", + "completed", + 1, + "fN-lMo94Qm2wXLDm8552qw", + 0, + 11, + "opt" + ], + [ + 1, + 524262245, + "feature-top-sites", + "feature-top-sites", + "build-components-feature-top-sites", + "B", + "2025-08-26T17:34:37.317936", + "AC-android-all", + 1711578, + "47e31ea0adff5b3270d76c73aa66f3eafde85316", + "success", + "be5d9f532f4df265c09f721f049b6d66ad6d59d7", + "completed", + 1, + "fnw9Zn-uShatL9VzKHWxgw", + 0, + 11, + "opt" + ], + [ + 1, + 524262247, + "feature-recentlyclosed", + "feature-recentlyclosed", + "build-components-feature-recentlyclosed", + "B", + "2025-08-26T17:31:59.213840", + "AC-android-all", + 1711578, + "47e31ea0adff5b3270d76c73aa66f3eafde85316", + "success", + "bf39325ec6c7d3c082101252cc2b09a17706a862", + "completed", + 1, + "FvIDlYTxR7KmkrTnLnzCOw", + 0, + 8, + "opt" + ], + [ + 1, + 524262249, + "unknown", + "?", + "test-components-ui-browser", + "ui-samples-browser", + "2025-08-26T17:41:47.193383", + "AC-ui-test", + 1711578, + "47e31ea0adff5b3270d76c73aa66f3eafde85316", + "success", + "0566f42118f53054d0908402b1ba94c7ed0551b7", + "completed", + 2, + "FXkVBiQRTseGCjkmyc4YJQ", + 0, + 18, + "opt" + ], + [ + 1, + 524262251, + "feature-toolbar", + "feature-toolbar", + "build-components-feature-toolbar", + "B", + "2025-08-26T17:35:47.720587", + "AC-android-all", + 1711578, + "47e31ea0adff5b3270d76c73aa66f3eafde85316", + "success", + "7c72db7493e0141c251cfb83a0f9efe3b3e56eec", + "completed", + 1, + "Fyb093RzRM--qS6tNgwH6Q", + 0, + 12, + "opt" + ], + [ + 1, + 524262253, + "service-sync-logins", + "service-sync-logins", + "build-components-service-sync-logins", + "B", + "2025-08-26T17:30:36.264207", + "AC-android-all", + 1711578, + "47e31ea0adff5b3270d76c73aa66f3eafde85316", + "success", + "be12c78d9886c4ff0033414802101c905a2145af", + "completed", + 1, + "G0H-MUj_TAKJti522bjByA", + 0, + 6, + "opt" + ], + [ + 1, + 524262255, + "Profile-guided optimization builds", + "Bpgo", + "instrumented-build-apk-fenix", + "instr", + "2025-08-26T17:24:40.441205", + "fenix-android-all", + 1711578, + "47e31ea0adff5b3270d76c73aa66f3eafde85316", + "success", + "838cd18dbac6c97c2c0525354c73f31f8782da53", + "completed", + 1, + "G7i7kiucTzOnaO6NpPq0DA", + 0, + 11, + "opt" + ], + [ + 1, + 524262257, + "feature-share", + "feature-share", + "test-components-android-feature-share", + "unit", + "2025-08-26T17:32:31.294252", + "AC-ui-test", + 1711578, + "47e31ea0adff5b3270d76c73aa66f3eafde85316", + "retry", + "b4e72c10d50a719cda5aca1f6ef807b9cf108a79", + "completed", + 2, + "Gi2Y-9FOS0SmkHIptuoOaw", + 0, + 9, + "opt" + ], + [ + 1, + 524262259, + "compose-tabstray", + "compose-tabstray", + "build-components-compose-tabstray", + "B", + "2025-08-26T17:36:00.752745", + "AC-android-all", + 1711578, + "47e31ea0adff5b3270d76c73aa66f3eafde85316", + "success", + "67e23f9f880155d25cf96bf130991c6723c5ed18", + "completed", + 1, + "GI3EwKEKRii7B1ALCU6EGQ", + 0, + 12, + "opt" + ], + [ + 1, + 524262263, + "browser-state", + "browser-state", + "build-components-browser-state", + "B", + "2025-08-26T17:31:47.300682", + "AC-android-all", + 1711578, + "47e31ea0adff5b3270d76c73aa66f3eafde85316", + "success", + "2d6045a7a6af839e9ed2f89b1f144f340c0793ec", + "completed", + 1, + "GzjChoqhRY6WJYSsu-_RGg", + 0, + 8, + "opt" + ], + [ + 1, + 524262265, + "feature-downloads", + "feature-downloads", + "test-components-android-feature-downloads", + "unit", + "2025-08-26T17:41:40.515094", + "AC-ui-test", + 1711578, + "47e31ea0adff5b3270d76c73aa66f3eafde85316", + "success", + "49a131e427245760101abb21b3681b3d08b5c580", + "completed", + 2, + "H37lvXJASg6SNEmpHcsVBA", + 0, + 18, + "opt" + ], + [ + 1, + 524262267, + "browser-toolbar", + "browser-toolbar", + "build-components-browser-toolbar", + "B", + "2025-08-26T17:32:16.297664", + "AC-android-all", + 1711578, + "47e31ea0adff5b3270d76c73aa66f3eafde85316", + "success", + "5e83bee51dcb01e5a884b1ebbde635e5068e4a0f", + "completed", + 1, + "HcX5TogoRym4dfBAjLlbPg", + 0, + 8, + "opt" + ], + [ + 1, + 524262269, + "support-remotesettings", + "support-remotesettings", + "build-components-support-remotesettings", + "B", + "2025-08-26T17:30:43.905298", + "AC-android-all", + 1711578, + "47e31ea0adff5b3270d76c73aa66f3eafde85316", + "success", + "dbe1a5acbf649caa27380f14df04022f492b8907", + "completed", + 1, + "Hh1wWjdfRUOwIw0tjksL3Q", + 0, + 6, + "opt" + ], + [ + 1, + 524262271, + "samples-glean-library", + "samples-glean-library", + "build-components-samples-glean-library", + "B", + "2025-08-26T17:29:30.855146", + "AC-android-all", + 1711578, + "47e31ea0adff5b3270d76c73aa66f3eafde85316", + "success", + "08efef511372c6fe92836edf7d5ff8cf6169f8db", + "completed", + 1, + "I9Z_VxD_T8iipwkV55T1Aw", + 0, + 5, + "opt" + ], + [ + 1, + 524262273, + "support-test-appservices", + "support-test-appservices", + "build-components-support-test-appservices", + "B", + "2025-08-26T17:29:09.739338", + "AC-android-all", + 1711578, + "47e31ea0adff5b3270d76c73aa66f3eafde85316", + "success", + "e8a3d03f8622087d595fa60e7a52df0a31bb5a8a", + "completed", + 1, + "IoiqKUX2Rkmcj-Q7NPV0LQ", + 0, + 5, + "opt" + ], + [ + 1, + 524262275, + "feature-tab-collections", + "feature-tab-collections", + "build-components-feature-tab-collections", + "B", + "2025-08-26T17:32:58.075694", + "AC-android-all", + 1711578, + "47e31ea0adff5b3270d76c73aa66f3eafde85316", + "success", + "f7d6b9b258edf1b16fd8077e1759974657f12c10", + "completed", + 1, + "IVP9VIi6REC7qQf-RvuHpQ", + 0, + 9, + "opt" + ], + [ + 1, + 524262277, + "ui-autocomplete", + "ui-autocomplete", + "build-components-ui-autocomplete", + "B", + "2025-08-26T17:30:37.692480", + "AC-android-all", + 1711578, + "47e31ea0adff5b3270d76c73aa66f3eafde85316", + "success", + "9d726fc27c85a69edcf96f9d6bddc723fcd6f1e0", + "completed", + 1, + "J0Jb3rsPSx6mhOeF9gCvfg", + 0, + 6, + "opt" + ], + [ + 1, + 524262279, + "concept-push", + "concept-push", + "build-components-concept-push", + "B", + "2025-08-26T17:29:49.162993", + "AC-android-all", + 1711578, + "47e31ea0adff5b3270d76c73aa66f3eafde85316", + "success", + "05ce7d837514c4c6ec63bb06019c4fb8a0bc536d", + "completed", + 1, + "JHAYvgbIQo2QT3n3bsPoQw", + 0, + 5, + "opt" + ], + [ + 1, + 524262281, + "support-android-test", + "support-android-test", + "build-components-support-android-test", + "B", + "2025-08-26T17:29:32.375352", + "AC-android-all", + 1711578, + "47e31ea0adff5b3270d76c73aa66f3eafde85316", + "success", + "7046886d77842c979ed0fad59c890e5acf54705c", + "completed", + 1, + "JA5WGLXmQ1qUCFxlsVMg1A", + 0, + 5, + "opt" + ], + [ + 1, + 524262282, + "lib-dataprotect", + "lib-dataprotect", + "build-components-lib-dataprotect", + "B", + "2025-08-26T17:30:10.192739", + "AC-android-all", + 1711578, + "47e31ea0adff5b3270d76c73aa66f3eafde85316", + "success", + "fce6e45cf6f8c87dd13d76df8ce60b731b0c0dc4", + "completed", + 1, + "JHnVdxHETlu1hpjHUZ6cWg", + 0, + 6, + "opt" + ], + [ + 1, + 524262284, + "feature-intent", + "feature-intent", + "build-components-feature-intent", + "B", + "2025-08-26T17:33:47.902522", + "AC-android-all", + 1711578, + "47e31ea0adff5b3270d76c73aa66f3eafde85316", + "success", + "25d303807bdef155bf995bf8e63a11a9e00aa00a", + "completed", + 1, + "K2TlM2RJTHCgfULEF2wkcw", + 0, + 9, + "opt" + ], + [ + 1, + 524262285, + "support-test", + "support-test", + "build-components-support-test", + "B", + "2025-08-26T17:30:40.343311", + "AC-android-all", + 1711578, + "47e31ea0adff5b3270d76c73aa66f3eafde85316", + "success", + "fdca6f0e5f7ec97c62e94e4649cf5450fb80b18b", + "completed", + 1, + "JiXtqeWaSUaYOFm5QjD2iQ", + 0, + 6, + "opt" + ], + [ + 1, + 524262286, + "feature-push", + "feature-push", + "build-components-feature-push", + "B", + "2025-08-26T17:30:10.660950", + "AC-android-all", + 1711578, + "47e31ea0adff5b3270d76c73aa66f3eafde85316", + "success", + "4f6fee84c6dfcb7c86c50365c984f6d98e29fe5c", + "completed", + 1, + "K9js3lafQt-bN5PruSyj8w", + 0, + 6, + "opt" + ], + [ + 1, + 524262287, + "concept-sync", + "concept-sync", + "build-components-concept-sync", + "B", + "2025-08-26T17:30:06.881511", + "AC-android-all", + 1711578, + "47e31ea0adff5b3270d76c73aa66f3eafde85316", + "success", + "ae989386cb4af2e7958abe5206837157b6eee100", + "completed", + 1, + "KVrq6rlyR5CJ_Jkj-s7h7g", + 0, + 6, + "opt" + ], + [ + 1, + 524262288, + "feature-webnotifications", + "feature-webnotifications", + "build-components-feature-webnotifications", + "B", + "2025-08-26T17:33:55.638292", + "AC-android-all", + 1711578, + "47e31ea0adff5b3270d76c73aa66f3eafde85316", + "success", + "7cc56a02dd9dc66e6b826aa068a07f1bda488c82", + "completed", + 1, + "LE7thpmRR9SGEfQsr7sYxw", + 0, + 9, + "opt" + ], + [ + 1, + 524262289, + "feature-containers", + "feature-containers", + "test-components-android-feature-containers", + "unit", + "2025-08-26T17:42:49.038137", + "AC-ui-test", + 1711578, + "47e31ea0adff5b3270d76c73aa66f3eafde85316", + "success", + "ee1bec3f378b015a56d0179af543e3bb683d86ef", + "completed", + 2, + "Lhf5vEcTRb-_J9LpF6EgJQ", + 0, + 18, + "opt" + ], + [ + 1, + 524262290, + "support-appservices", + "support-appservices", + "build-components-support-appservices", + "B", + "2025-08-26T17:30:13.549914", + "AC-android-all", + 1711578, + "47e31ea0adff5b3270d76c73aa66f3eafde85316", + "success", + "af7481d3086d78d67b881cf78e20eda90a2099dc", + "completed", + 1, + "LL0koXQzQNSBtcZP3VRDIQ", + 0, + 6, + "opt" + ], + [ + 1, + 524262291, + "feature-prompts", + "feature-prompts", + "test-components-android-feature-prompts", + "unit", + "2025-08-26T17:41:47.058307", + "AC-ui-test", + 1711578, + "47e31ea0adff5b3270d76c73aa66f3eafde85316", + "success", + "8b0b3001d5a6da7b223b7d1b37001a9130091720", + "completed", + 2, + "LJ0P0jU1SWW9Z8MQPJnGqw", + 0, + 17, + "opt" + ], + [ + 1, + 524262292, + "service-pocket", + "service-pocket", + "build-components-service-pocket", + "B", + "2025-08-26T17:31:52.847041", + "AC-android-all", + 1711578, + "47e31ea0adff5b3270d76c73aa66f3eafde85316", + "success", + "9f2f6cfdd518501b9bacf75c1797e92e4b92be3d", + "completed", + 1, + "MfAwGHH7TCa1sBvfDUpqKQ", + 0, + 7, + "opt" + ], + [ + 1, + 524262293, + "feature-pwa", + "feature-pwa", + "build-components-feature-pwa", + "B", + "2025-08-26T17:34:43.619814", + "AC-android-all", + 1711578, + "47e31ea0adff5b3270d76c73aa66f3eafde85316", + "success", + "c68ff4d0440c2e7a88d657f14ecb3981fa2f7c7c", + "completed", + 1, + "MNambVsgQ0ujZlfKlX3QQA", + 0, + 10, + "opt" + ], + [ + 1, + 524262294, + "feature-readerview", + "feature-readerview", + "build-components-feature-readerview", + "B", + "2025-08-26T17:32:24.710125", + "AC-android-all", + 1711578, + "47e31ea0adff5b3270d76c73aa66f3eafde85316", + "success", + "74dd6f9999ddc747b0f2d3fc919a17d21d0ede92", + "completed", + 1, + "Mo2Bw_YwQWayeGqgWmhwvQ", + 0, + 8, + "opt" + ], + [ + 1, + 524262295, + "service-firefox-accounts", + "service-firefox-accounts", + "build-components-service-firefox-accounts", + "B", + "2025-08-26T17:32:05.900240", + "AC-android-all", + 1711578, + "47e31ea0adff5b3270d76c73aa66f3eafde85316", + "success", + "641c695e2a0aa30e40612e735270f8a151982d84", + "completed", + 1, + "N3waPwX7QbmeAYQl8pdzRQ", + 0, + 7, + "opt" + ], + [ + 1, + 524262296, + "Fenix builds made for testing", + "fenix-debug", + "build-apk-fenix-android-test-debug", + "Bat", + "2025-08-26T17:24:20.431821", + "fenix-android-all", + 1711578, + "47e31ea0adff5b3270d76c73aa66f3eafde85316", + "success", + "c708c67905111215ae9008276fe4fe8204a52a45", + "completed", + 1, + "NalteNxCR9OShu2OzxzD-A", + 0, + 11, + "opt" + ], + [ + 1, + 524262297, + "Focus builds made for testing", + "focus-debug", + "build-apk-focus-android-test-debug", + "Bat", + "2025-08-26T17:23:29.205418", + "focus-android-all", + 1711578, + "47e31ea0adff5b3270d76c73aa66f3eafde85316", + "success", + "ee2868c638119bf64372c119e32d6ab6291885b5", + "completed", + 1, + "Nr40_o94QseEAbkdOvR_ww", + 0, + 10, + "opt" + ], + [ + 1, + 524262298, + "browser-session-storage", + "browser-session-storage", + "build-components-browser-session-storage", + "B", + "2025-08-26T17:34:19.011639", + "AC-android-all", + 1711578, + "47e31ea0adff5b3270d76c73aa66f3eafde85316", + "success", + "1d4bfad4267ea18f8c984c0ffded9c1d6a051b2d", + "completed", + 1, + "NTJFKNG7T3-z2gscOF5Q_Q", + 0, + 10, + "opt" + ], + [ + 1, + 524262299, + "browser-storage-sync", + "browser-storage-sync", + "build-components-browser-storage-sync", + "B", + "2025-08-26T17:31:23.072294", + "AC-android-all", + 1711578, + "47e31ea0adff5b3270d76c73aa66f3eafde85316", + "success", + "c691423e881cad2e7ee6f587cb1f7bd7ae700e4d", + "completed", + 1, + "Ny1Gk8TBTz2Yx4GztuOwxg", + 0, + 7, + "opt" + ], + [ + 1, + 524262300, + "feature-screendetection", + "feature-screendetection", + "build-components-feature-screendetection", + "B", + "2025-08-26T17:30:33.218985", + "AC-android-all", + 1711578, + "47e31ea0adff5b3270d76c73aa66f3eafde85316", + "success", + "431fa87fe56c9c0628d985e61662fe45442a044f", + "completed", + 1, + "O1_MJh2xT--bYcFRnMpQDg", + 0, + 6, + "opt" + ], + [ + 1, + 524262301, + "feature-awesomebar", + "feature-awesomebar", + "build-components-feature-awesomebar", + "B", + "2025-08-26T17:35:09.369803", + "AC-android-all", + 1711578, + "47e31ea0adff5b3270d76c73aa66f3eafde85316", + "success", + "5c8f7c50d6fe002ccbb442c73a0af5e9a81e4336", + "completed", + 1, + "ObD26MfRQb26dtbzg2QTZQ", + 0, + 10, + "opt" + ], + [ + 1, + 524262302, + "feature-pwa", + "feature-pwa", + "test-components-android-feature-pwa", + "unit", + "2025-08-26T17:43:32.068389", + "AC-ui-test", + 1711578, + "47e31ea0adff5b3270d76c73aa66f3eafde85316", + "success", + "81e52a25deafb14c750ea22c11bd5ac23d75849a", + "completed", + 2, + "O9CsAey3SZCb93Inbihlmw", + 0, + 19, + "opt" + ], + [ + 1, + 524262303, + "lib-fetch-okhttp", + "lib-fetch-okhttp", + "build-components-lib-fetch-okhttp", + "B", + "2025-08-26T17:30:19.519993", + "AC-android-all", + 1711578, + "47e31ea0adff5b3270d76c73aa66f3eafde85316", + "success", + "6fe31595b6e4a4e3b7d1164a99d44c8046bae86b", + "completed", + 1, + "OH0lF0f6Td-aD8icgjuWLA", + 0, + 5, + "opt" + ], + [ + 1, + 524262304, + "concept-menu", + "concept-menu", + "build-components-concept-menu", + "B", + "2025-08-26T17:31:10.099902", + "AC-android-all", + 1711578, + "47e31ea0adff5b3270d76c73aa66f3eafde85316", + "success", + "e3ac8fdde8ae1ca2089b944add2864ccb1798c4c", + "completed", + 1, + "OHU38rdFSZ6gw9fiVn3a2A", + 0, + 6, + "opt" + ], + [ + 1, + 524262305, + "feature-qr", + "feature-qr", + "build-components-feature-qr", + "B", + "2025-08-26T17:31:57.912212", + "AC-android-all", + 1711578, + "47e31ea0adff5b3270d76c73aa66f3eafde85316", + "success", + "a40bf330d28a92d84d809189fab4d44968f1d103", + "completed", + 1, + "OrBIGRkxQyiqUey2EaG7Qg", + 0, + 7, + "opt" + ], + [ + 1, + 524262306, + "samples-toolbar", + "samples-toolbar", + "build-components-samples-toolbar", + "B", + "2025-08-26T17:34:29.226190", + "AC-android-all", + 1711578, + "47e31ea0adff5b3270d76c73aa66f3eafde85316", + "success", + "a7ef335e534036e972a0fec137e7e6b4677026b4", + "completed", + 1, + "OuEN-prFTUurW6U5PtsOpQ", + 0, + 9, + "opt" + ], + [ + 1, + 524262307, + "lib-push-firebase", + "lib-push-firebase", + "build-components-lib-push-firebase", + "B", + "2025-08-26T17:30:45.018640", + "AC-android-all", + 1711578, + "47e31ea0adff5b3270d76c73aa66f3eafde85316", + "success", + "f08f958a039388413dda0ca445a687b79c0fe243", + "completed", + 1, + "OgwjuhTXRCuxlBj9UspJ4A", + 0, + 6, + "opt" + ], + [ + 1, + 524262308, + "service-sync-autofill", + "service-sync-autofill", + "build-components-service-sync-autofill", + "B", + "2025-08-26T17:31:44.137047", + "AC-android-all", + 1711578, + "47e31ea0adff5b3270d76c73aa66f3eafde85316", + "success", + "e7311ef209dfcda501a8bf40a0335426f28bf2e0", + "completed", + 1, + "OvBRee2CQMCLs4lzf5gQqQ", + 0, + 7, + "opt" + ], + [ + 1, + 524262309, + "support-ktx", + "support-ktx", + "build-components-support-ktx", + "B", + "2025-08-26T17:32:44.296181", + "AC-android-all", + 1711578, + "47e31ea0adff5b3270d76c73aa66f3eafde85316", + "success", + "e191263ca2536674a807c7f840f7a6315b9bed08", + "completed", + 1, + "OzbVIgaNTVCglJm6oCOR8w", + 0, + 7, + "opt" + ], + [ + 1, + 524262310, + "browser-menu", + "browser-menu", + "build-components-browser-menu", + "B", + "2025-08-26T17:33:34.042959", + "AC-android-all", + 1711578, + "47e31ea0adff5b3270d76c73aa66f3eafde85316", + "success", + "af8016ef6d71332e2f6dc282b00557499df7cf83", + "completed", + 1, + "OzEeS3nIRjySRj1Ija-LJg", + 0, + 8, + "opt" + ], + [ + 1, + 524262311, + "samples-firefox-accounts", + "samples-firefox-accounts", + "build-components-samples-firefox-accounts", + "B", + "2025-08-26T17:32:39.462760", + "AC-android-all", + 1711578, + "47e31ea0adff5b3270d76c73aa66f3eafde85316", + "success", + "84600ccd491e43d8c0e56409a4ee1148ea8610b7", + "completed", + 1, + "PapIlSVSThu7LzoJZnMcdQ", + 0, + 7, + "opt" + ], + [ + 1, + 524262312, + "service-glean", + "service-glean", + "build-components-service-glean", + "B", + "2025-08-26T17:31:42.570264", + "AC-android-all", + 1711578, + "47e31ea0adff5b3270d76c73aa66f3eafde85316", + "success", + "3b7535e34b7d600c4280f6402a9cccb4ae4e1e64", + "completed", + 1, + "PYx3lMQBTIi3PbnuvClIwA", + 0, + 6, + "opt" + ], + [ + 1, + 524262313, + "feature-search", + "feature-search", + "build-components-feature-search", + "B", + "2025-08-26T17:30:55.474974", + "AC-android-all", + 1711578, + "47e31ea0adff5b3270d76c73aa66f3eafde85316", + "retry", + "324b21fe436744d1654f0eb5cdf3109a592281c4", + "completed", + 1, + "PuJgAb5oQLKHob2a24VCpg", + 0, + 6, + "opt" + ], + [ + 1, + 524262314, + "feature-prompts", + "feature-prompts", + "build-components-feature-prompts", + "B", + "2025-08-26T17:35:45.243095", + "AC-android-all", + 1711578, + "47e31ea0adff5b3270d76c73aa66f3eafde85316", + "success", + "a085355089a6cd76b3458308db7903be8fd24e0b", + "completed", + 1, + "Q0MKR4qOTr-eoEvCHd2zuw", + 0, + 10, + "opt" + ], + [ + 1, + 524262315, + "concept-tabstray", + "concept-tabstray", + "build-components-concept-tabstray", + "B", + "2025-08-26T17:32:03.201142", + "AC-android-all", + 1711578, + "47e31ea0adff5b3270d76c73aa66f3eafde85316", + "success", + "89f3f7ded08750efc86827f06c22e1e41279138b", + "completed", + 1, + "Q9-d60MIS-eFJ0Kx13LRAA", + 0, + 7, + "opt" + ], + [ + 1, + 524262316, + "ui-tabcounter", + "ui-tabcounter", + "build-components-ui-tabcounter", + "B", + "2025-08-26T17:32:37.813296", + "AC-android-all", + 1711578, + "47e31ea0adff5b3270d76c73aa66f3eafde85316", + "success", + "10066b1edd042bbaf6117b6736f8039fffc89cde", + "completed", + 1, + "QgOEK29RSvqFA4qBVwBStQ", + 0, + 7, + "opt" + ], + [ + 1, + 524262317, + "browser-thumbnails", + "browser-thumbnails", + "build-components-browser-thumbnails", + "B", + "2025-08-26T17:33:02.115495", + "AC-android-all", + 1711578, + "47e31ea0adff5b3270d76c73aa66f3eafde85316", + "success", + "bb01167f03253d1cd99d2869687c359eab1d93a1", + "completed", + 1, + "Qj536eP2SwqWGF_QC4kSUA", + 0, + 8, + "opt" + ], + [ + 1, + 524262318, + "lib-crash-sentry", + "lib-crash-sentry", + "build-components-lib-crash-sentry", + "B", + "2025-08-26T17:32:30.160382", + "AC-android-all", + 1711578, + "47e31ea0adff5b3270d76c73aa66f3eafde85316", + "success", + "d79b1e17e8c7d2b0f7520f403a3e899c1f50ac3b", + "completed", + 1, + "Q-vEDw3wSCGxVqbjfxTCBQ", + 0, + 7, + "opt" + ], + [ + 1, + 524262319, + "feature-findinpage", + "feature-findinpage", + "build-components-feature-findinpage", + "B", + "2025-08-26T17:32:55.173192", + "AC-android-all", + 1711578, + "47e31ea0adff5b3270d76c73aa66f3eafde85316", + "success", + "e26fcbc6c34f25f893fc889432530cbaa9ccf9a8", + "completed", + 1, + "R0u--D0cSJCzOURI3bK-bg", + 0, + 7, + "opt" + ], + [ + 1, + 524262320, + "lib-jexl", + "lib-jexl", + "build-components-lib-jexl", + "B", + "2025-08-26T17:30:42.228978", + "AC-android-all", + 1711578, + "47e31ea0adff5b3270d76c73aa66f3eafde85316", + "success", + "e2871cf229f446b3a9c231b6e31a53e085c2a483", + "completed", + 1, + "RAGWwGmQQxajI6EK5H3dGw", + 0, + 5, + "opt" + ], + [ + 1, + 524262321, + "feature-webauthn", + "feature-webauthn", + "build-components-feature-webauthn", + "B", + "2025-08-26T17:32:26.518382", + "AC-android-all", + 1711578, + "47e31ea0adff5b3270d76c73aa66f3eafde85316", + "success", + "830d3c2b81691f62708e5f9817533b2c849de99d", + "completed", + 1, + "Rn_0dI1nTImpdfvYwIhfWw", + 0, + 7, + "opt" + ], + [ + 1, + 524262322, + "feature-downloads", + "feature-downloads", + "build-components-feature-downloads", + "B", + "2025-08-26T17:35:02.308397", + "AC-android-all", + 1711578, + "47e31ea0adff5b3270d76c73aa66f3eafde85316", + "success", + "25febeca18dd5d78be85b521b9b6b5e028fef4e0", + "completed", + 1, + "RNa6ftZDTIyNr7MoutbQYw", + 0, + 9, + "opt" + ], + [ + 1, + 524262323, + "lib-auth", + "lib-auth", + "build-components-lib-auth", + "B", + "2025-08-26T17:31:35.513439", + "AC-android-all", + 1711578, + "47e31ea0adff5b3270d76c73aa66f3eafde85316", + "success", + "ef55ca0db9b579160849bfea9c9adec1f8926497", + "completed", + 1, + "SeS2IN6iRieBuB8jtstAdA", + 0, + 6, + "opt" + ], + [ + 1, + 524262324, + "compose-engine", + "compose-engine", + "build-components-compose-engine", + "B", + "2025-08-26T17:33:42.195919", + "AC-android-all", + 1711578, + "47e31ea0adff5b3270d76c73aa66f3eafde85316", + "success", + "f45d9cade1c421025a6733d2c9254f969f42e4f5", + "completed", + 1, + "SKtszROkRbq54tvTg9yBkQ", + 0, + 8, + "opt" + ], + [ + 1, + 524262325, + "support-locale", + "support-locale", + "build-components-support-locale", + "B", + "2025-08-26T17:33:26.765767", + "AC-android-all", + 1711578, + "47e31ea0adff5b3270d76c73aa66f3eafde85316", + "success", + "f846929b99879e73e614744c4a4a56c1d94f8ef1", + "completed", + 1, + "SZcBpnBhR0uJ7e39XLneJQ", + 0, + 7, + "opt" + ], + [ + 1, + 524262326, + "unknown", + "?", + "test-components-ui-glean", + "ui-samples-glean", + "2025-08-26T17:41:05.630596", + "AC-ui-test", + 1711578, + "47e31ea0adff5b3270d76c73aa66f3eafde85316", + "success", + "1980aa26e4d1f3478cf128b5dc11dbf957a095cd", + "completed", + 2, + "T7ETZiVRTHCHJvqDC7-X0g", + 0, + 15, + "opt" + ], + [ + 1, + 524262327, + "browser-engine-system", + "browser-engine-system", + "build-components-browser-engine-system", + "B", + "2025-08-26T17:33:57.544826", + "AC-android-all", + 1711578, + "47e31ea0adff5b3270d76c73aa66f3eafde85316", + "success", + "1b98cd37acbc16b5cce59ed102132285a27cfe89", + "completed", + 1, + "T7SbqNZQSJa_58oVYNpzNw", + 0, + 8, + "opt" + ], + [ + 1, + 524262328, + "concept-fetch", + "concept-fetch", + "build-components-concept-fetch", + "B", + "2025-08-26T17:31:42.418532", + "AC-android-all", + 1711578, + "47e31ea0adff5b3270d76c73aa66f3eafde85316", + "success", + "22e869914c790bfc486be7aedff4dc9052c3dd81", + "completed", + 1, + "TFmVfGDGRqGyp4tqHpOs7g", + 0, + 6, + "opt" + ], + [ + 1, + 524262329, + "concept-toolbar", + "concept-toolbar", + "build-components-concept-toolbar", + "B", + "2025-08-26T17:33:02.343657", + "AC-android-all", + 1711578, + "47e31ea0adff5b3270d76c73aa66f3eafde85316", + "success", + "670eec8c0fcadad1bb60c25f88be308909ff3b01", + "completed", + 1, + "Ub6_U_tISZWQzW0nWXgaQA", + 0, + 7, + "opt" + ], + [ + 1, + 524262330, + "support-webextensions", + "support-webextensions", + "build-components-support-webextensions", + "B", + "2025-08-26T17:33:40.459125", + "AC-android-all", + 1711578, + "47e31ea0adff5b3270d76c73aa66f3eafde85316", + "success", + "bede93c983370e5cc2d20fda9446ac13b60c28a3", + "completed", + 1, + "UoC5PJ6JRNmVtjOGJIu8Rg", + 0, + 7, + "opt" + ], + [ + 1, + 524262331, + "support-base", + "support-base", + "build-components-support-base", + "B", + "2025-08-26T17:33:03.906975", + "AC-android-all", + 1711578, + "47e31ea0adff5b3270d76c73aa66f3eafde85316", + "success", + "816bbd2ab5542b8e90745230fe8e73d91af27e3d", + "completed", + 1, + "UP_ZG_2FQvyUH-mglS79Vw", + 0, + 7, + "opt" + ], + [ + 1, + 524262332, + "samples-sync-logins", + "samples-sync-logins", + "build-components-samples-sync-logins", + "B", + "2025-08-26T17:34:23.555380", + "AC-android-all", + 1711578, + "47e31ea0adff5b3270d76c73aa66f3eafde85316", + "success", + "4d063cf76e69e87887ae53b882c40c7168a70984", + "completed", + 1, + "Ut6bFAsxQRa3Pz9_EwBFXA", + 0, + 8, + "opt" + ], + [ + 1, + 524262333, + "feature-tabs", + "feature-tabs", + "build-components-feature-tabs", + "B", + "2025-08-26T17:46:42.718920", + "AC-android-all", + 1711578, + "47e31ea0adff5b3270d76c73aa66f3eafde85316", + "retry", + "a24a4849dd8c8c1ea4d991cd5eef2088fc0a78df", + "completed", + 1, + "UVdcQCe5SuiiF67SIidrJw", + 0, + 20, + "opt" + ], + [ + 1, + 524262334, + "feature-webcompat", + "feature-webcompat", + "build-components-feature-webcompat", + "B", + "2025-08-26T17:34:15.358256", + "AC-android-all", + 1711578, + "47e31ea0adff5b3270d76c73aa66f3eafde85316", + "success", + "3d7fb31e3c57fc1ad2ccdc8cc68304d107babd34", + "completed", + 1, + "V5VldtNLSIGewRwkVrcShA", + 0, + 7, + "opt" + ], + [ + 1, + 524262335, + "feature-accounts", + "feature-accounts", + "build-components-feature-accounts", + "B", + "2025-08-26T17:36:00.177341", + "AC-android-all", + 1711578, + "47e31ea0adff5b3270d76c73aa66f3eafde85316", + "success", + "aa4ae7dd89912f5e0d678aebe1252641ee767516", + "completed", + 1, + "VaHZAT5zQ6-gwG7zkxdi1Q", + 0, + 9, + "opt" + ], + [ + 1, + 524262336, + "lib-fetch-httpurlconnection", + "lib-fetch-httpurlconnecti", + "build-components-lib-fetch-httpurlconnection", + "B", + "2025-08-26T17:32:28.021445", + "AC-android-all", + 1711578, + "47e31ea0adff5b3270d76c73aa66f3eafde85316", + "success", + "699060dfdc658c8fab947a1b68e6e98c27cda61b", + "completed", + 1, + "VdJjZ_P8TVapTDFYDtmq_w", + 0, + 6, + "opt" + ], + [ + 1, + 524262337, + "tooling-fetch-tests", + "tooling-fetch-tests", + "build-components-tooling-fetch-tests", + "B", + "2025-08-26T17:32:27.018571", + "AC-android-all", + 1711578, + "47e31ea0adff5b3270d76c73aa66f3eafde85316", + "success", + "b4fbe085761a3cefb87f451f7b5c12494ddc5553", + "completed", + 1, + "VH71RtHzT3CyWk_CIgb66w", + 0, + 5, + "opt" + ], + [ + 1, + 524262338, + "feature-privatemode", + "feature-privatemode", + "build-components-feature-privatemode", + "B", + "2025-08-26T17:34:54.093228", + "AC-android-all", + 1711578, + "47e31ea0adff5b3270d76c73aa66f3eafde85316", + "success", + "f95df8b060bae73921b65852e2d032156944792c", + "completed", + 1, + "WCGRO4C9QWygPGia3y0JyQ", + 0, + 8, + "opt" + ], + [ + 1, + 524262339, + "lib-crash", + "lib-crash", + "build-components-lib-crash", + "B", + "2025-08-26T17:35:04.101235", + "AC-android-all", + 1711578, + "47e31ea0adff5b3270d76c73aa66f3eafde85316", + "success", + "08fe2c1791a9df717abafcd82be1952059386492", + "completed", + 1, + "WCv1hdU_QoeTSo_WNQOvHQ", + 0, + 8, + "opt" + ], + [ + 1, + 524262340, + "ui-colors", + "ui-colors", + "build-components-ui-colors", + "B", + "2025-08-26T17:32:24.617348", + "AC-android-all", + 1711578, + "47e31ea0adff5b3270d76c73aa66f3eafde85316", + "success", + "5ad72e80d06f7e3d5e2b9aee3fd5547a0fdf5250", + "completed", + 1, + "Wk_tnd2-RVykmtgNfTJ59A", + 0, + 5, + "opt" + ], + [ + 1, + 524262341, + "compose-engine", + "compose-awesomebar", + "build-components-compose-awesomebar", + "B", + "2025-08-26T17:34:43.329208", + "AC-android-all", + 1711578, + "47e31ea0adff5b3270d76c73aa66f3eafde85316", + "success", + "04f88c823da98283c8c24a993295a30b947910cc", + "completed", + 1, + "We1fwt7US_aM0dznicfR2Q", + 0, + 8, + "opt" + ], + [ + 1, + 524262342, + "feature-contextmenu", + "feature-contextmenu", + "build-components-feature-contextmenu", + "B", + "2025-08-26T17:36:42.269269", + "AC-android-all", + 1711578, + "47e31ea0adff5b3270d76c73aa66f3eafde85316", + "success", + "d2256b22d41fc5623c2e5def15b0ec830edff0a1", + "completed", + 1, + "WnLzZSN6R9WWpf_m_jMv3Q", + 0, + 9, + "opt" + ], + [ + 1, + 524262343, + "samples-glean", + "samples-glean", + "build-components-samples-glean", + "B", + "2025-08-26T17:35:32.662859", + "AC-android-all", + 1711578, + "47e31ea0adff5b3270d76c73aa66f3eafde85316", + "success", + "51a93026c0252a4530052770f0bfe8de28168043", + "completed", + 1, + "WRKR98CsSXyYe97MbDpt7Q", + 0, + 8, + "opt" + ], + [ + 1, + 524262344, + "samples-compose-browser", + "samples-compose-browser", + "build-components-samples-compose-browser", + "B", + "2025-08-26T17:39:56.634561", + "AC-android-all", + 1711578, + "47e31ea0adff5b3270d76c73aa66f3eafde85316", + "success", + "3d33136ef65801a072878408c65ec2b2e9195017", + "completed", + 1, + "WVegOe_DQW21fnZ1CBPtCw", + 0, + 12, + "opt" + ], + [ + 1, + 524262345, + "feature-containers", + "feature-containers", + "build-components-feature-containers", + "B", + "2025-08-26T17:35:23.844468", + "AC-android-all", + 1711578, + "47e31ea0adff5b3270d76c73aa66f3eafde85316", + "success", + "75ed2b9624cdbb1d0e0b8605b24bb95c94b497f7", + "completed", + 1, + "XcfQLaHkRjeCKUV_i5ff3A", + 0, + 8, + "opt" + ], + [ + 1, + 524262346, + "Focus builds made for testing", + "focus-debug", + "test-apk-focus-debug", + "T", + "2025-08-26T17:45:12.392267", + "focus-android-all", + 1711578, + "47e31ea0adff5b3270d76c73aa66f3eafde85316", + "success", + "490dfbcd03c5f1401d269153ce5c8c63c4658bbd", + "completed", + 1, + "Xk3oGQTtSLaPFgjR1XTzxg", + 0, + 18, + "opt" + ], + [ + 1, + 524262347, + "feature-logins", + "feature-logins", + "test-components-android-feature-logins", + "unit", + "2025-08-26T17:45:29.047924", + "AC-ui-test", + 1711578, + "47e31ea0adff5b3270d76c73aa66f3eafde85316", + "success", + "dd63b39e82bd6b04049b4b339bfb63a490ff25b6", + "completed", + 2, + "Xn2-Ix-ySie04ePo4Qm2tA", + 0, + 18, + "opt" + ], + [ + 1, + 524262348, + "compose-cfr", + "compose-cfr", + "build-components-compose-cfr", + "B", + "2025-08-26T17:34:49.565945", + "AC-android-all", + 1711578, + "47e31ea0adff5b3270d76c73aa66f3eafde85316", + "success", + "9d35578322079c638d94645d4a01cba1150d6bc0", + "completed", + 1, + "YBGKp0oORGqWuKyY5HbqhQ", + 0, + 7, + "opt" + ], + [ + 1, + 524262349, + "service-digitalassetlinks", + "service-digitalassetlinks", + "build-components-service-digitalassetlinks", + "B", + "2025-08-26T17:34:23.668158", + "AC-android-all", + 1711578, + "47e31ea0adff5b3270d76c73aa66f3eafde85316", + "success", + "68150da025e012be38921490d0071fdde4a3e7f0", + "completed", + 1, + "YBrqO60DR-6GL3WP9aBDgA", + 0, + 7, + "opt" + ], + [ + 1, + 524262350, + "feature-accounts-push", + "feature-accounts-push", + "build-components-feature-accounts-push", + "B", + "2025-08-26T17:35:41.372296", + "AC-android-all", + 1711578, + "47e31ea0adff5b3270d76c73aa66f3eafde85316", + "success", + "55905fabac8f0ca4fe0b71666b386508306f3175", + "completed", + 1, + "YddT9rfnTf65I3m2ylOrzA", + 0, + 8, + "opt" + ], + [ + 1, + 524262351, + "concept-engine", + "concept-engine", + "build-components-concept-engine", + "B", + "2025-08-26T17:35:15.047197", + "AC-android-all", + 1711578, + "47e31ea0adff5b3270d76c73aa66f3eafde85316", + "success", + "0fad8aebeed5cf2e24ecdc7bceb8e80ab4bcf277", + "completed", + 1, + "YlwN0EQtRrKKwN-T7WkyzA", + 0, + 7, + "opt" + ], + [ + 1, + 524262352, + "feature-top-sites", + "feature-top-sites", + "test-components-android-feature-top-sites", + "unit", + "2025-08-26T17:47:32.638329", + "AC-ui-test", + 1711578, + "47e31ea0adff5b3270d76c73aa66f3eafde85316", + "success", + "07320536c531d8662492010cc7ca307b39648e66", + "completed", + 2, + "YM0f1sbSTgC-q0X38HdQ9Q", + 0, + 19, + "opt" + ], + [ + 1, + 524262353, + "feature-syncedtabs", + "feature-syncedtabs", + "build-components-feature-syncedtabs", + "B", + "2025-08-26T17:35:48.640172", + "AC-android-all", + 1711578, + "47e31ea0adff5b3270d76c73aa66f3eafde85316", + "success", + "70d607b97adfec1bd5256d3e140d7e1a9c72e321", + "completed", + 1, + "Yp5GbGMhSiyTiNmB918CnQ", + 0, + 7, + "opt" + ], + [ + 1, + 524262354, + "concept-base", + "concept-base", + "build-components-concept-base", + "B", + "2025-08-26T17:32:53.526098", + "AC-android-all", + 1711578, + "47e31ea0adff5b3270d76c73aa66f3eafde85316", + "success", + "d559a00647990b2e373ea4a58ea118f04ee548f1", + "completed", + 1, + "YrfSjiuQRT6Vol2ukL2RfQ", + 0, + 4, + "opt" + ], + [ + 1, + 524262355, + "feature-app-links", + "feature-app-links", + "build-components-feature-app-links", + "B", + "2025-08-26T17:36:25.859211", + "AC-android-all", + 1711578, + "47e31ea0adff5b3270d76c73aa66f3eafde85316", + "success", + "5710a0d813a3800b775daf1f17bbab3ec8e7e61d", + "completed", + 1, + "ZAaVsnh3TQCbfqiI6wtrkw", + 0, + 7, + "opt" + ], + [ + 1, + 524262356, + "feature-webcompat-reporter", + "feature-webcompat-reporte", + "build-components-feature-webcompat-reporter", + "B", + "2025-08-26T17:36:03.910111", + "AC-android-all", + 1711578, + "47e31ea0adff5b3270d76c73aa66f3eafde85316", + "success", + "0fbe979013be0464270edf6c0c8012a2b1f4f1b7", + "completed", + 1, + "YYvFXhSMSweVqEPGDnMIDQ", + 0, + 7, + "opt" + ], + [ + 1, + 524262357, + "support-license", + "support-license", + "build-components-support-license", + "B", + "2025-08-26T17:33:27.812188", + "AC-android-all", + 1711578, + "47e31ea0adff5b3270d76c73aa66f3eafde85316", + "success", + "ba7fed1fd640534f8129593a0c0c3f72aa576f17", + "completed", + 1, + "ZbU2guU3Q6aAsVbN8s9DLg", + 0, + 4, + "opt" + ], + [ + 1, + 524262358, + "feature-logins", + "feature-logins", + "build-components-feature-logins", + "B", + "2025-08-26T17:38:05.831029", + "AC-android-all", + 1711578, + "47e31ea0adff5b3270d76c73aa66f3eafde85316", + "success", + "ce6f4688db1739c894a023107171174c0d3fe4e3", + "completed", + 1, + "ZfqVJzLtR9agIwAFOoz4QQ", + 0, + 9, + "opt" + ], + [ + 1, + 524262359, + "support-test-libstate", + "support-test-libstate", + "build-components-support-test-libstate", + "B", + "2025-08-26T17:35:01.468320", + "AC-android-all", + 1711578, + "47e31ea0adff5b3270d76c73aa66f3eafde85316", + "success", + "b5165977fcbbd403a51eec0aa6dbb8553fb3a8cc", + "completed", + 1, + "ZoU8aTDdSXOTSTsHBk-D1Q", + 0, + 6, + "opt" + ], + [ + 1, + 524262360, + "support-test-fakes", + "support-test-fakes", + "build-components-support-test-fakes", + "B", + "2025-08-26T17:35:23.180639", + "AC-android-all", + 1711578, + "47e31ea0adff5b3270d76c73aa66f3eafde85316", + "success", + "4dc6dbe2bb871361639d46011bbe35b4a08d2e0c", + "completed", + 1, + "Zw1MlsSRQoC-JUWrYXaIQQ", + 0, + 6, + "opt" + ], + [ + 1, + 524262994, + "Focus builds made for testing", + "focus-debug", + "signing-apk-focus-debug", + "Bfs", + "2025-08-26T17:22:57.824497", + "focus-android-all", + 1711578, + "47e31ea0adff5b3270d76c73aa66f3eafde85316", + "success", + "4ec77afc78d1790901e71b99029c00bf43d69f25", + "completed", + 1, + "MtjLasg-Q5Kfvxqbke7VRA", + 0, + 2, + "opt" + ], + [ + 1, + 524263142, + "Fenix builds made for testing", + "fenix-debug", + "signing-apk-fenix-debug", + "Bs", + "2025-08-26T17:26:24.772526", + "fenix-android-all", + 1711578, + "47e31ea0adff5b3270d76c73aa66f3eafde85316", + "success", + "04ead08e412f54c7ec25cc72ee418aee88060850", + "completed", + 1, + "aYE-3Nm5RH-fkycUNlPFuw", + 0, + 3, + "opt" + ], + [ + 1, + 524263164, + "Focus builds made for testing", + "focus-debug", + "signing-apk-focus-android-test-debug", + "Bats", + "2025-08-26T17:24:07.343728", + "focus-android-all", + 1711578, + "47e31ea0adff5b3270d76c73aa66f3eafde85316", + "success", + "b5f4d6e4f9e4312d835eeacc9e93aacfc13e8c66", + "completed", + 1, + "Wf_fF83dTKa9URnTGjInYw", + 0, + 1, + "opt" + ], + [ + 1, + 524263186, + "Focus builds made for testing", + "focus-debug", + "ui-test-apk-focus-arm-debug", + "ui-test-arm", + "2025-08-26T17:36:54.581995", + "focus-android-all", + 1711578, + "47e31ea0adff5b3270d76c73aa66f3eafde85316", + "success", + "f788a9e88ebf2b83b935f00ea02946f471a87389", + "completed", + 2, + "Qd8laJz3SBuiFX2Wym1kJQ", + 0, + 7, + "opt" + ], + [ + 1, + 524263191, + "Fenix builds made for testing", + "fenix-debug", + "signing-apk-fenix-android-test-debug", + "Bats", + "2025-08-26T17:24:48.540162", + "fenix-android-all", + 1711578, + "47e31ea0adff5b3270d76c73aa66f3eafde85316", + "success", + "39666ffc19edead9a77a469a8b0ecee9d84902be", + "completed", + 1, + "Kuse5iGnQhC6S_aOu0EKGQ", + 0, + 1, + "opt" + ], + [ + 1, + 524263194, + "Profile-guided optimization builds", + "Bpgo", + "generate-baseline-profile-firebase-fenix", + "run", + "2025-08-26T17:49:52.744481", + "fenix-android-all", + 1711578, + "47e31ea0adff5b3270d76c73aa66f3eafde85316", + "success", + "f7d3c37fb6911584616a2d3467eeabae7c42d087", + "completed", + 1, + "TESCYxLDRA6xuQFjXC5bNA", + 0, + 20, + "opt" + ], + [ + 1, + 524263361, + "Fenix builds made for testing", + "fenix-debug", + "ui-test-apk-fenix-arm-debug-smoke", + "smoke-arm", + "2025-08-26T17:36:35.685894", + "fenix-android-all", + 1711578, + "47e31ea0adff5b3270d76c73aa66f3eafde85316", + "success", + "952dcbb5504945495b15cb3d3750c86bf2eadaf5", + "completed", + 1, + "Q5nU1Rz6QcCqD6N2JXRoYw", + 0, + 6, + "opt" + ], + [ + 1, + 524263362, + "Fenix builds made for testing", + "fenix-debug", + "ui-test-apk-fenix-arm-debug", + "ui-test-arm", + "2025-08-26T17:39:54.451873", + "fenix-android-all", + 1711578, + "47e31ea0adff5b3270d76c73aa66f3eafde85316", + "success", + "aa0253b61bea023fbda83720856096a456015468", + "completed", + 2, + "DlC6YtCiTRafnWkG0X9NiA", + 0, + 10, + "opt" + ], + [ + 1, + 524265820, + "feature-search", + "feature-search", + "build-components-feature-search", + "B", + "2025-08-26T17:39:33.267165", + "AC-android-all", + 1711578, + "47e31ea0adff5b3270d76c73aa66f3eafde85316", + "success", + "324b21fe436744d1654f0eb5cdf3109a592281c4", + "completed", + 1, + "PuJgAb5oQLKHob2a24VCpg", + 1, + 9, + "opt" + ], + [ + 1, + 524266013, + "feature-sitepermissions", + "feature-sitepermissions", + "build-components-feature-sitepermissions", + "B", + "2025-08-26T17:41:55.171928", + "AC-android-all", + 1711578, + "47e31ea0adff5b3270d76c73aa66f3eafde85316", + "success", + "ef791ef06c59c78efccf81efc3298b0e4083d0b6", + "completed", + 1, + "d42cmsAySa2UWLfNyj1O-g", + 1, + 9, + "opt" + ], + [ + 1, + 524266014, + "feature-share", + "feature-share", + "test-components-android-feature-share", + "unit", + "2025-08-26T17:47:58.879596", + "AC-ui-test", + 1711578, + "47e31ea0adff5b3270d76c73aa66f3eafde85316", + "success", + "b4e72c10d50a719cda5aca1f6ef807b9cf108a79", + "completed", + 2, + "Gi2Y-9FOS0SmkHIptuoOaw", + 1, + 15, + "opt" + ], + [ + 1, + 524267177, + "feature-tabs", + "feature-tabs", + "build-components-feature-tabs", + "B", + "2025-08-26T17:55:26.500224", + "AC-android-all", + 1711578, + "47e31ea0adff5b3270d76c73aa66f3eafde85316", + "success", + "a24a4849dd8c8c1ea4d991cd5eef2088fc0a78df", + "completed", + 1, + "UVdcQCe5SuiiF67SIidrJw", + 1, + 9, + "opt" + ] + ], + "job_property_names": [ + "failure_classification_id", + "id", + "job_group_name", + "job_group_symbol", + "job_type_name", + "job_type_symbol", + "last_modified", + "platform", + "push_id", + "push_revision", + "result", + "signature", + "state", + "tier", + "task_id", + "retry_id", + "duration", + "platform_option" + ] +} \ No newline at end of file diff --git a/app/src/androidTest/assets/job_for_push_1712468.json b/app/src/androidTest/assets/job_for_push_1712468.json new file mode 100644 index 0000000..0aadea5 --- /dev/null +++ b/app/src/androidTest/assets/job_for_push_1712468.json @@ -0,0 +1,3607 @@ +{ + "count": 179, + "next": null, + "previous": null, + "results": [ + [ + 1, + 524429638, + "unknown", + "?", + "Gecko Decision Task", + "D", + "2025-08-27T13:58:31.085457", + "gecko-decision", + 1712468, + "bab9725e928ab3de804281a6d6eeb467a5709920", + "success", + "2aa083621bb989d6acf1151667288d5fe9616178", + "completed", + 1, + "TeL3NrUqTVS62Alobcn5nA", + 0, + 4, + "opt" + ], + [ + 1, + 524430411, + "unknown", + "?", + "build-android-x86/opt", + "Ba", + "2025-08-27T14:03:00.757209", + "android-5-0-x86", + 1712468, + "bab9725e928ab3de804281a6d6eeb467a5709920", + "success", + "76d2f0885564b84df6b664274360a49253d5c248", + "completed", + 1, + "A86TyNnrQAeCdP67mSGi3Q", + 0, + 6, + "opt" + ], + [ + 1, + 524430414, + "Validate strings.xml with compare-locales", + "compare-locales", + "source-test-android-compare-locales-compare-locales-android-components", + "AC", + "2025-08-27T13:59:58.284433", + "lint", + 1712468, + "bab9725e928ab3de804281a6d6eeb467a5709920", + "success", + "b70d6b81fcb498ffcf522a9429565733b15464c8", + "completed", + 2, + "aJT8oYeFT3yuVqnKpN8RQw", + 0, + 2, + "opt" + ], + [ + 1, + 524430415, + "unknown", + "?", + "build-android-aarch64/opt", + "Ba", + "2025-08-27T14:03:01.800232", + "android-5-0-aarch64", + 1712468, + "bab9725e928ab3de804281a6d6eeb467a5709920", + "success", + "dfa39c8d92b68e4e1307814a6e161c4524b579c1", + "completed", + 1, + "Bzuw5nChRZ2W-ciW4U3qrQ", + 0, + 6, + "opt" + ], + [ + 1, + 524430416, + "Validate strings.xml with compare-locales", + "compare-locales", + "source-test-android-compare-locales-compare-locales-focus", + "focus", + "2025-08-27T13:59:27.152184", + "lint", + 1712468, + "bab9725e928ab3de804281a6d6eeb467a5709920", + "success", + "0373f095aacb94058314765f40bad4d8041f93cf", + "completed", + 2, + "cya9cAxPRN2-Im-tO2eDNQ", + 0, + 1, + "opt" + ], + [ + 1, + 524430417, + "Check on texts", + "text", + "source-test-mozlint-rejected-words", + "rejected-words", + "2025-08-27T14:02:30.212430", + "lint", + 1712468, + "bab9725e928ab3de804281a6d6eeb467a5709920", + "success", + "f22644154e5ef26d261fa39ac64de643582d66b5", + "completed", + 2, + "d0n5A2vjS-Cyx3jIFgZKfg", + 0, + 8, + "opt" + ], + [ + 1, + 524430418, + "detekt linter", + "detekt", + "source-test-android-detekt-detekt-android-components", + "AC", + "2025-08-27T14:01:58.191929", + "lint", + 1712468, + "bab9725e928ab3de804281a6d6eeb467a5709920", + "success", + "7c07e5ff57d9261e7cc6a27ffb70aea702f239f9", + "completed", + 1, + "fHoIMTDbRkGUU7wymQyVVA", + 0, + 4, + "opt" + ], + [ + 1, + 524430419, + "unknown", + "?", + "build-android-x86_64/opt", + "Ba", + "2025-08-27T14:03:34.250813", + "android-5-0-x86_64", + 1712468, + "bab9725e928ab3de804281a6d6eeb467a5709920", + "success", + "403283030fcbd7c79a0fa1973708af105c983218", + "completed", + 1, + "EtJxSqyDTrykgCy20Ap9Fw", + 0, + 6, + "opt" + ], + [ + 1, + 524430420, + "Make sure the content of .buildconfig.yml matches what gradle knows about its projects", + "buildconfig", + "source-test-buildconfig-buildconfig-android-components", + "AC", + "2025-08-27T14:01:22.302533", + "lint", + 1712468, + "bab9725e928ab3de804281a6d6eeb467a5709920", + "success", + "7188e619c71cb2ff52e45c4c8efa961a70d5ee6d", + "completed", + 2, + "fJ21-VYbTO6hdjkEyUG3eg", + 0, + 6, + "opt" + ], + [ + 1, + 524430421, + "unknown", + "?", + "build-android-arm/opt", + "Ba", + "2025-08-27T14:03:42.183330", + "android-5-0-armv7", + 1712468, + "bab9725e928ab3de804281a6d6eeb467a5709920", + "success", + "77ffc689165cfb0c63d389e188e797410af8c447", + "completed", + 1, + "FYSYdcqnR8OOObZiMugCIw", + 0, + 6, + "opt" + ], + [ + 1, + 524430422, + "Python 3 unit tests", + "py3", + "source-test-python-android-android-gradle-build-linux2404-64/opt", + "agb", + "2025-08-27T14:18:27.090260", + "linux2404-64", + 1712468, + "bab9725e928ab3de804281a6d6eeb467a5709920", + "success", + "a793986369ed470436e94ab73c751ac42763e125", + "completed", + 2, + "GanVfQDfTLuaHpDqcxDSCQ", + 0, + 24, + "opt" + ], + [ + 1, + 524430423, + "Validate strings.xml with compare-locales", + "compare-locales", + "source-test-android-compare-locales-compare-locales-fenix", + "fenix", + "2025-08-27T13:59:28.837619", + "lint", + 1712468, + "bab9725e928ab3de804281a6d6eeb467a5709920", + "success", + "fedce0f857e8cfff0af4a592e29843a71cd034b7", + "completed", + 2, + "H2dQVRPYThqlK93qscHFTQ", + 0, + 1, + "opt" + ], + [ + 1, + 524430424, + "ktlint linter", + "ktlint", + "source-test-ktlint-fenix", + "fenix", + "2025-08-27T14:03:51.602217", + "lint", + 1712468, + "bab9725e928ab3de804281a6d6eeb467a5709920", + "success", + "6f89ad8095150763ffe8d190146d0bce3cb83599", + "completed", + 1, + "HjBC4NQfSu-H_B8-YFj4yQ", + 0, + 7, + "opt" + ], + [ + 1, + 524430425, + "pedantic checks", + "pedantic", + "source-test-mozlint-file-whitespace", + "file-whitespace", + "2025-08-27T14:00:04.345196", + "lint", + 1712468, + "bab9725e928ab3de804281a6d6eeb467a5709920", + "success", + "8762ce85f312620a908db2d256608d1c8c23fffa", + "completed", + 2, + "LGEdxkrvSDaiTTYd3gyxqQ", + 0, + 2, + "opt" + ], + [ + 1, + 524430426, + "Android Gradle tests", + "A", + "source-test-mozlint-android-android-components", + "ac-lints", + "2025-08-27T14:15:46.946817", + "lint", + 1712468, + "bab9725e928ab3de804281a6d6eeb467a5709920", + "success", + "e84cfc17c87572d08d28f46a6501711edd5beee1", + "completed", + 1, + "MxvvT-c0RtWh347Yg-LmSA", + 0, + 21, + "opt" + ], + [ + 1, + 524430427, + "pedantic checks", + "pedantic", + "source-test-mozlint-file-perm", + "file-perm", + "2025-08-27T14:00:50.205877", + "lint", + 1712468, + "bab9725e928ab3de804281a6d6eeb467a5709920", + "success", + "58b1d7accdebfa1395ee38cf4e1181c36555c4a1", + "completed", + 2, + "N20c2_KvRKKPaGAmDY--_Q", + 0, + 4, + "opt" + ], + [ + 1, + 524430428, + "detekt linter", + "detekt", + "source-test-android-detekt-detekt-fenix", + "fenix", + "2025-08-27T14:03:58.042324", + "lint", + 1712468, + "bab9725e928ab3de804281a6d6eeb467a5709920", + "success", + "9cf9e3292e270afd08c18d91ee3605b0a5df9049", + "completed", + 1, + "OXjIqZUmQx-Wjlr4ezyP5w", + 0, + 7, + "opt" + ], + [ + 1, + 524430429, + "Android Gradle tests", + "A", + "source-test-mozlint-android-lints", + "lints", + "2025-08-27T14:05:02.711880", + "lint", + 1712468, + "bab9725e928ab3de804281a6d6eeb467a5709920", + "success", + "6135ddac32ce2bce207c33c98a57ec3ee27f1c66", + "completed", + 1, + "RE2iv1zORqyWY9fkPJnzdw", + 0, + 11, + "opt" + ], + [ + 1, + 524430430, + "Android Gradle tests", + "A", + "source-test-mozlint-android-fenix", + "fenix-lints", + "2025-08-27T14:20:01.002265", + "lint", + 1712468, + "bab9725e928ab3de804281a6d6eeb467a5709920", + "success", + "1326e00ec86829fcbbca62688d7d0ffa06b30c0a", + "completed", + 1, + "SfvXMVXqQqq_R5LaEIIKWg", + 0, + 26, + "opt" + ], + [ + 1, + 524430431, + "ktlint linter", + "ktlint", + "source-test-ktlint-android-components", + "AC", + "2025-08-27T14:01:56.568665", + "lint", + 1712468, + "bab9725e928ab3de804281a6d6eeb467a5709920", + "success", + "19b2dbb17d2317489961d59d56a20b8c822a6425", + "completed", + 1, + "TTSkO8iWTHCeYsT3hTzI4g", + 0, + 4, + "opt" + ], + [ + 1, + 524430432, + "Make sure the content of .buildconfig.yml matches what gradle knows about its projects", + "buildconfig", + "source-test-buildconfig-buildconfig-fenix", + "fenix", + "2025-08-27T14:01:25.153293", + "lint", + 1712468, + "bab9725e928ab3de804281a6d6eeb467a5709920", + "success", + "21b7b90f765bec57c7e991e0d8085fc1a7fd982f", + "completed", + 2, + "UGo8OhS1QPWGiWAllv5vuA", + 0, + 6, + "opt" + ], + [ + 1, + 524430433, + "detekt linter", + "detekt", + "source-test-android-detekt-detekt-focus", + "focus", + "2025-08-27T14:03:53.379633", + "lint", + 1712468, + "bab9725e928ab3de804281a6d6eeb467a5709920", + "success", + "7ee68125000cfe80ac5f2ac8d122e733147269d0", + "completed", + 1, + "XnqbXEEsRZSI0E1fhNhWsg", + 0, + 7, + "opt" + ], + [ + 1, + 524430434, + "ktlint linter", + "ktlint", + "source-test-ktlint-focus", + "focus", + "2025-08-27T14:03:47.529175", + "lint", + 1712468, + "bab9725e928ab3de804281a6d6eeb467a5709920", + "success", + "043aa07c36173f1633e2ce2eb0d5164ea208a110", + "completed", + 1, + "YDifGJkTRQC0hlvc-AcX1Q", + 0, + 7, + "opt" + ], + [ + 1, + 524430435, + "JavaScript checks", + "js", + "source-test-mozlint-eslint", + "ES", + "2025-08-27T14:03:49.281299", + "lint", + 1712468, + "bab9725e928ab3de804281a6d6eeb467a5709920", + "success", + "01b2f1ca1f5d11dc77d82097b26ec9549d71f1e8", + "completed", + 1, + "YGBv_bV0QtivW8WFB_fwPg", + 0, + 9, + "opt" + ], + [ + 1, + 524430436, + "Check on texts", + "text", + "source-test-mozlint-dot-mozilla-reference", + "dot-mozilla-reference", + "2025-08-27T14:00:21.724701", + "lint", + 1712468, + "bab9725e928ab3de804281a6d6eeb467a5709920", + "success", + "ad31a3742ce4afc54ac78bdcc6f2b6f891c47559", + "completed", + 2, + "Ynku1I-YS9SMQxFkhGpsGg", + 0, + 3, + "opt" + ], + [ + 1, + 524430437, + "Android Gradle tests", + "A", + "source-test-mozlint-android-focus", + "focus-lints", + "2025-08-27T14:13:45.843573", + "lint", + 1712468, + "bab9725e928ab3de804281a6d6eeb467a5709920", + "success", + "ec71355f9f1dd054c2d09f84e32c5cf65004d6e1", + "completed", + 1, + "YqGjhfbhQBCCqda_ppzGkw", + 0, + 19, + "opt" + ], + [ + 1, + 524430438, + "pedantic checks", + "pedantic", + "source-test-mozlint-license", + "license", + "2025-08-27T13:59:59.456702", + "lint", + 1712468, + "bab9725e928ab3de804281a6d6eeb467a5709920", + "success", + "6b73bd01b6cf9a0b87c15c032e2da81bedddd157", + "completed", + 1, + "YYEfkUjFT-akqFSZ6CYkNQ", + 0, + 2, + "opt" + ], + [ + 1, + 524430439, + "Make sure the content of .buildconfig.yml matches what gradle knows about its projects", + "buildconfig", + "source-test-buildconfig-buildconfig-focus", + "focus", + "2025-08-27T14:01:22.571339", + "lint", + 1712468, + "bab9725e928ab3de804281a6d6eeb467a5709920", + "success", + "ccae5ecbd29e2ae9f2e2adc1ab359243f215d8f5", + "completed", + 2, + "Z0iKhNgrTcWfk1YAZt_w-A", + 0, + 6, + "opt" + ], + [ + 1, + 524432556, + "unknown", + "?", + "build-fat-aar-android-geckoview-fat-aar/opt", + "B", + "2025-08-27T14:12:24.661275", + "android-5-0-geckoview-fat-aar", + 1712468, + "bab9725e928ab3de804281a6d6eeb467a5709920", + "success", + "b18b9a54b1ed572910bd7fc677feb1be6fe69175", + "completed", + 1, + "PKp2BTGbRi2KJP0h_GWC9Q", + 0, + 6, + "opt" + ], + [ + 1, + 524434653, + "feature-privatemode", + "feature-privatemode", + "build-components-feature-privatemode", + "B", + "2025-08-27T14:24:52.832726", + "AC-android-all", + 1712468, + "bab9725e928ab3de804281a6d6eeb467a5709920", + "success", + "f95df8b060bae73921b65852e2d032156944792c", + "completed", + 1, + "a47jn3DfSiW8320RCUcf0A", + 0, + 11, + "opt" + ], + [ + 1, + 524434655, + "gradle lint linter", + "lint", + "source-test-android-lint-android-components", + "AC", + "2025-08-27T14:23:29.497985", + "lint", + 1712468, + "bab9725e928ab3de804281a6d6eeb467a5709920", + "success", + "b7f083eebe051945503cdaefc5af10852ac99140", + "completed", + 1, + "AAjHxpPvSYKu82O4PmHJ0A", + 0, + 11, + "opt" + ], + [ + 1, + 524434657, + "support-appservices", + "support-appservices", + "build-components-support-appservices", + "B", + "2025-08-27T14:23:43.150985", + "AC-android-all", + 1712468, + "bab9725e928ab3de804281a6d6eeb467a5709920", + "success", + "af7481d3086d78d67b881cf78e20eda90a2099dc", + "completed", + 1, + "aBjZoC4zR8OQwcg4wnIN4w", + 0, + 10, + "opt" + ], + [ + 1, + 524434659, + "concept-storage", + "concept-storage", + "build-components-concept-storage", + "B", + "2025-08-27T14:24:00.785581", + "AC-android-all", + 1712468, + "bab9725e928ab3de804281a6d6eeb467a5709920", + "success", + "77935e78010ae63a17318815ed1ac45e738bd142", + "completed", + 1, + "agr8P63OSoaWkYaat6OELA", + 0, + 10, + "opt" + ], + [ + 1, + 524434660, + "compose-tabstray", + "compose-tabstray", + "build-components-compose-tabstray", + "B", + "2025-08-27T14:27:06.093236", + "AC-android-all", + 1712468, + "bab9725e928ab3de804281a6d6eeb467a5709920", + "success", + "67e23f9f880155d25cf96bf130991c6723c5ed18", + "completed", + 1, + "aIHna_cNTByWk0UwDmCkqg", + 0, + 13, + "opt" + ], + [ + 1, + 524434661, + "feature-syncedtabs", + "feature-syncedtabs", + "build-components-feature-syncedtabs", + "B", + "2025-08-27T14:27:00.595804", + "AC-android-all", + 1712468, + "bab9725e928ab3de804281a6d6eeb467a5709920", + "success", + "70d607b97adfec1bd5256d3e140d7e1a9c72e321", + "completed", + 1, + "aIy56ZnVQJOUrpGs_3lbPw", + 0, + 13, + "opt" + ], + [ + 1, + 524434662, + "service-pocket", + "service-pocket", + "build-components-service-pocket", + "B", + "2025-08-27T14:25:24.650401", + "AC-android-all", + 1712468, + "bab9725e928ab3de804281a6d6eeb467a5709920", + "success", + "9f2f6cfdd518501b9bacf75c1797e92e4b92be3d", + "completed", + 1, + "AnBILYv4T2us5TX22HYs2A", + 0, + 12, + "opt" + ], + [ + 1, + 524434663, + "ui-widgets", + "ui-widgets", + "build-components-ui-widgets", + "B", + "2025-08-27T14:25:14.509826", + "AC-android-all", + 1712468, + "bab9725e928ab3de804281a6d6eeb467a5709920", + "success", + "c0f834b9f673616f074a9494c0ddc3f8f5032584", + "completed", + 1, + "APLxPlRVTX-TbhLRvPeYVA", + 0, + 11, + "opt" + ], + [ + 1, + 524434664, + "feature-top-sites", + "feature-top-sites", + "build-components-feature-top-sites", + "B", + "2025-08-27T14:25:00.409407", + "AC-android-all", + 1712468, + "bab9725e928ab3de804281a6d6eeb467a5709920", + "success", + "be5d9f532f4df265c09f721f049b6d66ad6d59d7", + "completed", + 1, + "AteH1aajTBKdsQqPB4allQ", + 0, + 11, + "opt" + ], + [ + 1, + 524434665, + "feature-customtabs", + "feature-customtabs", + "build-components-feature-customtabs", + "B", + "2025-08-27T14:29:25.973200", + "AC-android-all", + 1712468, + "bab9725e928ab3de804281a6d6eeb467a5709920", + "success", + "94f247243038cc8b364cab4978e6701fc8828f27", + "completed", + 1, + "ATycCOekRyuTbk8voM1Ngw", + 0, + 16, + "opt" + ], + [ + 1, + 524434666, + "feature-contextmenu", + "feature-contextmenu", + "build-components-feature-contextmenu", + "B", + "2025-08-27T14:28:09.097055", + "AC-android-all", + 1712468, + "bab9725e928ab3de804281a6d6eeb467a5709920", + "success", + "d2256b22d41fc5623c2e5def15b0ec830edff0a1", + "completed", + 1, + "AxnN7vtRTnWxT5yVBzkFWA", + 0, + 14, + "opt" + ], + [ + 1, + 524434667, + "support-license", + "support-license", + "build-components-support-license", + "B", + "2025-08-27T14:23:33.861407", + "AC-android-all", + 1712468, + "bab9725e928ab3de804281a6d6eeb467a5709920", + "success", + "ba7fed1fd640534f8129593a0c0c3f72aa576f17", + "completed", + 1, + "bdgM6I1uTgG7GHHqWwD2lA", + 0, + 10, + "opt" + ], + [ + 1, + 524434668, + "feature-containers", + "feature-containers", + "build-components-feature-containers", + "B", + "2025-08-27T14:25:16.740793", + "AC-android-all", + 1712468, + "bab9725e928ab3de804281a6d6eeb467a5709920", + "success", + "75ed2b9624cdbb1d0e0b8605b24bb95c94b497f7", + "completed", + 1, + "Ben_JrAWT1isi5PmTzCfYw", + 0, + 11, + "opt" + ], + [ + 1, + 524434669, + "concept-menu", + "concept-menu", + "build-components-concept-menu", + "B", + "2025-08-27T14:24:25.950775", + "AC-android-all", + 1712468, + "bab9725e928ab3de804281a6d6eeb467a5709920", + "success", + "e3ac8fdde8ae1ca2089b944add2864ccb1798c4c", + "completed", + 1, + "BmbzZHToRSuwvgD9ThCUhQ", + 0, + 11, + "opt" + ], + [ + 1, + 524434670, + "compose-engine", + "compose-engine", + "build-components-compose-engine", + "B", + "2025-08-27T14:26:07.913716", + "AC-android-all", + 1712468, + "bab9725e928ab3de804281a6d6eeb467a5709920", + "success", + "f45d9cade1c421025a6733d2c9254f969f42e4f5", + "completed", + 1, + "bppftn3MRqKC9Qaj72TDBg", + 0, + 12, + "opt" + ], + [ + 1, + 524434671, + "support-remotesettings", + "support-remotesettings", + "build-components-support-remotesettings", + "B", + "2025-08-27T14:25:23.844475", + "AC-android-all", + 1712468, + "bab9725e928ab3de804281a6d6eeb467a5709920", + "success", + "dbe1a5acbf649caa27380f14df04022f492b8907", + "completed", + 1, + "bUZOeDERRRKMINMotdhPvw", + 0, + 11, + "opt" + ], + [ + 1, + 524434672, + "concept-fetch", + "concept-fetch", + "build-components-concept-fetch", + "B", + "2025-08-27T14:23:51.280701", + "AC-android-all", + 1712468, + "bab9725e928ab3de804281a6d6eeb467a5709920", + "success", + "22e869914c790bfc486be7aedff4dc9052c3dd81", + "completed", + 1, + "BVyvqS75TfaifSgT16UiOA", + 0, + 10, + "opt" + ], + [ + 1, + 524434673, + "lib-fetch-okhttp", + "lib-fetch-okhttp", + "build-components-lib-fetch-okhttp", + "B", + "2025-08-27T14:23:52.777131", + "AC-android-all", + 1712468, + "bab9725e928ab3de804281a6d6eeb467a5709920", + "success", + "6fe31595b6e4a4e3b7d1164a99d44c8046bae86b", + "completed", + 1, + "BwRv_Fv9TpKqLEjA_FzTzQ", + 0, + 10, + "opt" + ], + [ + 1, + 524434674, + "concept-awesomebar", + "concept-awesomebar", + "build-components-concept-awesomebar", + "B", + "2025-08-27T14:23:51.078049", + "AC-android-all", + 1712468, + "bab9725e928ab3de804281a6d6eeb467a5709920", + "success", + "c364766b1201a44805804289be4f5c7e87a66165", + "completed", + 1, + "c2cr5NFRTnu68dBUVefqvQ", + 0, + 10, + "opt" + ], + [ + 1, + 524434675, + "support-test-fakes", + "support-test-fakes", + "build-components-support-test-fakes", + "B", + "2025-08-27T14:24:40.996913", + "AC-android-all", + 1712468, + "bab9725e928ab3de804281a6d6eeb467a5709920", + "success", + "4dc6dbe2bb871361639d46011bbe35b4a08d2e0c", + "completed", + 1, + "C378ucRoQSKc-HSGJT_qDA", + 0, + 11, + "opt" + ], + [ + 1, + 524434676, + "browser-toolbar", + "browser-toolbar", + "build-components-browser-toolbar", + "B", + "2025-08-27T14:26:31.309254", + "AC-android-all", + 1712468, + "bab9725e928ab3de804281a6d6eeb467a5709920", + "success", + "5e83bee51dcb01e5a884b1ebbde635e5068e4a0f", + "completed", + 1, + "c39r9WfaTS2i6FL-FqAMdQ", + 0, + 13, + "opt" + ], + [ + 1, + 524434677, + "browser-errorpages", + "browser-errorpages", + "build-components-browser-errorpages", + "B", + "2025-08-27T14:25:06.494966", + "AC-android-all", + 1712468, + "bab9725e928ab3de804281a6d6eeb467a5709920", + "success", + "3339983746effb0d4a1f019ce4a68cfa96d10d47", + "completed", + 1, + "cCFOlO9FQIO858UQumQCNA", + 0, + 11, + "opt" + ], + [ + 1, + 524434678, + "ui-tabcounter", + "ui-tabcounter", + "build-components-ui-tabcounter", + "B", + "2025-08-27T14:25:32.464771", + "AC-android-all", + 1712468, + "bab9725e928ab3de804281a6d6eeb467a5709920", + "success", + "10066b1edd042bbaf6117b6736f8039fffc89cde", + "completed", + 1, + "cenY5lItSV-U44DLStMZFA", + 0, + 12, + "opt" + ], + [ + 1, + 524434679, + "feature-addons", + "feature-addons", + "build-components-feature-addons", + "B", + "2025-08-27T14:27:08.333559", + "AC-android-all", + 1712468, + "bab9725e928ab3de804281a6d6eeb467a5709920", + "success", + "ab25215247c585400cd3e450a7d8135abb21d4be", + "completed", + 1, + "CfYNoynpSkGC_T-Uy7FieA", + 0, + 13, + "opt" + ], + [ + 1, + 524434680, + "feature-search", + "feature-search", + "build-components-feature-search", + "B", + "2025-08-27T14:28:39.091484", + "AC-android-all", + 1712468, + "bab9725e928ab3de804281a6d6eeb467a5709920", + "success", + "324b21fe436744d1654f0eb5cdf3109a592281c4", + "completed", + 1, + "cNGmWHB1T-avV6t0mdPGYg", + 0, + 15, + "opt" + ], + [ + 1, + 524434681, + "samples-sync", + "samples-sync", + "build-components-samples-sync", + "B", + "2025-08-27T14:26:11.219733", + "AC-android-all", + 1712468, + "bab9725e928ab3de804281a6d6eeb467a5709920", + "success", + "b415b3a78b84f086a6f7758dbce1656aaf606761", + "completed", + 1, + "ctB3W-fVRimb-yPssv3jUg", + 0, + 12, + "opt" + ], + [ + 1, + 524434682, + "support-base", + "support-base", + "build-components-support-base", + "B", + "2025-08-27T14:24:18.090201", + "AC-android-all", + 1712468, + "bab9725e928ab3de804281a6d6eeb467a5709920", + "success", + "816bbd2ab5542b8e90745230fe8e73d91af27e3d", + "completed", + 1, + "CsIR9uRgTD-30I1aPoDGTg", + 0, + 10, + "opt" + ], + [ + 1, + 524434683, + "support-android-test", + "support-android-test", + "build-components-support-android-test", + "B", + "2025-08-27T14:23:28.758166", + "AC-android-all", + 1712468, + "bab9725e928ab3de804281a6d6eeb467a5709920", + "success", + "7046886d77842c979ed0fad59c890e5acf54705c", + "completed", + 1, + "CuUcpXOWRl-pcB7ZUXh4tQ", + 0, + 9, + "opt" + ], + [ + 1, + 524434684, + "feature-fxsuggest", + "feature-fxsuggest", + "build-components-feature-fxsuggest", + "B", + "2025-08-27T14:27:02.291996", + "AC-android-all", + 1712468, + "bab9725e928ab3de804281a6d6eeb467a5709920", + "success", + "59e9d1d46af7f3ed675bfb0d0ecba8d9bcb59ab6", + "completed", + 1, + "d2SfOwgjSHi-rC4BGZyCbA", + 0, + 13, + "opt" + ], + [ + 1, + 524434685, + "ui-icons", + "ui-icons", + "build-components-ui-icons", + "B", + "2025-08-27T14:24:02.164151", + "AC-android-all", + 1712468, + "bab9725e928ab3de804281a6d6eeb467a5709920", + "success", + "08d9ea158bda0016e745a27673749724aca404a0", + "completed", + 1, + "D1_OvFoUR1SwG58bQrv0HQ", + 0, + 10, + "opt" + ], + [ + 1, + 524434686, + "samples-compose-browser", + "samples-compose-browser", + "build-components-samples-compose-browser", + "B", + "2025-08-27T14:32:17.823075", + "AC-android-all", + 1712468, + "bab9725e928ab3de804281a6d6eeb467a5709920", + "success", + "3d33136ef65801a072878408c65ec2b2e9195017", + "completed", + 1, + "D5jUfr3eTGiemjcSImXtqg", + 0, + 18, + "opt" + ], + [ + 1, + 524434687, + "service-glean", + "service-glean", + "build-components-service-glean", + "B", + "2025-08-27T14:25:25.963026", + "AC-android-all", + 1712468, + "bab9725e928ab3de804281a6d6eeb467a5709920", + "success", + "3b7535e34b7d600c4280f6402a9cccb4ae4e1e64", + "completed", + 1, + "d6SdP3-mQhqrZwX7rKDKDg", + 0, + 11, + "opt" + ], + [ + 1, + 524434688, + "Fenix builds made for testing", + "fenix-debug", + "build-apk-fenix-android-test-debug", + "Bat", + "2025-08-27T14:24:03.663309", + "fenix-android-all", + 1712468, + "bab9725e928ab3de804281a6d6eeb467a5709920", + "success", + "c708c67905111215ae9008276fe4fe8204a52a45", + "completed", + 1, + "DajdoP57QCy2cTzvvd1SGQ", + 0, + 11, + "opt" + ], + [ + 1, + 524434689, + "feature-logins", + "feature-logins", + "build-components-feature-logins", + "B", + "2025-08-27T14:29:41.129113", + "AC-android-all", + 1712468, + "bab9725e928ab3de804281a6d6eeb467a5709920", + "success", + "ce6f4688db1739c894a023107171174c0d3fe4e3", + "completed", + 1, + "DBGgaVPZRt-Br2aClGzv_w", + 0, + 16, + "opt" + ], + [ + 1, + 524434690, + "feature-push", + "feature-push", + "build-components-feature-push", + "B", + "2025-08-27T14:24:58.801945", + "AC-android-all", + 1712468, + "bab9725e928ab3de804281a6d6eeb467a5709920", + "success", + "4f6fee84c6dfcb7c86c50365c984f6d98e29fe5c", + "completed", + 1, + "dgCDnSoHSK-0FLLy-IcekQ", + 0, + 11, + "opt" + ], + [ + 1, + 524434691, + "samples-glean-library", + "samples-glean-library", + "build-components-samples-glean-library", + "B", + "2025-08-27T14:24:40.091680", + "AC-android-all", + 1712468, + "bab9725e928ab3de804281a6d6eeb467a5709920", + "success", + "08efef511372c6fe92836edf7d5ff8cf6169f8db", + "completed", + 1, + "dHIauFM-RMOXXDrLknUVOA", + 0, + 11, + "opt" + ], + [ + 1, + 524434692, + "ui-colors", + "ui-colors", + "build-components-ui-colors", + "B", + "2025-08-27T14:24:06.282750", + "AC-android-all", + 1712468, + "bab9725e928ab3de804281a6d6eeb467a5709920", + "success", + "5ad72e80d06f7e3d5e2b9aee3fd5547a0fdf5250", + "completed", + 1, + "Dnq-XtYUTKWhWwP3VsNUBA", + 0, + 10, + "opt" + ], + [ + 1, + 524434693, + "feature-accounts", + "feature-accounts", + "build-components-feature-accounts", + "B", + "2025-08-27T14:27:38.599215", + "AC-android-all", + 1712468, + "bab9725e928ab3de804281a6d6eeb467a5709920", + "success", + "aa4ae7dd89912f5e0d678aebe1252641ee767516", + "completed", + 1, + "DOuP3SbVRTeVaJ9glmLGbA", + 0, + 14, + "opt" + ], + [ + 1, + 524434694, + "browser-icons", + "browser-icons", + "build-components-browser-icons", + "B", + "2025-08-27T14:26:17.524555", + "AC-android-all", + 1712468, + "bab9725e928ab3de804281a6d6eeb467a5709920", + "success", + "0cc479368fa28a226328226e294cfe2f2fc920c3", + "completed", + 1, + "DT44zZIKRmGZTUv-numFqg", + 0, + 12, + "opt" + ], + [ + 1, + 524434695, + "feature-top-sites", + "feature-top-sites", + "test-components-android-feature-top-sites", + "unit", + "2025-08-27T14:32:37.578136", + "AC-ui-test", + 1712468, + "bab9725e928ab3de804281a6d6eeb467a5709920", + "retry", + "07320536c531d8662492010cc7ca307b39648e66", + "completed", + 2, + "dTHvnYJZQy2Z_g5uMy_5Ow", + 0, + 19, + "opt" + ], + [ + 1, + 524434696, + "support-test", + "support-test", + "build-components-support-test", + "B", + "2025-08-27T14:24:53.799307", + "AC-android-all", + 1712468, + "bab9725e928ab3de804281a6d6eeb467a5709920", + "success", + "fdca6f0e5f7ec97c62e94e4649cf5450fb80b18b", + "completed", + 1, + "DzuvMReDQyG7W_EKZh7iig", + 0, + 11, + "opt" + ], + [ + 1, + 524434697, + "Focus builds made for testing", + "focus-debug", + "build-apk-focus-android-test-debug", + "Bat", + "2025-08-27T14:23:30.700428", + "focus-android-all", + 1712468, + "bab9725e928ab3de804281a6d6eeb467a5709920", + "success", + "ee2868c638119bf64372c119e32d6ab6291885b5", + "completed", + 1, + "E8tLdkDjQWqMfPzOZ2KCsQ", + 0, + 10, + "opt" + ], + [ + 1, + 524434698, + "samples-sync-logins", + "samples-sync-logins", + "build-components-samples-sync-logins", + "B", + "2025-08-27T14:27:20.669147", + "AC-android-all", + 1712468, + "bab9725e928ab3de804281a6d6eeb467a5709920", + "success", + "4d063cf76e69e87887ae53b882c40c7168a70984", + "completed", + 1, + "dTRXSm36TuqgybHqm9OEdQ", + 0, + 13, + "opt" + ], + [ + 1, + 524434699, + "feature-tabs", + "feature-tabs", + "build-components-feature-tabs", + "B", + "2025-08-27T14:28:19.224131", + "AC-android-all", + 1712468, + "bab9725e928ab3de804281a6d6eeb467a5709920", + "success", + "a24a4849dd8c8c1ea4d991cd5eef2088fc0a78df", + "completed", + 1, + "Eic1aTcHQca8SoQdlQthxg", + 0, + 14, + "opt" + ], + [ + 1, + 524434700, + "feature-share", + "feature-share", + "build-components-feature-share", + "B", + "2025-08-27T14:25:26.978571", + "AC-android-all", + 1712468, + "bab9725e928ab3de804281a6d6eeb467a5709920", + "success", + "935e75e1a528d8cd16da68382945e74a760e1ef7", + "completed", + 1, + "EilInwtWT0-fQx1AoXAwmg", + 0, + 11, + "opt" + ], + [ + 1, + 524434701, + "concept-engine", + "concept-engine", + "build-components-concept-engine", + "B", + "2025-08-27T14:26:05.799153", + "AC-android-all", + 1712468, + "bab9725e928ab3de804281a6d6eeb467a5709920", + "success", + "0fad8aebeed5cf2e24ecdc7bceb8e80ab4bcf277", + "completed", + 1, + "eS0n0my7TMqkOcY8_Gcmww", + 0, + 12, + "opt" + ], + [ + 1, + 524434702, + "browser-session-storage", + "browser-session-storage", + "build-components-browser-session-storage", + "B", + "2025-08-27T14:27:42.316443", + "AC-android-all", + 1712468, + "bab9725e928ab3de804281a6d6eeb467a5709920", + "success", + "1d4bfad4267ea18f8c984c0ffded9c1d6a051b2d", + "completed", + 1, + "F9pCshA0RwmQQXltAsTk2g", + 0, + 14, + "opt" + ], + [ + 1, + 524434703, + "browser-thumbnails", + "browser-thumbnails", + "build-components-browser-thumbnails", + "B", + "2025-08-27T14:26:45.314064", + "AC-android-all", + 1712468, + "bab9725e928ab3de804281a6d6eeb467a5709920", + "success", + "bb01167f03253d1cd99d2869687c359eab1d93a1", + "completed", + 1, + "FDohJ4TYSEyn_8RKW4E98w", + 0, + 13, + "opt" + ], + [ + 1, + 524434704, + "browser-engine-system", + "browser-engine-system", + "build-components-browser-engine-system", + "B", + "2025-08-27T14:27:01.854994", + "AC-android-all", + 1712468, + "bab9725e928ab3de804281a6d6eeb467a5709920", + "success", + "1b98cd37acbc16b5cce59ed102132285a27cfe89", + "completed", + 1, + "FdTbE4duSRiqd-n3NIUWGw", + 0, + 13, + "opt" + ], + [ + 1, + 524434705, + "feature-pwa", + "feature-pwa", + "build-components-feature-pwa", + "B", + "2025-08-27T14:29:39.387286", + "AC-android-all", + 1712468, + "bab9725e928ab3de804281a6d6eeb467a5709920", + "success", + "c68ff4d0440c2e7a88d657f14ecb3981fa2f7c7c", + "completed", + 1, + "fgw0xhQ7QmabLL87HKXDsA", + 0, + 15, + "opt" + ], + [ + 1, + 524434706, + "service-location", + "service-location", + "build-components-service-location", + "B", + "2025-08-27T14:24:43.876334", + "AC-android-all", + 1712468, + "bab9725e928ab3de804281a6d6eeb467a5709920", + "success", + "9d17731772a3e6372245c4a3b931b59127058eca", + "completed", + 1, + "DWp0HZU8QnKQq4ldEzmDTA", + 0, + 11, + "opt" + ], + [ + 1, + 524434707, + "feature-recentlyclosed", + "feature-recentlyclosed", + "test-components-android-feature-recentlyclosed", + "unit", + "2025-08-27T14:35:47.946827", + "AC-ui-test", + 1712468, + "bab9725e928ab3de804281a6d6eeb467a5709920", + "success", + "652897acedd7f5af3749520368d82b32f889d566", + "completed", + 2, + "FH5CiGmnSCqSOUbBog7YuA", + 0, + 22, + "opt" + ], + [ + 1, + 524434708, + "awesomebar-browser-toolbar", + "compose-browser-toolbar", + "build-components-compose-browser-toolbar", + "B", + "2025-08-27T14:28:15.547973", + "AC-android-all", + 1712468, + "bab9725e928ab3de804281a6d6eeb467a5709920", + "success", + "51a19a587475ec7585bea456e2a22e20c63488cf", + "completed", + 1, + "fnXAcYq0S6i6sZuPnEEI5Q", + 0, + 14, + "opt" + ], + [ + 1, + 524434709, + "Fenix builds made for testing", + "fenix-debug", + "build-apk-fenix-debug", + "Bf", + "2025-08-27T14:22:28.356160", + "fenix-android-all", + 1712468, + "bab9725e928ab3de804281a6d6eeb467a5709920", + "success", + "8030e9dba410550485d5d81975321812bdb092c7", + "completed", + 1, + "foWZXALjTNe0jvB3pwTObw", + 0, + 9, + "opt" + ], + [ + 1, + 524434710, + "feature-session", + "feature-session", + "build-components-feature-session", + "B", + "2025-08-27T14:27:24.133755", + "AC-android-all", + 1712468, + "bab9725e928ab3de804281a6d6eeb467a5709920", + "success", + "2979e768e0f0d25e504a1f9de8cc20c15de478e5", + "completed", + 1, + "FqIj_AY3TWC7PKfFmhl1pg", + 0, + 13, + "opt" + ], + [ + 1, + 524434711, + "feature-pwa", + "feature-pwa", + "test-components-android-feature-pwa", + "unit", + "2025-08-27T14:35:40.846649", + "AC-ui-test", + 1712468, + "bab9725e928ab3de804281a6d6eeb467a5709920", + "success", + "81e52a25deafb14c750ea22c11bd5ac23d75849a", + "completed", + 2, + "fYaeuRv5Tcydd_DgVHXaTA", + 0, + 21, + "opt" + ], + [ + 1, + 524434712, + "Fenix builds made for testing", + "fenix-debug", + "test-apk-fenix-debug", + "T", + "2025-08-27T14:38:30.013233", + "fenix-android-all", + 1712468, + "bab9725e928ab3de804281a6d6eeb467a5709920", + "success", + "6ed819cd63350d33f3ee4365e286ac8716cb5018", + "completed", + 1, + "fvgfsZKBR8qAHDGefQXYFg", + 0, + 24, + "opt" + ], + [ + 1, + 524434713, + "samples-firefox-accounts", + "samples-firefox-accounts", + "build-components-samples-firefox-accounts", + "B", + "2025-08-27T14:27:12.567489", + "AC-android-all", + 1712468, + "bab9725e928ab3de804281a6d6eeb467a5709920", + "success", + "84600ccd491e43d8c0e56409a4ee1148ea8610b7", + "completed", + 1, + "G0JzXpK7R-2g7yWwPPY7OA", + 0, + 13, + "opt" + ], + [ + 1, + 524434714, + "service-sync-autofill", + "service-sync-autofill", + "build-components-service-sync-autofill", + "B", + "2025-08-27T14:25:44.722398", + "AC-android-all", + 1712468, + "bab9725e928ab3de804281a6d6eeb467a5709920", + "success", + "e7311ef209dfcda501a8bf40a0335426f28bf2e0", + "completed", + 1, + "G9InH01lRjm6eejAZqpmag", + 0, + 11, + "opt" + ], + [ + 1, + 524434715, + "Focus builds made for testing", + "focus-debug", + "test-apk-focus-debug", + "T", + "2025-08-27T14:37:07.436479", + "focus-android-all", + 1712468, + "bab9725e928ab3de804281a6d6eeb467a5709920", + "success", + "490dfbcd03c5f1401d269153ce5c8c63c4658bbd", + "completed", + 1, + "G1leIGRHRKKRHdqEF9IbWw", + 0, + 23, + "opt" + ], + [ + 1, + 524434716, + "support-test-appservices", + "support-test-appservices", + "build-components-support-test-appservices", + "B", + "2025-08-27T14:24:23.750497", + "AC-android-all", + 1712468, + "bab9725e928ab3de804281a6d6eeb467a5709920", + "success", + "e8a3d03f8622087d595fa60e7a52df0a31bb5a8a", + "completed", + 1, + "GCaZf7G_Q3iLy4TsEraVCQ", + 0, + 10, + "opt" + ], + [ + 1, + 524434717, + "support-ktx", + "support-ktx", + "test-components-android-support-ktx", + "unit", + "2025-08-27T14:36:03.123029", + "AC-ui-test", + 1712468, + "bab9725e928ab3de804281a6d6eeb467a5709920", + "success", + "a84579a328de7428d278134d257fb8cdde2f055a", + "completed", + 2, + "GckULZMzQriy8MlxIGLg-A", + 0, + 22, + "opt" + ], + [ + 1, + 524434718, + "unknown", + "?", + "test-components-unit-browser-engine-gecko-nightly", + "ui-components", + "2025-08-27T14:39:20.620610", + "AC-ui-test", + 1712468, + "bab9725e928ab3de804281a6d6eeb467a5709920", + "success", + "a8e77a818241350ec8337d716c524b27a13ddd09", + "completed", + 2, + "GM3u3yQCQNONvFwS9UuXgA", + 0, + 25, + "opt" + ], + [ + 1, + 524434719, + "feature-readerview", + "feature-readerview", + "build-components-feature-readerview", + "B", + "2025-08-27T14:27:51.559644", + "AC-android-all", + 1712468, + "bab9725e928ab3de804281a6d6eeb467a5709920", + "success", + "74dd6f9999ddc747b0f2d3fc919a17d21d0ede92", + "completed", + 1, + "GnMEKR_vTMGizb7UXEGBtQ", + 0, + 14, + "opt" + ], + [ + 1, + 524434720, + "feature-awesomebar", + "feature-awesomebar", + "build-components-feature-awesomebar", + "B", + "2025-08-27T14:29:52.936245", + "AC-android-all", + 1712468, + "bab9725e928ab3de804281a6d6eeb467a5709920", + "success", + "5c8f7c50d6fe002ccbb442c73a0af5e9a81e4336", + "completed", + 1, + "HGQFSrPGR6SBO422iIrqAQ", + 0, + 16, + "opt" + ], + [ + 1, + 524434721, + "concept-toolbar", + "concept-toolbar", + "build-components-concept-toolbar", + "B", + "2025-08-27T14:25:18.612132", + "AC-android-all", + 1712468, + "bab9725e928ab3de804281a6d6eeb467a5709920", + "success", + "670eec8c0fcadad1bb60c25f88be308909ff3b01", + "completed", + 1, + "HiMR4C6uTA-LHuW_rd7Mfg", + 0, + 11, + "opt" + ], + [ + 1, + 524434722, + "concept-push", + "concept-push", + "build-components-concept-push", + "B", + "2025-08-27T14:25:18.082057", + "AC-android-all", + 1712468, + "bab9725e928ab3de804281a6d6eeb467a5709920", + "success", + "05ce7d837514c4c6ec63bb06019c4fb8a0bc536d", + "completed", + 1, + "Hok8f-D3Sa6l_Rizp7whbA", + 0, + 11, + "opt" + ], + [ + 1, + 524434723, + "gradle lint linter", + "lint", + "source-test-android-lint-focus", + "focus", + "2025-08-27T14:19:46.643211", + "lint", + 1712468, + "bab9725e928ab3de804281a6d6eeb467a5709920", + "success", + "5b9de7abd8a1c4ed42d1f8b2ce818438d11a68c8", + "completed", + 1, + "HRzy41kgTUG-V8Ga519jdQ", + 0, + 7, + "opt" + ], + [ + 1, + 524434724, + "service-digitalassetlinks", + "service-digitalassetlinks", + "build-components-service-digitalassetlinks", + "B", + "2025-08-27T14:26:53.064613", + "AC-android-all", + 1712468, + "bab9725e928ab3de804281a6d6eeb467a5709920", + "success", + "68150da025e012be38921490d0071fdde4a3e7f0", + "completed", + 1, + "I4RPLh-ZRLa_xG2LL81EWA", + 0, + 13, + "opt" + ], + [ + 1, + 524434725, + "Focus builds made for testing", + "focus-debug", + "build-apk-focus-debug", + "Bf", + "2025-08-27T14:21:37.640954", + "focus-android-all", + 1712468, + "bab9725e928ab3de804281a6d6eeb467a5709920", + "success", + "fb6dc5399cf01ed282699758c95e77695743f8d2", + "completed", + 1, + "H_WQ5rq9QLu8DpTSfzqfHQ", + 0, + 8, + "opt" + ], + [ + 1, + 524434726, + "concept-tabstray", + "concept-tabstray", + "build-components-concept-tabstray", + "B", + "2025-08-27T14:26:41.940984", + "AC-android-all", + 1712468, + "bab9725e928ab3de804281a6d6eeb467a5709920", + "success", + "89f3f7ded08750efc86827f06c22e1e41279138b", + "completed", + 1, + "IaWIQK4mTYKzMcp5di1pWA", + 0, + 12, + "opt" + ], + [ + 1, + 524434727, + "service-nimbus", + "service-nimbus", + "build-components-service-nimbus", + "B", + "2025-08-27T14:27:22.797576", + "AC-android-all", + 1712468, + "bab9725e928ab3de804281a6d6eeb467a5709920", + "success", + "109765a04fffe435d7c9e0986eb030d46de19304", + "completed", + 1, + "Ia48EzkGQRqxtqwjfw5qCg", + 0, + 13, + "opt" + ], + [ + 1, + 524434728, + "support-test-libstate", + "support-test-libstate", + "build-components-support-test-libstate", + "B", + "2025-08-27T14:26:33.281301", + "AC-android-all", + 1712468, + "bab9725e928ab3de804281a6d6eeb467a5709920", + "success", + "b5165977fcbbd403a51eec0aa6dbb8553fb3a8cc", + "completed", + 1, + "IZ83L6NeSsGuMsIwI60Q4w", + 0, + 12, + "opt" + ], + [ + 1, + 524434729, + "lib-jexl", + "lib-jexl", + "build-components-lib-jexl", + "B", + "2025-08-27T14:24:22.134551", + "AC-android-all", + 1712468, + "bab9725e928ab3de804281a6d6eeb467a5709920", + "success", + "e2871cf229f446b3a9c231b6e31a53e085c2a483", + "completed", + 1, + "J46Sca6JRLGORyFSji4UHw", + 0, + 10, + "opt" + ], + [ + 1, + 524434730, + "samples-glean", + "samples-glean", + "build-components-samples-glean", + "B", + "2025-08-27T14:27:46.712014", + "AC-android-all", + 1712468, + "bab9725e928ab3de804281a6d6eeb467a5709920", + "success", + "51a93026c0252a4530052770f0bfe8de28168043", + "completed", + 1, + "JHgxgmuITG68vHTn8O8Vzg", + 0, + 13, + "opt" + ], + [ + 1, + 524434731, + "feature-webcompat", + "feature-webcompat", + "build-components-feature-webcompat", + "B", + "2025-08-27T14:26:26.073359", + "AC-android-all", + 1712468, + "bab9725e928ab3de804281a6d6eeb467a5709920", + "success", + "3d7fb31e3c57fc1ad2ccdc8cc68304d107babd34", + "completed", + 1, + "JDHVttm_R2-gMW7lqq47BQ", + 0, + 12, + "opt" + ], + [ + 1, + 524434732, + "feature-logins", + "feature-logins", + "test-components-android-feature-logins", + "unit", + "2025-08-27T14:37:59.689081", + "AC-ui-test", + 1712468, + "bab9725e928ab3de804281a6d6eeb467a5709920", + "success", + "dd63b39e82bd6b04049b4b339bfb63a490ff25b6", + "completed", + 2, + "JOsyVWe6TYqExrJaYryiYw", + 0, + 24, + "opt" + ], + [ + 1, + 524434734, + "browser-menu2", + "browser-menu2", + "build-components-browser-menu2", + "B", + "2025-08-27T14:26:21.634903", + "AC-android-all", + 1712468, + "bab9725e928ab3de804281a6d6eeb467a5709920", + "success", + "4ca831afebe68ba442f70b4c6c5c6309dde614f2", + "completed", + 1, + "Juj_NytvTc6dJnoXhmeRag", + 0, + 12, + "opt" + ], + [ + 1, + 524434736, + "concept-base", + "concept-base", + "build-components-concept-base", + "B", + "2025-08-27T14:24:17.193326", + "AC-android-all", + 1712468, + "bab9725e928ab3de804281a6d6eeb467a5709920", + "success", + "d559a00647990b2e373ea4a58ea118f04ee548f1", + "completed", + 1, + "K9k6M65iS8ehC7KQZFRBkQ", + 0, + 10, + "opt" + ], + [ + 1, + 524434737, + "lib-state", + "lib-state", + "build-components-lib-state", + "B", + "2025-08-27T14:27:09.803117", + "AC-android-all", + 1712468, + "bab9725e928ab3de804281a6d6eeb467a5709920", + "success", + "4f2d44a3f116359cbe875d59cd11e8c2b361d4bd", + "completed", + 1, + "KkCRlsMwRBGShdPCTJ7kbw", + 0, + 13, + "opt" + ], + [ + 1, + 524434738, + "feature-sitepermissions", + "feature-sitepermissions", + "test-components-android-feature-sitepermissions", + "unit", + "2025-08-27T14:39:32.318294", + "AC-ui-test", + 1712468, + "bab9725e928ab3de804281a6d6eeb467a5709920", + "success", + "6886a25fc95030657f8f5f5d97fec004d6a58714", + "completed", + 2, + "KpoETvPmQl-9rfuSXHZCCQ", + 0, + 25, + "opt" + ], + [ + 1, + 524434739, + "concept-sync", + "concept-sync", + "build-components-concept-sync", + "B", + "2025-08-27T14:24:45.379911", + "AC-android-all", + 1712468, + "bab9725e928ab3de804281a6d6eeb467a5709920", + "success", + "ae989386cb4af2e7958abe5206837157b6eee100", + "completed", + 1, + "KQjDRH3TS1y3MetWMKEXuA", + 0, + 10, + "opt" + ], + [ + 1, + 524434740, + "feature-autofill", + "feature-autofill", + "build-components-feature-autofill", + "B", + "2025-08-27T14:26:18.600312", + "AC-android-all", + 1712468, + "bab9725e928ab3de804281a6d6eeb467a5709920", + "success", + "e57236bf594b6fd4b648764d9d5039e810025fc7", + "completed", + 1, + "KUs-U-xtTLGojqWjjy27Qg", + 0, + 12, + "opt" + ], + [ + 1, + 524434741, + "lib-auth", + "lib-auth", + "build-components-lib-auth", + "B", + "2025-08-27T14:24:47.485254", + "AC-android-all", + 1712468, + "bab9725e928ab3de804281a6d6eeb467a5709920", + "success", + "ef55ca0db9b579160849bfea9c9adec1f8926497", + "completed", + 1, + "KuzenpgHQ3-im9Pnq6k5tQ", + 0, + 10, + "opt" + ], + [ + 1, + 524434742, + "support-webextensions", + "support-webextensions", + "build-components-support-webextensions", + "B", + "2025-08-27T14:26:32.162156", + "AC-android-all", + 1712468, + "bab9725e928ab3de804281a6d6eeb467a5709920", + "success", + "bede93c983370e5cc2d20fda9446ac13b60c28a3", + "completed", + 1, + "L5eRRcPmSOufa1qPLftb_w", + 0, + 12, + "opt" + ], + [ + 1, + 524434743, + "feature-webnotifications", + "feature-webnotifications", + "build-components-feature-webnotifications", + "B", + "2025-08-27T14:28:57.785240", + "AC-android-all", + 1712468, + "bab9725e928ab3de804281a6d6eeb467a5709920", + "success", + "7cc56a02dd9dc66e6b826aa068a07f1bda488c82", + "completed", + 1, + "LbxzOAqoQwiFRuW_S3F0Wg", + 0, + 15, + "opt" + ], + [ + 1, + 524434744, + "feature-sitepermissions", + "feature-sitepermissions", + "build-components-feature-sitepermissions", + "B", + "2025-08-27T14:29:16.139137", + "AC-android-all", + 1712468, + "bab9725e928ab3de804281a6d6eeb467a5709920", + "success", + "ef791ef06c59c78efccf81efc3298b0e4083d0b6", + "completed", + 1, + "LNEMr9TBTS-GHfJH8S-Qxg", + 0, + 15, + "opt" + ], + [ + 1, + 524434745, + "lib-dataprotect", + "lib-dataprotect", + "build-components-lib-dataprotect", + "B", + "2025-08-27T14:25:12.454452", + "AC-android-all", + 1712468, + "bab9725e928ab3de804281a6d6eeb467a5709920", + "success", + "fce6e45cf6f8c87dd13d76df8ce60b731b0c0dc4", + "completed", + 1, + "LrUS-kCJST-nJkzmQ7QbAA", + 0, + 11, + "opt" + ], + [ + 1, + 524434746, + "samples-toolbar", + "samples-toolbar", + "build-components-samples-toolbar", + "B", + "2025-08-27T14:29:42.652811", + "AC-android-all", + 1712468, + "bab9725e928ab3de804281a6d6eeb467a5709920", + "success", + "a7ef335e534036e972a0fec137e7e6b4677026b4", + "completed", + 1, + "LTAe1ntGTya7IbDuJxLQHQ", + 0, + 15, + "opt" + ], + [ + 1, + 524434747, + "feature-recentlyclosed", + "feature-recentlyclosed", + "build-components-feature-recentlyclosed", + "B", + "2025-08-27T14:27:15.747809", + "AC-android-all", + 1712468, + "bab9725e928ab3de804281a6d6eeb467a5709920", + "success", + "bf39325ec6c7d3c082101252cc2b09a17706a862", + "completed", + 1, + "LWnpO47ZSPWKFkPafKSHGQ", + 0, + 13, + "opt" + ], + [ + 1, + 524434748, + "support-images", + "support-images", + "build-components-support-images", + "B", + "2025-08-27T14:26:41.477942", + "AC-android-all", + 1712468, + "bab9725e928ab3de804281a6d6eeb467a5709920", + "success", + "42809d52ec24f3c6d13b22679c33a823889e4e04", + "completed", + 1, + "MoAW7wy6RDy6faj1koFkNw", + 0, + 12, + "opt" + ], + [ + 1, + 524434749, + "samples-dataprotect", + "samples-dataprotect", + "build-components-samples-dataprotect", + "B", + "2025-08-27T14:26:45.859665", + "AC-android-all", + 1712468, + "bab9725e928ab3de804281a6d6eeb467a5709920", + "success", + "b9236328559eb94a6829bd0baebde64b5d3707d9", + "completed", + 1, + "Mt2pGDpZTDmIFJJ2Zl8kNg", + 0, + 12, + "opt" + ], + [ + 1, + 524434750, + "browser-domains", + "browser-domains", + "build-components-browser-domains", + "B", + "2025-08-27T14:26:54.116290", + "AC-android-all", + 1712468, + "bab9725e928ab3de804281a6d6eeb467a5709920", + "success", + "342aacc8cb0eb357ab8361aa8861e445a90f87c9", + "completed", + 1, + "N8OhVn8iQnuivLyJ2QWdsQ", + 0, + 12, + "opt" + ], + [ + 1, + 524434751, + "feature-share", + "feature-share", + "test-components-android-feature-share", + "unit", + "2025-08-27T14:43:59.906465", + "AC-ui-test", + 1712468, + "bab9725e928ab3de804281a6d6eeb467a5709920", + "success", + "b4e72c10d50a719cda5aca1f6ef807b9cf108a79", + "completed", + 2, + "NS5_9UtURFmJQJ4GOL-JQg", + 0, + 29, + "opt" + ], + [ + 1, + 524434752, + "feature-media", + "feature-media", + "build-components-feature-media", + "B", + "2025-08-27T14:27:35.410322", + "AC-android-all", + 1712468, + "bab9725e928ab3de804281a6d6eeb467a5709920", + "success", + "02985175132ccb9621f21a68bb3a8a325c87e4aa", + "completed", + 1, + "NwzJaEwBQqS-s-TrEaq2pg", + 0, + 13, + "opt" + ], + [ + 1, + 524434753, + "support-locale", + "support-locale", + "build-components-support-locale", + "B", + "2025-08-27T14:27:39.894264", + "AC-android-all", + 1712468, + "bab9725e928ab3de804281a6d6eeb467a5709920", + "success", + "f846929b99879e73e614744c4a4a56c1d94f8ef1", + "completed", + 1, + "O7DmKC-9R4CumavQeb-DJw", + 0, + 13, + "opt" + ], + [ + 1, + 524434754, + "browser-storage-sync", + "browser-storage-sync", + "build-components-browser-storage-sync", + "B", + "2025-08-27T14:26:37.222894", + "AC-android-all", + 1712468, + "bab9725e928ab3de804281a6d6eeb467a5709920", + "success", + "c691423e881cad2e7ee6f587cb1f7bd7ae700e4d", + "completed", + 1, + "O9-4x63UTTmSChg4Vj319g", + 0, + 12, + "opt" + ], + [ + 1, + 524434755, + "feature-app-links", + "feature-app-links", + "build-components-feature-app-links", + "B", + "2025-08-27T14:28:15.470964", + "AC-android-all", + 1712468, + "bab9725e928ab3de804281a6d6eeb467a5709920", + "success", + "5710a0d813a3800b775daf1f17bbab3ec8e7e61d", + "completed", + 1, + "O-IcQQTQQcCptGtHxNB59A", + 0, + 14, + "opt" + ], + [ + 1, + 524434756, + "service-mars", + "service-mars", + "build-components-service-mars", + "B", + "2025-08-27T14:26:53.517671", + "AC-android-all", + 1712468, + "bab9725e928ab3de804281a6d6eeb467a5709920", + "success", + "19019a93f7b944dab18889fe4c2873de69c7a243", + "completed", + 1, + "P0_zwyhZTO--98Bg3JU2Dg", + 0, + 12, + "opt" + ], + [ + 1, + 524434757, + "compose-engine", + "compose-awesomebar", + "build-components-compose-awesomebar", + "B", + "2025-08-27T14:26:58.042207", + "AC-android-all", + 1712468, + "bab9725e928ab3de804281a6d6eeb467a5709920", + "success", + "04f88c823da98283c8c24a993295a30b947910cc", + "completed", + 1, + "PNv33xJsRPCpl91rLj7r5Q", + 0, + 12, + "opt" + ], + [ + 1, + 524434758, + "ui-autocomplete", + "ui-autocomplete", + "build-components-ui-autocomplete", + "B", + "2025-08-27T14:25:15.269358", + "AC-android-all", + 1712468, + "bab9725e928ab3de804281a6d6eeb467a5709920", + "success", + "9d726fc27c85a69edcf96f9d6bddc723fcd6f1e0", + "completed", + 1, + "PPMzm3acQHK_s4deuKyCAw", + 0, + 11, + "opt" + ], + [ + 1, + 524434759, + "browser-state", + "browser-state", + "build-components-browser-state", + "B", + "2025-08-27T14:27:36.831602", + "AC-android-all", + 1712468, + "bab9725e928ab3de804281a6d6eeb467a5709920", + "success", + "2d6045a7a6af839e9ed2f89b1f144f340c0793ec", + "completed", + 1, + "PTj0oxOgRM-gscHvJPsZ2Q", + 0, + 13, + "opt" + ], + [ + 1, + 524434760, + "lib-publicsuffixlist", + "lib-publicsuffixlist", + "build-components-lib-publicsuffixlist", + "B", + "2025-08-27T14:25:03.373689", + "AC-android-all", + 1712468, + "bab9725e928ab3de804281a6d6eeb467a5709920", + "success", + "8cd4f2430dc181c38e58179a340e3e5e9d4ce2d9", + "completed", + 1, + "Qbf_f7ZySfaspO83l7DCxw", + 0, + 10, + "opt" + ], + [ + 1, + 524434761, + "browser-menu", + "browser-menu", + "build-components-browser-menu", + "B", + "2025-08-27T14:28:08.696889", + "AC-android-all", + 1712468, + "bab9725e928ab3de804281a6d6eeb467a5709920", + "success", + "af8016ef6d71332e2f6dc282b00557499df7cf83", + "completed", + 1, + "R5msLWRqQ2OYQc_M461UXw", + 0, + 14, + "opt" + ], + [ + 1, + 524434762, + "feature-webauthn", + "feature-webauthn", + "build-components-feature-webauthn", + "B", + "2025-08-27T14:27:20.147274", + "AC-android-all", + 1712468, + "bab9725e928ab3de804281a6d6eeb467a5709920", + "success", + "830d3c2b81691f62708e5f9817533b2c849de99d", + "completed", + 1, + "RLjKPxaKRICNt2OJMm2zoA", + 0, + 13, + "opt" + ], + [ + 1, + 524434763, + "feature-prompts", + "feature-prompts", + "test-components-android-feature-prompts", + "unit", + "2025-08-27T14:44:39.188928", + "AC-ui-test", + 1712468, + "bab9725e928ab3de804281a6d6eeb467a5709920", + "retry", + "8b0b3001d5a6da7b223b7d1b37001a9130091720", + "completed", + 2, + "S7rXUhZlSUu8jO6opPOalQ", + 0, + 30, + "opt" + ], + [ + 1, + 524434764, + "compose-base", + "compose-base", + "build-components-compose-base", + "B", + "2025-08-27T14:27:50.165071", + "AC-android-all", + 1712468, + "bab9725e928ab3de804281a6d6eeb467a5709920", + "success", + "ebdfb6933136d86aecc2ca567512d74db5783957", + "completed", + 1, + "SIpJtF0wS3Cq_WgDr3Enog", + 0, + 13, + "opt" + ], + [ + 1, + 524434765, + "browser-tabstray", + "browser-tabstray", + "build-components-browser-tabstray", + "B", + "2025-08-27T14:27:57.736479", + "AC-android-all", + 1712468, + "bab9725e928ab3de804281a6d6eeb467a5709920", + "success", + "0c5184c356f159ed5e48be84046112a02d21d33c", + "completed", + 1, + "S-YDU7JOQbapOdFSoK6aeA", + 0, + 13, + "opt" + ], + [ + 1, + 524434766, + "service-firefox-accounts", + "service-firefox-accounts", + "build-components-service-firefox-accounts", + "B", + "2025-08-27T14:27:33.810996", + "AC-android-all", + 1712468, + "bab9725e928ab3de804281a6d6eeb467a5709920", + "success", + "641c695e2a0aa30e40612e735270f8a151982d84", + "completed", + 1, + "TAANZSfERiOjWaPstklONQ", + 0, + 13, + "opt" + ], + [ + 1, + 524434767, + "ui-fonts", + "ui-fonts", + "build-components-ui-fonts", + "B", + "2025-08-27T14:24:37.169635", + "AC-android-all", + 1712468, + "bab9725e928ab3de804281a6d6eeb467a5709920", + "success", + "6b02bb8304f40d4f22d0855b199060adfd85cc11", + "completed", + 1, + "TIAfzHHIToygjp3uZxE6-w", + 0, + 10, + "opt" + ], + [ + 1, + 524434768, + "unknown", + "?", + "test-components-ui-browser", + "ui-samples-browser", + "2025-08-27T14:35:40.317510", + "AC-ui-test", + 1712468, + "bab9725e928ab3de804281a6d6eeb467a5709920", + "success", + "0566f42118f53054d0908402b1ba94c7ed0551b7", + "completed", + 2, + "TNPkiisnTCmCmio2346E9Q", + 0, + 21, + "opt" + ], + [ + 1, + 524434769, + "feature-tab-collections", + "feature-tab-collections", + "build-components-feature-tab-collections", + "B", + "2025-08-27T14:29:02.813641", + "AC-android-all", + 1712468, + "bab9725e928ab3de804281a6d6eeb467a5709920", + "success", + "f7d6b9b258edf1b16fd8077e1759974657f12c10", + "completed", + 1, + "TQ-MVH06S6KaD-JoSAbEQw", + 0, + 14, + "opt" + ], + [ + 1, + 524434770, + "feature-findinpage", + "feature-findinpage", + "build-components-feature-findinpage", + "B", + "2025-08-27T14:27:58.331668", + "AC-android-all", + 1712468, + "bab9725e928ab3de804281a6d6eeb467a5709920", + "success", + "e26fcbc6c34f25f893fc889432530cbaa9ccf9a8", + "completed", + 1, + "TrkADWoJSveQcXsjW5xz9Q", + 0, + 13, + "opt" + ], + [ + 1, + 524434771, + "lib-fetch-httpurlconnection", + "lib-fetch-httpurlconnecti", + "build-components-lib-fetch-httpurlconnection", + "B", + "2025-08-27T14:25:19.975924", + "AC-android-all", + 1712468, + "bab9725e928ab3de804281a6d6eeb467a5709920", + "success", + "699060dfdc658c8fab947a1b68e6e98c27cda61b", + "completed", + 1, + "UZW0thXYRkmG_yac9_JaPw", + 0, + 11, + "opt" + ], + [ + 1, + 524434772, + "samples-crash", + "samples-crash", + "build-components-samples-crash", + "B", + "2025-08-27T14:28:14.401451", + "AC-android-all", + 1712468, + "bab9725e928ab3de804281a6d6eeb467a5709920", + "success", + "36bd21032d5e98b3c7cd4547a02727bef81f60bb", + "completed", + 1, + "V0CzeVOAQ8i_KQqA8YnXpw", + 0, + 14, + "opt" + ], + [ + 1, + 524434773, + "tooling-fetch-tests", + "tooling-fetch-tests", + "build-components-tooling-fetch-tests", + "B", + "2025-08-27T14:25:20.931233", + "AC-android-all", + 1712468, + "bab9725e928ab3de804281a6d6eeb467a5709920", + "success", + "b4fbe085761a3cefb87f451f7b5c12494ddc5553", + "completed", + 1, + "V7tigTkOSrySwvlL6COKqg", + 0, + 11, + "opt" + ], + [ + 1, + 524434774, + "feature-qr", + "feature-qr", + "build-components-feature-qr", + "B", + "2025-08-27T14:27:53.102939", + "AC-android-all", + 1712468, + "bab9725e928ab3de804281a6d6eeb467a5709920", + "success", + "a40bf330d28a92d84d809189fab4d44968f1d103", + "completed", + 1, + "VcecCmpDQnKAOCW4P4yzhQ", + 0, + 13, + "opt" + ], + [ + 1, + 524434775, + "lib-push-firebase", + "lib-push-firebase", + "build-components-lib-push-firebase", + "B", + "2025-08-27T14:26:07.766142", + "AC-android-all", + 1712468, + "bab9725e928ab3de804281a6d6eeb467a5709920", + "success", + "f08f958a039388413dda0ca445a687b79c0fe243", + "completed", + 1, + "VJEV2aBMQ_S6ig0tBPlPkQ", + 0, + 11, + "opt" + ], + [ + 1, + 524434776, + "feature-downloads", + "feature-downloads", + "build-components-feature-downloads", + "B", + "2025-08-27T14:30:27.237176", + "AC-android-all", + 1712468, + "bab9725e928ab3de804281a6d6eeb467a5709920", + "success", + "25febeca18dd5d78be85b521b9b6b5e028fef4e0", + "completed", + 1, + "VJlr-1GNSLiIGgPUWsM6Ig", + 0, + 16, + "opt" + ], + [ + 1, + 524434777, + "browser-engine-gecko", + "browser-engine-gecko", + "build-components-browser-engine-gecko", + "B", + "2025-08-27T14:30:13.222616", + "AC-android-all", + 1712468, + "bab9725e928ab3de804281a6d6eeb467a5709920", + "success", + "af71760b61bccf9d0879f06bef863b053dcfc4ba", + "completed", + 1, + "Vt0XnErfRzKktunkKE754A", + 0, + 16, + "opt" + ], + [ + 1, + 524434778, + "lib-crash-sentry", + "lib-crash-sentry", + "build-components-lib-crash-sentry", + "B", + "2025-08-27T14:27:22.151565", + "AC-android-all", + 1712468, + "bab9725e928ab3de804281a6d6eeb467a5709920", + "success", + "d79b1e17e8c7d2b0f7520f403a3e899c1f50ac3b", + "completed", + 1, + "VWjjY-anR1WDnT6BGmVVUA", + 0, + 13, + "opt" + ], + [ + 1, + 524434779, + "tooling-detekt", + "tooling-detekt", + "build-components-tooling-detekt", + "B", + "2025-08-27T14:24:52.786513", + "AC-android-all", + 1712468, + "bab9725e928ab3de804281a6d6eeb467a5709920", + "success", + "842236e43d9cb875e9972906653877336d88933e", + "completed", + 1, + "Wb8XfVYdQPqZTE8pZsqFwg", + 0, + 10, + "opt" + ], + [ + 1, + 524434780, + "feature-serviceworker", + "feature-serviceworker", + "build-components-feature-serviceworker", + "B", + "2025-08-27T14:29:00.444312", + "AC-android-all", + 1712468, + "bab9725e928ab3de804281a6d6eeb467a5709920", + "success", + "b7270e43c080390f34f45784fc158a13fb37c784", + "completed", + 1, + "WDrzURmsTsKWbCNB-ZKL3Q", + 0, + 14, + "opt" + ], + [ + 1, + 524434781, + "gradle lint linter", + "lint", + "source-test-android-lint-fenix", + "fenix", + "2025-08-27T14:22:36.041043", + "lint", + 1712468, + "bab9725e928ab3de804281a6d6eeb467a5709920", + "success", + "2e3f6994fb7910c850881b5ec54cd004d76abce9", + "completed", + 1, + "WezHDUQWTDyBHL_2NREcaQ", + 0, + 10, + "opt" + ], + [ + 1, + 524434782, + "tooling-lint", + "tooling-lint", + "build-components-tooling-lint", + "B", + "2025-08-27T14:26:42.207730", + "AC-android-all", + 1712468, + "bab9725e928ab3de804281a6d6eeb467a5709920", + "success", + "fea54c65d9e1aa9f1c37b497769749af648f6bc8", + "completed", + 1, + "WKIsVxsCRyKCC2ZQ37aSGw", + 0, + 12, + "opt" + ], + [ + 1, + 524434783, + "feature-toolbar", + "feature-toolbar", + "build-components-feature-toolbar", + "B", + "2025-08-27T14:28:48.275291", + "AC-android-all", + 1712468, + "bab9725e928ab3de804281a6d6eeb467a5709920", + "success", + "7c72db7493e0141c251cfb83a0f9efe3b3e56eec", + "completed", + 1, + "WLxZI0KERlOdrbL7Yxo7iA", + 0, + 14, + "opt" + ], + [ + 1, + 524434784, + "lib-crash", + "lib-crash", + "build-components-lib-crash", + "B", + "2025-08-27T14:27:38.347558", + "AC-android-all", + 1712468, + "bab9725e928ab3de804281a6d6eeb467a5709920", + "success", + "08fe2c1791a9df717abafcd82be1952059386492", + "completed", + 1, + "WQ9EjA6aQFKGkP9kSiMYOg", + 0, + 13, + "opt" + ], + [ + 1, + 524434785, + "support-ktx", + "support-ktx", + "build-components-support-ktx", + "B", + "2025-08-27T14:28:10.492503", + "AC-android-all", + 1712468, + "bab9725e928ab3de804281a6d6eeb467a5709920", + "success", + "e191263ca2536674a807c7f840f7a6315b9bed08", + "completed", + 1, + "WsWVLPfcRG6lOXaGd4OVQQ", + 0, + 13, + "opt" + ], + [ + 1, + 524434786, + "feature-containers", + "feature-containers", + "test-components-android-feature-containers", + "unit", + "2025-08-27T14:36:18.742173", + "AC-ui-test", + 1712468, + "bab9725e928ab3de804281a6d6eeb467a5709920", + "success", + "ee1bec3f378b015a56d0179af543e3bb683d86ef", + "completed", + 2, + "X7v-8FYaSi6k9WjqbnkbiQ", + 0, + 22, + "opt" + ], + [ + 1, + 524434787, + "service-sync-logins", + "service-sync-logins", + "build-components-service-sync-logins", + "B", + "2025-08-27T14:26:43.372137", + "AC-android-all", + 1712468, + "bab9725e928ab3de804281a6d6eeb467a5709920", + "success", + "be12c78d9886c4ff0033414802101c905a2145af", + "completed", + 1, + "XmiRN_R-SeaJMQNg-Tz5ow", + 0, + 12, + "opt" + ], + [ + 1, + 524434788, + "feature-webcompat-reporter", + "feature-webcompat-reporte", + "build-components-feature-webcompat-reporter", + "B", + "2025-08-27T14:27:34.814253", + "AC-android-all", + 1712468, + "bab9725e928ab3de804281a6d6eeb467a5709920", + "success", + "0fbe979013be0464270edf6c0c8012a2b1f4f1b7", + "completed", + 1, + "XsXWopbWQjKyM2FIWASOOQ", + 0, + 13, + "opt" + ], + [ + 1, + 524434789, + "feature-downloads", + "feature-downloads", + "test-components-android-feature-downloads", + "unit", + "2025-08-27T14:38:57.049915", + "AC-ui-test", + 1712468, + "bab9725e928ab3de804281a6d6eeb467a5709920", + "success", + "49a131e427245760101abb21b3681b3d08b5c580", + "completed", + 2, + "XUwQ30NNRiWTb7GTtuO3uA", + 0, + 24, + "opt" + ], + [ + 1, + 524434790, + "feature-intent", + "feature-intent", + "build-components-feature-intent", + "B", + "2025-08-27T14:29:41.298043", + "AC-android-all", + 1712468, + "bab9725e928ab3de804281a6d6eeb467a5709920", + "success", + "25d303807bdef155bf995bf8e63a11a9e00aa00a", + "completed", + 1, + "YruLsMy3SUGSOAPYjTDvmg", + 0, + 15, + "opt" + ], + [ + 1, + 524434791, + "support-utils", + "support-utils", + "build-components-support-utils", + "B", + "2025-08-27T14:27:00.219161", + "AC-android-all", + 1712468, + "bab9725e928ab3de804281a6d6eeb467a5709920", + "success", + "6520c0e8af9838655007c68076ae57e5490584b5", + "completed", + 1, + "Y5K2cO_vRcGWhmd5iEj9yQ", + 0, + 12, + "opt" + ], + [ + 1, + 524434792, + "feature-screendetection", + "feature-screendetection", + "build-components-feature-screendetection", + "B", + "2025-08-27T14:26:16.750900", + "AC-android-all", + 1712468, + "bab9725e928ab3de804281a6d6eeb467a5709920", + "success", + "431fa87fe56c9c0628d985e61662fe45442a044f", + "completed", + 1, + "YsnA7JwjTQKhp7Hh8ZQY2A", + 0, + 11, + "opt" + ], + [ + 1, + 524434793, + "Profile-guided optimization builds", + "Bpgo", + "instrumented-build-apk-fenix", + "instr", + "2025-08-27T14:25:39.329202", + "fenix-android-all", + 1712468, + "bab9725e928ab3de804281a6d6eeb467a5709920", + "success", + "838cd18dbac6c97c2c0525354c73f31f8782da53", + "completed", + 1, + "YtQxFD08RQ2DtYkDsVG3DQ", + 0, + 11, + "opt" + ], + [ + 1, + 524434794, + "feature-prompts", + "feature-prompts", + "build-components-feature-prompts", + "B", + "2025-08-27T14:30:44.165708", + "AC-android-all", + 1712468, + "bab9725e928ab3de804281a6d6eeb467a5709920", + "success", + "a085355089a6cd76b3458308db7903be8fd24e0b", + "completed", + 1, + "YZfvO_g3Qw6EaIGFYboN5g", + 0, + 16, + "opt" + ], + [ + 1, + 524434795, + "unknown", + "?", + "test-components-ui-glean", + "ui-samples-glean", + "2025-08-27T14:34:46.702813", + "AC-ui-test", + 1712468, + "bab9725e928ab3de804281a6d6eeb467a5709920", + "success", + "1980aa26e4d1f3478cf128b5dc11dbf957a095cd", + "completed", + 2, + "Z1dYc39VRP-3ggWg0BXDPg", + 0, + 20, + "opt" + ], + [ + 1, + 524434796, + "feature-accounts-push", + "feature-accounts-push", + "build-components-feature-accounts-push", + "B", + "2025-08-27T14:28:35.831247", + "AC-android-all", + 1712468, + "bab9725e928ab3de804281a6d6eeb467a5709920", + "success", + "55905fabac8f0ca4fe0b71666b386508306f3175", + "completed", + 1, + "ZvRQHxP8Qy61YBFjNr3ROw", + 0, + 13, + "opt" + ], + [ + 1, + 524434797, + "compose-cfr", + "compose-cfr", + "build-components-compose-cfr", + "B", + "2025-08-27T14:27:44.090990", + "AC-android-all", + 1712468, + "bab9725e928ab3de804281a6d6eeb467a5709920", + "success", + "9d35578322079c638d94645d4a01cba1150d6bc0", + "completed", + 1, + "ZnH9-1t8TzeU9J4qUuclHA", + 0, + 13, + "opt" + ], + [ + 1, + 524436264, + "Focus builds made for testing", + "focus-debug", + "signing-apk-focus-debug", + "Bfs", + "2025-08-27T14:24:40.478017", + "focus-android-all", + 1712468, + "bab9725e928ab3de804281a6d6eeb467a5709920", + "success", + "4ec77afc78d1790901e71b99029c00bf43d69f25", + "completed", + 1, + "WDJb1HJaTr-dfSkshBxw4w", + 0, + 2, + "opt" + ], + [ + 1, + 524436364, + "Fenix builds made for testing", + "fenix-debug", + "signing-apk-fenix-debug", + "Bs", + "2025-08-27T14:26:17.753530", + "fenix-android-all", + 1712468, + "bab9725e928ab3de804281a6d6eeb467a5709920", + "success", + "04ead08e412f54c7ec25cc72ee418aee88060850", + "completed", + 1, + "cnZtdaVgTpeS3Vk4FtvYhA", + 0, + 3, + "opt" + ], + [ + 1, + 524436773, + "Focus builds made for testing", + "focus-debug", + "signing-apk-focus-android-test-debug", + "Bats", + "2025-08-27T14:24:48.518022", + "focus-android-all", + 1712468, + "bab9725e928ab3de804281a6d6eeb467a5709920", + "success", + "b5f4d6e4f9e4312d835eeacc9e93aacfc13e8c66", + "completed", + 1, + "SZwToRuhRcuO6Lnzab9hgQ", + 0, + 1, + "opt" + ], + [ + 1, + 524436844, + "Fenix builds made for testing", + "fenix-debug", + "signing-apk-fenix-android-test-debug", + "Bats", + "2025-08-27T14:24:56.069783", + "fenix-android-all", + 1712468, + "bab9725e928ab3de804281a6d6eeb467a5709920", + "success", + "39666ffc19edead9a77a469a8b0ecee9d84902be", + "completed", + 1, + "F_5UaojsRYGoqBSvRQA9aw", + 0, + 1, + "opt" + ], + [ + 1, + 524436868, + "Focus builds made for testing", + "focus-debug", + "ui-test-apk-focus-arm-debug", + "ui-test-arm", + "2025-08-27T14:32:01.846122", + "focus-android-all", + 1712468, + "bab9725e928ab3de804281a6d6eeb467a5709920", + "success", + "f788a9e88ebf2b83b935f00ea02946f471a87389", + "completed", + 2, + "OxYXvAAzToyvUsPbRnNI-Q", + 0, + 7, + "opt" + ], + [ + 1, + 524437021, + "Profile-guided optimization builds", + "Bpgo", + "generate-baseline-profile-firebase-fenix", + "run", + "2025-08-27T14:58:59.469527", + "fenix-android-all", + 1712468, + "bab9725e928ab3de804281a6d6eeb467a5709920", + "success", + "f7d3c37fb6911584616a2d3467eeabae7c42d087", + "completed", + 1, + "Du4vpjA3TFO9vQcqC64A1w", + 0, + 33, + "opt" + ], + [ + 1, + 524437292, + "Fenix builds made for testing", + "fenix-debug", + "ui-test-apk-fenix-arm-debug-smoke", + "smoke-arm", + "2025-08-27T14:30:41.412792", + "fenix-android-all", + 1712468, + "bab9725e928ab3de804281a6d6eeb467a5709920", + "success", + "952dcbb5504945495b15cb3d3750c86bf2eadaf5", + "completed", + 1, + "SEIq8yPZTYuG5O2NwTzj0g", + 0, + 4, + "opt" + ], + [ + 1, + 524437294, + "Fenix builds made for testing", + "fenix-debug", + "ui-test-apk-fenix-arm-debug", + "ui-test-arm", + "2025-08-27T14:37:20.968247", + "fenix-android-all", + 1712468, + "bab9725e928ab3de804281a6d6eeb467a5709920", + "success", + "aa0253b61bea023fbda83720856096a456015468", + "completed", + 2, + "VXjS2j8LT22-TfTTV2fOLw", + 0, + 11, + "opt" + ], + [ + 1, + 524438258, + "feature-top-sites", + "feature-top-sites", + "test-components-android-feature-top-sites", + "unit", + "2025-08-27T14:49:48.330651", + "AC-ui-test", + 1712468, + "bab9725e928ab3de804281a6d6eeb467a5709920", + "success", + "07320536c531d8662492010cc7ca307b39648e66", + "completed", + 2, + "dTHvnYJZQy2Z_g5uMy_5Ow", + 1, + 17, + "opt" + ], + [ + 1, + 524441082, + "feature-prompts", + "feature-prompts", + "test-components-android-feature-prompts", + "unit", + "2025-08-27T15:03:59.631338", + "AC-ui-test", + 1712468, + "bab9725e928ab3de804281a6d6eeb467a5709920", + "success", + "8b0b3001d5a6da7b223b7d1b37001a9130091720", + "completed", + 2, + "S7rXUhZlSUu8jO6opPOalQ", + 1, + 19, + "opt" + ] + ], + "job_property_names": [ + "failure_classification_id", + "id", + "job_group_name", + "job_group_symbol", + "job_type_name", + "job_type_symbol", + "last_modified", + "platform", + "push_id", + "push_revision", + "result", + "signature", + "state", + "tier", + "task_id", + "retry_id", + "duration", + "platform_option" + ] +} \ No newline at end of file diff --git a/app/src/androidTest/assets/profile-pushes-for-npoon.json b/app/src/androidTest/assets/profile-pushes-for-npoon.json new file mode 100644 index 0000000..9415f67 --- /dev/null +++ b/app/src/androidTest/assets/profile-pushes-for-npoon.json @@ -0,0 +1,61 @@ +{ + "meta": { + "count": 10, + "repository": "try", + "filter_params": { + "full": "true", + "count": "10", + "author": "npoon@mozilla.com" + } + }, + "results": [ + { + "id": 1712468, + "revision": "bab9725e928ab3de804281a6d6eeb467a5709920", + "author": "npoon@mozilla.com", + "revisions": [ + { + "result_set_id": 1712468, + "repository_id": 4, + "revision": "bab9725e928ab3de804281a6d6eeb467a5709920", + "author": "Nicholas Poon ", + "comments": "Fuzzy query='build-components&query='test-components&query='build-apk-fenix-debug&query='signing-apk-fenix-debug&query='build-apk-fenix-android-test-debug&query='signing-apk-fenix-android-test-debug&query='test-apk-fenix-debug&query='ui-test-apk-fenix-arm-debug&query='build-apk-focus-debug&query='signing-apk-focus-debug&query='build-apk-focus-android-test-debug&query='signing-apk-focus-android-test-debug&query='test-apk-focus-debug&query='ui-test-apk-focus-arm-debug&query=^source-test 'android | 'fenix | 'focus&query='generate-baseline-profile-firebase-fenix\n\nmach try command: `./mach try --preset firefox-android`\n\nPushed via `mach try fuzzy`" + }, + { + "result_set_id": 1712468, + "repository_id": 4, + "revision": "548e16edbdad1b992a03a6113d2f37f9a3ea23ef", + "author": "Nicholas Poon ", + "comments": "Bug 1985035 - Update tests that use `PingType.testBeforeNextSubmit` to ensure that the callback is running\n\nI also manually added failing assertions to the callbacks to ensure that the test would fail in this case\n\nDifferential Revision: https://phabricator.services.mozilla.com/D262585" + } + ], + "revision_count": 2, + "push_timestamp": 1756302348, + "repository_id": 4 + }, + { + "id": 1711578, + "revision": "47e31ea0adff5b3270d76c73aa66f3eafde85316", + "author": "npoon@mozilla.com", + "revisions": [ + { + "result_set_id": 1711578, + "repository_id": 4, + "revision": "47e31ea0adff5b3270d76c73aa66f3eafde85316", + "author": "Nicholas Poon ", + "comments": "Fuzzy query='build-components&query='test-components&query='build-apk-fenix-debug&query='signing-apk-fenix-debug&query='build-apk-fenix-android-test-debug&query='signing-apk-fenix-android-test-debug&query='test-apk-fenix-debug&query='ui-test-apk-fenix-arm-debug&query='build-apk-focus-debug&query='signing-apk-focus-debug&query='build-apk-focus-android-test-debug&query='signing-apk-focus-android-test-debug&query='test-apk-focus-debug&query='ui-test-apk-focus-arm-debug&query=^source-test 'android | 'fenix | 'focus&query='generate-baseline-profile-firebase-fenix\n\nmach try command: `./mach try --preset firefox-android`\n\nPushed via `mach try fuzzy`" + }, + { + "result_set_id": 1711578, + "repository_id": 4, + "revision": "4dd18bad252fc883504960b2efd1f3f6441854bd", + "author": "Nicholas Poon ", + "comments": "Bug 1984474 - Fix AbstractFetchDownloadServiceTest.WHEN clearAllDownloadsNotificationsAndJobs is called THEN all non-completed downloads are cancelled to test the correct behaviour\n\nDifferential Revision: https://phabricator.services.mozilla.com/D262424" + } + ], + "revision_count": 2, + "push_timestamp": 1756227150, + "repository_id": 4 + } + ] +} \ No newline at end of file diff --git a/app/src/androidTest/java/org/mozilla/tryfox/MainActivityDeeplinkTest.kt b/app/src/androidTest/java/org/mozilla/tryfox/MainActivityDeeplinkTest.kt index c0d2dc6..382a0d9 100644 --- a/app/src/androidTest/java/org/mozilla/tryfox/MainActivityDeeplinkTest.kt +++ b/app/src/androidTest/java/org/mozilla/tryfox/MainActivityDeeplinkTest.kt @@ -98,4 +98,40 @@ class MainActivityDeeplinkTest { composeTestRule.onNodeWithText(email).assertExists() } } + + @Test + fun testTryfoxScheme_withRevision_populatesRevision() { + val project = "mozilla-central" + val revision = "1234abcdef" + val deeplinkUri = + Uri.parse("tryfox://jobs?repo=$project&revision=$revision") + val intent = + Intent(ApplicationProvider.getApplicationContext(), MainActivity::class.java).apply { + action = Intent.ACTION_VIEW + data = deeplinkUri + } + + ActivityScenario.launch(intent).use { + composeTestRule.waitForIdle() + composeTestRule.onNodeWithText(revision).assertExists() + } + } + + @Test + fun testTryfoxScheme_withAuthorEmail_populatesProfileScreen() { + val email = "tthibaud@mozilla.com" + val encodedEmail = "tthibaud%40mozilla.com" + val deeplinkUri = + Uri.parse("tryfox://jobs?author=$encodedEmail") + val intent = + Intent(ApplicationProvider.getApplicationContext(), MainActivity::class.java).apply { + action = Intent.ACTION_VIEW + data = deeplinkUri + } + + ActivityScenario.launch(intent).use { + composeTestRule.waitForIdle() + composeTestRule.onNodeWithText(email).assertExists() + } + } } diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index fecc0a3..bb0db51 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -44,6 +44,15 @@ + + + + + + + - \ No newline at end of file + diff --git a/app/src/main/assets/kotzilla.key b/app/src/main/assets/kotzilla.key new file mode 100644 index 0000000..7e938ba --- /dev/null +++ b/app/src/main/assets/kotzilla.key @@ -0,0 +1 @@ +Omt0ei1zZGsteG1JNVFMckd6RkJvd0NuR3QwLWJ5VUZsUm83clhVZFVmcGFsODhfMndPbw== \ No newline at end of file diff --git a/app/src/main/java/org/mozilla/tryfox/AppDeepLinkParser.kt b/app/src/main/java/org/mozilla/tryfox/AppDeepLinkParser.kt new file mode 100644 index 0000000..dc24b78 --- /dev/null +++ b/app/src/main/java/org/mozilla/tryfox/AppDeepLinkParser.kt @@ -0,0 +1,125 @@ +package org.mozilla.tryfox + +import android.net.Uri +import java.net.URI +import java.net.URLDecoder +import java.nio.charset.StandardCharsets + +sealed interface AppDeepLinkDestination { + data class TreeherderSearch( + val project: String, + val revision: String, + ) : AppDeepLinkDestination + + data class Profile( + val email: String, + ) : AppDeepLinkDestination +} + +object AppDeepLinkParser { + private const val TREEHERDER_HOST = "treeherder.mozilla.org" + private const val TRYFOX_SCHEME = "tryfox" + private const val JOBS_TARGET = "jobs" + private const val DEFAULT_PROJECT = "try" + + fun parse(uri: Uri?): AppDeepLinkDestination? = parse(uri?.toString()) + + fun parse(uriString: String?): AppDeepLinkDestination? { + if (uriString.isNullOrBlank()) return null + val uri = runCatching { URI(uriString) }.getOrNull() ?: return null + + return when (uri.scheme?.lowercase()) { + "https" -> parseTreeherderUri(uri) + TRYFOX_SCHEME -> parseTryFoxUri(uri) + else -> null + } + } + + private fun parseTreeherderUri(uri: URI): AppDeepLinkDestination? { + if (uri.host?.lowercase() != TREEHERDER_HOST) return null + + val target = parseTarget(uri) + if (target != JOBS_TARGET) return null + + return destinationFromParameters(parseParameters(uri)) + } + + private fun parseTryFoxUri(uri: URI): AppDeepLinkDestination? { + val target = parseTarget(uri) + if (target != JOBS_TARGET) return null + + return destinationFromParameters(parseParameters(uri)) + } + + private fun destinationFromParameters(parameters: Map): AppDeepLinkDestination? { + val revision = parameters["revision"]?.takeIf { it.isNotBlank() } + if (revision != null) { + val project = parameters["repo"]?.takeIf { it.isNotBlank() } ?: DEFAULT_PROJECT + return AppDeepLinkDestination.TreeherderSearch( + project = project, + revision = revision, + ) + } + + val author = parameters["author"]?.takeIf { it.isNotBlank() } + if (author != null) { + return AppDeepLinkDestination.Profile(email = author) + } + + return null + } + + private fun parseTarget(uri: URI): String? { + val fragmentTarget = parseTargetFromFragment(uri.fragment) + if (fragmentTarget != null) { + return fragmentTarget + } + + uri.host?.takeIf { it.equals(JOBS_TARGET, ignoreCase = true) }?.let { + return JOBS_TARGET + } + + val pathSegments = uri.path?.trim('/')?.split('/')?.filter { it.isNotBlank() }.orEmpty() + return when { + uri.host.equals("treeherder", ignoreCase = true) -> pathSegments.firstOrNull() + else -> pathSegments.firstOrNull() + }?.lowercase() + } + + private fun parseParameters(uri: URI): Map { + val directQuery = uri.rawQuery + if (!directQuery.isNullOrBlank()) { + return parseQueryString(directQuery) + } + + return parseParametersFromFragment(uri.fragment) + } + + private fun parseParametersFromFragment(fragment: String?): Map { + if (fragment.isNullOrBlank() || !fragment.contains("?")) return emptyMap() + val query = fragment.substringAfter('?', "") + return parseQueryString(query) + } + + private fun parseTargetFromFragment(fragment: String?): String? { + if (fragment.isNullOrBlank()) return null + val path = fragment.substringBefore('?').trim('/') + if (path.isBlank()) return null + return path.substringAfterLast('/').lowercase() + } + + private fun parseQueryString(query: String): Map { + if (query.isBlank()) return emptyMap() + + return query.split('&') + .mapNotNull { parameter -> + if (parameter.isBlank()) return@mapNotNull null + val key = decode(parameter.substringBefore('=')) + val value = decode(parameter.substringAfter('=', "")) + key.takeIf { it.isNotBlank() }?.let { it to value } + } + .toMap() + } + + private fun decode(value: String): String = URLDecoder.decode(value, StandardCharsets.UTF_8) +} diff --git a/app/src/main/java/org/mozilla/tryfox/MainActivity.kt b/app/src/main/java/org/mozilla/tryfox/MainActivity.kt index e97bef2..5f2e446 100644 --- a/app/src/main/java/org/mozilla/tryfox/MainActivity.kt +++ b/app/src/main/java/org/mozilla/tryfox/MainActivity.kt @@ -1,26 +1,26 @@ package org.mozilla.tryfox import android.content.Intent +import android.net.Uri import android.os.Bundle import android.util.Log import androidx.activity.ComponentActivity import androidx.activity.compose.setContent import androidx.activity.enableEdgeToEdge import androidx.compose.runtime.Composable +import androidx.compose.runtime.LaunchedEffect import androidx.navigation.NavHostController import androidx.navigation.NavType import androidx.navigation.compose.NavHost import androidx.navigation.compose.composable import androidx.navigation.compose.rememberNavController import androidx.navigation.navArgument -import androidx.navigation.navDeepLink import org.koin.androidx.compose.koinViewModel import org.koin.core.parameter.parametersOf import org.mozilla.tryfox.ui.screens.HomeScreen import org.mozilla.tryfox.ui.screens.ProfileScreen import org.mozilla.tryfox.ui.screens.TryFoxMainScreen import org.mozilla.tryfox.ui.theme.TryFoxTheme -import java.net.URLDecoder /** * Sealed class representing the navigation screens in the application. @@ -58,7 +58,9 @@ sealed class NavScreen(val route: String) { /** * Represents the Profile screen filtered by email. */ - data object ProfileByEmail : NavScreen("profile_by_email?email={email}") + data object ProfileByEmail : NavScreen("profile_by_email?email={email}") { + fun createRoute(email: String) = "profile_by_email?email=${Uri.encode(email)}" + } } /** @@ -86,7 +88,7 @@ class MainActivity : ComponentActivity() { Log.d("MainActivity", "onNewIntent called. Intent: $intent, Data: ${intent.data}") setIntent(intent) if (::navController.isInitialized) { - navController.handleDeepLink(intent) + routeDeepLink(intent) } } @@ -100,6 +102,10 @@ class MainActivity : ComponentActivity() { this@MainActivity.navController = localNavController Log.d("MainActivity", "AppNavigation: NavController instance assigned: $localNavController") + LaunchedEffect(localNavController) { + routeDeepLink(intent) + } + NavHost(navController = localNavController, startDestination = NavScreen.Home.route) { composable(NavScreen.Home.route) { // Inject HomeViewModel using Koin in Composable @@ -122,16 +128,6 @@ class MainActivity : ComponentActivity() { navArgument("project") { type = NavType.StringType }, navArgument("revision") { type = NavType.StringType }, ), - deepLinks = listOf( - navDeepLink { - uriPattern = - "https://treeherder.mozilla.org/#/jobs?repo={project}&revision={revision}" - }, - navDeepLink { - uriPattern = - "https://treeherder.mozilla.org/jobs?repo={project}&revision={revision}" - }, - ), ) { backStackEntry -> val project = backStackEntry.arguments?.getString("project") val revision = backStackEntry.arguments?.getString("revision") @@ -153,11 +149,8 @@ class MainActivity : ComponentActivity() { composable( route = NavScreen.ProfileByEmail.route, arguments = listOf(navArgument("email") { type = NavType.StringType }), - deepLinks = listOf(navDeepLink { uriPattern = "https://treeherder.mozilla.org/jobs?repo={repo}&author={email}" }), ) { backStackEntry -> - val email = backStackEntry.arguments?.getString("email")?.let { - URLDecoder.decode(it, "UTF-8") - } + val email = backStackEntry.arguments?.getString("email")?.let(Uri::decode) ProfileScreen( onNavigateUp = { localNavController.popBackStack() }, @@ -166,4 +159,24 @@ class MainActivity : ComponentActivity() { } } } + + private fun routeDeepLink(intent: Intent?) { + val destination = AppDeepLinkParser.parse(intent?.data) ?: return + val route = when (destination) { + is AppDeepLinkDestination.TreeherderSearch -> { + NavScreen.TreeherderSearchWithArgs.createRoute( + project = destination.project, + revision = destination.revision, + ) + } + + is AppDeepLinkDestination.Profile -> { + NavScreen.ProfileByEmail.createRoute(destination.email) + } + } + + navController.navigate(route) { + launchSingleTop = true + } + } } diff --git a/app/src/test/java/org/mozilla/tryfox/AppDeepLinkParserTest.kt b/app/src/test/java/org/mozilla/tryfox/AppDeepLinkParserTest.kt new file mode 100644 index 0000000..f8fe574 --- /dev/null +++ b/app/src/test/java/org/mozilla/tryfox/AppDeepLinkParserTest.kt @@ -0,0 +1,89 @@ +package org.mozilla.tryfox + +import org.junit.jupiter.api.Assertions.assertEquals +import org.junit.jupiter.api.Assertions.assertNull +import org.junit.jupiter.api.Test + +class AppDeepLinkParserTest { + + @Test + fun `parses treeherder jobs link with revision`() { + val uri = "https://treeherder.mozilla.org/jobs?repo=try&revision=abcdef123456" + + val destination = AppDeepLinkParser.parse(uri) + + assertEquals( + AppDeepLinkDestination.TreeherderSearch( + project = "try", + revision = "abcdef123456", + ), + destination, + ) + } + + @Test + fun `parses treeherder hash link with revision`() { + val uri = "https://treeherder.mozilla.org/#/jobs?repo=mozilla-central&revision=abcdef123456" + + val destination = AppDeepLinkParser.parse(uri) + + assertEquals( + AppDeepLinkDestination.TreeherderSearch( + project = "mozilla-central", + revision = "abcdef123456", + ), + destination, + ) + } + + @Test + fun `parses tryfox jobs link with revision`() { + val uri = "tryfox://jobs?repo=mozilla-beta&revision=abcdef123456" + + val destination = AppDeepLinkParser.parse(uri) + + assertEquals( + AppDeepLinkDestination.TreeherderSearch( + project = "mozilla-beta", + revision = "abcdef123456", + ), + destination, + ) + } + + @Test + fun `parses tryfox jobs link with author`() { + val uri = "tryfox://jobs?author=tthibaud%40mozilla.com" + + val destination = AppDeepLinkParser.parse(uri) + + assertEquals( + AppDeepLinkDestination.Profile(email = "tthibaud@mozilla.com"), + destination, + ) + } + + @Test + fun `defaults repo to try when missing`() { + val uri = "tryfox://jobs?revision=abcdef123456" + + val destination = AppDeepLinkParser.parse(uri) + + assertEquals( + AppDeepLinkDestination.TreeherderSearch( + project = "try", + revision = "abcdef123456", + ), + destination, + ) + } + + @Test + fun `ignores unsupported targets`() { + val uri = "tryfox://pushes?revision=abcdef123456" + + val destination = AppDeepLinkParser.parse(uri) + + assertNull(destination) + } +} diff --git a/metro.txt b/metro.txt new file mode 100644 index 0000000..0fc21ee --- /dev/null +++ b/metro.txt @@ -0,0 +1,669 @@ +# Aggregation (aka + +Author: Zac Sweers +Date: 2025-09-06T12:14:48.440Z +Source: zacsweers.github.io +URL: https://zacsweers.github.io/metro/0.6.4/aggregation.html +Date saved: 2025-09-06T12:14:48.440Z + +> A multiplatform dependency injection framework for Kotlin + +--- + +Metro supports Anvil-style aggregation in graphs via `@ContributesTo` and `@ContributesBinding` annotations. As aggregation is a first-class citizen of Metro’s API, there is no `@MergeComponent` annotation like in Anvil. Instead, `@DependencyGraph` defines which contribution scope it supports directly. + +``` +@DependencyGraph(scope=AppScope::class)interfaceAppGraph +``` + +When a graph declares a `scope`, all contributions to that scope are aggregated into the final graph implementation in code gen. + +If a graph supports multiple scopes, use `additionalScopes`. + +``` +@DependencyGraph(AppScope::class,additionalScopes=[LoggedOutScope::class])interfaceAppGraph +``` + +Similar to [kotlin-inject-anvil](https://github.com/amzn/kotlin-inject-anvil), `@DependencyGraph` supports excluding contributions by class. This is useful for cases like tests, where you may want to contribute a test/fake implementation that supersedes the “real” graph. + +``` +@DependencyGraph(scope=AppScope::class,excludes=[RealNetworkProviders::class])interfaceTestAppGraph@ContributesTo(AppScope::class)interfaceTestNetworkProviders{@ProvidesfunprovideHttpClient():TestHttpClient} +``` + +## @ContributesTo[¶](#contributesto "Permanent link") + +This annotation is used to contribute graph interfaces to the target scope to be merged in at graph-processing time to the final merged graph class as another supertype. + +``` +@ContributesTo(AppScope::class)interfaceNetworkProviders{@ProvidesfunprovideHttpClient():HttpClient} +``` + +This annotation is _repeatable_ and can be used to contribute to multiple scopes. + +``` +@ContributesTo(AppScope::class)@ContributesTo(LoggedInScope::class)interfaceNetworkProviders{@ProvidesfunprovideHttpClient():HttpClient} +``` + +Similar to [kotlin-inject-anvil](https://github.com/amzn/kotlin-inject-anvil), `@ContributesBinding` (as well as the other `@Contributes*` annotations) supports replacing other contributions by class. This is useful for cases like tests, where you may want to contribute a test/fake implementation that supersedes the “real” graph. + +``` +@DependencyGraph(AppScope::class)interfaceTestAppGraph@ContributesTo(AppScope::class,replaces=[RealNetworkProviders::class])interfaceTestNetworkProviders{@ProvidesfunprovideHttpClient():TestHttpClient} +``` + +## @ContributesBinding[¶](#contributesbinding "Permanent link") + +This annotation is used to contribute injected classes to a target scope as a given bound type. + +The below example will contribute the `CacheImpl` class as a `Cache` type to `AppScope`. + +``` +@ContributesBinding(AppScope::class)@InjectclassCacheImpl(...):Cache +``` + +For simple cases where there is a single supertype, that type is implicitly used as the bound type. If your bound type is qualified, for the implicit case you can put the qualifier on the class. + +``` +@Named("cache")@ContributesBinding(AppScope::class)@InjectclassCacheImpl(...):Cache +``` + +For classes with multiple supertypes or advanced cases where you want to bind an ancestor type, you can explicitly define this via `binding` parameter. + +``` +@Named("cache")@ContributesBinding(scope=AppScope::class,binding=binding())@InjectclassCacheImpl(...):Cache,AnotherType +``` + +Tip + +Whoa, is that a function call in an annotation argument? Nope! `binding` is just a decapitalized class in this case, intentionally designed for readability. It’s an adjective in this context and the functional syntax better conveys that. + +Note that the bound type is defined as the type argument to `@ContributesBinding`. This allows for the bound type to be generic and is validated in FIR. + +Qualifier annotations can also be specified on the `binding` type parameter and will take precedence over any qualifiers on the class itself. + +``` +@ContributesBinding(scope=AppScope::class,binding=binding<@Named("cache")Cache>())@InjectclassCacheImpl(...):Cache,AnotherType +``` + +This annotation is _repeatable_ and can be used to contribute to multiple scopes. + +``` +@ContributesBinding(scope=AppScope::class,binding=binding())@ContributesBinding(scope=AppScope::class,binding=binding())@InjectclassCacheImpl(...):Cache,AnotherType +``` + +Tip + +Contributions may be `object` classes. In this event, Metro will automatically provide the object instance in its binding. + +## @ContributesIntoSet/@ContributesIntoMap[¶](#contributesintosetcontributesintomap "Permanent link") + +To contribute into a multibinding, use the `@ContributesIntoSet` or `@ContributesIntoMap` annotations as needed. + +``` +@ContributesIntoSet(AppScope::class)@InjectclassCacheImpl(...):Cache +``` + +Same rules around qualifiers and `binding()` apply in this scenario + +To contribute into a Map multibinding, the map key annotation must be specified on the class or `binding` type argument. + +``` +// Will be contributed into a Map multibinding with @StringKey("Networking")@ContributesIntoMap(AppScope::class)@StringKey("Networking")@InjectclassCacheImpl(...):Cache// Or if using binding@ContributesIntoMap(scope=AppScope::class,binding=binding<@StringKey("Networking")Cache>())@InjectclassCacheImpl(...):Cache +``` + +This annotation is also repeatable and can be used to contribute to multiple scopes, multiple bound types, and multiple map keys. + +You can use `@IntoMap`/`@IntoSet` to provide into the same container: + +``` +// Method 1: applying @ContributesIntoMap to bind directly from the implementation class@ContributesIntoMap(AppScope::class)@StringKey("remote")@InjectclassRemoteCache(...):Cache// Method 2: Declare the class, then provide @IntoMap binding separately via a BindingContainerclassLocalCache(...):Cache@BindingContainer@ContributesTo(AppScope::class)objectCacheBindingContainer{@Provides@IntoMap@StringKey("local")funcache():Cache=LocalCache(...)}// Accessing the resultant map, containing both implementations:@InjectclassCompositeCache(privatevalcaches:Map){vallocal:Cache=caches["local"]valremote:Cache=caches["remote"]}// Alternatively, specify Provider in the map type to lazily-initialize the implementations@InjectclassCompositeCacheAlternate(privatevalcaches:Map>){vallocal:Cache=caches["local"]()valremote:Provider=caches["remote"]funsomeTimeLater(){remote().doSomethingWithCache()}} +``` + +## Contributing Binding Containers[¶](#contributing-binding-containers "Permanent link") + +Binding containers (see [Binding Containers](dependency-graphs.html#binding-containers)) can also be contributed to scopes via `@ContributesTo`: + +``` +@ContributesTo(AppScope::class)@BindingContainerobjectNetworkBindings{@ProvidesfunprovideHttpClient():HttpClient=HttpClient()}@DependencyGraph(AppScope::class)interfaceAppGraph{valhttpClient:HttpClient} +``` + +### Replacing Contributed Binding Containers[¶](#replacing-contributed-binding-containers "Permanent link") + +Similar to other contribution types, binding containers can replace other contributed binding containers: + +``` +// In production@ContributesTo(AppScope::class)@BindingContainerobjectNetworkBindings{@ProvidesfunprovideHttpClient():HttpClient=HttpClient()}// In tests@ContributesTo(AppScope::class,replaces=[NetworkBindings::class])@BindingContainerobjectFakeNetworkBindings{@ProvidesfunprovideFakeHttpClient():HttpClient=FakeHttpClient()} +``` + +### Replacing Contributed Bindings[¶](#replacing-contributed-bindings "Permanent link") + +Binding containers can replace other contributed bindings, too: + +``` +// In production@ContributesBinding(AppScope::class)@InjectclassHttpClientImpl:HttpClient// In tests@ContributesTo(AppScope::class,replaces=[HttpClientImpl::class])@BindingContainerobjectFakeNetworkBindings{@ProvidesfunprovideFakeHttpClient():HttpClient=FakeHttpClient()} +``` + +### Excluding Contributed Binding Containers[¶](#excluding-contributed-binding-containers "Permanent link") + +Graphs can exclude specific contributed binding containers: + +``` +@ContributesTo(AppScope::class)@BindingContainerobjectNetworkBindings{@ProvidesfunprovideHttpClient():HttpClient=HttpClient()}@DependencyGraph(AppScope::class,excludes=[NetworkBindings::class])interfaceTestAppGraph{// NetworkBindings will not be included} +``` + +## Implementation notes[¶](#implementation-notes "Permanent link") + +This leans on Kotlin’s ability to put generic type parameters on annotations. That in turn allows for both generic bound types and to contribute map bindings to multiple map keys. + +Because it’s a first-party feature, there’s no need for intermediary “merged” components like kotlin-inject-anvil and anvil-ksp do. + +Generated contributing interfaces are generated to the `metro.hints` package and located during graph supertype generation in FIR downstream. Any contributed bindings are implemented as `@Binds` (± IntoSet/IntoMap/etc) annotated properties.# Bindings - Metro + +Author: Zac Sweers +Date: 2025-09-06T12:14:41.575Z +Source: zacsweers.github.io +URL: https://zacsweers.github.io/metro/0.6.4/bindings.html +Date saved: 2025-09-06T12:14:41.575Z + +> A multiplatform dependency injection framework for Kotlin + +--- + +## Qualifiers[¶](#qualifiers "Permanent link") + +Like Dagger and KI, Metro supports _qualifier annotations_ to allow disambiguation of types. These are applied at injection and provision sites. A qualifier annotation is any annotation annotated with `@Qualifier`. For convenience, there is an included `@Named` qualifier available in Metro’s runtime that can be used too. + +A “type key” in Metro is composed of a concrete type and (if any) qualifier annotation attached to it. + +``` +@DependencyGraphinterfaceAppGraph{valint:Int@Named("named")valnamedInt:Int@ProvidesfunprovideInt():Int=3@Provides@Named("named")funprovideNamedInt():Int=4} +``` + +## @Binds[¶](#binds "Permanent link") + +In many cases, a developer may have an implementation type on the graph that they want to expose as just its supertype. + +Like Dagger, Metro supports this with `@Binds`. + +For these cases, an abstract provider can be specified with the following conditions. + +* It must be abstract +* It must define one extension receiver that is a subtype of its provided type + +``` +@DependencyGraphinterfaceAppGraph{valmessage:Message// Bind MessageImpl as Message@BindsvalMessageImpl.bind:Message@ProvidesfunprovideText():String="Hello, world!"}@InjectclassMessageImpl(valtext:String):Message +``` + +If you want to limit access to these from your API, you can make these declarations `private` and just return `this`. Note it’s still important to annotate them with `@Binds` so that the Metro compiler understands its intent! Otherwise, it’s an error to _implement_ these declarations. + +`@Binds` declarations can also declare multibinding annotations. + +``` +@DependencyGraphinterfaceAppGraph{valmessages:Message@Binds@IntoSetvalMessageImpl.bind:Message} +``` + +`@Binds` declarations may also be declared in [binding Containers](dependency-graphs.html#binding-containers). + +Note + +In theory, you can implement a provider with a getter that replicates this (similar to how kotlin-inject uses `@get:Provider` + `this`), but this will be an error in FIR because Metro can generate more efficient code at compile-time if you use `@Binds`. This is because Metro can avoid calling the function entirely and just use this information at compile-time to optimize the generated code. + +## Multibindings[¶](#multibindings "Permanent link") + +Like Dagger and KI, Metro supports `Set` and `Map` multibindings. Multibindings are collections of bindings of a common type. Multibindings are implicitly declared by the existence of providers annotated with `@IntoSet`, `@IntoMap`, or `@ElementsIntoSet`. + +``` +@DependencyGraphinterfaceSetMultibinding{// contains a set of [1, 2, 3, 4]valints:Set@Provides@IntoSetfunprovideInt1()=1@Provides@IntoSetfunprovideInt2()=2@Provides@ElementsIntoSetfunprovideInts()=setOf(3,4)} +``` + +Map multibindings use `@IntoMap` and require a _map key_ annotation. Map keys are any annotation annotated with `@MapKey`. Metro’s runtime includes a number of common ones like `@ClassKey` and `@StringKey`. + +``` +@DependencyGraphinterfaceMapMultibinding{// contains a map of {1:1, 2:2}valints:Map@Provides@IntoMap@IntKey(1)funprovideInt1()=1@Provides@IntoMap@IntKey(2)funprovideInt2()=2} +``` + +Alternatively, they can be declared with an `@Multibinds`\-annotated accessor property/function in a component. This member will be implemented by the Metro compiler and is useful for scenarios where the multibinding may be empty. + +``` +@DependencyGraphinterfaceMapMultibinding{@Multibinds(allowEmpty=true)valints:Map} +``` + +Multibinding collections are immutable at runtime and cannot be defined as mutable at request sites. + +Map multibindings support injecting _map providers_, where the value type can be wrapped in `Provider`. + +``` +@DependencyGraphinterfaceMapMultibinding{@Multibinds(allowEmpty=true)valints:Map>} +``` + +Unlike Dagger, empty multibindings in Metro are a compile error by default. Empty multibindings are allowed but must be opted into via `@Multibinds(allowEmpty = true)`. + +#### Implementation notes[¶](#implementation-notes "Permanent link") + +Metro takes inspiration from Guice in handling these in the binding graph. Since they cannot be added directly to the graph as-is (otherwise they would cause duplicate binding errors), a synthetic `@MultibindingElement`_qualifier_ annotation is generated for them at compile-time to disambiguate them. These are user-invisible but allows them to participate directly in graph validation like any other dependency. Metro then just adds these bindings as dependencies to `Binding.Multibinding` types. + +## Optional Dependencies[¶](#optional-dependencies "Permanent link") + +Metro supports optional dependencies by leaning on Kotlin’s native support for default parameter values. These are checked at injection sites and are allowed to be missing from the dependency graph when performing a lookup at validation/code-gen time. + +The below example would, since there is no `Int` binding provided, provide a message of `Count: -1`. + +``` +@DependencyGraphinterfaceAppGraph{valmessage:String@ProvidesfunprovideMessage(count:Int=-1)="Count: $count"} +``` + +Dagger supports a similar feature via `@BindsOptionalOf`, but requires a separate declaration of this optional dependency to the graph. + +KI supports the same feature. + +## Nullability[¶](#nullability "Permanent link") + +As nullability is a first-class concept in Kotlin, Metro supports it too. Bindings in Metro graphs may be nullable, but it’s important to understand how Metro treats them! + +In short, Metro will treat nullable types as different type keys than their non-nullable analogues. That is to say, `String` and `String?` are treated as distinct types in Metro. + +Furthermore, a `String` binding cannot satisfy a `String?` automatically. You _may_ however `@Binds` a `String` to a `String?` and Metro will treat it as a valid binding. + +``` +@DependencyGraph(Unit::class)interfaceExampleGraph{valint:IntvalnullableInt:Int?@ProvidesfunprovideInt():Int=1@BindsvalInt.bindAsNullable:Int?} +``` + +#### Implementation notes[¶](#implementation-notes_1 "Permanent link") + +While kotlin-inject can support this by simply invoking functions with omitted arguments, Metro has to support this in generated factories. + +To accomplish this, Metro will slightly modify how generated provider/constructor injection factory classes look compared to Dagger. Since we are working in IR, we can copy the default value expressions from the source function/constructor to the factory’s newInstance and create() functions. This in turn allows calling generated graphs to simply omit absent binding arguments from their creation calls. This is a tried and tested pattern used by other first party plugins, namely kotlinx-serialization. + +There are a few cases that need to be handled here: + +* Expressions may reference previous parameters or instance members. To support this, we’ll transform them in IR to point at new parameters in those functions. +* Expressions may reference private instance members. To support this, Metro factories are generated as nested classes within the source class or graph. + * This does depart from how dagger factories work, but if we ever wanted to have some sort of interop for that we could always generate bridging factory classes in the places dagger expects later. +* Parameters in `create()` need to be wrapped in `Provider` calls. This means that for cases where they back-reference other parameters, those will need to be transformed into `invoke()` calls on those providers too.# Injection Types - Metro + +Author: Zac Sweers +Date: 2025-09-06T12:14:27.204Z +Source: zacsweers.github.io +URL: https://zacsweers.github.io/metro/0.6.4/injection-types.html +Date saved: 2025-09-06T12:14:27.204Z + +> A multiplatform dependency injection framework for Kotlin + +--- + +Metro supports multiple common injection types. + +## Constructor Injection[¶](#constructor-injection "Permanent link") + +Most types should use constructor injection if possible. For this case, you can annotate either a class itself (if it has exactly one, primary constructor) or exactly one specific constructor. + +``` +@InjectclassClassInjectedclassSpecificConstructorInjection(valtext:String){@Injectconstructor(value:Int):this(value.toString())} +``` + +Constructor-injected classes can be instantiated+managed entirely by Metro and encourages immutability. + +## Assisted Injection[¶](#assisted-injection "Permanent link") + +For types that require dynamic dependencies at instantiation, assisted injection can be used to supply these inputs. In this case - an injected constructor (or class with one constructor) must be annotated with `@Inject`, assisted parameters annotated with `@Assisted`, and a factory interface or abstract class with one single abstract function that accepts these assisted parameters and returns the target class. + +``` +@InjectclassHttpClient(@Assistedvaltimeout:Duration,valcache:Cache){@AssistedFactoryfuninterfaceFactory{funcreate(timeout:Duration):HttpClient}} +``` + +Then, the `@AssistedFactory`\-annotated type can be accessed from the dependency graph. + +``` +@InjectclassApiClient(httpClientFactory:HttpClient.Factory){privatevalhttpClient=httpClientFactory.create(30.seconds)} +``` + +Like Dagger, the `@Assisted` parameters can take optional `value` keys to disambiguate matching types. + +``` +@InjectclassHttpClient(@Assisted("connect")valconnectTimeout:Duration,@Assisted("request")valrequestTimeout:Duration,valcache:Cache){@AssistedFactoryfuninterfaceFactory{funcreate(@Assisted("connect")connectTimeout:Duration,@Assisted("request")requestTimeout:Duration,):HttpClient}} +``` + +### Automatic Assisted Factory Generation[¶](#automatic-assisted-factory-generation "Permanent link") + +Metro supports automatic generation of assisted factories via opt-in compiler option. If enabled, Metro will automatically generate a default factory as a nested class within the injected type. + +``` +@InjectclassHttpClient(@AssistedtimeoutDuration:Duration,cache:Cache,){// Generated by Metro@AssistedFactoryfuninterfaceFactory{funcreate(timeoutDuration:Duration):HttpClient}} +``` + +If a nested class called `Factory` is already present, Metro will do nothing. + +### Why opt-in?[¶](#why-opt-in "Permanent link") + +The main reason this is behind an opt-in option at the moment is because compiler plugin IDE support is rudimentary at best and currently requires enabling a custom registry flag. See [the docs for how to enable IDE support](installation.html#ide-support). + +Because of this, it’s likely better for now to just hand-write the equivalent class that Metro generates. If you still wish to proceed with using this, it can be enabled via the Gradle DSL. + +``` +metro { generateAssistedFactories.set(true) } +``` + +## Member Injection[¶](#member-injection "Permanent link") + +Metro supports _member injection_ to inject mutable properties or functions post-construction or into existing class instances. + +This can be useful for classes that cannot be constructor-injected, for example Android Activity classes (on older SDK versions) as well as constructor-injected classes that perhaps don’t want or need to expose certain types directly in their constructors. + +Tip + +Unlike Dagger and kotlin-inject, injected members in Metro can be `private`. + +Note + +Member function injection does not (currently) support default values. + +``` +classProfileActivity:Activity(){// Property injection@Injectprivatelateinitvardb:UserDatabase@Injectprivatevarnotifications:Notifications? =null// Function injection@InjectprivatefuninjectUser(user:User){// ...}} +``` + +Like Dagger, these classes can be injected via multiple avenues. + +### 1\. In constructor-injected types, `@Inject`\-annotated members are injected _automatically_.[¶](#1-in-constructor-injected-types-inject-annotated-members-are-injected-automatically "Permanent link") + +``` +// Injection with constructor injection@InjectclassProfileInjector(// ...){// Automatically injected during constructor injection@InjectprivatefuninjectUser(value:String){// ...}} +``` + +In these cases, Metro will automatically inject these members automatically and immediately after instantiation during constructor injection. + +### 2\. Exposing a `fun inject(target: ProfileActivity)` function on the graph[¶](#2-exposing-a-fun-injecttarget-profileactivity-function-on-the-graph "Permanent link") + +``` +// Graph inject() functions@DependencyGraphinterfaceAppGraph{// ...funinject(target:ProfileActivity)}// Somewhere elsevalgraph=createGraph()graph.inject(profileActivity) +``` + +With this option, you can call `graph.inject(target)` on the instance with members you wish to inject. + +### 3\. Requesting a `MembersInjector` instance from the dependency graph.[¶](#3-requesting-a-membersinjector-instance-from-the-dependency-graph "Permanent link") + +``` +// Injection with MembersInjector@InjectclassProfileInjector(privatevalinjector:MembersInjector){funperformInjection(activity:ProfileActivity){injector.inject(activity)}} +``` + +Like Dagger, option #3 is accomplished via `MembersInjector` interface at runtime and in code gen. This should be reserved for advanced use cases. + +### Implementation notes[¶](#implementation-notes "Permanent link") + +* Property accessors don’t use `get`/`set` names in `inject{name}()` function names. +* MembersInjector classes are generated as nested classes, allowing private member access. + * This includes parent classes’ private members (!!) +* Optional bindings are not supported for injected member functions currently, but may be possible in the future. + +## Top-level Function Injection[¶](#top-level-function-injection "Permanent link") + +Like KI, Metro supports top-level function injection (behind an opt-in compiler option). The primary use case for this is composable functions and standalone applications that run from `main` functions. + +``` +@InjectfunApp(message:String){// ...} +``` + +To do this, Metro’s FIR plugin will generate a concrete type that acts as a bridge for this function. + +``` +@InjectclassAppClass(privatevalmessage:Provider){operatorfuninvoke(){App(message())}} +``` + +Because it’s generated in FIR, this type will be user-visible in the IDE and can then be referenced in a graph. + +_Note that this feature requires enabling third party FIR plugins in the IDE to fully work. It will compile without it, but generated wrapper classes will be red/missing in the IDE._ + +Note + +The generated class is called `` + `Class` because of a limitation in the Kotlin compiler. TODO Link issue? + +``` +@DependencyGraphinterfaceAppGraph{valapp:AppClass@DependencyGraph.FactoryfuninterfaceFactory{funcreate(@Providesmessage:String):AppGraph}}// Usagevalapp=createGraphFactory().create("Hello, world!").app// Run the appapp() +``` + +To add assisted parameters, use `@Assisted` on the parameters in the function description. These will be propagated accordingly. + +``` +@InjectfunApp(@Assistedmessage:String){// ...}// Generates...@InjectclassAppClass{operatorfuninvoke(message:String){App(message)}}// Usagevalapp=createGraph().app// Run the appapp("Hello, world!") +``` + +This is particularly useful for Compose, and `@Composable` functions will be copied over accordingly. + +``` +@Inject@ComposablefunApp(@Assistedmessage:String){// ...}// Generates...@InjectclassAppClass{@Composableoperatorfuninvoke(message:String){App(message)}}// UsagevalApp=createGraph().app// Call it in compositionsetContent{App("Hello, world!")} +``` + +Similarly, if the injected function is a `suspend` function, the `suspend` keyword will be ported to the generated `invoke()` function too. + +### Why opt-in?[¶](#why-opt-in_1 "Permanent link") + +There are two reasons this is behind an opt-in option at the moment. + +1. Generating top-level declarations in Kotlin compiler plugins (in FIR specifically) is not currently compatible with incremental compilation. +2. IDE support is rudimentary at best and currently requires enabling a custom registry flag. See [the docs for how to enable IDE support](installation.html#ide-support). + +Because of this, it’s likely better for now to just hand-write the equivalent class that Metro generates. If you still wish to proceed with using this, it can be enabled via the Gradle DSL. + +``` +metro{enableTopLevelFunctionInjection.set(true)} +``` + +### Implementation notes[¶](#implementation-notes_1 "Permanent link") + +* This is fairly different from kotlin-inject’s typealias approach. This is necessary because Metro doesn’t use higher order function types or typealiases as qualifiers. +* Since the compose-compiler’s IR transformer may run _before_ Metro’s, we check for this during implementation body generation and look up the transformed target composable function as needed.# Installation - Metro + +Author: Zac Sweers +Date: 2025-09-06T12:14:02.312Z +Source: zacsweers.github.io +URL: https://zacsweers.github.io/metro/0.6.4/installation.html +Date saved: 2025-09-06T12:14:02.312Z + +> A multiplatform dependency injection framework for Kotlin + +--- + +Metro is primarily applied via its companion Gradle plugin. + +``` +plugins{kotlin("multiplatform")// or jvm, android, etcid("dev.zacsweers.metro")} +``` + +…and that’s it! This will add metro’s runtime dependencies and do all the necessary compiler plugin wiring. + +If applying in other build systems, apply it however that build system conventionally applies Kotlin compiler plugins. For example with [Bazel](https://github.com/bazelbuild/rules_kotlin?tab=readme-ov-file#kotlin-compiler-plugins): + +``` +load("@rules_kotlin//kotlin:core.bzl","kt_compiler_plugin")load("@rules_kotlin//kotlin:jvm.bzl","kt_jvm_library")kt_compiler_plugin(name="metro_plugin",compile_phase=True,id="dev.zacsweers.metro.compiler",options={"enabled":"true","debug":"false",},deps=["@maven//:dev_zacsweers_metro_compiler",],)kt_jvm_library(name="sample",# The SampleGraph class is annotated with @DependencyGraphsrcs=["SampleGraph.kt"],plugins=[":metro_plugin",],deps=["@maven//:dev_zacsweers_metro_runtime_jvm",],) +``` + +## IDE Support[¶](#ide-support "Permanent link") + +The K2 Kotlin IntelliJ plugin supports running third party FIR plugins in the IDE, but this feature is hidden behind a flag. Some Metro features can take advantage of this, namely diagnostic reporting directly in the IDE and some opt-in features to see generated declarations. + +To enable it, do the following: + +1. Enable K2 Mode for the Kotlin IntelliJ plugin. +2. Open the Registry +3. Set the `kotlin.k2.only.bundled.compiler.plugins.enabled` entry to `false`. + +Note that support is unstable and subject to change.# Metro + +Author: Zac Sweers +Date: 2025-09-06T12:13:13.575Z +Source: zacsweers.github.io +URL: https://zacsweers.github.io/metro/0.6.4/index.html +Date saved: 2025-09-06T12:13:13.575Z + +> A multiplatform dependency injection framework for Kotlin + +--- + +## Introduction[¶](#introduction "Permanent link") + +Metro is a compile-time dependency injection framework that draws heavy inspiration from [Dagger](https://github.com/google/dagger), [Anvil](https://github.com/square/anvil), and [Kotlin-Inject](https://github.com/evant/kotlin-inject). It seeks to unify their best features under one, cohesive solution while adding a few new features and implemented as a compiler plugin. + +### Why another DI framework?[¶](#why-another-di-framework "Permanent link") + +It’s felt for some time like the Kotlin community has been waiting for a library at the intersection of these different tools and features. Different tools exist for parts of these, but there’s not yet been a unified solution that checks all these boxes, leaves behind some of these tools’ limitations, and embraces newer features that native compiler plugins offer. + +In short, Metro stands on the shoulders of giants. It doesn’t try to reinvent the wheel, it does try to make those wheels work better together. + +Note + +_I’m aware of the [XKCD comic](https://xkcd.com/927/) 🙂, I think Metro offers a compelling feature set with interop hooks that make it easy to integrate with an existing codebase._ + +## Installation[¶](#installation "Permanent link") + +Apply the gradle plugin. + +``` +plugins{id("dev.zacsweers.metro")version"x.y.z"} +``` + +And that’s it! The default configuration will add the multiplatform `runtime` artifact (which has annotations you can use) and wire it all automatically. + +You can configure custom behaviors with APIs on the `metro` DSL extension. + +``` +metro{// Defines whether or not metro is enabled. Useful if you want to gate this behind a dynamic// build configuration.enabled=true// Default// Enable (extremely) verbose debug loggingdebug=false// Default// See the kdoc on MetroPluginExtension for full details} +``` + +Snapshots of the development version are available in [Sonatype’s `snapshots` repository](https://central.sonatype.com/repository/maven-snapshots/). + +## Supported platforms[¶](#supported-platforms "Permanent link") + +The compiler plugin itself supports all multiplatform project types. The first-party annotations artifact is also multiplatform and supports all common JVM, JS, and native targets. + +Contribution hint generation is _not_ currently supported on native or Wasm targets until [KT-58886](https://youtrack.jetbrains.com/issue/KT-58886) is resolved. They do work within the same compilation though. + +## Caveats[¶](#caveats "Permanent link") + +* Kotlin compiler plugins are not a stable API! Compiled outputs from this plugin _should_ be stable, but usage in newer versions of kotlinc are not guaranteed to be stable. That said, Metro will strive to make matching releases available quickly and test against Kotlin prereleases eagerly. + +# Metro Intrinsics - Metro + +Author: Zac Sweers +Date: 2025-09-06T12:14:37.330Z +Source: zacsweers.github.io +URL: https://zacsweers.github.io/metro/0.6.4/metro-intrinsics.html +Date saved: 2025-09-06T12:14:37.330Z + +> A multiplatform dependency injection framework for Kotlin + +--- + +Like Dagger, Metro supports injection of bindings wrapped in intrinsic types. Namely - `Provider` and `Lazy`. These are useful for deferring creation/initialization of dependencies. These only need to be requested at the injection site, Metro’s code gen will generate all the necessary stitching to fulfill that request. + +## `Provider`[¶](#provider "Permanent link") + +`Provider` is like Dagger’s `Provider` — it is a simple interface who’s `invoke()` call returns a new instance every time. If the underlying binding is scoped, then the same (scoped) instance is returned every time `invoke()` is called. + +``` +@InjectclassHttpClient(valcacheProvider:Provider){funcreateCache(){valcache=cacheProvider()}} +``` + +## `Lazy`[¶](#lazy "Permanent link") + +`Lazy` is Kotlin’s standard library `Lazy`. It lazily computes a value the first time it’s evaluated and is thread-safe. + +``` +@InjectclassHttpClient(valcacheProvider:Lazy){funcreateCache(){// The value is computed once and cached aftervalcache=cacheProvider.value}} +``` + +Note that `Lazy` is different from _scoping_ in that it is confined to the scope of the _injected type_, rather than the component instance itself. There is functionally no difference between injecting a `Provider` or `Lazy` of a _scoped_ binding. A `Lazy` of a scoped binding can still be useful to defer initialization. The underlying implementation in Metro’s `DoubleCheck` prevents double memoization in this case. + +Why doesn’t `Provider` just use a property like `Lazy`? + +A property is appropriate for `Lazy` because it fits the definition of being a _computed_ value that is idempotent for repeat calls. Metro opts to make its `Provider` use an `invoke()` function because it does not abide by that contract. + +## Providers of Lazy[¶](#providers-of-lazy "Permanent link") + +Metro supports combining `Provider` and `Lazy` to inject `Provider>`. On unscoped bindings this means the provider will return a new deferrable computable value (i.e. a new Lazy). Meanwhile `Lazy>` is meaningless and not supported.# Provides - Metro + +Author: Zac Sweers +Date: 2025-09-06T12:14:23.508Z +Source: zacsweers.github.io +URL: https://zacsweers.github.io/metro/0.6.4/provides.html +Date saved: 2025-09-06T12:14:23.508Z + +> A multiplatform dependency injection framework for Kotlin + +--- + +Providers can be defined in graphs or supertypes that graphs extend. Defining them in supertypes allows for them to be reused across multiple graphs and organize providers into logic groups. This is similar to how modules in Dagger work. + +``` +interfaceNetworkProviders{@ProvidesfunprovideHttpClient():HttpClient=HttpClient()}@DependencyGraphinterfaceAppGraph:NetworkProviders +``` + +Provider _functions_ should be `private` by default and are _automatically_ transformed to be private by the Metro compiler. This means you can write a provider function with no explicit (or public) visibility and it will be made private by Metro at compile-time. + +Provider _properties_ cannot be private yet due to [KT-76257](https://youtrack.jetbrains.com/issue/KT-76257/), but may be supported in the future. + +Providers may also be declared in [binding Containers](dependency-graphs.html#binding-containers). + +Tip + +It’s recommended to _not_ call providers from each other. + +#### Overrides[¶](#overrides "Permanent link") + +It is an error to override providers declarations. While it can be enticing for testing reasons to try to replicate Dagger 1’s _module overrides_, it quickly becomes difficult to reason about in code gen. + +* What if you override with sub/supertypes? +* What if your override’s implementation needs different dependencies? + +To the testing end, it is recommended to instead leverage the `DependencyGraph.excludes` + `ContributesTo.replaces` APIs in merging. + +``` +// Don't do this pattern!interfaceNetworkProviders{@ProvidesfunprovideHttpClient():HttpClient=HttpClient()}@DependencyGraphinterfaceTestAppGraph:NetworkProviders{// This will fail to compileoverridefunprovideHttpClient():HttpClient=TestHttpClient()} +``` + +#### Companion Providers[¶](#companion-providers "Permanent link") + +Providers can alternatively be implemented in `companion object`s for staticization. + +``` +interfaceMessageGraph{valmessage:Stringcompanionobject{@ProvidesprivatefunprovideMessage():String="Hello, world!"}} +``` + +#### Implementation Notes[¶](#implementation-notes "Permanent link") + +private interface functions are not usually visible to downstream compilations in IR. To work around this, Metro will use a [new API in Kotlin 2.1.20](https://github.com/JetBrains/kotlin/blob/b2bceb12ef57664c4f9b168157c3a097a81a6e5f/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/extensions/IrGeneratedDeclarationsRegistrar.kt#L26) to add custom metadata to the parent class to denote these private providers’ existence and where to find them.# Scopes - Metro + +Author: Zac Sweers +Date: 2025-09-06T12:14:31.001Z +Source: zacsweers.github.io +URL: https://zacsweers.github.io/metro/0.6.4/scopes.html +Date saved: 2025-09-06T12:14:31.001Z + +> A multiplatform dependency injection framework for Kotlin + +--- + +Like Dagger and KI, Metro supports _scopes_ to limit instances of types on the dependency graph. A scope is any annotation annotated with `@Scope`, with a convenience `@SingleIn` scope available in Metro’s runtime. + +Scopes must be applied to either the injected class or the provider function providing that binding. They must also match the graph that they are used in. + +``` +@SingleIn(AppScope::class)@DependencyGraphabstractclassAppGraph{privatevarcounter=0abstractvalcount:Int@SingleIn(AppScope::class)@ProvidesfunprovideCount()=counter++} +``` + +In the above example, multiple calls to `AppGraph.count` will always return 0 because the returned value from `provideCount()` will be cached in the `AppGraph` instance the first time it’s called. + +It is an error for an unscoped graph to access scoped bindings. + +``` +@DependencyGraphinterfaceAppGraph{// This is an error!valexampleClass:ExampleClass}@SingleIn(AppScope::class)@InjectclassExampleClass +``` + +It is also an error for a scoped graph to access scoped bindings whose scope does not match. + +``` +@SingleIn(AppScope::class)@DependencyGraphinterfaceAppGraph{// This is an error!valexampleClass:ExampleClass}@SingleIn(UserScope::class)@InjectclassExampleClass +``` + +Like Dagger, graphs can have multiple scopes that they support. + +``` +@ScopeannotationclassSingleton@Singleton@SingleIn(AppScope::class)@DependencyGraphinterfaceAppGraph{// This is okvalexampleClass:ExampleClass}@SingleIn(AppScope::class)@InjectclassExampleClass +``` \ No newline at end of file diff --git a/tracebox b/tracebox new file mode 100755 index 0000000..2500d9d --- /dev/null +++ b/tracebox @@ -0,0 +1,286 @@ +#!/usr/bin/env python3 +# Copyright (C) 2021 The Android Open Source Project +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! +# DO NOT EDIT. Auto-generated by tools/gen_amalgamated_python_tools +# !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + +# This file should do the same thing when being invoked in any of these ways: +# ./tracebox +# python tracebox +# bash tracebox +# cat ./tracebox | bash +# cat ./tracebox | python - + +BASH_FALLBACK=""" " +exec python3 - "$@" <<'#'EOF +#""" # yapf: disable + + +# ----- Amalgamator: begin of python/perfetto/prebuilts/manifests/tracebox.py +# This file has been generated by: tools/roll-prebuilts v53.0 +TRACEBOX_MANIFEST = [{ + 'arch': + 'mac-amd64', + 'file_name': + 'tracebox', + 'file_size': + 1778968, + 'url': + 'https://commondatastorage.googleapis.com/perfetto-luci-artifacts/v53.0/mac-amd64/tracebox', + 'sha256': + '6d615049fead10da71d6bd1b077c201612e0f007d79553f556c65deb83dcec75', + 'platform': + 'darwin', + 'machine': ['x86_64'] +}, { + 'arch': + 'mac-arm64', + 'file_name': + 'tracebox', + 'file_size': + 1625400, + 'url': + 'https://commondatastorage.googleapis.com/perfetto-luci-artifacts/v53.0/mac-arm64/tracebox', + 'sha256': + '1232dbae5b37ff38c9f655b5c3ba62e1a16904c140b9964bc532306bbb95d65a', + 'platform': + 'darwin', + 'machine': ['arm64'] +}, { + 'arch': + 'linux-amd64', + 'file_name': + 'tracebox', + 'file_size': + 2569928, + 'url': + 'https://commondatastorage.googleapis.com/perfetto-luci-artifacts/v53.0/linux-amd64/tracebox', + 'sha256': + 'e043839849454df3b185e889fe627e05d73e38cb1ed0c573fae900365a66a8d3', + 'platform': + 'linux', + 'machine': ['x86_64'] +}, { + 'arch': + 'linux-arm', + 'file_name': + 'tracebox', + 'file_size': + 1574276, + 'url': + 'https://commondatastorage.googleapis.com/perfetto-luci-artifacts/v53.0/linux-arm/tracebox', + 'sha256': + 'f879bc806e2656cba56fa8e684b1e8bcb1ebd277d1f7929b266c3ff7ec5f491b', + 'platform': + 'linux', + 'machine': ['armv6l', 'armv7l', 'armv8l'] +}, { + 'arch': + 'linux-arm64', + 'file_name': + 'tracebox', + 'file_size': + 2445000, + 'url': + 'https://commondatastorage.googleapis.com/perfetto-luci-artifacts/v53.0/linux-arm64/tracebox', + 'sha256': + '09647e0bf0248775f98b8a5e82225fc3861cdd951a2512a727a4ac134a8e056c', + 'platform': + 'linux', + 'machine': ['aarch64'] +}, { + 'arch': + 'android-arm', + 'file_name': + 'tracebox', + 'file_size': + 1450300, + 'url': + 'https://commondatastorage.googleapis.com/perfetto-luci-artifacts/v53.0/android-arm/tracebox', + 'sha256': + '5daa7a406e0b15efb9cd373ee0476088df71f3b4f6e0637aefd3d2d8b648dc87' +}, { + 'arch': + 'android-arm64', + 'file_name': + 'tracebox', + 'file_size': + 2275792, + 'url': + 'https://commondatastorage.googleapis.com/perfetto-luci-artifacts/v53.0/android-arm64/tracebox', + 'sha256': + '30421bd191fc97863878757f85941a5fa2de84617b42a359da7d00818158ec69' +}, { + 'arch': + 'android-x86', + 'file_name': + 'tracebox', + 'file_size': + 2499780, + 'url': + 'https://commondatastorage.googleapis.com/perfetto-luci-artifacts/v53.0/android-x86/tracebox', + 'sha256': + '20e5e39a8921209cab4ab103ac5c3936480dea2d28d733a0fb2578a05296ca1f' +}, { + 'arch': + 'android-x64', + 'file_name': + 'tracebox', + 'file_size': + 2321104, + 'url': + 'https://commondatastorage.googleapis.com/perfetto-luci-artifacts/v53.0/android-x64/tracebox', + 'sha256': + '6b55d3b210726450a364b22190abfd8f2c3066d78d812161b4d12004bcb4d971' +}] + +# ----- Amalgamator: end of python/perfetto/prebuilts/manifests/tracebox.py + +# ----- Amalgamator: begin of python/perfetto/prebuilts/perfetto_prebuilts.py +# Copyright (C) 2021 The Android Open Source Project +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +""" +Functions to fetch pre-pinned Perfetto prebuilts. + +This function is used in different places: +- Into the //tools/{trace_processor, traceconv} scripts, which are just plain + wrappers around executables. +- Into the //tools/{heap_profiler, record_android_trace} scripts, which contain + some other hand-written python code. + +The manifest argument looks as follows: +TRACECONV_MANIFEST = [ + { + 'arch': 'mac-amd64', + 'file_name': 'traceconv', + 'file_size': 7087080, + 'url': https://commondatastorage.googleapis.com/.../trace_to_text', + 'sha256': 7d957c005b0dc130f5bd855d6cec27e060d38841b320d04840afc569f9087490', + 'platform': 'darwin', + 'machine': 'x86_64' + }, + ... +] + +The intended usage is: + + from perfetto.prebuilts.manifests.traceconv import TRACECONV_MANIFEST + bin_path = get_perfetto_prebuilt(TRACECONV_MANIFEST) + subprocess.call(bin_path, ...) +""" + +import hashlib +import os +import platform +import random +import subprocess +import sys + + +def download_or_get_cached(file_name, url, sha256): + """ Downloads a prebuilt or returns a cached version + + The first time this is invoked, it downloads the |url| and caches it into + ~/.local/share/perfetto/prebuilts/$tool_name. On subsequent invocations it + just runs the cached version. + """ + dir = os.path.join( + os.path.expanduser('~'), '.local', 'share', 'perfetto', 'prebuilts') + os.makedirs(dir, exist_ok=True) + bin_path = os.path.join(dir, file_name) + sha256_path = os.path.join(dir, file_name + '.sha256') + needs_download = True + + # Avoid recomputing the SHA-256 on each invocation. The SHA-256 of the last + # download is cached into file_name.sha256, just check if that matches. + if os.path.exists(bin_path) and os.path.exists(sha256_path): + with open(sha256_path, 'rb') as f: + digest = f.read().decode() + if digest == sha256: + needs_download = False + + if needs_download: # The file doesn't exist or the SHA256 doesn't match. + # Use a unique random file to guard against concurrent executions. + # See https://github.com/google/perfetto/issues/786 . + tmp_path = '%s.%d.tmp' % (bin_path, random.randint(0, 100000)) + print('Downloading ' + url) + subprocess.check_call(['curl', '-f', '-L', '-#', '-o', tmp_path, url]) + with open(tmp_path, 'rb') as fd: + actual_sha256 = hashlib.sha256(fd.read()).hexdigest() + if actual_sha256 != sha256: + raise Exception('Checksum mismatch for %s (actual: %s, expected: %s)' % + (url, actual_sha256, sha256)) + os.chmod(tmp_path, 0o755) + os.replace(tmp_path, bin_path) + with open(tmp_path, 'w') as f: + f.write(sha256) + os.replace(tmp_path, sha256_path) + return bin_path + + +def get_perfetto_prebuilt(manifest, soft_fail=False, arch=None): + """ Downloads the prebuilt, if necessary, and returns its path on disk. """ + plat = sys.platform.lower() + machine = platform.machine().lower() + manifest_entry = None + for entry in manifest: + # If the caller overrides the arch, just match that (for Android prebuilts). + if arch: + if entry.get('arch') == arch: + manifest_entry = entry + break + continue + # Otherwise guess the local machine arch. + if entry.get('platform') == plat and machine in entry.get('machine', []): + manifest_entry = entry + break + if manifest_entry is None: + if soft_fail: + return None + raise Exception( + ('No prebuilts available for %s-%s\n' % (plat, machine)) + + 'See https://perfetto.dev/docs/contributing/build-instructions') + + return download_or_get_cached( + file_name=manifest_entry['file_name'], + url=manifest_entry['url'], + sha256=manifest_entry['sha256']) + + +def run_perfetto_prebuilt(manifest): + bin_path = get_perfetto_prebuilt(manifest) + if sys.platform.lower() == 'win32': + sys.exit(subprocess.check_call([bin_path, *sys.argv[1:]])) + os.execv(bin_path, [bin_path] + sys.argv[1:]) + + +# ----- Amalgamator: end of python/perfetto/prebuilts/perfetto_prebuilts.py + +if __name__ == '__main__': + run_perfetto_prebuilt(TRACEBOX_MANIFEST) + +#EOF