-
Notifications
You must be signed in to change notification settings - Fork 45
/
GitHubPullRequestSender.java
131 lines (122 loc) · 7.04 KB
/
GitHubPullRequestSender.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
package com.salesforce.dockerfileimageupdate.process;
import com.google.common.collect.HashMultimap;
import com.google.common.collect.Multimap;
import com.salesforce.dockerfileimageupdate.model.GitForkBranch;
import com.salesforce.dockerfileimageupdate.model.GitHubContentToProcess;
import com.salesforce.dockerfileimageupdate.model.ShouldForkResult;
import com.salesforce.dockerfileimageupdate.utils.DockerfileGitHubUtil;
import java.util.regex.Pattern;
import org.kohsuke.github.GHContent;
import org.kohsuke.github.GHRepository;
import org.kohsuke.github.PagedSearchIterable;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.IOException;
import java.util.Optional;
public class GitHubPullRequestSender {
private static final Logger log = LoggerFactory.getLogger(GitHubPullRequestSender.class);
public static final String REPO_IS_FORK = "it's a fork already. Sending a PR to a fork is unsupported at the moment.";
private final DockerfileGitHubUtil dockerfileGitHubUtil;
private final ForkableRepoValidator forkableRepoValidator;
private final Pattern excludes;
public GitHubPullRequestSender(DockerfileGitHubUtil dockerfileGitHubUtil, ForkableRepoValidator forkableRepoValidator, String excludes) {
this.dockerfileGitHubUtil = dockerfileGitHubUtil;
this.forkableRepoValidator = forkableRepoValidator;
this.excludes = excludes == null ? null : Pattern.compile(excludes);
}
/* There is a separation here with forking and performing the Dockerfile update. This is because of the delay
* on Github, where after the fork, there may be a time gap between repository creation and content replication
* when forking. So, in hopes of alleviating the situation a little bit, we do all the forking before the
* Dockerfile updates.
*
* NOTE: We are not currently forking repositories that are already forks
*/
public Multimap<String, GitHubContentToProcess> forkRepositoriesFoundAndGetPathToDockerfiles(
PagedSearchIterable<GHContent> contentsWithImage,
GitForkBranch gitForkBranch) {
log.info("Forking repositories...");
Multimap<String, GitHubContentToProcess> pathToDockerfilesInParentRepo = HashMultimap.create();
GHRepository parent;
String parentRepoName;
int totalContentsFound = 0;
int contentsShouldFork = 0;
for (GHContent ghContent : contentsWithImage) {
/* Kohsuke's GitHub API library, when retrieving the forked repository, looks at the name of the parent to
* retrieve. The issue with that is: GitHub, when forking two or more repositories with the same name,
* automatically fixes the names to be unique (by appending "-#" to the end). Because of this edge case, we
* cannot save the forks and iterate over the repositories; else, we end up missing/not updating the
* repositories that were automatically fixed by GitHub. Instead, we save the names of the parent repos
* in the map above, find the list of repositories under the authorized user, and iterate through that list.
*/
totalContentsFound++;
parent = ghContent.getOwner();
parentRepoName = parent.getFullName();
if (excludes != null && excludes.matcher(parent.getName()).matches()) {
log.info("Skipping repository {} as its name ({}) matches the excludes regex",
parentRepoName, parent.getName());
continue;
}
// Refresh the repo to ensure that the object has full details
try {
parent = dockerfileGitHubUtil.getRepo(parentRepoName);
ShouldForkResult shouldForkResult = forkableRepoValidator.shouldFork(parent, ghContent, gitForkBranch);
if (shouldForkResult.isForkable()) {
contentsShouldFork++;
// fork the parent if not already forked
ensureForkedAndAddToListForProcessing(pathToDockerfilesInParentRepo, parent, parentRepoName, ghContent);
} else {
log.warn("Skipping {} because {}", parentRepoName, shouldForkResult.getReason());
}
} catch (IOException exception) {
log.warn("Could not refresh details of {}", parentRepoName);
}
}
log.info("Out of {} content search results processed, {} were deemed eligible for forking to yield {} repositories to fork.",
totalContentsFound, contentsShouldFork, pathToDockerfilesInParentRepo.keys().size());
log.info("Path to files in repos: {}", pathToDockerfilesInParentRepo);
return pathToDockerfilesInParentRepo;
}
/**
* Ensure that we have forked this repository if it hasn't already been forked and add the content for processing
*
* @param pathToDockerfilesInParentRepo multimap for current and later processing
* @param parent the actual parent repo with content
* @param parentRepoName the name of the parent repo
* @param ghContent the content that was found which should have this image
*/
private void ensureForkedAndAddToListForProcessing(Multimap<String, GitHubContentToProcess> pathToDockerfilesInParentRepo,
GHRepository parent,
String parentRepoName,
GHContent ghContent) {
GHRepository fork = getForkFromExistingRecordToProcess(pathToDockerfilesInParentRepo, parentRepoName);
if (fork == null) {
log.info("Getting or creating fork: {}", parentRepoName);
fork = dockerfileGitHubUtil.getOrCreateFork(parent);
}
// Add repos to pathToDockerfilesInParentRepo only if we forked it successfully.
if (fork == null) {
log.info("Could not fork {}", parentRepoName);
} else {
pathToDockerfilesInParentRepo.put(parentRepoName, new GitHubContentToProcess(fork, parent, ghContent.getPath()));
}
}
/**
* If there's an existing record, return the fork from that.
*
* @param pathToDockerfilesInParentRepo processing multimap
* @param parentRepoName name of parent repo to find
* @return {@code GHRepository} return the fork from existing record
*/
protected GHRepository getForkFromExistingRecordToProcess(Multimap<String, GitHubContentToProcess> pathToDockerfilesInParentRepo,
String parentRepoName) {
if (pathToDockerfilesInParentRepo.containsKey(parentRepoName)) {
Optional<GitHubContentToProcess> firstForkData = pathToDockerfilesInParentRepo.get(parentRepoName).stream().findFirst();
if (firstForkData.isPresent()) {
return firstForkData.get().getFork();
} else {
log.warn("For some reason we have data inconsistency when trying to find the fork for {}", parentRepoName);
}
}
return null;
}
}