Skip to content

Commit

Permalink
Merge pull request #17 from square/develop
Browse files Browse the repository at this point in the history
Release of v0.1.2
  • Loading branch information
pablobaxter committed Nov 29, 2023
2 parents 1dfb915 + 0b6ce5e commit 47b6c3b
Show file tree
Hide file tree
Showing 18 changed files with 523 additions and 42 deletions.
4 changes: 2 additions & 2 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -33,9 +33,9 @@ jobs:
- name: Setup gradle
uses: gradle/gradle-build-action@v2
- name: Build and test tooling
run: ./gradlew --no-daemon --profile --stacktrace -p tooling build test
run: ./gradlew --no-daemon --profile --stacktrace -PRELEASE_SIGNING_ENABLED=false -p tooling publishToMavenLocal build test
- name: Build and test affected-paths
run: ./gradlew --no-daemon --profile --stacktrace -p affected-paths build test
run: ./gradlew --no-daemon --profile --stacktrace -PRELEASE_SIGNING_ENABLED=false -p affected-paths publishToMavenLocal build test

env:
GRADLE_OPTS: -Dorg.gradle.parallel=true -Dorg.gradle.caching=true
6 changes: 6 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,11 @@
## Unreleased

## v0.1.2
- `affected-paths-core`, `tooling-support-*`: Add in support for composite builds being analyzed
- `affected-paths-core`: Remove filter of root project
- `affected-paths-core`: Fix improper project mapping for file changes in nested projects
- `affected-paths-core`: Allow a custom Gradle installation path to be passed in to the Gradle Tooling API

## v0.1.1
- `tooling-support`: Fix crash from `SquareProjectModelBuilder` when used on a non-Java/Android project
- `affected-paths-core`: Adds `autoInjectPlugin` flag to `CoreOptions`, which auto-injects the "com.squareup.tooling" plugin to the build
Expand Down
14 changes: 9 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
# Affected-Paths

