Added API to get data from GitHub's Web API

This took me quite a long time, but I did it!
This commit is contained in:
Florian CUNY 2019-02-12 15:34:26 +01:00
parent 600634db2e
commit 9d41991c75
6 changed files with 487 additions and 0 deletions

View File

@ -0,0 +1,39 @@
package world.bentobox.bentobox.api.github;
import org.eclipse.jdt.annotation.NonNull;
/**
* Represents a Contributor on a GitHub repository.
* @author Poslovitch
* @since 1.3.0
*/
public class Contributor {
private final @NonNull String name;
private final @NonNull String profile;
private int commits;
public Contributor(@NonNull String name, int commits) {
this.name = name;
this.profile = "https://github.com/" + name;
this.commits = commits;
}
@NonNull
public String getName() {
return name;
}
@NonNull
public String getProfile() {
return profile;
}
public int getCommits() {
return commits;
}
public void setCommits(int commits) {
this.commits = commits;
}
}

View File

@ -0,0 +1,124 @@
package world.bentobox.bentobox.api.github;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import com.google.gson.JsonParser;
import org.eclipse.jdt.annotation.NonNull;
import org.eclipse.jdt.annotation.Nullable;
import world.bentobox.bentobox.util.Util;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.util.stream.Collectors;
/**
* Handles connection to the GitHub API, retrieves data and handles the {@link Repository} data that emerges from it.
* @author Poslovitch
* @since 1.3.0
*/
public class GitHubConnector {
private @NonNull String repositoryName;
private Repository repository;
public GitHubConnector(@NonNull String repositoryName) {
this.repositoryName = repositoryName;
}
public void connect() {
JsonElement repositoryData;
JsonElement releasesData;
JsonElement contributorData;
// Get the data
try {
repositoryData = getData(null);
// TODO getting other data is pointless if we couldn't get the data from the repository
contributorData = getData("contributors");
releasesData = getData("releases");
} catch (IOException e) {
e.printStackTrace();
// TODO better logging and do not override data instead
return;
}
// Parse the data
/* It must be done in a specific order:
1. repository;
2. contributors;
3. releases.
*/
parseRepositoryData(repositoryData);
parseContributorsData(contributorData);
parseReleasesData(releasesData);
}
@NonNull
private JsonElement getData(@Nullable String suffix) throws IOException {
HttpURLConnection connection = new GitHubURL(getRepositoryName(), suffix).openConnection();
String data = new BufferedReader(new InputStreamReader(connection.getInputStream())).lines().collect(Collectors.joining("\n"));
return new JsonParser().parse(data);
}
private void parseRepositoryData(@NonNull JsonElement jsonElement) {
JsonObject jsonObject = jsonElement.getAsJsonObject();
Repository.Builder builder = new Repository.Builder(repositoryName.split("/")[0], repositoryName.split("/")[1])
.stars(jsonObject.get("stargazers_count").getAsInt())
.forks(jsonObject.get("forks_count").getAsInt())
.openIssues(jsonObject.get("open_issues_count").getAsInt())
.latestCommit(Util.parseGitHubDate(jsonObject.get("pushed_at").getAsString()));
this.repository = builder.build();
}
private void parseContributorsData(@NonNull JsonElement jsonElement) {
for (JsonElement contributorElement : jsonElement.getAsJsonArray()) {
JsonObject contributor = contributorElement.getAsJsonObject();
this.repository.getContributors().add(new Contributor(contributor.get("login").getAsString(), contributor.get("contributions").getAsInt()));
}
}
private void parseReleasesData(@NonNull JsonElement jsonElement) {
for (JsonElement releaseElement : jsonElement.getAsJsonArray()) {
JsonObject release = releaseElement.getAsJsonObject();
String tag = release.get("tag_name").getAsString();
String url = repository.getUrl() + "/releases/tag/" + tag;
Release.Builder builder = new Release.Builder(release.get("name").getAsString(), tag, url)
.preRelease(release.get("prerelease").getAsBoolean())
.publishedAt(Util.parseGitHubDate( release.get("published_at").getAsString()));
// Run through the releases assets and try to find the correct one
for (JsonElement assetElement : release.get("assets").getAsJsonArray()) {
JsonObject asset = assetElement.getAsJsonObject();
String assetName = asset.get("name").getAsString();
if (assetName.endsWith(".jar") && !assetName.contains("javadoc") && !assetName.contains("sources")) {
// We found our asset!
builder.downloadUrl(asset.get("browser_download_url").getAsString())
.downloadSize(asset.get("size").getAsLong())
.downloadCount(asset.get("download_count").getAsInt());
break;
}
}
this.repository.getReleases().add(builder.build());
}
}
@NonNull
public String getRepositoryName() {
return repositoryName;
}
public Repository getRepository() {
return repository;
}
}

