Skip to content

Commit

Permalink
Allowing customizing lock content (#46)
Browse files Browse the repository at this point in the history
  • Loading branch information
gmazzo authored Nov 5, 2024
1 parent 6e95099 commit 04b72f5
Show file tree
Hide file tree
Showing 7 changed files with 121 additions and 11 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
*.iml
.gradle/
.idea/
.kotlin/
/local.properties
.DS_Store
build/
14 changes: 14 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,20 @@ android {
}
```

### Customizing the content of the lock file
There are many configuration options to customize the content of the lock file, such as: `sdkVersion`, `permissions`, `features`, `libraries` and `exports`.

For instance, to remove the `exports` section from the lock file, you can set the `exports` property to `false`:
```kotlin
android {
manifestLock {
content {
exports = false
}
}
}
```

### Failing if lock has changes on CI
```kotlin
android {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
package io.github.gmazzo.android.manifest.lock

import org.gradle.api.Action
import org.gradle.api.file.RegularFileProperty
import org.gradle.api.provider.Property
import org.gradle.api.tasks.Input
import org.gradle.api.tasks.Nested

@JvmDefaultWithoutCompatibility
interface AndroidManifestLockExtension {
Expand All @@ -22,4 +25,29 @@ interface AndroidManifestLockExtension {
*/
val failOnLockChange: Property<Boolean>

@get:Nested
val content: Content

fun content(action: Action<Content>) =
apply { action.execute(content) }

interface Content {

@get:Input
val sdkVersion: Property<Boolean>

@get:Input
val permissions: Property<Boolean>

@get:Input
val features: Property<Boolean>

@get:Input
val libraries: Property<Boolean>

@get:Input
val exports: Property<Boolean>

}

}
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ class AndroidManifestLockPlugin : Plugin<Project> {
val extension = project.createExtension(android, manifest)
val lockTask = project.tasks.register<AndroidManifestLockTask>("androidManifestLock") {
variantManifests.set(manifests)
manifestContent.set(extension.content)
lockFile.set(extension.lockFile)
failOnLockChange.set(extension.failOnLockChange)
}
Expand All @@ -48,6 +49,30 @@ class AndroidManifestLockPlugin : Plugin<Project> {
.create<AndroidManifestLockExtension>("manifestLock")
.apply {

content {

sdkVersion
.convention(true)
.finalizeValueOnRead()

permissions
.convention(true)
.finalizeValueOnRead()

features
.convention(true)
.finalizeValueOnRead()

libraries
.convention(true)
.finalizeValueOnRead()

exports
.convention(true)
.finalizeValueOnRead()

}

lockFile
.convention(manifest.map { file ->
val lock = file.resolveSibling("${file.nameWithoutExtension}.lock.yaml")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import org.gradle.api.tasks.CacheableTask
import org.gradle.api.tasks.Input
import org.gradle.api.tasks.InputFiles
import org.gradle.api.tasks.Internal
import org.gradle.api.tasks.Nested
import org.gradle.api.tasks.OutputFile
import org.gradle.api.tasks.PathSensitive
import org.gradle.api.tasks.PathSensitivity
Expand All @@ -26,6 +27,9 @@ abstract class AndroidManifestLockTask : DefaultTask() {
internal val variantManifestsFiles =
variantManifests.map { it.values }

@get:Nested
abstract val manifestContent: Property<AndroidManifestLockExtension.Content>

@get:OutputFile
abstract val lockFile: RegularFileProperty

Expand All @@ -36,8 +40,18 @@ abstract class AndroidManifestLockTask : DefaultTask() {

@TaskAction
fun generateLock() {
val contentSpec = manifestContent.get()
val manifests = variantManifests.get()
.mapValues { (_, manifest) -> ManifestReader.parse(manifest.asFile) }
.mapValues { (_, manifest) ->
ManifestReader.parse(
manifest = manifest.asFile,
readSDKVersion = contentSpec.sdkVersion.get(),
readPermissions = contentSpec.permissions.get(),
readFeatures = contentSpec.features.get(),
readLibraries = contentSpec.libraries.get(),
readExports = contentSpec.exports.get(),
)
}

val lock = ManifestLockFactory.create(manifests)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,17 +24,29 @@ internal object ManifestReader {
private val getLibraries = xPath.compile("/manifest/application/uses-library")
private val getExports = xPath.compile("//*[@android:exported='true']")

fun parse(manifest: File): Manifest {
fun parse(
manifest: File,
readSDKVersion: Boolean = true,
readPermissions: Boolean = true,
readFeatures: Boolean = true,
readLibraries: Boolean = true,
readExports: Boolean = true
): Manifest {
val source = docBuilderFactory.newDocumentBuilder().parse(manifest)
val packageName = getPackageName.evaluate(source).takeUnless { it.isBlank() }
val minSDK = getMinSDK.evaluate(source).toIntOrNull()
val targetSDK = getTargetSDK.evaluate(source).toIntOrNull()
val permissions = getPermissions.collectEntries(source)
val features = getFeatures.collectEntries(source)
val libraries = getLibraries.collectEntries(source)
val exports = getExports.collect(source)
.groupingBy { it.nodeName }
.fold(emptySet<String>()) { acc, node -> acc + node.attributes.getNamedItemNS(ANDROID_NS, "name").nodeValue }
val minSDK = if (readSDKVersion) getMinSDK.evaluate(source).toIntOrNull() else null
val targetSDK = if (readSDKVersion) getTargetSDK.evaluate(source).toIntOrNull() else null
val permissions = if (readPermissions) getPermissions.collectEntries(source) else null
val features = if (readFeatures) getFeatures.collectEntries(source) else null
val libraries = if (readLibraries) getLibraries.collectEntries(source) else null
val exports =
if (readExports) getExports
.collect(source)
.groupingBy { it.nodeName }
.fold(emptySet<String>()) { acc, node ->
acc + node.attributes.getNamedItemNS(ANDROID_NS, "name").nodeValue
}
else null

return Manifest(packageName, minSDK, targetSDK, permissions, features, libraries, exports)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,11 @@ import java.io.File

class ManifestReaderTest {

private val source = File(javaClass.getResource("/AndroidManifest.xml")!!.file)


@Test
fun `parses a manifest correctly`() {
val source = File(javaClass.getResource("/AndroidManifest.xml")!!.file)
val parsed = ManifestReader.parse(source)

assertEquals("io.github.gmazzo.android.manifest.lock.test", parsed.namespace)
Expand Down Expand Up @@ -76,4 +78,18 @@ class ManifestReaderTest {
)
}

@Test
fun `when disabled all features, parses a manifest correctly`() {
val parsed = ManifestReader.parse(
source,
readSDKVersion = false,
readPermissions = false,
readFeatures = false,
readLibraries = false,
readExports = false
)

assertEquals(Manifest(namespace = "io.github.gmazzo.android.manifest.lock.test"), parsed)
}

}

0 comments on commit 04b72f5

Please # to comment.