diff --git a/cli/BUILD b/cli/BUILD index b082b05..47d7477 100644 --- a/cli/BUILD +++ b/cli/BUILD @@ -92,6 +92,12 @@ kt_jvm_test( runtime_deps = [":cli-test-lib"], ) +kt_jvm_test( + name = "BazelRuleTest", + test_class = "com.bazel_diff.bazel.BazelRuleTest", + runtime_deps = [":cli-test-lib"], +) + kt_jvm_test( name = "E2ETest", test_class = "com.bazel_diff.e2e.E2ETest", 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 1957738..069fdff 100644 --- a/cli/src/main/kotlin/com/bazel_diff/bazel/BazelRule.kt +++ b/cli/src/main/kotlin/com/bazel_diff/bazel/BazelRule.kt @@ -4,6 +4,11 @@ import com.bazel_diff.hash.safePutBytes import com.bazel_diff.hash.sha256 import com.google.devtools.build.lib.query2.proto.proto2api.Build +// Ignore generator_location when computing a target's hash since it is likely to change and does not +// affect a target's generated actions. Internally, Bazel also does this when computing a target's hash: +// https://github.com/bazelbuild/bazel/blob/6971b016f1e258e3bb567a0f9fe7a88ad565d8f2/src/main/java/com/google/devtools/build/lib/query2/query/output/SyntheticAttributeHashCalculator.java#L78-L81 +private val IGNORED_ATTRS = arrayOf("generator_location") + class BazelRule(private val rule: Build.Rule) { val digest: ByteArray by lazy { sha256 { @@ -11,7 +16,8 @@ class BazelRule(private val rule: Build.Rule) { safePutBytes(rule.nameBytes.toByteArray()) safePutBytes(rule.skylarkEnvironmentHashCodeBytes.toByteArray()) for (attribute in rule.attributeList) { - safePutBytes(attribute.toByteArray()) + if (!IGNORED_ATTRS.contains(attribute.name)) + safePutBytes(attribute.toByteArray()) } } } diff --git a/cli/src/test/kotlin/com/bazel_diff/bazel/BazelRuleTest.kt b/cli/src/test/kotlin/com/bazel_diff/bazel/BazelRuleTest.kt new file mode 100644 index 0000000..85b2233 --- /dev/null +++ b/cli/src/test/kotlin/com/bazel_diff/bazel/BazelRuleTest.kt @@ -0,0 +1,46 @@ +package com.bazel_diff.bazel + +import assertk.assertThat +import assertk.assertions.isEqualTo +import assertk.assertions.isNotEqualTo +import com.google.devtools.build.lib.query2.proto.proto2api.Build.Rule +import com.google.devtools.build.lib.query2.proto.proto2api.Build.Attribute +import org.junit.Test + +class BazelRuleTest { + @Test + fun testHashDiffers() { + val rule1Pb = Rule.newBuilder() + .setRuleClass("java_library") + .setName("libfoo") + .build() + + val rule2Pb = Rule.newBuilder() + .setRuleClass("java_library") + .setName("libbar") + .build() + assertThat(BazelRule(rule1Pb).digest).isNotEqualTo(BazelRule(rule2Pb).digest) + } + @Test + fun testIgnoreAttributes() { + val rule1Pb = Rule.newBuilder() + .setRuleClass("java_library") + .setName("foo_library") + .addAttribute(0, Attribute.newBuilder() + .setType(Attribute.Discriminator.STRING) + .setName("generator_location") + .setStringValue("path/to/BUILD:107:12").build()) + .build() + + val rule2Pb = Rule.newBuilder() + .setRuleClass("java_library") + .setName("foo_library") + .addAttribute(0, Attribute.newBuilder() + .setType(Attribute.Discriminator.STRING) + .setName("generator_location") + .setStringValue("path/to/BUILD:111:1").build()) + .build() + + assertThat(BazelRule(rule1Pb).digest).isEqualTo(BazelRule(rule2Pb).digest) + } +} \ No newline at end of file