View File

@ -0,0 +1,37 @@
package world.bentobox.bentobox.api.github;
import org.eclipse.jdt.annotation.NonNull;
import org.eclipse.jdt.annotation.Nullable;
import java.io.IOException;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;
/**
* Somehow wraps {@link URL} and {@link java.net.URLConnection} to avoid boilerplate code when accessing to the GitHub API.
* @author Poslovitch
* @since 1.3.0
*/
public class GitHubURL {
private @NonNull final URL url;
public GitHubURL(@NonNull String repository, @Nullable String suffix) throws MalformedURLException {
suffix = (suffix != null && !suffix.isEmpty()) ? "/" + suffix : "";
this.url = new URL("https://api.github.com/repos/" + repository + suffix);
}
@NonNull
public URL toURL() {
return url;
}
public HttpURLConnection openConnection() throws IOException {
HttpURLConnection connection = (HttpURLConnection) url.openConnection();
connection.setConnectTimeout(2500);
connection.addRequestProperty("User-Agent", "BentoBox GitHubLink (@BentoBoxWorld)");
connection.setDoOutput(true);
return connection;
}
}

View File

@ -0,0 +1,130 @@
package world.bentobox.bentobox.api.github;
import org.eclipse.jdt.annotation.NonNull;
import org.eclipse.jdt.annotation.Nullable;
import java.util.Date;
/**
* Represents a release on a Github repository.
* See https://api.github.com/repos/BentoBoxWorld/BentoBox/releases.
* @author Poslovitch
* @since 1.3.0
*/
public class Release {
private final @NonNull String name;
private final @NonNull String tag;
private final @NonNull String url;
private final boolean preRelease;
private final @Nullable Date publishedAt;
/* Release asset related fields */
private final @Nullable String downloadUrl;
private final long downloadSize;
private int downloadCount;
private Release(@NonNull Builder builder) {
this.name = builder.name;
this.tag = builder.tag;
this.url = builder.url;
this.preRelease = builder.preRelease;
this.publishedAt = builder.publishedAt;
this.downloadUrl = builder.downloadUrl;
this.downloadSize = builder.downloadSize;
this.downloadCount = builder.downloadCount;
}
@NonNull
public String getName() {
return name;
}
@NonNull
public String getTag() {
return tag;
}
@NonNull
public String getUrl() {
return url;
}
public boolean isPreRelease() {
return preRelease;
}
@Nullable
public Date getPublishedAt() {
return publishedAt;
}
@Nullable
public String getDownloadUrl() {
return downloadUrl;
}
public long getDownloadSize() {
return downloadSize;
}
public int getDownloadCount() {
return downloadCount;
}
public void setDownloadCount(int downloadCount) {
this.downloadCount = downloadCount;
}
public static class Builder {
private final @NonNull String name;
private final @NonNull String tag;
private final @NonNull String url;
private boolean preRelease;
private @Nullable Date publishedAt;
private @Nullable String downloadUrl;
private long downloadSize;
private int downloadCount;
public Builder(@NonNull String name, @NonNull String tag, @NonNull String url) {
this.name = name;
this.tag = tag;
this.url = url;
this.preRelease = false;
this.downloadSize = 0L;
this.downloadCount = 0;
}
public Builder preRelease(boolean preRelease) {
this.preRelease = preRelease;
return this;
}
public Builder publishedAt(@Nullable Date publishedAt) {
this.publishedAt = publishedAt;
return this;
}
public Builder downloadUrl(@Nullable String downloadUrl) {
this.downloadUrl = downloadUrl;
return this;
}
public Builder downloadSize(long downloadSize) {
this.downloadSize = downloadSize;
return this;
}
public Builder downloadCount(int downloadCount) {
this.downloadCount = downloadCount;
return this;
}
public Release build() {
return new Release(this);
}
}
}

