1 /*
  2  * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved.
  3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  4  *
  5  * This code is free software; you can redistribute it and/or modify it
  6  * under the terms of the GNU General Public License version 2 only, as
  7  * published by the Free Software Foundation.
  8  *
  9  * This code is distributed in the hope that it will be useful, but WITHOUT
 10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 11  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 12  * version 2 for more details (a copy is included in the LICENSE file that
 13  * accompanied this code).
 14  *
 15  * You should have received a copy of the GNU General Public License version
 16  * 2 along with this work; if not, write to the Free Software Foundation,
 17  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
 18  *
 19  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
 20  * or visit www.oracle.com if you need additional information or have any
 21  * questions.
 22  */
 23 package org.openjdk.skara.bots.bridgekeeper;
 24 
 25 import org.openjdk.skara.bot.*;
 26 import org.openjdk.skara.forge.*;
 27 
 28 import java.nio.file.Path;
 29 import java.util.*;
 30 import java.util.function.Consumer;
 31 import java.util.logging.Logger;
 32 
 33 class BridgekeeperWorkItem implements WorkItem {
 34     private final Logger log = Logger.getLogger("org.openjdk.skara.bots");;
 35     private final HostedRepository repository;
 36     private final PullRequest pr;
 37     private final Consumer<RuntimeException> errorHandler;
 38 
 39     BridgekeeperWorkItem(HostedRepository repository, PullRequest pr, Consumer<RuntimeException> errorHandler) {
 40         this.pr = pr;
 41         this.repository = repository;
 42         this.errorHandler = errorHandler;
 43     }
 44 
 45     private final String welcomeMarker = "<!-- BridgeKeeperBot welcome message -->";
 46 
 47     private void checkWelcomeMessage() {
 48         log.info("Checking welcome message of " + pr);
 49 
 50         var comments = pr.comments();
 51         var welcomePosted = comments.stream()
 52                                     .anyMatch(comment -> comment.body().contains(welcomeMarker));
 53 
 54         if (!welcomePosted) {
 55             var message = "Welcome to the OpenJDK organization on GitHub!\n\n" +
 56                     "This repository is currently a read-only git mirror of the official Mercurial " +
 57                     "repository (located at https://hg.openjdk.java.net/). As such, we are not " +
 58                     "currently accepting pull requests here. If you would like to contribute to " +
 59                     "the OpenJDK project, please see http://openjdk.java.net/contribute/ on how " +
 60                     "to proceed.\n\n" +
 61                     "This pull request will be automatically closed.";
 62 
 63             log.fine("Posting welcome message");
 64             pr.addComment(welcomeMarker + "\n\n" + message);
 65         }
 66         pr.setState(PullRequest.State.CLOSED);
 67     }
 68 
 69 
 70     @Override
 71     public boolean concurrentWith(WorkItem other) {
 72         if (!(other instanceof BridgekeeperWorkItem)) {
 73             return true;
 74         }
 75         BridgekeeperWorkItem otherItem = (BridgekeeperWorkItem)other;
 76         if (!pr.id().equals(otherItem.pr.id())) {
 77             return true;
 78         }
 79         if (!repository.name().equals(otherItem.repository.name())) {
 80             return true;
 81         }
 82         return false;
 83     }
 84 
 85     @Override
 86     public void run(Path scratchPath) {
 87         checkWelcomeMessage();
 88     }
 89 
 90     @Override
 91     public void handleRuntimeException(RuntimeException e) {
 92         errorHandler.accept(e);
 93     }
 94 }
 95 
 96 public class BridgekeeperBot implements Bot {
 97     private final HostedRepository remoteRepo;
 98     private final PullRequestUpdateCache updateCache;
 99 
100     BridgekeeperBot(HostedRepository repo) {
101         this.remoteRepo = repo;
102         this.updateCache = new PullRequestUpdateCache();
103     }
104 
105     @Override
106     public List<WorkItem> getPeriodicItems() {
107         List<WorkItem> ret = new LinkedList<>();
108 
109         for (var pr : remoteRepo.pullRequests()) {
110             if (updateCache.needsUpdate(pr)) {
111                 var item = new BridgekeeperWorkItem(remoteRepo, pr, e -> updateCache.invalidate(pr));
112                 ret.add(item);
113             }
114         }
115 
116         return ret;
117     }
118 }