diff --git a/changelog/index.html b/changelog/index.html index 7717a886e..b3a0a22af 100644 --- a/changelog/index.html +++ b/changelog/index.html @@ -378,6 +378,13 @@
2023-11-09
+8.3.0-alpha13
.2023-11-08
This repository contains the core Gradle plugin and associated logic used for Slack\u2019s Android app.
This repo is effectively read-only and does not publish artifacts to Maven Central. We develop these in the open to knowledge-share with the community.
As such, our issue tracker is closed and we don\u2019t normally accept external PRs, but we welcome your questions in the discussions section of the project!
We may later publish some of these components. If you\u2019re interested in this, feel free to raise in a discussions post or vote for existing suggestions.
"},{"location":"#highlights","title":"Highlights","text":""},{"location":"#common-project-configuration","title":"Common project configuration","text":"The slack.base
plugin offers common configuration for all projects implementing it, covering a wide spectrum of Android, Kotlin, and Java configurations.
This includes a whole host of things! - Common Android configuration (single variant libraries, disabling unused features, compose, etc). - Common Kotlin configuration (freeCompilerArgs, JVM target, etc). - Common Java configuration (toolchains, release versions, etc). - Common annotation processors. - SlackExtension (see next section). - Formatting (via Spotless). - Platforms and BOM dependencies (see \u201cPlatform plugins\u201d section below). - Common lint checks (both on Android and plain JVM projects).
Full docs can be found in the architecture docs.
"},{"location":"#feature-dsl","title":"Feature DSL","text":"To ease use and configuration of common features in projects, we expose a slack
DSL in projects that allows for configuration of these in a semantically easy and boilerplate-free way. This is controlled via SlackExtension
.
slack {\nfeatures {\ndagger()\nmoshi(codegen = true)\n}\nandroid {\nfeatures {\nrobolectric()\n}\n}\n}\n
A major benefit of this is that we can intelligently configure features and avoid applying costly plugins like Kapt unless they\u2019re actually needed for a specific feature, such as Java injections in projects using Dagger. Since this is pure code, we can also propagate deprecated behavior by deprecating the corresponding functions in the DSL.
"},{"location":"#platform-plugins","title":"Platform plugins","text":"Platforms.kt
contains an implementation that sources a VersionCatalog
and applies it to a Gradle platform project. This allows us to effectively treat our versions catalog as a BOM and apply it to all projects in the consuming repo and reduce dependency version stratification.
MacBooks can suffer thermal throttling and result in poor build performance. We built instrumentation for this to capture these and include them in our build scans to better understand their impact. We support both Intel and Apple Silicon macs now and contain this implementation in ThermalsWatcher.kt
. This also includes helpful charting APIs for visualizing the data (courtesy of our friends at Square).
Gradle\u2019s built-in property support is limited and has surprising behavior, so we have our own system on top of it that has consistent precedence, local.properties
support, project-local gradle.properties
, and configuration caching support. Check out safeProperty()
in PropertyUtil.kt
.
DependencyRake.kt
contains an extension to the gradle-dependency-analysis-plugin
that applies its advice to a project to automatically optimize it and rake dependencies.
As a part of our modularization efforts, we developed a scoring mechanism for modules that we could use as a measure of their \u201cmodularization\u201d. This includes a number of metrics and weighs them in a formula to compute a score. This includes LoC, language mixtures, and build graph centrality. This logic is under the slack.stats
package.
Robolectric uses preinstrumented Android API jars that live on maven central. While it can handle downloading of these automatically, we found this implementation to be brittle and unreliable, so we built our own version of it that handles downloading these into a local .cache
directory. This implementation lives in UpdateRobolectricJarsTask.kt
and that task is configured to be a dependency of all Test
tasks.
We try to simplify and streamline the bootstrap process for both local development and on CI. This involves computing optimized JVM arguments for the Gradle and Kotlin daemons (which differ between CI and local) as well as toe-holds for future customizations. This logic lives in BootstrapTask.kt
.
To avoid accidentally checking in any new, unexpected manifest permissions, we have a CheckManifestPermissionsTask
that compares the final merged manifest\u2019s permissions to an allow list of known permissions. This is allow list is checked in and expected to be guarded by a CODEOWNERS
watch and will fail the build if they differ.
slack {\nandroid {\napp {\npermissionAllowlist {\nif (name == \"externalRelease\") {\nsetAllowlistFile(file(\"permissionsAllowlist.txt\"))\n}\n}\n}\n}\n}\n
"},{"location":"#apk-versioning-computers","title":"APK Versioning Computers","text":"AGP offers new property-based APIs for computing APK version codes and version names. We use this to compute information from different inputs (CI build number, git state, etc) and control this logic in ApkVersioningPlugin.kt
.
Sometimes a dependency update may bring with it a surprise update to a transitive dependency that we also declare. In order to avoid this happening unexpectedly, the CheckDependencyVersionsTask
checks that any transitive dependency versions that also correspond to a version declared in our VersionCatalog
match the version there. It\u2019s ok if they don\u2019t, but the author just need to update the version in the catalog too to be explicit (or investigate further if it\u2019s an unwanted surprise!).
AGP occasionally contains new or breaking API changes that we want to handle gracefully in early testing. We regularly test against newer preview versions of AGP so we can\u2019t just hardcode in new APIs and expect them to work everywhere. To handle this, we have an AgpHandler
interface that can be used to abstract these new APIs in a backward-compatible way. Then we ship implementations of this as different artifacts that are built against different AGP versions. Then, at runtime, we pick the appropriate instance (via service loading) to use for the current AGP version being used in that build.
Detekt is a static analysis tool that we use to check for common issues in our code. We use one global baseline file for baselined issues (when introducing new checks or updates), but Detekt doesn\u2019t currently support this easily. So, we built MergeDetektBaselinesTask
to merge all the generated baselines from each subproject into a single global baseline.
There are a ton of miscellaneous tools, utilities, and glue code for Gradle (and various plugins) sprinkled throughout this project.
"},{"location":"#usage-requirements","title":"Usage requirements","text":"SGP expects there to be a libs
version catalog.
The following versions are required to be set the above catalog. Their docs can be found in SlackVersions.kt
. - jdk
For Android projects, some extra definitions need to be defined - libs.versions.toml
libraries - google-coreLibraryDesugaring
- the core library desugaring libraries to use with L8. - gradle.properties
properties - slack.compileSdkVersion
- slack.targetSdkVersion
- slack.minSdkVersion
The following plugins are applied by default but can be disabled if you don\u2019t need them. - Gradle\u2019s test retry \u2013 slack.auto-apply.test-retry
- By default, this uses the Gradle test-retry plugin, but can be configured to use the Gradle Enterprise plugin\u2019s implementation instead by setting the slack.test.retry.pluginType
property to GE
. - Spotless \u2013 slack.auto-apply.spotless
- Detekt \u2013 slack.auto-apply.detekt
- NullAway \u2013 slack.auto-apply.nullaway
- Android Cache Fix \u2013 slack.auto-apply.cache-fix
The installCommitHooks
task can install commit hooks for formatting kotlin and java files. They expect binaries to be in <root>/config/git/hooks
and it\u2019s highly recommended to enable git-lfs for these objects. These binaries can be downloaded via the updateKtfmt
, updateGjf
, etc tasks.
Copyright 2022 Slack Technologies, LLC\n\nLicensed under the Apache License, Version 2.0 (the \"License\");\nyou may not use this file except in compliance with the License.\nYou may obtain a copy of the License at\n\n http://www.apache.org/licenses/LICENSE-2.0\n\nUnless required by applicable law or agreed to in writing, software\ndistributed under the License is distributed on an \"AS IS\" BASIS,\nWITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\nSee the License for the specific language governing permissions and\nlimitations under the License.\n
"},{"location":"architecture/","title":"Architecture","text":"SGP consists of three Gradle plugins and some associated helper artifacts.
"},{"location":"architecture/#slackrootplugin","title":"SlackRootPlugin
","text":"This is the root plugin that is applied to the root project of a multi-project build.
plugins {\nid(\"com.slack.gradle.root\")\n}\n
Its responsibilities include:
SlackTools
build service.libs.versions.toml
.SlackBasePlugin
","text":"This is the base plugin that is applied to all projects (including the root project).
plugins {\nid(\"com.slack.gradle.base\")\n}\n
Its responsibilities include:
StandardProjectConfigurations
.UnitTests
. This also includes configuring the Gradle test retry plugin, if enabled.StandardProjectConfigurations
","text":"This class warrants special mention as it is responsible for the bulk of the configuration applied to projects SGP manages.
slack
extension DSL.All JVM projects (Android, Java, Kotlin) receive some common configuration for their JVM tasks.
"},{"location":"architecture/#common","title":"Common","text":"DependencyRake
.StandardProjectConfigurations.configureAnnotationProcessors()
and StandardProjectConfigurations.APT_OPTION_CONFIGS
, which seeks to apply common configs for known processors like Dagger and Moshi.Java projects are fairly simple. Note that these are applied on all projects that apply the java
plugin, which is most of them!
JavaCompile
tasks have their options.release
property set to this as well.JavaCompile
tasks in non-android projects to ensure consistency.JavaCompile
tasks have -parameters
added to options.compilerArgs
for better static analysis and annotation processing support.slack.epAutoPatch
property.compileOptions
, defaultConfig
, compileSdk/targetSdk/minSdk/ndkVersion, etc.vectorDrawables.useSupportLibrary
.testOptions
like orchestrator, unitTests
, etc.unitTests.isReturnDefaultValues
is always enabled for convenience.unitTests.isIncludeAndroidResources
is only enabled if robolectric is enabled on the project, as this is expensive to enable.Test
tasks to depend on the UpdateRobolectricJarsTask
if robolectric is enabled.com.android.library
and com.android.application
projects. com.android.test
is supported but somewhat limited.jniLibs
handling.PermissionChecks
.android.namespace
, if none is manually specified in the buildscript. The namespace is inferred from the project\u2019s Gradle path.release
.Kotlin projects are configured with KGP and Detekt in mind. SGP supports configuring Android, JVM, Multiplatform, and Compose Multiplatform projects. Multiplatform for targets other than JVM/android is limited at the moment.
Common configurations include:
jvmToolchain
to align with the repo\u2019s JDK target.KotlinCompilation
tasks with common configurations.allWarningsAsErrors
.freeCompilerArgs
.jvmTarget
and javaParameters
.StandardProjectConfigurations.configureFreeKotlinCompilerArgs()
. This is an annoying thing to have to do, but necessary because kotlinc will complain if you add opt-ins that are not recognized by any dependencies on that classpath.DetektTasks
.com.android.lint
plugin and LintTasks
.src/{variant}/kotlin
source set in android projects, as these are still not automatically enabled.android.extensions
extension.correctErrorTypes
is set to true for better error messages.mapDiagnosticLocations
is set to false because it\u2019s broken.plugins {\nid(\"com.slack.gradle.apk-versioning\")\n}\n
This plugin is applied in Android application projects and is solely to configure the versionCode
and versionName
of APKs based on git and Gradle property inputs.
The following properties are sourced
versionMajor=...\nversionMinor=...\nversionPatch=...\n
This also adds a generateVersionProperties
task that is more or less only relevant for Slack\u2019s internal CI.
SGP is designed to work with multiple versions of AGP at a time, albeit only for forward compatibility and testing reasons. Generally SGP will only be tested against the latest stable version of AGP. To support multiple beta/canary versions of upcoming AGP versions, SGP has an API called AgpHandler
, which is intended to be an AGP-agnostic common interface for configuring AGP projects across breaking API (source or binary) changes. When a new such change is introduced, we create an AgpHandler{version}
artifact and implementation with that AGP version as its minimum. At runtime, SGP loads the relevant AgpHandler
instance for the AGP version it is running against and relevant APIs use this instance via SlackTools
to interact with them in a version-agnostic way. These aren\u2019t always needed so there may be times when there are no implementations needed for the current suite of AGP versions.
An example handler for AGP 8.0 looks like this.
// AutoService makes it available via ServiceLoader\n// The factory should always be AGP-api agnostic.\nclass AgpHandler80 : AgpHandler {\n@Suppress(\"DEPRECATION\")\noverride val agpVersion: String\nget() = com.android.builder.model.Version.ANDROID_GRADLE_PLUGIN_VERSION\n\n@AutoService(AgpHandlerFactory::class)\nclass Factory : AgpHandlerFactory {\noverride val minVersion: VersionNumber = VersionNumber.parse(\"8.0.0\")\n\n@Suppress(\"DEPRECATION\")\noverride fun currentVersion(): String =\ncom.android.builder.model.Version.ANDROID_GRADLE_PLUGIN_VERSION\n\noverride fun create(): AgpHandler {\nreturn AgpHandler80()\n}\n}\n}\n
"},{"location":"bootstrap/","title":"Bootstrap","text":"Bootstrap is a tool for bootstrapping local dev environments. This is usually used in tandem with a bootstrap bash script that runs the ./gradlew bootstrap
task and any other repo-specific setups.
The core implementation lives in BootstrapTask.kt
.
At a high level, bootstrap is mostly focused on configuring the JDK and daemon environments. Gradle has extremely limited configurability for the Gradle daemon, and we want to optimize the JDK for available space on different developer machines. To support this, we compute optimal daemon jvm arguments in bootstrap and write them to the user\u2019s home ~/.gradle/gradle.properties
to override repo-specific settings with client-side properties.
For the JDK, it requests the JDK toolchain from Gradle\u2019s first-party APIs. This includes allowing Gradle to download the JDK if it\u2019s missing, which is useful for getting developers set up and running faster.
Bootstrap is also useful on CI for its ability to scale available memory to the machine it\u2019s running on, so we generally run it as a preflight step for all of our CI jobs too.
Finally, there are some other specific things it does to optimize things:
2023-11-08
slack.detekt.baseline-file-name
property to indicate what the simple file name should be. This is evaluated against project.layout.projectDirectory.file(...)
. This replaces the previous slack.detekt.baseline
property.1.9.20
.8.1.3
.1.5.10
.2023-11-02
2023-10-30
null
if their property values are blank.2023-10-22
sgp.isTestLibrary
property to indicate if a library is a test library. Note that projects that are named test-fixtures
are implicitly considered test libraries.VisibleForTests
lint on test libraries.2023-10-22
slack.lint.update-baselines
property in favor of AGP\u2019s modern updateBaselines
task.ImplicitSamInstance
lint config.2023-10-19
8.3.0-alpha08
.8.4
.1.5.3
.2023-10-02
slack.gradle.debugVersionCode
and defaults to 90009999
.slack.gradle.debugUserString
and defaults to debug
.8.1.0
.2023-09-28
allowListFile
file property instead.4.9.1
.1.5.2
.6.4.6
.2023-09-22
coreLibraryDesugaring
configuration.compilerOptions.moduleName
to a dashified version of the Gradle project path.0.24.3
2.4.8
.1.5.1
.1.22.0
.1.6.1
.2023-08-29
2023-08-29
sgp-tracing
artifact ID. We use this internally to collect extra build metadata, but it\u2019s generic enough for general use. Not currently used in slack-plugin yet.sgp.android.buildToolsVersionOverride
property to override the default build tools version in Android.AndroidPluginVersion
API in AgpHandler
.8.1.1
.6.21.0
.1.5.0
.1.9.10
.1.9.10-1.0.13
.3.1.7
.2.2.1
.6.4.5
.4.8.1
1.21.0
.8.3
.2023-08-15
com.android.test
projects in a few waysProject.buildDir
API usages.kotlin-cli-util
to 2.1.0
.2023-08-10
This streamlines configuration of enabling androidResources
and enforces use of a resource prefix to avoid conflicts.
May your avatars never be wrongly sized again.
slack {\nandroid {\nfeatures {\nresources(\"prefix_\")\n}\n}\n}\n
2.0.0
.1.15.0
.0.4
.1.9.0-1.0.13
.3.5.0
.0.5.0
.2023-08-08
32.1.2-jre
.2023-08-08
slack.gradle.defaultVersionCode
). The default is 90009999
, for reasons.2023-08-07
{rootProject}/build/ci/release.version
. The default behavior will be to just use the version set in the android
DSL.1.23.1
.3.14.1
.1.4.3
.2.0.0
.2.4.7
.2023-07-25
1.9.0
.1.9.0-1.0.12
.8.1.0
.1.2.3
.0.24.0
.1.5.0
.4.8.0
.2023-07-12
slack.dependencyrake.dryRun
gradle property flag for dependency rake to enable dry-run. If enabled, the project build files will not be modified and a separate new-build.gradle.kts
file will be written to instead.3.4.0
.2023-07-07
RakeDependencies
task on platform projects../gradlew aggregateMissingIdentifiers -Pslack.gradle.config.enableAnalysisPlugin=true --no-configuration-cache
2023-06-30
DependencyRake
.32.1.0-jre
.2023-06-29
kotlin-cli-util
to 1.2.2.2023-06-25
2023-06-24
2023-06-24
2023-06-24
sgp.compose.multiplatform.forceAndroidXComposeCompiler
Gradle property flag to force use of the AndroidX compose compiler in Compose Multiplatform projects.sgp.config.jvmVendor.optOut
Gradle property flag to disable jvmVendor configuration in toolchains.2023-06-06
2023-06-06
robolectric
key in the primary version catalog.sgp.config.jvmVendor
property.4.7.0
.2.4.6
.8.0.2
.1.23.0
.2023-05-15
slack
DSL.2023-05-15
2023-05-09
disallowChanges()
on javaCompiler
in JavaCompile tasks. It seems that Gradle sets this multiple times.2023-05-09
disallowChanges()
where possible on properties SGP controls in order to avoid accidental overwrites.ComputeAffectedProjectsTask
also generate a affected_android_test_projects.txt
file with a newline-delimited list of affected projects that enable androidTest()
. This can be used in CI scripts to statically determine if instrumentation tests need to run.2023-05-06
SlackVersions
. See SlackVersions.kt
for updated expected naming of aliases.2023-05-05
jdk.compiler/com.sun.tools.javac.model
to Bootstrap Gradle JVM args and exec prefixes for binaries for GJF 17.2023-05-05
2023-05-04
Happy May the Fourth!
sgp.config.jvmVendor
property to control the JVM vendor used in Kotlin and Java toolchains. This value is used to match a known vendor spec, such as AZUL
.afterEvaluate
block to avoid https://github.com/Kotlin/kotlinx-kover/issues/362.2023-04-30
OkHttpClient
setup in SlackTools
.slack.features.dagger
DSL controls. There are two new properties to control this:slack.ksp.allow-dagger
\u2013 allow use of Dagger in KSP.slack.ksp.allow-anvil
\u2013 allow use of Anvil in KSP. Note this is not yet implemented in Anvil, just a toe-hold for the future.SlackToolsExtension
instances + fix classloader used for it.SlackToolsExtension
extensions that fail to load.2023-04-25
Context
to SlackToolsExtension
.2023-04-25
SlackTools.findExtension
API.SlackTools.SERVICE_NAME
for @ServiceReference
API.2023-04-25
moshi-kotlin
, only use generated adapters now.sgp.ge.apply-common-build-tags
property flag to gate applying common build tags to a project.SlackToolsExtension
to work as a ServiceLoader
instead.2023-04-23
SlackTools
because this apparently invalidates configuration cache every time.2023-04-22
class
for SAM conversions due to https://github.com/gradle/gradle/issues/24871.2023-04-22
SlackTools
and support enabling property at different scopes (local.properties, etc).SlackTools
is closed.class
for SAM conversions. The minimum supported Gradle version is now 8.1, which introduced support for this.2023-04-22
2023-04-22
SlackTools
instances when reporting background data to Gradle Enterprise. These instances would be orphaned because this would happen after Gradle had closed all existing services, and create a memory leak.SlackTools
instances.Executor
for SlackTools
\u2018 thermals heartbeat.2023-04-22
Throwable
with multiple instances of SlackTools
to help track origin points.2023-04-22
SlackTools
to track multiple instances.2023-04-15
ValueSource
for Gradle 8.x compatibility.PLATFORM_NATIVE
in spotless by default. Its default of looking at .gitattributes
is expensive and incompatible with Gradle 8.1+ configuration caching.slack.auto-apply.sort-dependencies
boolean Gradle property to gate auto-applying the sort-dependencies plugin.2023-04-01
Happy April Fool\u2019s Day!
2023-03-28
detekt
task dependencies for globalDetekt
.2023-03-27
slack.detekt.full
property to gate whether or to run full detekt (i.e. with type resolution). If disabled, detektRelease
/detektMain
and associated tasks will be disabled and not used in detektGlobal
.2023-03-25
DetektCreateBaselineTask
tasks too due to https://github.com/detekt/detekt/issues/5940.2023-03-24
slack.avoidance.build-upon-default-affected-project-configurations
flag to make provided configurations build upon defaults.globalDetekt
task that runs detekt
on all subprojects. This is Skippy-compatible and responds to slack.avoidance.affectedProjectsFile
.2023-03-22
androidExtension
publicly in SlackExtension
to avoid Gradle mismatching number of type arguments in AGP 8.1.0-alpha10+.2023-03-22
Detekt.jdkHome
to null to avoid https://github.com/detekt/detekt/issues/5925.String.safeCapitalize()
to String.capitalizeUS()
to make it more explicit.2023-03-21
-Pslack.compose.android.enableLiveLiterals=true
..github/actions/**
to default never skip filters.2023-03-20
affected_projects.txt
and allow non-existent files as a value. This makes it easy to gracefully fall back in CI.6.4.1
.2023-03-17
"},{"location":"changelog/#project-skippy","title":"Project Skippy","text":"This release introduces an experimental new computeAffectedProjects
task for computing affected projects based on an input of changed files. The goal of this is to statically detect which unit test, lint, and androidTest checks can be safely skipped in CI on pull requests.
Example usage
./gradlew computeAffectedProjects --changed-files changed_files.txt\n
Where changed_files.txt
is resolved against the root repo directory and contains a newline-delimited list of changed files (usually inferred from a PR).
A simple example of how to produce such a file with the gh
CLI:
gh pr view ${{ github.event.number }} --json files -q '.files[].path' > changed_files.txt\n
One would run this task first as a preflight task, then run subsequent builds with the slack.avoidance.affectedProjectsFile
Gradle property pointing to its output file location (printed at the end of the task).
./gradlew ... -Pslack.avoidance.affectedProjectsFile=/Users/zacsweers/dev/slack/slack-android-ng/build/skippy/affected_projects.txt\n
The globalCiLint
, globalCiUnitTest
, and aggregateAndroidTestApks
tasks all support reading this property and will avoid adding dependencies on tasks in projects that are not present in this set.
The ComputeAffectedProjectsTask
task has some sensible defaults, but can be configured further in the root projects like so.
tasks.named<ComputeAffectedProjectsTask>(\"computeAffectedProjects\") {\n// Glob patterns of files to include in computing\nincludePatterns.addAll(\n\"**/*.kt\",\n\"**/*.java\",\n)\n// Glob patterns of files that, if changed, should result in not skipping anything in the build\nneverSkipPatterns.addAll(\n\"**/*.versions.toml\",\n\"gradle/wrapper/**\",\n)\n}\n
Debug logging can be enabled via the slack.debug=true
Gradle property. This will output timings, logs, and diagnostics for the task.
The configurations used to determine the build graph can be customized via comma-separated list to the slack.avoidance.affected-project-configurations
property.
2023-03-15
Happy Ted Lasso season 3 premier day!
UseContainerSupport
jvm arg from unit tests as this appears to only work on Linux.2023-03-14
Happy Pi day!
Test
tasks are now configured more consistently across CI and local, so there should be more cache hits.globalCiUnitTest
task to the root project to ease running ciUnitTest
tasks across all subprojects.SlackProperties
for controlling max parallelism and forkEvery
options in Test
tasks.ciLint
task to every project that depends on all lint tasks in that project. This is intended to be the inverse behavior of the built-in lint
task in Android projects, which only runs the default variant\u2019s lint task.globalCiLint
task to the root project to ease running ciLint
tasks across all subprojects.SlackProperties
for controlling which variants should be linted.lint.xml
is the right place for this kind of logic.2023-03-07
slack.lint.severity.errorRuleIds
Gradle property to specify lint rule IDs that should always be error severity.2023-02-27
2023-02-20
checkDependencies
is no longer enabled by default.slack.lint.baseline-file-name
property. Defaults to lint-baseline.xml
.ImplicitSamInstance
lint not being enabled.2023-02-15
MergeFileTask.kt
was accidentally removed during a previous release.jna-platform
dependency to align with the jna
dependency version.2023-02-15
Do not use! Release was accidentally messed up.
"},{"location":"changelog/#055","title":"0.5.5","text":"2023-02-13
LocTask
is now compatible with Gradle 8.0 and has the correct task dependencies when Ksp, Kapt, etc are running.LocTask
is now compatible with remote build cache.KtfmtDownloadTask
, DetektDownloadTask
, etc) now have prettier and more reliable download progress indications.UpdateRobolectricJarsTask
now uses Gradle workers to parallelize downloads. On gigabit wifi, this takes the task runtime down from ~21sec to ~13sec.SLACK_FORCE_REDOWNLOAD_ROBOLECTRIC_JARS
env variable can be used to force UpdateRobolectricJarsTask
to redownload jars even if already downloaded. Behavior change: Mod score must now be opted in to via the slack.gradle.config.modscore.enabled=true
gradle property.slack.gradle.config.modscore.ignore=true
gradle property.2023-02-07
sortDependencies
toml version is present, and you can have it download+create executable binaries via ./gradlew downloadDependenciesSorter
.compose()
DSL is moved to slack.features
and offers an optional multiplatform
parameter to enable the compose multiplatform plugin. slack {\nfeatures {\ncompose(multiplatform = <true|false>)\n}\n}\n
1.8.10
and AGP 7.4.1
.2023-01-27
MergeFilesTask
monkeypatch using env vars instead of system props.2023-01-26
MergeFilesTask
monkeypatch plus extra logging. Feel free to skip this update if you\u2019re unaffected.2023-01-23
Optional
for google-coreLibraryDesugaring
dependency before adding it. The Gradle API\u2019s lack of type safety strikes again.2023-01-23
sgp-monkeypatch-agp
artifact. This contains monkeypatches for AGP where we try to fix bugs. This initial version contains a patched MergeFilesTask
that sorts files before merging them to ensure deterministic outputs, as we believe this is causing our lint tasks to be non-cacheable across machines. This can be enabled via setting the com.slack.sgp.sort-merge-files
system property to true
.slack.gradle.config.bugsnag.enabled
gradle property to true.slack.gradle.config.bugsnag.enabledBranchPattern
gradle property. For example: slack.gradle.config.bugsnag.enabledBranchPattern=main|release_.*
.libs.versions.toml
instead of assuming the artifact name. Starting with 1.2.0, desugar JDK libs offers multiple artifacts. Point google-coreLibraryDesugaring
in [libraries] to whichever artifact should be used.2023-01-13
2023-01-09
Happy new year!
3.3.0
.2022-12-29
compilerOptions
API now.2022-12-22
2022-12-19
2022-12-15
android.packagingOptions.jniLibs.pickFirst
for AGP 8.x compatibility, as the returned type by jniLibs
changed from JniLibsPackagingOptions
to JniLibsPackaging
.2022-12-06
compileCiUnitTest
lifecycle task to just compile (but not run!) unit tests that are run by ciUnitTest
.2022-12-04
isIncludeAndroidResources
in Android unit tests automatically when robolectric()
is used.2022-11-11
2022-11-10
AndroidManifest.xml
files in androidTest sources + ensure they\u2019re debuggable.2022-10-20
**/build/**
from Detekt
tasks.2022-10-14
com.android.test
projects.org.jetbrains.compose
) projects.me.tongfei:progressbar
to 0.9.5
.2022-10-06
2022-10-03
2022-10-03
--add-opens
to Test
tasks for Robolectric 4.9+ when it\u2019s enabled.subprojects
module stats and allprojects
in bootstrap for better project isolation support.2022-09-27
androidTest(allowedVariants = ...)
wasn\u2019t running on com.android.application
projects.Lint
DSL block for com.android.library
and org.jetbrains.kotlin.jvm
projects too.2022-09-23
slack {\nandroid {\nfeatures {\nandroidTest(allowedVariants = setOf(\"internalDebug\"))\n}\n}\n}\n
"},{"location":"changelog/#012","title":"0.1.2","text":"2022-09-20
2022-09-08
slack.unit-test
plugin application.2022-09-07
Instantiatable
lint in min SDK 28+ due to lint bug.Diversity and inclusion make our community strong. We encourage participation from the most varied and diverse backgrounds possible and want to be very clear about where we stand.
Our goal is to maintain a safe, helpful and friendly community for everyone, regardless of experience, gender identity and expression, sexual orientation, disability, personal appearance, body size, race, ethnicity, age, religion, nationality, or other defining characteristic.
This code and related procedures also apply to unacceptable behavior occurring outside the scope of community activities, in all community venues (online and in-person) as well as in all one-on-one communications, and anywhere such behavior has the potential to adversely affect the safety and well-being of community members.
For more information on our code of conduct, please visit https://slackhq.github.io/code-of-conduct
"},{"location":"configuration/","title":"Configuration","text":"TODO
"},{"location":"contributing/","title":"Contributors Guide","text":"Note that this project is considered READ-ONLY. You are welcome to discuss or ask questions in the discussions section of the repo, but we do not normally accept external contributions without prior discussion.
"},{"location":"contributing/#development","title":"Development","text":"Check out this repo with Android Studio or IntelliJ. It\u2019s a standard gradle project and conventional to check out.
The primary project is slack-plugin
.
Kotlin should be used for more idiomatic use with Gradle/AGP APIs
Code formatting is checked via Spotless. To run the formatter, use the spotlessApply
command.
./gradlew spotlessApply\n
Optionally, there are commit hooks in the repo you can enable by running the below
git config core.hooksPath config/git/hooks\n
"},{"location":"dependency-rake/","title":"Dependency Rake","text":"Dependency rake is an tool we develop within slack-gradle-plugin (SGP) to automatically clean up Gradle build files.
This tool uses the outputs of the dependency-analysis-gradle-plugin ( DAGP) to infer and apply fixes it recommends.
"},{"location":"dependency-rake/#types-of-fixes","title":"Types of Fixes","text":"There are three main categories of fixes that DR applies.
The primary benefit of dependency rake is to improve build times by more or less \u201craking\u201d the build dependency graph. By removing and fixing dependencies, we remove unneeded edges in the build graph. This in turn provides improved build parallelism and better avoidance in Skippy CI pipelines.
A secondary benefit is automatic upkeep of build files. As projects change over time, dependencies become obsolete and out of date. Most developers do not keep up with these changes over time, so automating this affords us extra upkeep that we currently do not do.
"},{"location":"dependency-rake/#implementation","title":"Implementation","text":"The core implementation of DR lives in DependencyRake.kt
.
To run dependency rake in a project, use the below command
$ ./gradlew rakeDependencies -Pslack.gradle.config.enableAnalysisPlugin=true --no-configuration-cache\n
This will run all rakeDependencies
tasks in the project. This task exists on all subprojects as well, but it works best if all are run together.
Sometimes dependency rake will try to replace identifiers with ones that are not present in any available version catalogs. Sometimes this is acceptable, but often times it can result in \u201cmissing\u201d dependencies from the build after it runs. To help fix these, DR will write all missing identifiers out to a build output file.
For convenience, you can also run ./gradlew aggregateMissingIdentifiers -Pslack.gradle.config.enableAnalysisPlugin=true --no-configuration-cache
to run all dependency rake tasks and aggregate these missing identifiers into a root project build output file.
SGP offers a DSL extension for configuring project behavior via the plugin. The idea is that developers don\u2019t really want to think about specific dependency wirings, and instead want to express what features they want and allow SGP to automatically wire these up for them.
Some examples of this include Dagger, Moshi code gen, Robolectric, and more.
The primary entry point is the slack
extension in the build file, which is backed by the SlackExtension
interface.
slack {\nfeatures {\ndagger(...)\nmoshi(...)\n}\nandroid {\nfeatures {\nrobolectric(...)\n}\n}\n}\n
"},{"location":"dsl/#features","title":"Features","text":""},{"location":"dsl/#dagger","title":"Dagger","text":"The Dagger feature automatically sets up both Dagger and Anvil. This includes optional parameters to control whether or not you want the runtime only, component merging, or other features. This automatically handles applying the Anvil, kapt, or KSP plugins under the hood and any necessary dependencies to run them.
The default dagger()
call will just enable Dagger\u2019s runtime + Anvil\u2019s factory generation with no component merging ( to avoid the Kapt cost).
The Moshi feature handles setting up both Moshi and MoshiX. This includes handling applying code gen logic (either KSP or IR) as well as moshi-sealed
support if requested.
This enables the redacted-compiler-plugin compiler plugin.
"},{"location":"dsl/#compose","title":"Compose","text":"The Compose feature handles setting up Compose in both Android and multiplatform projects. This handles a bunch of boilerplate (see ComposeUtil.kt
) for applying the right compose-compiler artifact version as well as enabling the right controls in the Android plugin.
The Robolectric feature handles setting up Robolectric in an Android project. This entails common Robolectric dependencies (including any bundles or core Robolectric project dependencies). This also sets up Robolectric jar downloads (via UpdateRobolectricJarsTask
) for test tasks and enabling resource merging in tests (which Robolectric requires). There are a few other controls that StandardProjectConfigurations
use to control or patch Robolectric\u2019s behavior.
By default, SGP disables androidTests in projects. These can be enabled via the androidTest()
feature, which will enable the relevant controls in the Android plugin. This can also accept specified variants to enable/disable.
This is important for opting in tests to AndroidTest APK Aggregation.
"},{"location":"dsl/#resources","title":"Resources","text":"By default, we disable Android resources (different from Java resources) and libraries have to opt-in to using them.
This can be enabled via the resources()
feature, which will enable the relevant BuildFeature
in the Android plugin and also takes a required prefix
parameter that is used as the required resourcePrefix
for that library\u2019s resources to avoid naming conflicts.
This enables checking of a permission allowlist. See PermissionChecks
for more details.
SGP supports running a number of formatters and static analysis tools.
Individual tools are usually gated on whether they have a version specified in libs.versions.toml
. If they do not have a version specified, they are deemed not enabled.
The core set of formatters are:
The core set of analysis tools supported in SGP are:
SGP ships with a standard set of git hooks (pre-commit, etc) that it can bootstrap in projects by running ./gradlew installCommitHooks
. These hooks rely on checking in relevant binaries for each formatter/checker, it\u2019s strongly recommended to use git-lfs for these. These files should be edited as needed to best serve the project they\u2019re running in.
SGP can configure these hooks in the project automatically during bootstrap if you add the slack.git.hooksPath
gradle property and point it at the hooks directory that the above command output to, or wherever the host project opts to store them.
Note that Detekt is not yet supported in git hooks as these require extra parameters for baselines.
"},{"location":"formatters-and-analysis/#downloading-binaries","title":"Downloading binaries","text":"Each tool (ktfmt, gjf, etc) has corresponding ./gradlew update<tool name>
tasks that you can run to download and install them, by default to config/bin/<tool name>
. You should re-run these any time you update a tool to re-run them.
TODO
"},{"location":"mod-score/","title":"Mod Score","text":"TODO
"},{"location":"properties/","title":"Properties","text":"TODO
"},{"location":"skippy/","title":"Skippy","text":"TODO
"},{"location":"testing/","title":"Testing","text":"TODO
"},{"location":"thermals-logging/","title":"Thermals Logging","text":"TODO
"},{"location":"utilities/","title":"Utilities","text":"There are a bunch of miscellaneous utilities and tools in this project that don\u2019t necessarily warrant their own dedicated docs page.
"},{"location":"utilities/#androidsourcesconfigurer","title":"AndroidSourcesConfigurer
","text":"When testing new Android SDK betas, the compile SDK version is available months before sources are. Developers want to build against these APIs, but we don\u2019t want to make their experience in the IDE worse than necessary. The problem with using a compile SDK version that doesn\u2019t have sources is that the IDE can\u2019t provide any documentation for the APIs and will just show stub files instead.
To work mitigate this, we will patch the SDK by putting a copy of the previous version\u2019s sources in the location of the new SDK. This allows most sources to still index properly during the beta period. Then, once the new sources are available, the consuming repo needs only to update the slack.latestCompileSdkWithSources
gradle property to that new SDK version and the patcher will clear out that copy and let AGP download the real ones.
This runs automatically in the root plugin.
"},{"location":"utilities/#androidtest-apk-aggregation","title":"AndroidTest APK Aggregation","text":"At Slack we use FTL + Fladle for running our instrumentation tests. In order to add more test APKs from modularized instrumentation tests in other subprojects, we have to aggregate a list of their locations and pass them on to Fladle. This is done via AndroidTestApksTask
, which is registered in the root project and can be wired to pipe its output file into Fladle\u2019s config input.
Example
val aggregatedApksProvider = rootProject.tasks\n.named<AndroidTestApksTask>(\"aggregateAndroidTestApks\")\n.flatMap { it.outputFile }\n.map { it.asFile.readLines() }\n\ntasks\n.withType<YamlConfigWriterTask>()\n.matching { it.name == \"writeConfigProps${fladleTarget}\" }\n.configureEach { additionalTestApks.value(testInputsProvider) }\n
This task is automatically added to whenever a subproject uses the androidTest()
DSL feature.
PermissionChecks
","text":"Permissions are an integral part of Android apps, and oversight into what permissions are required in the app is critical to a release pipeline. PermissionChecks
is a feature to help with this.
The workflow we use at Slack is like this:
permissionsAllowlist.txt
file in the Slack android repo.allowListFile
DSL feature in the application project.This way new permissions are not accidentally or secretly added to the app.
"}]} \ No newline at end of file +{"config":{"lang":["en"],"separator":"[\\s\\-]+","pipeline":["stopWordFilter"]},"docs":[{"location":"","title":"slack-gradle-plugin","text":"This repository contains the core Gradle plugin and associated logic used for Slack\u2019s Android app.
This repo is effectively read-only and does not publish artifacts to Maven Central. We develop these in the open to knowledge-share with the community.
As such, our issue tracker is closed and we don\u2019t normally accept external PRs, but we welcome your questions in the discussions section of the project!
We may later publish some of these components. If you\u2019re interested in this, feel free to raise in a discussions post or vote for existing suggestions.
"},{"location":"#highlights","title":"Highlights","text":""},{"location":"#common-project-configuration","title":"Common project configuration","text":"The slack.base
plugin offers common configuration for all projects implementing it, covering a wide spectrum of Android, Kotlin, and Java configurations.
This includes a whole host of things! - Common Android configuration (single variant libraries, disabling unused features, compose, etc). - Common Kotlin configuration (freeCompilerArgs, JVM target, etc). - Common Java configuration (toolchains, release versions, etc). - Common annotation processors. - SlackExtension (see next section). - Formatting (via Spotless). - Platforms and BOM dependencies (see \u201cPlatform plugins\u201d section below). - Common lint checks (both on Android and plain JVM projects).
Full docs can be found in the architecture docs.
"},{"location":"#feature-dsl","title":"Feature DSL","text":"To ease use and configuration of common features in projects, we expose a slack
DSL in projects that allows for configuration of these in a semantically easy and boilerplate-free way. This is controlled via SlackExtension
.
slack {\nfeatures {\ndagger()\nmoshi(codegen = true)\n}\nandroid {\nfeatures {\nrobolectric()\n}\n}\n}\n
A major benefit of this is that we can intelligently configure features and avoid applying costly plugins like Kapt unless they\u2019re actually needed for a specific feature, such as Java injections in projects using Dagger. Since this is pure code, we can also propagate deprecated behavior by deprecating the corresponding functions in the DSL.
"},{"location":"#platform-plugins","title":"Platform plugins","text":"Platforms.kt
contains an implementation that sources a VersionCatalog
and applies it to a Gradle platform project. This allows us to effectively treat our versions catalog as a BOM and apply it to all projects in the consuming repo and reduce dependency version stratification.
MacBooks can suffer thermal throttling and result in poor build performance. We built instrumentation for this to capture these and include them in our build scans to better understand their impact. We support both Intel and Apple Silicon macs now and contain this implementation in ThermalsWatcher.kt
. This also includes helpful charting APIs for visualizing the data (courtesy of our friends at Square).
Gradle\u2019s built-in property support is limited and has surprising behavior, so we have our own system on top of it that has consistent precedence, local.properties
support, project-local gradle.properties
, and configuration caching support. Check out safeProperty()
in PropertyUtil.kt
.
DependencyRake.kt
contains an extension to the gradle-dependency-analysis-plugin
that applies its advice to a project to automatically optimize it and rake dependencies.
As a part of our modularization efforts, we developed a scoring mechanism for modules that we could use as a measure of their \u201cmodularization\u201d. This includes a number of metrics and weighs them in a formula to compute a score. This includes LoC, language mixtures, and build graph centrality. This logic is under the slack.stats
package.
Robolectric uses preinstrumented Android API jars that live on maven central. While it can handle downloading of these automatically, we found this implementation to be brittle and unreliable, so we built our own version of it that handles downloading these into a local .cache
directory. This implementation lives in UpdateRobolectricJarsTask.kt
and that task is configured to be a dependency of all Test
tasks.
We try to simplify and streamline the bootstrap process for both local development and on CI. This involves computing optimized JVM arguments for the Gradle and Kotlin daemons (which differ between CI and local) as well as toe-holds for future customizations. This logic lives in BootstrapTask.kt
.
To avoid accidentally checking in any new, unexpected manifest permissions, we have a CheckManifestPermissionsTask
that compares the final merged manifest\u2019s permissions to an allow list of known permissions. This is allow list is checked in and expected to be guarded by a CODEOWNERS
watch and will fail the build if they differ.
slack {\nandroid {\napp {\npermissionAllowlist {\nif (name == \"externalRelease\") {\nsetAllowlistFile(file(\"permissionsAllowlist.txt\"))\n}\n}\n}\n}\n}\n
"},{"location":"#apk-versioning-computers","title":"APK Versioning Computers","text":"AGP offers new property-based APIs for computing APK version codes and version names. We use this to compute information from different inputs (CI build number, git state, etc) and control this logic in ApkVersioningPlugin.kt
.
Sometimes a dependency update may bring with it a surprise update to a transitive dependency that we also declare. In order to avoid this happening unexpectedly, the CheckDependencyVersionsTask
checks that any transitive dependency versions that also correspond to a version declared in our VersionCatalog
match the version there. It\u2019s ok if they don\u2019t, but the author just need to update the version in the catalog too to be explicit (or investigate further if it\u2019s an unwanted surprise!).
AGP occasionally contains new or breaking API changes that we want to handle gracefully in early testing. We regularly test against newer preview versions of AGP so we can\u2019t just hardcode in new APIs and expect them to work everywhere. To handle this, we have an AgpHandler
interface that can be used to abstract these new APIs in a backward-compatible way. Then we ship implementations of this as different artifacts that are built against different AGP versions. Then, at runtime, we pick the appropriate instance (via service loading) to use for the current AGP version being used in that build.
Detekt is a static analysis tool that we use to check for common issues in our code. We use one global baseline file for baselined issues (when introducing new checks or updates), but Detekt doesn\u2019t currently support this easily. So, we built MergeDetektBaselinesTask
to merge all the generated baselines from each subproject into a single global baseline.
There are a ton of miscellaneous tools, utilities, and glue code for Gradle (and various plugins) sprinkled throughout this project.
"},{"location":"#usage-requirements","title":"Usage requirements","text":"SGP expects there to be a libs
version catalog.
The following versions are required to be set the above catalog. Their docs can be found in SlackVersions.kt
. - jdk
For Android projects, some extra definitions need to be defined - libs.versions.toml
libraries - google-coreLibraryDesugaring
- the core library desugaring libraries to use with L8. - gradle.properties
properties - slack.compileSdkVersion
- slack.targetSdkVersion
- slack.minSdkVersion
The following plugins are applied by default but can be disabled if you don\u2019t need them. - Gradle\u2019s test retry \u2013 slack.auto-apply.test-retry
- By default, this uses the Gradle test-retry plugin, but can be configured to use the Gradle Enterprise plugin\u2019s implementation instead by setting the slack.test.retry.pluginType
property to GE
. - Spotless \u2013 slack.auto-apply.spotless
- Detekt \u2013 slack.auto-apply.detekt
- NullAway \u2013 slack.auto-apply.nullaway
- Android Cache Fix \u2013 slack.auto-apply.cache-fix
The installCommitHooks
task can install commit hooks for formatting kotlin and java files. They expect binaries to be in <root>/config/git/hooks
and it\u2019s highly recommended to enable git-lfs for these objects. These binaries can be downloaded via the updateKtfmt
, updateGjf
, etc tasks.
Copyright 2022 Slack Technologies, LLC\n\nLicensed under the Apache License, Version 2.0 (the \"License\");\nyou may not use this file except in compliance with the License.\nYou may obtain a copy of the License at\n\n http://www.apache.org/licenses/LICENSE-2.0\n\nUnless required by applicable law or agreed to in writing, software\ndistributed under the License is distributed on an \"AS IS\" BASIS,\nWITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\nSee the License for the specific language governing permissions and\nlimitations under the License.\n
"},{"location":"architecture/","title":"Architecture","text":"SGP consists of three Gradle plugins and some associated helper artifacts.
"},{"location":"architecture/#slackrootplugin","title":"SlackRootPlugin
","text":"This is the root plugin that is applied to the root project of a multi-project build.
plugins {\nid(\"com.slack.gradle.root\")\n}\n
Its responsibilities include:
SlackTools
build service.libs.versions.toml
.SlackBasePlugin
","text":"This is the base plugin that is applied to all projects (including the root project).
plugins {\nid(\"com.slack.gradle.base\")\n}\n
Its responsibilities include:
StandardProjectConfigurations
.UnitTests
. This also includes configuring the Gradle test retry plugin, if enabled.StandardProjectConfigurations
","text":"This class warrants special mention as it is responsible for the bulk of the configuration applied to projects SGP manages.
slack
extension DSL.All JVM projects (Android, Java, Kotlin) receive some common configuration for their JVM tasks.
"},{"location":"architecture/#common","title":"Common","text":"DependencyRake
.StandardProjectConfigurations.configureAnnotationProcessors()
and StandardProjectConfigurations.APT_OPTION_CONFIGS
, which seeks to apply common configs for known processors like Dagger and Moshi.Java projects are fairly simple. Note that these are applied on all projects that apply the java
plugin, which is most of them!
JavaCompile
tasks have their options.release
property set to this as well.JavaCompile
tasks in non-android projects to ensure consistency.JavaCompile
tasks have -parameters
added to options.compilerArgs
for better static analysis and annotation processing support.slack.epAutoPatch
property.compileOptions
, defaultConfig
, compileSdk/targetSdk/minSdk/ndkVersion, etc.vectorDrawables.useSupportLibrary
.testOptions
like orchestrator, unitTests
, etc.unitTests.isReturnDefaultValues
is always enabled for convenience.unitTests.isIncludeAndroidResources
is only enabled if robolectric is enabled on the project, as this is expensive to enable.Test
tasks to depend on the UpdateRobolectricJarsTask
if robolectric is enabled.com.android.library
and com.android.application
projects. com.android.test
is supported but somewhat limited.jniLibs
handling.PermissionChecks
.android.namespace
, if none is manually specified in the buildscript. The namespace is inferred from the project\u2019s Gradle path.release
.Kotlin projects are configured with KGP and Detekt in mind. SGP supports configuring Android, JVM, Multiplatform, and Compose Multiplatform projects. Multiplatform for targets other than JVM/android is limited at the moment.
Common configurations include:
jvmToolchain
to align with the repo\u2019s JDK target.KotlinCompilation
tasks with common configurations.allWarningsAsErrors
.freeCompilerArgs
.jvmTarget
and javaParameters
.StandardProjectConfigurations.configureFreeKotlinCompilerArgs()
. This is an annoying thing to have to do, but necessary because kotlinc will complain if you add opt-ins that are not recognized by any dependencies on that classpath.DetektTasks
.com.android.lint
plugin and LintTasks
.src/{variant}/kotlin
source set in android projects, as these are still not automatically enabled.android.extensions
extension.correctErrorTypes
is set to true for better error messages.mapDiagnosticLocations
is set to false because it\u2019s broken.plugins {\nid(\"com.slack.gradle.apk-versioning\")\n}\n
This plugin is applied in Android application projects and is solely to configure the versionCode
and versionName
of APKs based on git and Gradle property inputs.
The following properties are sourced
versionMajor=...\nversionMinor=...\nversionPatch=...\n
This also adds a generateVersionProperties
task that is more or less only relevant for Slack\u2019s internal CI.
SGP is designed to work with multiple versions of AGP at a time, albeit only for forward compatibility and testing reasons. Generally SGP will only be tested against the latest stable version of AGP. To support multiple beta/canary versions of upcoming AGP versions, SGP has an API called AgpHandler
, which is intended to be an AGP-agnostic common interface for configuring AGP projects across breaking API (source or binary) changes. When a new such change is introduced, we create an AgpHandler{version}
artifact and implementation with that AGP version as its minimum. At runtime, SGP loads the relevant AgpHandler
instance for the AGP version it is running against and relevant APIs use this instance via SlackTools
to interact with them in a version-agnostic way. These aren\u2019t always needed so there may be times when there are no implementations needed for the current suite of AGP versions.
An example handler for AGP 8.0 looks like this.
// AutoService makes it available via ServiceLoader\n// The factory should always be AGP-api agnostic.\nclass AgpHandler80 : AgpHandler {\n@Suppress(\"DEPRECATION\")\noverride val agpVersion: String\nget() = com.android.builder.model.Version.ANDROID_GRADLE_PLUGIN_VERSION\n\n@AutoService(AgpHandlerFactory::class)\nclass Factory : AgpHandlerFactory {\noverride val minVersion: VersionNumber = VersionNumber.parse(\"8.0.0\")\n\n@Suppress(\"DEPRECATION\")\noverride fun currentVersion(): String =\ncom.android.builder.model.Version.ANDROID_GRADLE_PLUGIN_VERSION\n\noverride fun create(): AgpHandler {\nreturn AgpHandler80()\n}\n}\n}\n
"},{"location":"bootstrap/","title":"Bootstrap","text":"Bootstrap is a tool for bootstrapping local dev environments. This is usually used in tandem with a bootstrap bash script that runs the ./gradlew bootstrap
task and any other repo-specific setups.
The core implementation lives in BootstrapTask.kt
.
At a high level, bootstrap is mostly focused on configuring the JDK and daemon environments. Gradle has extremely limited configurability for the Gradle daemon, and we want to optimize the JDK for available space on different developer machines. To support this, we compute optimal daemon jvm arguments in bootstrap and write them to the user\u2019s home ~/.gradle/gradle.properties
to override repo-specific settings with client-side properties.
For the JDK, it requests the JDK toolchain from Gradle\u2019s first-party APIs. This includes allowing Gradle to download the JDK if it\u2019s missing, which is useful for getting developers set up and running faster.
Bootstrap is also useful on CI for its ability to scale available memory to the machine it\u2019s running on, so we generally run it as a preflight step for all of our CI jobs too.
Finally, there are some other specific things it does to optimize things:
2023-11-09
8.3.0-alpha13
.2023-11-08
slack.detekt.baseline-file-name
property to indicate what the simple file name should be. This is evaluated against project.layout.projectDirectory.file(...)
. This replaces the previous slack.detekt.baseline
property.1.9.20
.8.1.3
.1.5.10
.2023-11-02
2023-10-30
null
if their property values are blank.2023-10-22
sgp.isTestLibrary
property to indicate if a library is a test library. Note that projects that are named test-fixtures
are implicitly considered test libraries.VisibleForTests
lint on test libraries.2023-10-22
slack.lint.update-baselines
property in favor of AGP\u2019s modern updateBaselines
task.ImplicitSamInstance
lint config.2023-10-19
8.3.0-alpha08
.8.4
.1.5.3
.2023-10-02
slack.gradle.debugVersionCode
and defaults to 90009999
.slack.gradle.debugUserString
and defaults to debug
.8.1.0
.2023-09-28
allowListFile
file property instead.4.9.1
.1.5.2
.6.4.6
.2023-09-22
coreLibraryDesugaring
configuration.compilerOptions.moduleName
to a dashified version of the Gradle project path.0.24.3
2.4.8
.1.5.1
.1.22.0
.1.6.1
.2023-08-29
2023-08-29
sgp-tracing
artifact ID. We use this internally to collect extra build metadata, but it\u2019s generic enough for general use. Not currently used in slack-plugin yet.sgp.android.buildToolsVersionOverride
property to override the default build tools version in Android.AndroidPluginVersion
API in AgpHandler
.8.1.1
.6.21.0
.1.5.0
.1.9.10
.1.9.10-1.0.13
.3.1.7
.2.2.1
.6.4.5
.4.8.1
1.21.0
.8.3
.2023-08-15
com.android.test
projects in a few waysProject.buildDir
API usages.kotlin-cli-util
to 2.1.0
.2023-08-10
This streamlines configuration of enabling androidResources
and enforces use of a resource prefix to avoid conflicts.
May your avatars never be wrongly sized again.
slack {\nandroid {\nfeatures {\nresources(\"prefix_\")\n}\n}\n}\n
2.0.0
.1.15.0
.0.4
.1.9.0-1.0.13
.3.5.0
.0.5.0
.2023-08-08
32.1.2-jre
.2023-08-08
slack.gradle.defaultVersionCode
). The default is 90009999
, for reasons.2023-08-07
{rootProject}/build/ci/release.version
. The default behavior will be to just use the version set in the android
DSL.1.23.1
.3.14.1
.1.4.3
.2.0.0
.2.4.7
.2023-07-25
1.9.0
.1.9.0-1.0.12
.8.1.0
.1.2.3
.0.24.0
.1.5.0
.4.8.0
.2023-07-12
slack.dependencyrake.dryRun
gradle property flag for dependency rake to enable dry-run. If enabled, the project build files will not be modified and a separate new-build.gradle.kts
file will be written to instead.3.4.0
.2023-07-07
RakeDependencies
task on platform projects../gradlew aggregateMissingIdentifiers -Pslack.gradle.config.enableAnalysisPlugin=true --no-configuration-cache
2023-06-30
DependencyRake
.32.1.0-jre
.2023-06-29
kotlin-cli-util
to 1.2.2.2023-06-25
2023-06-24
2023-06-24
2023-06-24
sgp.compose.multiplatform.forceAndroidXComposeCompiler
Gradle property flag to force use of the AndroidX compose compiler in Compose Multiplatform projects.sgp.config.jvmVendor.optOut
Gradle property flag to disable jvmVendor configuration in toolchains.2023-06-06
2023-06-06
robolectric
key in the primary version catalog.sgp.config.jvmVendor
property.4.7.0
.2.4.6
.8.0.2
.1.23.0
.2023-05-15
slack
DSL.2023-05-15
2023-05-09
disallowChanges()
on javaCompiler
in JavaCompile tasks. It seems that Gradle sets this multiple times.2023-05-09
disallowChanges()
where possible on properties SGP controls in order to avoid accidental overwrites.ComputeAffectedProjectsTask
also generate a affected_android_test_projects.txt
file with a newline-delimited list of affected projects that enable androidTest()
. This can be used in CI scripts to statically determine if instrumentation tests need to run.2023-05-06
SlackVersions
. See SlackVersions.kt
for updated expected naming of aliases.2023-05-05
jdk.compiler/com.sun.tools.javac.model
to Bootstrap Gradle JVM args and exec prefixes for binaries for GJF 17.2023-05-05
2023-05-04
Happy May the Fourth!
sgp.config.jvmVendor
property to control the JVM vendor used in Kotlin and Java toolchains. This value is used to match a known vendor spec, such as AZUL
.afterEvaluate
block to avoid https://github.com/Kotlin/kotlinx-kover/issues/362.2023-04-30
OkHttpClient
setup in SlackTools
.slack.features.dagger
DSL controls. There are two new properties to control this:slack.ksp.allow-dagger
\u2013 allow use of Dagger in KSP.slack.ksp.allow-anvil
\u2013 allow use of Anvil in KSP. Note this is not yet implemented in Anvil, just a toe-hold for the future.SlackToolsExtension
instances + fix classloader used for it.SlackToolsExtension
extensions that fail to load.2023-04-25
Context
to SlackToolsExtension
.2023-04-25
SlackTools.findExtension
API.SlackTools.SERVICE_NAME
for @ServiceReference
API.2023-04-25
moshi-kotlin
, only use generated adapters now.sgp.ge.apply-common-build-tags
property flag to gate applying common build tags to a project.SlackToolsExtension
to work as a ServiceLoader
instead.2023-04-23
SlackTools
because this apparently invalidates configuration cache every time.2023-04-22
class
for SAM conversions due to https://github.com/gradle/gradle/issues/24871.2023-04-22
SlackTools
and support enabling property at different scopes (local.properties, etc).SlackTools
is closed.class
for SAM conversions. The minimum supported Gradle version is now 8.1, which introduced support for this.2023-04-22
2023-04-22
SlackTools
instances when reporting background data to Gradle Enterprise. These instances would be orphaned because this would happen after Gradle had closed all existing services, and create a memory leak.SlackTools
instances.Executor
for SlackTools
\u2018 thermals heartbeat.2023-04-22
Throwable
with multiple instances of SlackTools
to help track origin points.2023-04-22
SlackTools
to track multiple instances.2023-04-15
ValueSource
for Gradle 8.x compatibility.PLATFORM_NATIVE
in spotless by default. Its default of looking at .gitattributes
is expensive and incompatible with Gradle 8.1+ configuration caching.slack.auto-apply.sort-dependencies
boolean Gradle property to gate auto-applying the sort-dependencies plugin.2023-04-01
Happy April Fool\u2019s Day!
2023-03-28
detekt
task dependencies for globalDetekt
.2023-03-27
slack.detekt.full
property to gate whether or to run full detekt (i.e. with type resolution). If disabled, detektRelease
/detektMain
and associated tasks will be disabled and not used in detektGlobal
.2023-03-25
DetektCreateBaselineTask
tasks too due to https://github.com/detekt/detekt/issues/5940.2023-03-24
slack.avoidance.build-upon-default-affected-project-configurations
flag to make provided configurations build upon defaults.globalDetekt
task that runs detekt
on all subprojects. This is Skippy-compatible and responds to slack.avoidance.affectedProjectsFile
.2023-03-22
androidExtension
publicly in SlackExtension
to avoid Gradle mismatching number of type arguments in AGP 8.1.0-alpha10+.2023-03-22
Detekt.jdkHome
to null to avoid https://github.com/detekt/detekt/issues/5925.String.safeCapitalize()
to String.capitalizeUS()
to make it more explicit.2023-03-21
-Pslack.compose.android.enableLiveLiterals=true
..github/actions/**
to default never skip filters.2023-03-20
affected_projects.txt
and allow non-existent files as a value. This makes it easy to gracefully fall back in CI.6.4.1
.2023-03-17
"},{"location":"changelog/#project-skippy","title":"Project Skippy","text":"This release introduces an experimental new computeAffectedProjects
task for computing affected projects based on an input of changed files. The goal of this is to statically detect which unit test, lint, and androidTest checks can be safely skipped in CI on pull requests.
Example usage
./gradlew computeAffectedProjects --changed-files changed_files.txt\n
Where changed_files.txt
is resolved against the root repo directory and contains a newline-delimited list of changed files (usually inferred from a PR).
A simple example of how to produce such a file with the gh
CLI:
gh pr view ${{ github.event.number }} --json files -q '.files[].path' > changed_files.txt\n
One would run this task first as a preflight task, then run subsequent builds with the slack.avoidance.affectedProjectsFile
Gradle property pointing to its output file location (printed at the end of the task).
./gradlew ... -Pslack.avoidance.affectedProjectsFile=/Users/zacsweers/dev/slack/slack-android-ng/build/skippy/affected_projects.txt\n
The globalCiLint
, globalCiUnitTest
, and aggregateAndroidTestApks
tasks all support reading this property and will avoid adding dependencies on tasks in projects that are not present in this set.
The ComputeAffectedProjectsTask
task has some sensible defaults, but can be configured further in the root projects like so.
tasks.named<ComputeAffectedProjectsTask>(\"computeAffectedProjects\") {\n// Glob patterns of files to include in computing\nincludePatterns.addAll(\n\"**/*.kt\",\n\"**/*.java\",\n)\n// Glob patterns of files that, if changed, should result in not skipping anything in the build\nneverSkipPatterns.addAll(\n\"**/*.versions.toml\",\n\"gradle/wrapper/**\",\n)\n}\n
Debug logging can be enabled via the slack.debug=true
Gradle property. This will output timings, logs, and diagnostics for the task.
The configurations used to determine the build graph can be customized via comma-separated list to the slack.avoidance.affected-project-configurations
property.
2023-03-15
Happy Ted Lasso season 3 premier day!
UseContainerSupport
jvm arg from unit tests as this appears to only work on Linux.2023-03-14
Happy Pi day!
Test
tasks are now configured more consistently across CI and local, so there should be more cache hits.globalCiUnitTest
task to the root project to ease running ciUnitTest
tasks across all subprojects.SlackProperties
for controlling max parallelism and forkEvery
options in Test
tasks.ciLint
task to every project that depends on all lint tasks in that project. This is intended to be the inverse behavior of the built-in lint
task in Android projects, which only runs the default variant\u2019s lint task.globalCiLint
task to the root project to ease running ciLint
tasks across all subprojects.SlackProperties
for controlling which variants should be linted.lint.xml
is the right place for this kind of logic.2023-03-07
slack.lint.severity.errorRuleIds
Gradle property to specify lint rule IDs that should always be error severity.2023-02-27
2023-02-20
checkDependencies
is no longer enabled by default.slack.lint.baseline-file-name
property. Defaults to lint-baseline.xml
.ImplicitSamInstance
lint not being enabled.2023-02-15
MergeFileTask.kt
was accidentally removed during a previous release.jna-platform
dependency to align with the jna
dependency version.2023-02-15
Do not use! Release was accidentally messed up.
"},{"location":"changelog/#055","title":"0.5.5","text":"2023-02-13
LocTask
is now compatible with Gradle 8.0 and has the correct task dependencies when Ksp, Kapt, etc are running.LocTask
is now compatible with remote build cache.KtfmtDownloadTask
, DetektDownloadTask
, etc) now have prettier and more reliable download progress indications.UpdateRobolectricJarsTask
now uses Gradle workers to parallelize downloads. On gigabit wifi, this takes the task runtime down from ~21sec to ~13sec.SLACK_FORCE_REDOWNLOAD_ROBOLECTRIC_JARS
env variable can be used to force UpdateRobolectricJarsTask
to redownload jars even if already downloaded. Behavior change: Mod score must now be opted in to via the slack.gradle.config.modscore.enabled=true
gradle property.slack.gradle.config.modscore.ignore=true
gradle property.2023-02-07
sortDependencies
toml version is present, and you can have it download+create executable binaries via ./gradlew downloadDependenciesSorter
.compose()
DSL is moved to slack.features
and offers an optional multiplatform
parameter to enable the compose multiplatform plugin. slack {\nfeatures {\ncompose(multiplatform = <true|false>)\n}\n}\n
1.8.10
and AGP 7.4.1
.2023-01-27
MergeFilesTask
monkeypatch using env vars instead of system props.2023-01-26
MergeFilesTask
monkeypatch plus extra logging. Feel free to skip this update if you\u2019re unaffected.2023-01-23
Optional
for google-coreLibraryDesugaring
dependency before adding it. The Gradle API\u2019s lack of type safety strikes again.2023-01-23
sgp-monkeypatch-agp
artifact. This contains monkeypatches for AGP where we try to fix bugs. This initial version contains a patched MergeFilesTask
that sorts files before merging them to ensure deterministic outputs, as we believe this is causing our lint tasks to be non-cacheable across machines. This can be enabled via setting the com.slack.sgp.sort-merge-files
system property to true
.slack.gradle.config.bugsnag.enabled
gradle property to true.slack.gradle.config.bugsnag.enabledBranchPattern
gradle property. For example: slack.gradle.config.bugsnag.enabledBranchPattern=main|release_.*
.libs.versions.toml
instead of assuming the artifact name. Starting with 1.2.0, desugar JDK libs offers multiple artifacts. Point google-coreLibraryDesugaring
in [libraries] to whichever artifact should be used.2023-01-13
2023-01-09
Happy new year!
3.3.0
.2022-12-29
compilerOptions
API now.2022-12-22
2022-12-19
2022-12-15
android.packagingOptions.jniLibs.pickFirst
for AGP 8.x compatibility, as the returned type by jniLibs
changed from JniLibsPackagingOptions
to JniLibsPackaging
.2022-12-06
compileCiUnitTest
lifecycle task to just compile (but not run!) unit tests that are run by ciUnitTest
.2022-12-04
isIncludeAndroidResources
in Android unit tests automatically when robolectric()
is used.2022-11-11
2022-11-10
AndroidManifest.xml
files in androidTest sources + ensure they\u2019re debuggable.2022-10-20
**/build/**
from Detekt
tasks.2022-10-14
com.android.test
projects.org.jetbrains.compose
) projects.me.tongfei:progressbar
to 0.9.5
.2022-10-06
2022-10-03
2022-10-03
--add-opens
to Test
tasks for Robolectric 4.9+ when it\u2019s enabled.subprojects
module stats and allprojects
in bootstrap for better project isolation support.2022-09-27
androidTest(allowedVariants = ...)
wasn\u2019t running on com.android.application
projects.Lint
DSL block for com.android.library
and org.jetbrains.kotlin.jvm
projects too.2022-09-23
slack {\nandroid {\nfeatures {\nandroidTest(allowedVariants = setOf(\"internalDebug\"))\n}\n}\n}\n
"},{"location":"changelog/#012","title":"0.1.2","text":"2022-09-20
2022-09-08
slack.unit-test
plugin application.2022-09-07
Instantiatable
lint in min SDK 28+ due to lint bug.Diversity and inclusion make our community strong. We encourage participation from the most varied and diverse backgrounds possible and want to be very clear about where we stand.
Our goal is to maintain a safe, helpful and friendly community for everyone, regardless of experience, gender identity and expression, sexual orientation, disability, personal appearance, body size, race, ethnicity, age, religion, nationality, or other defining characteristic.
This code and related procedures also apply to unacceptable behavior occurring outside the scope of community activities, in all community venues (online and in-person) as well as in all one-on-one communications, and anywhere such behavior has the potential to adversely affect the safety and well-being of community members.
For more information on our code of conduct, please visit https://slackhq.github.io/code-of-conduct
"},{"location":"configuration/","title":"Configuration","text":"TODO
"},{"location":"contributing/","title":"Contributors Guide","text":"Note that this project is considered READ-ONLY. You are welcome to discuss or ask questions in the discussions section of the repo, but we do not normally accept external contributions without prior discussion.
"},{"location":"contributing/#development","title":"Development","text":"Check out this repo with Android Studio or IntelliJ. It\u2019s a standard gradle project and conventional to check out.
The primary project is slack-plugin
.
Kotlin should be used for more idiomatic use with Gradle/AGP APIs
Code formatting is checked via Spotless. To run the formatter, use the spotlessApply
command.
./gradlew spotlessApply\n
Optionally, there are commit hooks in the repo you can enable by running the below
git config core.hooksPath config/git/hooks\n
"},{"location":"dependency-rake/","title":"Dependency Rake","text":"Dependency rake is an tool we develop within slack-gradle-plugin (SGP) to automatically clean up Gradle build files.
This tool uses the outputs of the dependency-analysis-gradle-plugin ( DAGP) to infer and apply fixes it recommends.
"},{"location":"dependency-rake/#types-of-fixes","title":"Types of Fixes","text":"There are three main categories of fixes that DR applies.
The primary benefit of dependency rake is to improve build times by more or less \u201craking\u201d the build dependency graph. By removing and fixing dependencies, we remove unneeded edges in the build graph. This in turn provides improved build parallelism and better avoidance in Skippy CI pipelines.
A secondary benefit is automatic upkeep of build files. As projects change over time, dependencies become obsolete and out of date. Most developers do not keep up with these changes over time, so automating this affords us extra upkeep that we currently do not do.
"},{"location":"dependency-rake/#implementation","title":"Implementation","text":"The core implementation of DR lives in DependencyRake.kt
.
To run dependency rake in a project, use the below command
$ ./gradlew rakeDependencies -Pslack.gradle.config.enableAnalysisPlugin=true --no-configuration-cache\n
This will run all rakeDependencies
tasks in the project. This task exists on all subprojects as well, but it works best if all are run together.
Sometimes dependency rake will try to replace identifiers with ones that are not present in any available version catalogs. Sometimes this is acceptable, but often times it can result in \u201cmissing\u201d dependencies from the build after it runs. To help fix these, DR will write all missing identifiers out to a build output file.
For convenience, you can also run ./gradlew aggregateMissingIdentifiers -Pslack.gradle.config.enableAnalysisPlugin=true --no-configuration-cache
to run all dependency rake tasks and aggregate these missing identifiers into a root project build output file.
SGP offers a DSL extension for configuring project behavior via the plugin. The idea is that developers don\u2019t really want to think about specific dependency wirings, and instead want to express what features they want and allow SGP to automatically wire these up for them.
Some examples of this include Dagger, Moshi code gen, Robolectric, and more.
The primary entry point is the slack
extension in the build file, which is backed by the SlackExtension
interface.
slack {\nfeatures {\ndagger(...)\nmoshi(...)\n}\nandroid {\nfeatures {\nrobolectric(...)\n}\n}\n}\n
"},{"location":"dsl/#features","title":"Features","text":""},{"location":"dsl/#dagger","title":"Dagger","text":"The Dagger feature automatically sets up both Dagger and Anvil. This includes optional parameters to control whether or not you want the runtime only, component merging, or other features. This automatically handles applying the Anvil, kapt, or KSP plugins under the hood and any necessary dependencies to run them.
The default dagger()
call will just enable Dagger\u2019s runtime + Anvil\u2019s factory generation with no component merging ( to avoid the Kapt cost).
The Moshi feature handles setting up both Moshi and MoshiX. This includes handling applying code gen logic (either KSP or IR) as well as moshi-sealed
support if requested.
This enables the redacted-compiler-plugin compiler plugin.
"},{"location":"dsl/#compose","title":"Compose","text":"The Compose feature handles setting up Compose in both Android and multiplatform projects. This handles a bunch of boilerplate (see ComposeUtil.kt
) for applying the right compose-compiler artifact version as well as enabling the right controls in the Android plugin.
The Robolectric feature handles setting up Robolectric in an Android project. This entails common Robolectric dependencies (including any bundles or core Robolectric project dependencies). This also sets up Robolectric jar downloads (via UpdateRobolectricJarsTask
) for test tasks and enabling resource merging in tests (which Robolectric requires). There are a few other controls that StandardProjectConfigurations
use to control or patch Robolectric\u2019s behavior.
By default, SGP disables androidTests in projects. These can be enabled via the androidTest()
feature, which will enable the relevant controls in the Android plugin. This can also accept specified variants to enable/disable.
This is important for opting in tests to AndroidTest APK Aggregation.
"},{"location":"dsl/#resources","title":"Resources","text":"By default, we disable Android resources (different from Java resources) and libraries have to opt-in to using them.
This can be enabled via the resources()
feature, which will enable the relevant BuildFeature
in the Android plugin and also takes a required prefix
parameter that is used as the required resourcePrefix
for that library\u2019s resources to avoid naming conflicts.
This enables checking of a permission allowlist. See PermissionChecks
for more details.
SGP supports running a number of formatters and static analysis tools.
Individual tools are usually gated on whether they have a version specified in libs.versions.toml
. If they do not have a version specified, they are deemed not enabled.
The core set of formatters are:
The core set of analysis tools supported in SGP are:
SGP ships with a standard set of git hooks (pre-commit, etc) that it can bootstrap in projects by running ./gradlew installCommitHooks
. These hooks rely on checking in relevant binaries for each formatter/checker, it\u2019s strongly recommended to use git-lfs for these. These files should be edited as needed to best serve the project they\u2019re running in.
SGP can configure these hooks in the project automatically during bootstrap if you add the slack.git.hooksPath
gradle property and point it at the hooks directory that the above command output to, or wherever the host project opts to store them.
Note that Detekt is not yet supported in git hooks as these require extra parameters for baselines.
"},{"location":"formatters-and-analysis/#downloading-binaries","title":"Downloading binaries","text":"Each tool (ktfmt, gjf, etc) has corresponding ./gradlew update<tool name>
tasks that you can run to download and install them, by default to config/bin/<tool name>
. You should re-run these any time you update a tool to re-run them.
TODO
"},{"location":"mod-score/","title":"Mod Score","text":"TODO
"},{"location":"properties/","title":"Properties","text":"TODO
"},{"location":"skippy/","title":"Skippy","text":"TODO
"},{"location":"testing/","title":"Testing","text":"TODO
"},{"location":"thermals-logging/","title":"Thermals Logging","text":"TODO
"},{"location":"utilities/","title":"Utilities","text":"There are a bunch of miscellaneous utilities and tools in this project that don\u2019t necessarily warrant their own dedicated docs page.
"},{"location":"utilities/#androidsourcesconfigurer","title":"AndroidSourcesConfigurer
","text":"When testing new Android SDK betas, the compile SDK version is available months before sources are. Developers want to build against these APIs, but we don\u2019t want to make their experience in the IDE worse than necessary. The problem with using a compile SDK version that doesn\u2019t have sources is that the IDE can\u2019t provide any documentation for the APIs and will just show stub files instead.
To work mitigate this, we will patch the SDK by putting a copy of the previous version\u2019s sources in the location of the new SDK. This allows most sources to still index properly during the beta period. Then, once the new sources are available, the consuming repo needs only to update the slack.latestCompileSdkWithSources
gradle property to that new SDK version and the patcher will clear out that copy and let AGP download the real ones.
This runs automatically in the root plugin.
"},{"location":"utilities/#androidtest-apk-aggregation","title":"AndroidTest APK Aggregation","text":"At Slack we use FTL + Fladle for running our instrumentation tests. In order to add more test APKs from modularized instrumentation tests in other subprojects, we have to aggregate a list of their locations and pass them on to Fladle. This is done via AndroidTestApksTask
, which is registered in the root project and can be wired to pipe its output file into Fladle\u2019s config input.
Example
val aggregatedApksProvider = rootProject.tasks\n.named<AndroidTestApksTask>(\"aggregateAndroidTestApks\")\n.flatMap { it.outputFile }\n.map { it.asFile.readLines() }\n\ntasks\n.withType<YamlConfigWriterTask>()\n.matching { it.name == \"writeConfigProps${fladleTarget}\" }\n.configureEach { additionalTestApks.value(testInputsProvider) }\n
This task is automatically added to whenever a subproject uses the androidTest()
DSL feature.
PermissionChecks
","text":"Permissions are an integral part of Android apps, and oversight into what permissions are required in the app is critical to a release pipeline. PermissionChecks
is a feature to help with this.
The workflow we use at Slack is like this:
permissionsAllowlist.txt
file in the Slack android repo.allowListFile
DSL feature in the application project.This way new permissions are not accidentally or secretly added to the app.
"}]} \ No newline at end of file diff --git a/sitemap.xml.gz b/sitemap.xml.gz index 04f2465a6..34764cb43 100644 Binary files a/sitemap.xml.gz and b/sitemap.xml.gz differ