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.notify;
 24 
 25 import org.openjdk.skara.bot.*;
 26 import org.openjdk.skara.email.EmailAddress;
 27 import org.openjdk.skara.network.URIBuilder;
 28 import org.openjdk.skara.json.JSONObject;
 29 import org.openjdk.skara.mailinglist.MailingListServerFactory;
 30 import org.openjdk.skara.storage.StorageBuilder;
 31 import org.openjdk.skara.vcs.Tag;
 32 
 33 import java.nio.file.Path;
 34 import java.time.Duration;
 35 import java.util.*;
 36 import java.util.logging.Logger;
 37 import java.util.regex.Pattern;
 38 import java.util.stream.Collectors;
 39 
 40 public class JNotifyBotFactory implements BotFactory {
 41     private final Logger log = Logger.getLogger("org.openjdk.skara.bots");;
 42 
 43     @Override
 44     public String name() {
 45         return "notify";
 46     }
 47 
 48     @Override
 49     public List<Bot> create(BotConfiguration configuration) {
 50         var ret = new ArrayList<Bot>();
 51         var specific = configuration.specific();
 52 
 53         var database = specific.get("database").asObject();
 54         var databaseRepo = configuration.repository(database.get("repository").asString());
 55         var databaseRef = configuration.repositoryRef(database.get("repository").asString());
 56         var databaseName = database.get("name").asString();
 57         var databaseEmail = database.get("email").asString();
 58 
 59         for (var repo : specific.get("repositories").fields()) {
 60             var repoName = repo.name();
 61             var branchPattern = Pattern.compile("^master$");
 62             if (repo.value().contains("branches")) {
 63                 branchPattern = Pattern.compile(repo.value().get("branches").asString());
 64             }
 65 
 66             var includeBranchNames = false;
 67             if (repo.value().contains("branchnames")) {
 68                 includeBranchNames = repo.value().get("branchnames").asBoolean();
 69             }
 70 
 71             var updaters = new ArrayList<UpdateConsumer>();
 72             if (repo.value().contains("json")) {
 73                 var folder = repo.value().get("folder").asString();
 74                 var build = repo.value().get("build").asString();
 75                 var version = repo.value().get("version").asString();
 76                 updaters.add(new JsonUpdater(Path.of(folder), version, build));
 77             }
 78             if (repo.value().contains("mailinglists")) {
 79                 var email = specific.get("email").asObject();
 80                 var smtp = email.get("smtp").asString();
 81                 var sender = EmailAddress.parse(email.get("sender").asString());
 82                 var archive = URIBuilder.base(email.get("archive").asString()).build();
 83                 var interval = email.contains("interval") ? Duration.parse(email.get("interval").asString()) : Duration.ofSeconds(1);
 84                 var listServer = MailingListServerFactory.createMailmanServer(archive, smtp, interval);
 85 
 86                 for (var mailinglist : repo.value().get("mailinglists").asArray()) {
 87                     var recipient = mailinglist.get("recipient").asString();
 88                     var recipientAddress = EmailAddress.parse(recipient);
 89 
 90                     var mode = MailingListUpdater.Mode.ALL;
 91                     if (mailinglist.contains("mode")) {
 92                         switch (mailinglist.get("mode").asString()) {
 93                             case "pr":
 94                                 mode = MailingListUpdater.Mode.PR;
 95                                 break;
 96                             case "pr-only":
 97                                 mode = MailingListUpdater.Mode.PR_ONLY;
 98                                 break;
 99                             default:
100                                 throw new RuntimeException("Unknown mode");
101                         }
102                     }
103 
104                     Map<String, String> headers = mailinglist.contains("headers") ?
105                             mailinglist.get("headers").fields().stream()
106                                        .collect(Collectors.toMap(JSONObject.Field::name, field -> field.value().asString())) :
107                             Map.of();
108                     var author = mailinglist.contains("author") ? EmailAddress.parse(mailinglist.get("author").asString()) : null;
109                     var allowedDomains = author == null ? Pattern.compile(mailinglist.get("domains").asString()) : null;
110                     updaters.add(new MailingListUpdater(listServer.getList(recipient), recipientAddress, sender, author,
111                                                         includeBranchNames, mode, headers, allowedDomains));
112                 }
113             }
114             if (repo.value().contains("issues")) {
115                 var issueProject = configuration.issueProject(repo.value().get("issues").asString());
116                 updaters.add(new IssueUpdater(issueProject));
117             }
118 
119             if (updaters.isEmpty()) {
120                 log.warning("No consumers configured for notify bot repository: " + repoName);
121                 continue;
122             }
123 
124             var baseName = repo.value().contains("basename") ? repo.value().get("basename").asString() : configuration.repositoryName(repoName);
125 
126             var tagStorageBuilder = new StorageBuilder<Tag>(baseName + ".tags.txt")
127                     .remoteRepository(databaseRepo, databaseRef, databaseName, databaseEmail, "Added tag for " + repoName);
128             var branchStorageBuilder = new StorageBuilder<ResolvedBranch>(baseName + ".branches.txt")
129                     .remoteRepository(databaseRepo, databaseRef, databaseName, databaseEmail, "Added branch hash for " + repoName);
130             var bot = new JNotifyBot(configuration.repository(repoName), configuration.storageFolder(), branchPattern, tagStorageBuilder, branchStorageBuilder, updaters);
131             ret.add(bot);
132         }
133 
134         return ret;
135     }
136 }