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.mlbridge;
24
25 import org.openjdk.skara.forge.PullRequest;
26 import org.openjdk.skara.network.URIBuilder;
27 import org.openjdk.skara.vcs.*;
28 import org.openjdk.skara.vcs.openjdk.Issue;
29
30 import java.io.*;
31 import java.net.URI;
32 import java.nio.file.Path;
33 import java.util.Optional;
34 import java.util.stream.Collectors;
35
36 class PullRequestInstance {
37 private final PullRequest pr;
38 private final Repository localRepo;
39 private final Hash targetHash;
40 private final Hash headHash;
41 private final Hash baseHash;
42 private final URI issueTracker;
43 private final String projectPrefix;
44
45 PullRequestInstance(Path localRepoPath, PullRequest pr, URI issueTracker, String projectPrefix) {
46 this.pr = pr;
47 this.issueTracker = issueTracker;
48 this.projectPrefix = projectPrefix;
49
50 // Materialize the PR's target ref
51 try {
52 var repository = pr.repository();
53 localRepo = Repository.materialize(localRepoPath, repository.url(), pr.targetRef());
54 targetHash = localRepo.fetch(repository.url(), pr.targetRef());
55 headHash = localRepo.fetch(repository.url(), pr.headHash().hex());
56 baseHash = localRepo.mergeBase(targetHash, headHash);
57 } catch (IOException e) {
58 throw new UncheckedIOException(e);
59 }
60 }
61
62 Repository localRepo() {
63 return this.localRepo;
64 }
65
66 Hash baseHash() {
67 return this.baseHash;
68 }
69
70 Hash headHash() {
71 return this.headHash;
72 }
73
74 String diffUrl() {
75 return pr.webUrl() + ".diff";
76 }
77
78 String fetchCommand() {
79 var repoUrl = pr.repository().webUrl();
80 return "git fetch " + repoUrl + " " + pr.sourceRef() + ":pull/" + pr.id();
81 }
82
83 String stats(Hash base, Hash head) {
84 try {
85 var diff = localRepo.diff(base, head);
86 var inserted = diff.added();
87 var deleted = diff.removed();
88 var modified = diff.modified();
89 var linesChanged = inserted + deleted + modified;
90 var filesChanged = diff.patches().size();
91 return String.format("%d line%s in %d file%s changed: %d ins; %d del; %d mod",
92 linesChanged,
93 linesChanged == 1 ? "" : "s",
94 filesChanged,
95 filesChanged == 1 ? "" : "s",
96 inserted,
97 deleted,
98 modified);
99 } catch (IOException e) {
100 throw new UncheckedIOException(e);
101 }
102 }
103
104 Optional<String> issueUrl() {
105 var issue = Issue.fromString(pr.title());
106 return issue.map(value -> URIBuilder.base(issueTracker).appendPath(projectPrefix + "-" + value.id()).build().toString());
107 }
108
109 @FunctionalInterface
110 interface CommitFormatter {
111 String format(Commit commit);
112 }
113
114 String formatCommitMessages(Hash first, Hash last, CommitFormatter formatter) {
115 try (var commits = localRepo().commits(first.hex() + ".." + last.hex())) {
116 return commits.stream()
117 .map(formatter::format)
118 .collect(Collectors.joining("\n"));
119 } catch (IOException e) {
120 throw new UncheckedIOException(e);
121 }
122 }
123
124 String id() {
125 return pr.id();
126 }
127
128 PullRequest pr() {
129 return pr;
130 }
131 }