View File

@ -0,0 +1,152 @@
package world.bentobox.bentobox.api.github;
import org.eclipse.jdt.annotation.NonNull;
import org.eclipse.jdt.annotation.Nullable;
import java.util.Arrays;
import java.util.Date;
import java.util.LinkedList;
import java.util.List;
/**
* Represents a GitHub repository.
* @author Poslovitch
* @since 1.3.0
*/
public class Repository {
private final @NonNull String owner;
private final @NonNull String name;
private final @NonNull List<Contributor> contributors;
private final @NonNull List<Release> releases;
private int stars;
private int forks;
private int openIssues;
private @Nullable Date latestCommit;
private Repository(@NonNull Builder builder) {
this.owner = builder.owner;
this.name = builder.name;
this.contributors = builder.contributors;
this.releases = builder.releases;
this.stars = builder.stars;
this.forks = builder.forks;
this.openIssues = builder.openIssues;
this.latestCommit = builder.latestCommit;
}
@NonNull
public String getOwner() {
return owner;
}
@NonNull
public String getName() {
return name;
}
@NonNull
public List<Contributor> getContributors() {
return contributors;
}
@NonNull
public List<Release> getReleases() {
return releases;
}
public int getStars() {
return stars;
}
public void setStars(int stars) {
this.stars = stars;
}
public int getForks() {
return forks;
}
public void setForks(int forks) {
this.forks = forks;
}
public int getOpenIssues() {
return openIssues;
}
public void setOpenIssues(int openIssues) {
this.openIssues = openIssues;
}
@NonNull
public String getUrl() {
return "https://github.com/" + getOwner() + "/" + getName();
}
@Nullable
public Date getLatestCommit() {
return latestCommit;
}
public void setLatestCommit(@Nullable Date latestCommit) {
this.latestCommit = latestCommit;
}
public static class Builder {
private final @NonNull String owner;
private final @NonNull String name;
private final @NonNull List<Contributor> contributors;
private final @NonNull List<Release> releases;
private int stars;
private int forks;
private int openIssues;
private @Nullable Date latestCommit;
public Builder(@NonNull String owner, @NonNull String name) {
this.owner = owner;
this.name = name;
this.contributors = new LinkedList<>();
this.releases = new LinkedList<>();
}
public Builder contributors(@NonNull Contributor... contributors) {
this.contributors.addAll(Arrays.asList(contributors));
return this;
}
public Builder releases(@NonNull Release... releases) {
this.releases.addAll(Arrays.asList(releases));
return this;
}
public Builder stars(int stars) {
this.stars = stars;
return this;
}
public Builder forks(int forks) {
this.forks = forks;
return this;
}
public Builder openIssues(int openIssues) {
this.openIssues = openIssues;
return this;
}
public Builder latestCommit(@Nullable Date latestCommit) {
this.latestCommit = latestCommit;
return this;
}
public Repository build() {
return new Repository(this);
}
}
}

View File

@ -0,0 +1,5 @@
/**
* Contains objects and classes to get, retrieve and store data from GitHub.
* @since 1.3.0
*/
package world.bentobox.bentobox.api.github;