![GitHub Workflow Status (with event)](https://img.shields.io/github/actions/workflow/status/square/affected-paths/test.yml)
![Maven Central](https://img.shields.io/maven-central/v/com.squareup.affected.paths/affected-paths-core)
![GitHub](https://img.shields.io/github/license/square/affected-paths)

Affected-Paths is a Java library that utilizes the Gradle Tooling API to parse Gradle based projects and identifies all modules affected
(directly and indirectly) given the file changes from git.

Expand Down Expand Up @@ -48,20 +52,20 @@ The affected-paths library can be found on [MavenCentral][1]:
### Gradle
Groovy
```groovy
implementation 'com.squareup.affected.paths:affected-paths-core:0.1.1'
implementation 'com.squareup.affected.paths:affected-paths-core:<<latest>>'
```

Kotlin
```kotlin
implementation("com.squareup.affected.paths:affected-paths-core:0.1.1")
implementation("com.squareup.affected.paths:affected-paths-core:<<latest>>")
```

### Maven
```xml
<dependency>
<groupId>com.squareup.affected.paths</groupId>
<artifactId>affected-paths-core</artifactId>
<version>0.1.1</version>
<version>*latest*</version>
</dependency>
```

Expand Down Expand Up @@ -123,15 +127,15 @@ If the auto-inject flag is disabled, the tooling plugin will have to be applied
Gradle DSL
```groovy
plugins {
id 'com.squareup.tooling' version '0.1.1'
id 'com.squareup.tooling' version '<<latest>>'
}
```

Legacy
```groovy
buildscript {
dependencies {
classpath "com.squareup.affected.paths:tooling-support:0.1.1"
classpath "com.squareup.affected.paths:tooling-support:<<latest>>"
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -112,4 +112,18 @@ internal class BaseConfigurationOptions {
)
var autoInject: Boolean = false
internal set

@Option(
names = ["--changed-files"],
description = ["List of changed files to use instead of the Git diff"]
)
var changedFiles: List<String> = emptyList()
internal set

@Option(
names = ["--gradle-installation-path"],
description = ["Use a custom Gradle installation"]
)
var gradleInstallationPath: Path? = null
internal set
}
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,8 @@ internal fun BaseConfigurationOptions.toCoreOptions(): CoreOptions {
maxGradleMemory = maxGradleMemory,
customJvmFlags = listOf("-XX:-MaxFDLimit"),
customGradleFlags = listOf("--stacktrace"),
autoInjectPlugin = autoInject
autoInjectPlugin = autoInject,
changedFiles = changedFiles,
gradleInstallationPath = gradleInstallationPath,
)
}
1 change: 1 addition & 0 deletions affected-paths/core/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -13,4 +13,5 @@ dependencies {
implementation(libs.slf4j.api)

testImplementation(libs.kotlin.test.junit5)
testImplementation(libs.kotlinx.coroutines.test)
}
Original file line number Diff line number Diff line change
Expand Up @@ -77,14 +77,24 @@ public class CoreAnalyzer @JvmOverloads constructor(private val coreOptions: Cor
val projectsDeferred = projects?.let { CompletableDeferred(it) } ?: async(Dispatchers.IO) {
ensureActive() // In case this is cancelled before start

val projectConnector = affectedPathsApplication.koin.get<GradleConnector>()
.forProjectDirectory(rootDir.toFile())
.useBuildDistribution()
.connect()
val projectConnector = with(affectedPathsApplication.koin.get<GradleConnector>()) {
forProjectDirectory(rootDir.toFile())
if (coreOptions.gradleInstallationPath != null) {
useInstallation(coreOptions.gradleInstallationPath.toFile())
} else {
useBuildDistribution()
}
return@with connect()
}

ensureActive()

val actionExecutor = projectConnector.action(SquareBuildAction(coreOptions.allowGradleParallel))
val actionExecutor = projectConnector.action(
SquareBuildAction(
coreOptions.allowGradleParallel,
coreOptions.useIncludeBuild
)
)
actionExecutor.withCancellationToken(cancellationTokenSource.token())
actionExecutor.addArguments(coreOptions.gradleArgs)
actionExecutor.addJvmArguments(coreOptions.jvmArgs)
Expand All @@ -101,7 +111,7 @@ public class CoreAnalyzer @JvmOverloads constructor(private val coreOptions: Cor
}

val affectedResultsDeferred = async(Dispatchers.Default) {
projectsDeferred.await().findAffectedPaths(changedFilesDeferred.await())
findAffectedPaths(projectsDeferred.await(), changedFilesDeferred.await())
}

// Cancel the Gradle build if the coroutine was cancelled
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,13 @@ public data class CoreOptions @JvmOverloads constructor(
val changedFiles: List<String> = emptyList(),

/** Auto-injects the "com.squareup.tooling" plugin to all projects in the build */
val autoInjectPlugin: Boolean = true
val autoInjectPlugin: Boolean = true,

/** Include any "includeBuild" builds from the current build */
val useIncludeBuild: Boolean = true,

/** Pass in a custom Gradle installation, instead of using the build distribution */
val gradleInstallationPath: Path? = null,
) {

init {
Expand Down Expand Up @@ -97,10 +103,11 @@ public data class CoreOptions @JvmOverloads constructor(
beforeProject { project ->
project.buildscript {
repositories {
mavenLocal()
mavenCentral()
}
dependencies {
classpath "com.squareup.affected.paths:tooling-support:0.1.1"
classpath "com.squareup.affected.paths:tooling-support:0.1.2"
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,16 +29,26 @@ import kotlinx.coroutines.launch
/*
* Finds all the affected paths of the list of Square Projects with the given list of changed files
*/
internal suspend fun List<SquareProject>.findAffectedPaths(
internal suspend fun findAffectedPaths(
projectList: List<SquareProject>,
changedFiles: List<String>
): List<AffectedResult> {
return coroutineScope {
val slices = async(Dispatchers.Default) { getReverseDependencies() }
val filesToDocs = async(Dispatchers.Default) {
filesToProjects(changedFiles, associateBy { it.pathToProject })
// Separate the projects to their distinct builds
val projectsMappedToBuilds = buildMap<String, MutableList<SquareProject>> {
projectList.forEach {
val list = getOrPut(it.namespace) { arrayListOf() }
list.add(it)
}
}

return@coroutineScope findAffectedAddresses(slices.await(), filesToDocs.await())
return@coroutineScope projectsMappedToBuilds.flatMap { (_, projects) ->
val slices = async(Dispatchers.Default) { projects.getReverseDependencies() }
val filesToDocs = async(Dispatchers.Default) {
filesToProjects(changedFiles, projects.associateBy { it.pathToProject })
}
return@flatMap findAffectedAddresses(slices.await(), filesToDocs.await())
}
}
}

Expand Down Expand Up @@ -107,10 +117,11 @@ private fun filesToProjects(
val fileToDocsMap = hashMapOf<String, MutableSet<SquareProject>>()
val list = changedFiles.mapNotNull { file ->
val modulePath = arrayListOf<String>()
val doc = file.trim('/').split('/').firstNotNullOfOrNull { element ->
val docSet = file.trim('/').split('/').mapNotNull docSet@ { element ->
modulePath.add(element)
return@firstNotNullOfOrNull projects[modulePath.joinToString("/")]
} ?: return@mapNotNull null
return@docSet projects[modulePath.joinToString("/")]
}
val doc = docSet.lastOrNull() ?: return@mapNotNull null
return@mapNotNull file to doc
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,19 +36,36 @@ private class ProjectBuildAction(private val project: Model) : BuildAction<Squar
*/
internal class SquareBuildAction(
private val allowParallelConfiguration: Boolean,
private val useIncludeBuild: Boolean,
) : BuildAction<List<SquareProject>> {
override fun execute(controller: BuildController): List<SquareProject> {
// Run the ProjectBuildAction in parallel, if we can
val canRunParallel = controller.getCanQueryProjectModelInParallel(SquareProject::class.java)

// The "BuildModel" is the Gradle build after evaluating the "settings.gradle" file
val actions = controller.buildModel
.projects // All projects included in the "settings.gradle" file
.asSequence()
.filter { it.path != ":" } // Filter out the root project
.map { project ->
return@map ProjectBuildAction(project)
}.toList()
val actions = buildList {
// Include any builds along with the root build
if (useIncludeBuild) {
controller.buildModel.includedBuilds.forEach { build ->
addAll(
build.projects // All projects included in the "settings.gradle" file of all builds
.asSequence()
.map { project ->
return@map ProjectBuildAction(project)
}
)
}
}

// The "BuildModel" is the Gradle build after evaluating the "settings.gradle" file
addAll(
controller.buildModel
.projects // All projects included in the "settings.gradle" file
.asSequence()
.map { project ->
return@map ProjectBuildAction(project)
}.toList()
)
}

if (actions.isEmpty()) return emptyList()
return if (allowParallelConfiguration && canRunParallel) {
Expand Down

0 comments on commit 47b6c3b

Please sign in to comment.