diff --git a/MODULE.bazel.lock b/MODULE.bazel.lock index 94d5605..60b8394 100644 --- a/MODULE.bazel.lock +++ b/MODULE.bazel.lock @@ -127,7 +127,7 @@ "@@rules_jvm_external~//:extensions.bzl%maven": { "general": { "bzlTransitiveDigest": "aME0tyUxYd+PGhICmzT9zEnIgZNf05hZhsfDD5v0JXM=", - "usagesDigest": "+dpflq+TpnHw1wMaSLFQaN4wOlDKqv7WllhW2Ba0Eg0=", + "usagesDigest": "RiESu1RzypJ/tRsAUBEwT8uAvAL02bjB08j6rSK2pT8=", "recordedFileInputs": { "@@rules_jvm_external~//rules_jvm_external_deps_install.json": "cafb5d2d8119391eb2b322ce3840d3352ea82d496bdb8cbd4b6779ec4d044dda", "@@//maven_install.json": "8ab3e635bbd52fcff5900e530933fbdc41c45d1d5b2a2aef8af1becf7a7d0784" diff --git a/README.md b/README.md index c7bb1ca..916f111 100644 --- a/README.md +++ b/README.md @@ -143,7 +143,10 @@ workspace. targets. For example, one wants to specify `maven` here if they user rules_jvm_external so that individual third party dependency change won't - invalidate all targets in the mono repo. + invalidate all targets in the mono repo. Note that + when `--useCquery` is used, the canonical repo name + must be provided but with single `@`, e.g. + `@rules_jvm_external~~maven~maven` -h, --help Show this help message and exit. --ignoredRuleHashingAttributes= Attributes that should be ignored when hashing rule diff --git a/cli/src/main/kotlin/com/bazel_diff/bazel/BazelQueryService.kt b/cli/src/main/kotlin/com/bazel_diff/bazel/BazelQueryService.kt index f240136..39bf49d 100644 --- a/cli/src/main/kotlin/com/bazel_diff/bazel/BazelQueryService.kt +++ b/cli/src/main/kotlin/com/bazel_diff/bazel/BazelQueryService.kt @@ -45,7 +45,7 @@ class BazelQueryService( val targets = outputFile.inputStream().buffered().use { proto -> if (useCquery) { val cqueryResult = AnalysisProtosV2.CqueryResult.parseFrom(proto) - cqueryResult.resultsList.filter { inCompatibleTargetSet(it, compatibleTargetSet) }.map { it.target } + cqueryResult.resultsList.filter { it.target.rule.name in compatibleTargetSet }.map { it.target } } else { mutableListOf().apply { while (true) { @@ -60,15 +60,6 @@ class BazelQueryService( return targets } - private fun inCompatibleTargetSet( - target: AnalysisProtosV2.ConfiguredTarget, - compatibleTargetSet: Set - ): Boolean { - val name = target.target.rule.name - return name in compatibleTargetSet || - name.startsWith("@") && !name.startsWith("@@") && "@${name}" in compatibleTargetSet - } - @OptIn(ExperimentalCoroutinesApi::class) private suspend fun runQuery( query: String, @@ -111,13 +102,7 @@ class BazelQueryService( # printed return "" if "IncompatiblePlatformProvider" not in providers(target): - label = str(target.label) - # normalize label to be consistent with content inside proto - if label.startswith("@//"): - return label[1:] - if label.startswith("@@//"): - return label[2:] - return label + return str(target.label) return "" """.trimIndent()) add(cqueryOutputFile.toString()) @@ -137,6 +122,7 @@ class BazelQueryService( } if (useCquery) { addAll(cqueryOptions) + add("--consistent_labels") } else { addAll(commandOptions) } diff --git a/cli/src/main/kotlin/com/bazel_diff/bazel/BazelRule.kt b/cli/src/main/kotlin/com/bazel_diff/bazel/BazelRule.kt index 3ef015a..6ed2ccc 100644 --- a/cli/src/main/kotlin/com/bazel_diff/bazel/BazelRule.kt +++ b/cli/src/main/kotlin/com/bazel_diff/bazel/BazelRule.kt @@ -37,7 +37,7 @@ class BazelRule(private val rule: Build.Rule) { val name: String = rule.name private fun transformRuleInput(fineGrainedHashExternalRepos: Set, ruleInput: String): String { - if (ruleInput.startsWith("@") && fineGrainedHashExternalRepos.none { ruleInput.startsWith("@$it") || ruleInput.startsWith("@@${it}") }) { + if (isNotMainRepo(ruleInput) && ruleInput.startsWith("@") && fineGrainedHashExternalRepos.none { ruleInput.startsWith("@$it") || ruleInput.startsWith("@@${it}") }) { val splitRule = ruleInput.split("//".toRegex()).dropLastWhile { it.isEmpty() }.toTypedArray() if (splitRule.size == 2) { var externalRule = splitRule[0] @@ -47,4 +47,8 @@ class BazelRule(private val rule: Build.Rule) { } return ruleInput } + + private fun isNotMainRepo(ruleInput: String): Boolean { + return !ruleInput.startsWith("//") && !ruleInput.startsWith("@//") && !ruleInput.startsWith("@@//") + } } diff --git a/cli/src/main/kotlin/com/bazel_diff/hash/SourceFileHasher.kt b/cli/src/main/kotlin/com/bazel_diff/hash/SourceFileHasher.kt index e988af7..c26c8e6 100644 --- a/cli/src/main/kotlin/com/bazel_diff/hash/SourceFileHasher.kt +++ b/cli/src/main/kotlin/com/bazel_diff/hash/SourceFileHasher.kt @@ -44,8 +44,9 @@ class SourceFileHasher : KoinComponent { ): ByteArray { return sha256 { val name = sourceFileTarget.name - val filenamePath = if (name.startsWith("//")) { - val filenameSubstring = name.substring(2) + val index = isMainRepo(name); + val filenamePath = if (index != -1) { + val filenameSubstring = name.substring(index) Paths.get(filenameSubstring.removePrefix(":").replace(':', '/')) } else if (name.startsWith("@")) { val parts = if (name.startsWith("@@")) { @@ -95,9 +96,10 @@ class SourceFileHasher : KoinComponent { fun softDigest(sourceFileTarget: BazelSourceFileTarget, modifiedFilepaths: Set = emptySet()): ByteArray? { val name = sourceFileTarget.name - if (!name.startsWith("//")) return null + val index = isMainRepo(name) + if (index == -1) return null - val filenameSubstring = name.substring(2) + val filenameSubstring = name.substring(index) val filenamePath = filenameSubstring.replaceFirst(":".toRegex(), "/") val absoluteFilePath = Paths.get(workingDirectory.toString(), filenamePath) val file = absoluteFilePath.toFile() @@ -105,4 +107,17 @@ class SourceFileHasher : KoinComponent { return digest(sourceFileTarget, modifiedFilepaths) } + + private fun isMainRepo(name: String): Int { + if (name.startsWith("//")) { + return 2; + } + if (name.startsWith("@//")) { + return 3; + } + if (name.startsWith("@@//")) { + return 4; + } + return -1; + } } diff --git a/cli/src/test/kotlin/com/bazel_diff/e2e/E2ETest.kt b/cli/src/test/kotlin/com/bazel_diff/e2e/E2ETest.kt index 7dbfcad..042940e 100644 --- a/cli/src/test/kotlin/com/bazel_diff/e2e/E2ETest.kt +++ b/cli/src/test/kotlin/com/bazel_diff/e2e/E2ETest.kt @@ -123,8 +123,7 @@ class E2ETest { assertThat(actual).isEqualTo(expected) } - @Test - fun testFineGrainedHashBzlMod() { + private fun testFineGrainedHashBzlMod(extraGenerateHashesArgs: List, fineGrainedHashExternalRepo: String, expectedResultFile: String) { // The difference between these two snapshots is simply upgrading the Guava version. // Following is the diff. (The diff on maven_install.json is omitted) // @@ -161,11 +160,11 @@ class E2ETest { val cli = CommandLine(BazelDiff()) //From cli.execute( - "generate-hashes", "-w", workingDirectoryA.absolutePath, "-b", bazelPath, "--fineGrainedHashExternalRepos", "bazel_diff_maven", from.absolutePath + listOf("generate-hashes", "-w", workingDirectoryA.absolutePath, "-b", bazelPath, "--fineGrainedHashExternalRepos", fineGrainedHashExternalRepo, from.absolutePath) + extraGenerateHashesArgs ) //To cli.execute( - "generate-hashes", "-w", workingDirectoryB.absolutePath, "-b", bazelPath, "--fineGrainedHashExternalRepos", "bazel_diff_maven", to.absolutePath + listOf("generate-hashes", "-w", workingDirectoryB.absolutePath, "-b", bazelPath, "--fineGrainedHashExternalRepos", fineGrainedHashExternalRepo, to.absolutePath) + extraGenerateHashesArgs ) //Impacted targets cli.execute( @@ -174,11 +173,21 @@ class E2ETest { val actual: Set = impactedTargetsOutput.readLines().filter { it.isNotBlank() }.toSet() val expected: Set = - javaClass.getResourceAsStream("/fixture/fine-grained-hash-bzlmod-test-impacted-targets.txt").use { it.bufferedReader().readLines().filter { it.isNotBlank() }.toSet() } + javaClass.getResourceAsStream(expectedResultFile).use { it.bufferedReader().readLines().filter { it.isNotBlank() }.toSet() } assertThat(actual).isEqualTo(expected) } + @Test + fun testFineGrainedHashBzlMod() { + testFineGrainedHashBzlMod(emptyList(), "bazel_diff_maven", "/fixture/fine-grained-hash-bzlmod-test-impacted-targets.txt") + } + + @Test + fun testFineGrainedHashBzlModCquery() { + testFineGrainedHashBzlMod(listOf("--useCquery"), "@rules_jvm_external~~maven~maven", "/fixture/fine-grained-hash-bzlmod-cquery-test-impacted-targets.txt") + } + // TODO: re-enable the test after https://github.com/bazelbuild/bazel/issues/21010 is fixed @Ignore("cquery mode is broken with Bazel 7 because --transition=lite is crashes due to https://github.com/bazelbuild/bazel/issues/21010") @Test diff --git a/cli/src/test/resources/fixture/fine-grained-hash-bzlmod-cquery-test-impacted-targets.txt b/cli/src/test/resources/fixture/fine-grained-hash-bzlmod-cquery-test-impacted-targets.txt new file mode 100644 index 0000000..4632b12 --- /dev/null +++ b/cli/src/test/resources/fixture/fine-grained-hash-bzlmod-cquery-test-impacted-targets.txt @@ -0,0 +1,13 @@ +@@//src/main/java/com/integration:guava-user +@@rules_jvm_external~~maven~com_google_errorprone_error_prone_annotations_2_18_0//file:file +@@rules_jvm_external~~maven~com_google_guava_guava_32_0_0_jre//file:file +@@rules_jvm_external~~maven~com_google_j2objc_j2objc_annotations_2_8//file:file +@@rules_jvm_external~~maven~maven//:com_google_errorprone_error_prone_annotations +@@rules_jvm_external~~maven~maven//:com_google_errorprone_error_prone_annotations_2_18_0_extension +@@rules_jvm_external~~maven~maven//:com_google_guava_guava +@@rules_jvm_external~~maven~maven//:com_google_guava_guava_32_0_0_jre_extension +@@rules_jvm_external~~maven~maven//:com_google_j2objc_j2objc_annotations +@@rules_jvm_external~~maven~maven//:com_google_j2objc_j2objc_annotations_2_8_extension +@@rules_jvm_external~~maven~maven//:org_checkerframework_checker_qual +@@rules_jvm_external~~maven~maven//:org_checkerframework_checker_qual_3_33_0_extension +@@rules_jvm_external~~maven~org_checkerframework_checker_qual_3_33_0//file:file diff --git a/cli/src/test/resources/fixture/fine-grained-hash-bzlmod-test-1.zip b/cli/src/test/resources/fixture/fine-grained-hash-bzlmod-test-1.zip index f96c205..bfecb4d 100644 Binary files a/cli/src/test/resources/fixture/fine-grained-hash-bzlmod-test-1.zip and b/cli/src/test/resources/fixture/fine-grained-hash-bzlmod-test-1.zip differ diff --git a/cli/src/test/resources/fixture/fine-grained-hash-bzlmod-test-2.zip b/cli/src/test/resources/fixture/fine-grained-hash-bzlmod-test-2.zip index d1d025c..0d66ae6 100644 Binary files a/cli/src/test/resources/fixture/fine-grained-hash-bzlmod-test-2.zip and b/cli/src/test/resources/fixture/fine-grained-hash-bzlmod-test-2.zip differ