/src/main/java/com/atlassian/stash/unapprove/UnapproveReviewersHook.java

https://bitbucket.org/markmielke/stash-unapprove-reviewers-hook · Java · 82 lines · 57 code · 9 blank · 16 comment · 5 complexity · af2f8a2cdd850e76534f6db23891e1ab MD5 · raw file

  1. package com.atlassian.stash.unapprove;
  2. import com.atlassian.sal.api.transaction.TransactionCallback;
  3. import com.atlassian.sal.api.transaction.TransactionTemplate;
  4. import com.atlassian.stash.hook.repository.AsyncPostReceiveRepositoryHook;
  5. import com.atlassian.stash.hook.repository.RepositoryHookContext;
  6. import com.atlassian.stash.pull.*;
  7. import com.atlassian.stash.repository.RefChange;
  8. import com.atlassian.stash.repository.RefChangeType;
  9. import com.atlassian.stash.user.SecurityService;
  10. import com.atlassian.stash.util.*;
  11. import javax.annotation.Nonnull;
  12. import java.util.Collection;
  13. /**
  14. * A simple repository hook for automatically marking reviewers as unapproved when a pull request is updated.
  15. */
  16. public class UnapproveReviewersHook implements AsyncPostReceiveRepositoryHook {
  17. private static final PageRequestImpl ALL = new PageRequestImpl(0, 10000);
  18. private final PullRequestService pullRequestService;
  19. private final SecurityService securityService;
  20. private final TransactionTemplate txTemplate;
  21. public UnapproveReviewersHook(PullRequestService pullRequestService, SecurityService securityService,
  22. TransactionTemplate txTemplate) {
  23. this.pullRequestService = pullRequestService;
  24. this.securityService = securityService;
  25. this.txTemplate = txTemplate;
  26. }
  27. /**
  28. * Withdraw approval for all reviewers on any outgoing Pull Request from this repository where the source ref has
  29. * been updated.
  30. */
  31. @Override
  32. public void postReceive(@Nonnull final RepositoryHookContext hookContext, @Nonnull Collection<RefChange> refChanges) {
  33. // iterate through refs that have been updated with this push
  34. for (RefChange change : refChanges) {
  35. if (change.getType() == RefChangeType.UPDATE) {
  36. // iterate through all pull requests 'pulling' this branch into another
  37. for (final PullRequest pr : iterateOutgoingOpenPullRequests(hookContext, change)) {
  38. // batch withdrawal of approval per pull request
  39. txTemplate.execute(new TransactionCallback<Void>() {
  40. @Override
  41. public Void doInTransaction() {
  42. for (PullRequestParticipant participant : pr.getReviewers()) {
  43. // the withdrawApproval method withdraws approval for the currently authenticated user,
  44. // so use SecurityService to impersonate the reviewer we are withdrawing approval for
  45. securityService.doAsUser("Unapproving pull-request on behalf of user", participant.getUser().getName(), new Operation<Object, RuntimeException>() {
  46. @Override
  47. public Object perform() {
  48. return pullRequestService.withdrawApproval(hookContext.getRepository().getId(), pr.getId());
  49. }
  50. });
  51. }
  52. return null;
  53. }
  54. });
  55. }
  56. }
  57. }
  58. }
  59. /**
  60. * Use {@link PagedIterable} to wrap the paging behaviour of {@link PullRequestService}, giving us an exhaustive
  61. * {@link Iterable} of all open pull requests from the specified updated ref.
  62. */
  63. private Iterable<PullRequest> iterateOutgoingOpenPullRequests(final RepositoryHookContext hookContext, final RefChange change) {
  64. return new PagedIterable<PullRequest>(new PageProvider<PullRequest>() {
  65. @Override
  66. public Page<PullRequest> get(PageRequest pageRequest) {
  67. return pullRequestService.findInDirection(PullRequestDirection.OUTGOING,
  68. hookContext.getRepository().getId(), change.getRefId(), PullRequestState.OPEN, null,
  69. pageRequest);
  70. }
  71. }, ALL);
  72. }
  73. }