)]}'
{
  "commit": "0a509d897aa02b86ae6ae98c0a64654b57cb2a8d",
  "tree": "09da5a5a1196f21f8d5f3321fbc2ae03ae247574",
  "parents": [
    "35febff8677f369c2e0f547a56545dbbf557d5cc"
  ],
  "author": {
    "name": "Antonio Barone",
    "email": "syntonyze@gmail.com",
    "time": "Tue Nov 11 19:42:46 2025 +0100"
  },
  "committer": {
    "name": "Antonio Barone",
    "email": "syntonyze@gmail.com",
    "time": "Thu Jan 08 09:57:55 2026 +0100"
  },
  "message": "Add predicate for sticky owner approvals\n\nIntroduce a new approval query operand, `already-approved-by_owners`,\nthat allows copying owner approvals across patch sets only when it is\nsafe to do so.\n\n`AlreadyApprovedByOwnerOperand` registers a `UserInOperandFactory` for\nthe new operand, and `AlreadyApprovedByOwnerPredicate` implements the\nmatching logic. When evaluating a copy condition for an approval, the\npredicate:\n\n- Computes the set of files modified between the source and target\n  patch sets using `DiffOperations`.\n- Checks whether any of the newly modified files are owned by the\n  current approver. If so, the approval is not copied and the owner\n  must re-approve.\n- If none of the newly modified files are owned by the approver, copies\n  the approval only when the approver has owned at least one file in the\n  previous patchset.\n\nTo support this, `GetFilesOwners` is extended with an `isAnyFileOwnedBy`\nhelper that computes ownership for a given set of paths, and the\nconstruction of `PathOwners` is factored into a private `getPathOwners`\nmethod reused by both the REST endpoint and the new predicate.\n\nFinally, `OwnersModule` is updated to install the new operand module so\nthat the `alreadyApprovedBy` operand is available to approval query\nexpressions.\n\nBug: Issue 458084508\nChange-Id: I1fb57d70756e1a04cae19475afe80b2a329a4d11\n",
  "tree_diff": [
    {
      "type": "add",
      "old_id": "0000000000000000000000000000000000000000",
      "old_mode": 0,
      "old_path": "/dev/null",
      "new_id": "2f90db1112aa9980ef1e580101f605f7aa4692d5",
      "new_mode": 33188,
      "new_path": "owners/src/main/java/com/googlesource/gerrit/owners/AlreadyApprovedByOperand.java"
    },
    {
      "type": "add",
      "old_id": "0000000000000000000000000000000000000000",
      "old_mode": 0,
      "old_path": "/dev/null",
      "new_id": "f7ee5b06ce956f01ba3a808a1e67115c6c876100",
      "new_mode": 33188,
      "new_path": "owners/src/main/java/com/googlesource/gerrit/owners/AlreadyApprovedByPredicate.java"
    },
    {
      "type": "modify",
      "old_id": "2d5a2b032c72319e1039e3a36cab91c5be352a02",
      "old_mode": 33188,
      "old_path": "owners/src/main/java/com/googlesource/gerrit/owners/OwnersModule.java",
      "new_id": "3e38324acbcf387d3d8595d2416244233904fe29",
      "new_mode": 33188,
      "new_path": "owners/src/main/java/com/googlesource/gerrit/owners/OwnersModule.java"
    },
    {
      "type": "modify",
      "old_id": "1327fcba1389abd831f174ec2b698a49f5968722",
      "old_mode": 33188,
      "old_path": "owners/src/main/java/com/googlesource/gerrit/owners/restapi/GetFilesOwners.java",
      "new_id": "d13e709aae8eb0843b21bab692daca04b8570220",
      "new_mode": 33188,
      "new_path": "owners/src/main/java/com/googlesource/gerrit/owners/restapi/GetFilesOwners.java"
    },
    {
      "type": "add",
      "old_id": "0000000000000000000000000000000000000000",
      "old_mode": 0,
      "old_path": "/dev/null",
      "new_id": "de970f10684499013e443966f24b9e2c7468f62d",
      "new_mode": 33188,
      "new_path": "owners/src/main/resources/Documentation/copy-conditions.md"
    },
    {
      "type": "add",
      "old_id": "0000000000000000000000000000000000000000",
      "old_mode": 0,
      "old_path": "/dev/null",
      "new_id": "0e2ea6e97ae70c36a2c1f822af96aedae81fdb13",
      "new_mode": 33188,
      "new_path": "owners/src/test/java/com/googlesource/gerrit/owners/AlreadyApprovedByCopyConditionIT.java"
    }
  ]
}
