-
-
Save tinder-maxwellelliott/f223d4892e27d43a95038da5af4a4294 to your computer and use it in GitHub Desktop.
A pseudo code example of an approach to doing Bazel Target Diffing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
func main() { | |
// convertToBazelSourceTargets should take a filepath in your repo and return a bazel source target path | |
// Use bazel query to do this | |
let modifiedFileSourceTargets = convertToBazelSourceTargets(system("git diff --name-only HEAD^ HEAD")) | |
let initialTargetShas = createTargetShas() | |
system("git checkout HEAD^") | |
let finalTargetShas = createTargetShas() | |
system("git checkout -") | |
var modifiedTargets: [String] = [] | |
for target, value in finalTargetShas { | |
if initialTargetShas[target] != value || initialTargetShas[target] == nil { | |
modifiedTargets.append(target) | |
} | |
} | |
var targetsToTest: Set<String> = .init() | |
for modifiedTarget in modifiedTargets { | |
// queryRDepsForTarget: Run a bazel rdeps query on the target and return an array of targets | |
targetsToTest = targetsToTest.union(queryRDepsForTarget(modifiedTarget)) | |
} | |
let query = targetsToTest.joined(" ") | |
system("bazel test \(query)") | |
} | |
private func createTargetShas(modifiedFileSourceTargets: [String]) -> [String: String] { | |
let protoFileName = UUID() + ".proto" | |
let queryCommand = "bazel query \"'//external:all-targets' + '//...:all-targets'\" --output proto > \(protoFileName)" | |
system(queryCommand) | |
// You will need Proto models for this, find them here https://github.com/bazelbuild/bazel/blob/master/src/main/protobuf/build.proto | |
let bazelQuery = BlazeQuery_Rule(serializedData: Data(protoFileName)) | |
var targetShas[String: String] = [:] | |
let targets = bazelQuery.targets.filter{ $0.hasRule } | |
for target in targets { | |
targetShas[target.rule.name] = createShaForRule(target.rule, | |
modifiedFileSourceTargets: modifiedFileSourceTargets).hexString | |
} | |
defer { system("rm \(protoFileName)") } | |
return targetShas | |
} | |
private func createShaForRule(rule: Blaze_Rule, | |
modifiedFileSourceTargets: [String]) -> SHA256.Digest { | |
var sha: SHA256 = .init() | |
sha.update(rule.ruleClass.data(using: .utf8)) | |
sha.update(rule.name.data(using: .utf8)) | |
sha.update(rule.skylarkEnvironmentHashCode.data(using: .utf8)) | |
for attribute in rule.attribute { | |
sha.update(attribute.serializedData) | |
} | |
for ruleInput in rule.ruleInputs { | |
// Use hashmaps to implement isRule | |
if ruleInput.isRule { | |
sha.update(createShaForRule(rule: ruleInput).asData) | |
} else if let modifiedPath = modifiedFileSourceTargets.first?(ruleInput) { | |
// RuleInputs always contain the set of source file targets needed for a rule, we will | |
// use this to cross reference the modified files from Git and read the data to create | |
// Shas for the modified file targets | |
sha.update(Data(modifiedPath)) | |
} | |
} | |
sha.finalize() | |
} |
Thanks for posting this. I've only taken a quick look through the code (and don't know Swift), but I'm wondering if this supports the case where a file/target has been deleted and thus won't match to anything in a
bazel query
?
Yes this will work for files that are deleted or moved, I just tested it now
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Thanks for posting this. I've only taken a quick look through the code (and don't know Swift), but I'm wondering if this supports the case where a file/target has been deleted and thus won't match to anything in a
bazel query
?