Using the tree deltas in rules ============================== Gitano is able to use the tree deltas produced by changes in ref tips when evaluating whether or not an update is permitted. Since the tree deltas can be expensive to generate, we only trigger generation of them on demand. As such they are an area of the code where errors could easily trickle in unless we keep a close eye on things. Start and Target trees ---------------------- The first part of the treedelta support are the gitano/starttree and gitano/targetttee lists. These contain the flattened entry names for everything in the trees. First, let's look at what it takes to prevent the creation of files with FOO in. SCENARIO may not create files called FOO GIVEN a standard instance AND testinstance using adminkey has patched gitano-admin with no-create-FOO.patch GIVEN a unix user called alice AND alice has keys called main WHEN testinstance, using adminkey, adds user alice, using alice main AND testinstance adminkey runs create testrepo alice AND alice, using main, clones testrepo as testrepo THEN alice testrepo has no file called FOO WHEN alice applies add-a-FOO.patch in testrepo AND alice, using main, expecting failure, pushes testrepo to testrepo.git THEN stderr contains No FOOs allowed FINALLY the instance is torn down Next, let's look at how we might require a FOO to be present... SCENARIO source must have a FOO GIVEN a standard instance AND a unix user called alice AND alice has keys called main WHEN testinstance, using adminkey, adds user alice, using alice main AND testinstance adminkey runs create testrepo alice AND alice, using main, clones testrepo as testrepo THEN alice testrepo has no file called FOO We now have a repo which has no FOO in it, let's first check that our admin rule which requires `start_tree` contain a FOO by trying to push an empty tree GIVEN testinstance using adminkey has patched gitano-admin with must-start-with-FOO.patch WHEN alice, using main, expecting failure, pushes an empty commit in testrepo THEN stderr contains Needs a FOO Next, let's create a FOO in our tree, prove that `start_tree` != `target_tree` WHEN alice applies add-a-FOO.patch in testrepo AND alice, using main, pushes testrepo to testrepo.git THEN stderr contains Needs a FOO And if we back out the rule, we can push it... GIVEN testinstance using adminkey has patched gitano-admin with the reverse of must-start-with-FOO.patch WHEN alice, using main, pushes testrepo to testrepo.git THEN the output contains new branch And if we put the rule back in, an empty commit will make it through because `start_tree` now does contain a FOO GIVEN testinstance using adminkey has patched gitano-admin with must-start-with-FOO.patch WHEN alice, using main, pushes an empty commit in testrepo THEN the output contains master -> master And once again, prove `start_tree` != `target_tree` by backing out the FOO and proving we can push that. WHEN alice reverts add-a-FOO.patch in testrepo AND alice, using main, pushes testrepo to testrepo.git THEN the output contains master -> master And of course, now `start_tree` does not contain a FOO, so no matter what we do to `target_tree` we can't push... WHEN alice applies add-a-FOO.patch in testrepo AND alice, using main, pushes testrepo to testrepo.git THEN stderr contains Needs a FOO FINALLY the instance is torn down Tree deltas ----------- When there are trees in play, the `treediff/targets`, `treediff/added`, `treediff/deleted`, `treediff/modified`, `treediff/renamed`, and `treediff/renamedto` values end up set. The _targets_ are any name which shows up in any of _added_, _deleted_, _modified_, _renamed_, or _renamedto_. The others are, respectively, the names of new tree entries, removed tree entries, entries whose content has changed, and then rename detection logic. > Sadly currently Gitano can't tell which rename from/to is matched with which. First up, let's ensure that `treediff/targets` works for the various kinds of adding, modifying, removing, and renaming operations... SCENARIO any change must affect FOO GIVEN a standard instance AND a unix user called alice AND alice has keys called main WHEN testinstance, using adminkey, adds user alice, using alice main AND testinstance adminkey runs create testrepo alice AND alice, using main, clones testrepo as testrepo THEN alice testrepo has no file called FOO GIVEN testinstance using adminkey has patched gitano-admin with must-affect-FOO.patch First up, when we try an empty commit we can't push it... WHEN alice, using main, expecting failure, pushes an empty commit in testrepo THEN stderr contains Needs a FOO Next, when a FOO is added, it should turn up in `treediff/targets` WHEN alice applies add-a-FOO.patch in testrepo AND alice, using main, pushes testrepo to testrepo.git THEN the output contains new branch But its mere presence in `start_tree` shouldn't allow empty commits... WHEN alice, using main, expecting failure, pushes an empty commit in testrepo THEN stderr contains Needs a FOO Now we verify that altering the content turns up in `treediff/targets` WHEN alice applies change-a-FOO.patch in testrepo AND alice, using main, pushes testrepo to testrepo.git THEN the output contains master -> master Next, when the FOO gets removed, it should show in `treediff/targets` WHEN alice reverts change-a-FOO.patch in testrepo AND alice reverts add-a-FOO.patch in testrepo AND alice, using main, pushes testrepo to testrepo.git THEN the output contains master -> master Next we need to rename a FOO, to do that, first add it back... WHEN alice applies add-a-FOO.patch in testrepo AND alice, using main, pushes testrepo to testrepo.git THEN the output contains master -> master and then check that renaming the FOO causes it to turn up in `treediff/targets` WHEN alice applies rename-a-FOO.patch in testrepo AND alice, using main, pushes testrepo to testrepo.git THEN the output contains master -> master and finally we ensure that renaming it *back* works too... WHEN alice reverts rename-a-FOO.patch in testrepo AND alice, using main, pushes testrepo to testrepo.git THEN the output contains master -> master FINALLY the instance is torn down Now that we know that `treediff/targets` works in all cases, we ensure that the particular `treediff/*` element is also populated for the given activity SCENARIO any change must affect FOO with specificity GIVEN a standard instance AND a unix user called alice AND alice has keys called main WHEN testinstance, using adminkey, adds user alice, using alice main AND testinstance adminkey runs create testrepo alice AND alice, using main, clones testrepo as testrepo THEN alice testrepo has no file called FOO GIVEN testinstance using adminkey has patched gitano-admin with must-add-FOO.patch First up, when we try an empty commit we can't push it... WHEN alice, using main, expecting failure, pushes an empty commit in testrepo THEN stderr contains Needs a FOO Next, when a FOO is added, it should turn up in `treediff/added` WHEN alice applies add-a-FOO.patch in testrepo AND alice, using main, pushes testrepo to testrepo.git THEN the output contains new branch But its mere presence in `start_tree` shouldn't allow empty commits... WHEN alice, using main, expecting failure, pushes an empty commit in testrepo THEN stderr contains Needs a FOO Now we verify that altering the content turns up in `treediff/modified` GIVEN testinstance using adminkey has patched gitano-admin with the reverse of must-add-FOO.patch AND testinstance using adminkey has patched gitano-admin with must-modify-FOO.patch WHEN alice applies change-a-FOO.patch in testrepo AND alice, using main, pushes testrepo to testrepo.git THEN the output contains master -> master Next, when the FOO gets removed, it should show in `treediff/deleted` GIVEN testinstance using adminkey has patched gitano-admin with the reverse of must-modify-FOO.patch AND testinstance using adminkey has patched gitano-admin with must-remove-FOO.patch WHEN alice reverts change-a-FOO.patch in testrepo AND alice reverts add-a-FOO.patch in testrepo AND alice, using main, pushes testrepo to testrepo.git THEN the output contains master -> master Next we need to rename a FOO, to do that, first add it back... GIVEN testinstance using adminkey has patched gitano-admin with the reverse of must-remove-FOO.patch WHEN alice applies add-a-FOO.patch in testrepo AND alice, using main, pushes testrepo to testrepo.git THEN the output contains master -> master and then check that renaming the FOO causes it to turn up in `treediff/renamed` GIVEN testinstance using adminkey has patched gitano-admin with must-rename-from-FOO.patch WHEN alice applies rename-a-FOO.patch in testrepo AND alice, using main, pushes testrepo to testrepo.git THEN the output contains master -> master and finally we ensure that renaming it *back* works too... GIVEN testinstance using adminkey has patched gitano-admin with the reverse of must-rename-from-FOO.patch AND testinstance using adminkey has patched gitano-admin with must-rename-to-FOO.patch WHEN alice reverts rename-a-FOO.patch in testrepo AND alice, using main, pushes testrepo to testrepo.git THEN the output contains master -> master FINALLY the instance is torn down