Compare commits

...

34 Commits

Author SHA1 Message Date
Kohsuke Kawaguchi
336924ef23 [maven-release-plugin] prepare release github-api-1.87 2017-09-09 08:06:18 -07:00
Kohsuke Kawaguchi
ad28ca4a90 Use string constant like other previews 2017-09-09 07:59:31 -07:00
Kohsuke Kawaguchi
aebbe86cfc Keeping findbugs happy 2017-09-09 07:57:49 -07:00
Kohsuke Kawaguchi
df9faf4943 Auto-retry flaky tests 2017-09-08 16:09:41 -07:00
Kohsuke Kawaguchi
3e295b6be4 Merge branch 'master' of github.com:kohsuke/github-api 2017-09-08 15:52:31 -07:00
Kohsuke Kawaguchi
8dd6dbf995 getRef never returns null 2017-09-08 15:52:11 -07:00
Kohsuke Kawaguchi
612139f2ff Merge pull request #375 from stephenc/tag-object-support
Add basic support for tag objects
2017-09-08 15:49:33 -07:00
Kohsuke Kawaguchi
240bcabb76 Merge pull request #351 2017-09-08 14:16:45 -07:00
Kohsuke Kawaguchi
cda27d5963 This field should be still final 2017-09-08 14:16:09 -07:00
Kohsuke Kawaguchi
2f8c3997f7 Restored signature of the previous enableProtection() method 2017-09-08 14:13:21 -07:00
Kohsuke Kawaguchi
46b89a48db Merge Pull request #369 2017-09-08 14:06:22 -07:00
Kohsuke Kawaguchi
5c9cbee2f9 Merge pull request #332 from sebkur/fix_javadoc
Fix a bug in the Javadocs (due to copy and paste)
2017-09-08 10:39:58 -07:00
Kohsuke Kawaguchi
ee8973c239 Merge pull request #338 from sebkur/ignore-eclipse-files
Ignore eclipse files
2017-09-08 10:39:39 -07:00
Kohsuke Kawaguchi
2e2813f363 Merge pull request #343 from kamontat/feature/latest-release
add latest release
2017-09-08 10:39:13 -07:00
Kohsuke Kawaguchi
7ceca0769f Merge pull request #363 from PauloMigAlmeida/master
Add missing event types used by repository webhooks
2017-09-08 10:36:33 -07:00
Kohsuke Kawaguchi
4d277cc61f Merge pull request #352 from stephenc/pr-reviews
Add support for PR reviews preview
2017-09-08 10:35:58 -07:00
Kohsuke Kawaguchi
e67fbb4621 Merge pull request #362 from KostyaSha/pingHook
Add ping hook method
2017-09-08 10:34:45 -07:00
Kohsuke Kawaguchi
29b5357ceb Merge pull request #358 from jglick/no-preview-JENKINS-36240
[JENKINS-36240] /repos/:owner/:repo/collaborators/:username/permission no longer requires korra preview
2017-09-08 10:33:31 -07:00
Stephen Connolly
9dabec107b Add basic support for tag objects 2017-09-01 12:52:15 +01:00
Jae Gangemi
23cd51a6da - improved branch protection support 2017-08-08 16:17:58 -06:00
Jae Gangemi
7396395f90 - updated ignore entries for eclipse/moc os 2017-08-08 14:31:11 -06:00
Paulo Miguel Almeida
4abe87036c Add missing event types used by repository webhooks 2017-07-14 04:23:08 +00:00
Kanstantsin Shautsou
8d1b44db97 Add ping hook method 2017-07-10 02:39:03 +03:00
Kohsuke Kawaguchi
f2fe8eaf86 [maven-release-plugin] prepare for next development iteration 2017-07-02 17:08:35 -07:00
Jesse Glick
3a40af8871 [JENKINS-36240] /repos/:owner/:repo/collaborators/:username/permission no longer requires korra preview. 2017-06-12 10:28:25 -04:00
mdeverdelhan
c9b5074bc4 Fix the wrapping of retrieved commits (owner/repository) 2017-05-11 12:32:34 +02:00
Stephen Connolly
44d4d0d767 Add support for PR reviews preview 2017-03-30 12:17:06 +01:00
mdeverdelhan
64af13f40d Add the Commit search API (still in preview) 2017-03-30 12:55:55 +02:00
kamontat
5554332b5b add return null if latest release not found 2017-02-20 10:20:53 +07:00
kamontat
1cffea892b add test 2017-02-20 10:20:08 +07:00
kamontat
fd859815b0 fixed indent, rename to getLastestRelease 2017-02-20 09:36:28 +07:00
kamontat
166e26d101 add latest release 2017-02-19 23:57:44 +07:00
Sebastian Kürten
429b26cee8 Ignore eclipse files 2017-02-09 18:18:08 +01:00
Sebastian Kürten
75f0c08ca4 Fix a bug in the Javadocs (due to copy and paste) 2017-01-23 12:21:13 +01:00
25 changed files with 1115 additions and 70 deletions

4
.gitignore vendored
View File

@@ -3,3 +3,7 @@ target
*.iml
*.ipr
*.iws
.classpath
.project
.settings/
.DS_Store

10
pom.xml
View File

@@ -7,7 +7,7 @@
</parent>
<artifactId>github-api</artifactId>
<version>1.86</version>
<version>1.87</version>
<name>GitHub API for Java</name>
<url>http://github-api.kohsuke.org/</url>
<description>GitHub API for Java</description>
@@ -16,7 +16,7 @@
<connection>scm:git:git@github.com/kohsuke/${project.artifactId}.git</connection>
<developerConnection>scm:git:ssh://git@github.com/kohsuke/${project.artifactId}.git</developerConnection>
<url>http://${project.artifactId}.kohsuke.org/</url>
<tag>github-api-1.86</tag>
<tag>github-api-1.87</tag>
</scm>
<distributionManagement>
@@ -34,6 +34,12 @@
<build>
<plugins>
<plugin>
<artifactId>maven-surefire-plugin</artifactId>
<configuration>
<rerunFailingTestsCount>2</rerunFailingTestsCount>
</configuration>
</plugin>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>animal-sniffer-maven-plugin</artifactId>

View File

@@ -1,21 +0,0 @@
package org.kohsuke.github;
import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
import java.util.ArrayList;
import java.util.List;
/**
* @author Kohsuke Kawaguchi
* @see GHBranch#disableProtection()
*/
@SuppressFBWarnings(value = {"UWF_UNWRITTEN_FIELD", "NP_UNWRITTEN_FIELD", "URF_UNREAD_FIELD"}, justification = "JSON API")
class BranchProtection {
boolean enabled;
RequiredStatusChecks requiredStatusChecks;
static class RequiredStatusChecks {
EnforcementLevel enforcement_level;
List<String> contexts = new ArrayList<String>();
}
}

View File

@@ -3,8 +3,11 @@ package org.kohsuke.github;
import java.util.Locale;
/**
* This was added during preview API period but it has changed since then.
*
* @author Kohsuke Kawaguchi
*/
@Deprecated
public enum EnforcementLevel {
OFF, NON_ADMINS, EVERYONE;

View File

@@ -4,21 +4,18 @@ import static org.kohsuke.github.Previews.LOKI;
import java.io.IOException;
import java.net.URL;
import java.util.Arrays;
import java.util.Collection;
import org.kohsuke.github.BranchProtection.RequiredStatusChecks;
import com.fasterxml.jackson.annotation.JsonProperty;
import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
/**
* A branch in a repository.
*
*
* @author Yusuke Kokubo
*/
@SuppressFBWarnings(value = {"UWF_UNWRITTEN_PUBLIC_OR_PROTECTED_FIELD", "UWF_UNWRITTEN_FIELD",
@SuppressFBWarnings(value = {"UWF_UNWRITTEN_PUBLIC_OR_PROTECTED_FIELD", "UWF_UNWRITTEN_FIELD",
"NP_UNWRITTEN_FIELD", "URF_UNREAD_FIELD"}, justification = "JSON API")
public class GHBranch {
private GitHub root;
@@ -33,7 +30,7 @@ public class GHBranch {
public static class Commit {
String sha;
@SuppressFBWarnings(value = "UUF_UNUSED_FIELD", justification = "We don't provide it in API now")
String url;
}
@@ -69,6 +66,10 @@ public class GHBranch {
return GitHub.parseURL(protection_url);
}
@Preview @Deprecated
public GHBranchProtection getProtection() throws IOException {
return root.retrieve().withPreview(LOKI).to(protection_url, GHBranchProtection.class);
}
/**
* The commit that this branch currently points to.
@@ -82,9 +83,7 @@ public class GHBranch {
*/
@Preview @Deprecated
public void disableProtection() throws IOException {
BranchProtection bp = new BranchProtection();
bp.enabled = false;
setProtection(bp);
new Requester(root).method("DELETE").withPreview(LOKI).to(protection_url);
}
/**
@@ -93,28 +92,31 @@ public class GHBranch {
* @see GHCommitStatus#getContext()
*/
@Preview @Deprecated
public GHBranchProtectionBuilder enableProtection() {
return new GHBranchProtectionBuilder(this);
}
// backward compatibility with previous signature
@Deprecated
public void enableProtection(EnforcementLevel level, Collection<String> contexts) throws IOException {
BranchProtection bp = new BranchProtection();
bp.enabled = true;
bp.requiredStatusChecks = new RequiredStatusChecks();
bp.requiredStatusChecks.enforcement_level = level;
bp.requiredStatusChecks.contexts.addAll(contexts);
setProtection(bp);
}
@Preview @Deprecated
public void enableProtection(EnforcementLevel level, String... contexts) throws IOException {
enableProtection(level, Arrays.asList(contexts));
}
private void setProtection(BranchProtection bp) throws IOException {
new Requester(root).method("PATCH").withPreview(LOKI)._with("protection",bp).to(getApiRoute());
switch (level) {
case OFF:
disableProtection();
break;
case NON_ADMINS:
case EVERYONE:
enableProtection()
.addRequiredChecks(contexts)
.includeAdmins(level==EnforcementLevel.EVERYONE)
.enable();
break;
}
}
String getApiRoute() {
return owner.getApiTailUrl("/branches/"+name);
}
@Override
public String toString() {
final String url = owner != null ? owner.getUrl().toString() : "unknown";

View File

@@ -0,0 +1,152 @@
package org.kohsuke.github;
import java.util.Collection;
import com.fasterxml.jackson.annotation.JsonProperty;
import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
@SuppressFBWarnings(value = { "UWF_UNWRITTEN_PUBLIC_OR_PROTECTED_FIELD", "UWF_UNWRITTEN_FIELD", "NP_UNWRITTEN_FIELD",
"URF_UNREAD_FIELD" }, justification = "JSON API")
public class GHBranchProtection {
@JsonProperty("enforce_admins")
private EnforceAdmins enforceAdmins;
@JsonProperty("required_pull_request_reviews")
private RequiredReviews requiredReviews;
@JsonProperty("required_status_checks")
private RequiredStatusChecks requiredStatusChecks;
@JsonProperty
private Restrictions restrictions;
@JsonProperty
private String url;
public EnforceAdmins getEnforceAdmins() {
return enforceAdmins;
}
public RequiredReviews getRequiredReviews() {
return requiredReviews;
}
public RequiredStatusChecks getRequiredStatusChecks() {
return requiredStatusChecks;
}
public Restrictions getRestrictions() {
return restrictions;
}
public String getUrl() {
return url;
}
public static class EnforceAdmins {
@JsonProperty
private boolean enabled;
@JsonProperty
private String url;
public String getUrl() {
return url;
}
public boolean isEnabled() {
return enabled;
}
}
public static class RequiredReviews {
@JsonProperty("dismissal_restrictions")
private Restrictions dismissalRestriction;
@JsonProperty("dismiss_stale_reviews")
private boolean dismissStaleReviews;
@JsonProperty("require_code_owner_reviews")
private boolean requireCodeOwnerReviews;
@JsonProperty
private String url;
public Restrictions getDismissalRestrictions() {
return dismissalRestriction;
}
public String getUrl() {
return url;
}
public boolean isDismissStaleReviews() {
return dismissStaleReviews;
}
public boolean isRequireCodeOwnerReviews() {
return requireCodeOwnerReviews;
}
}
public static class RequiredStatusChecks {
@JsonProperty
private Collection<String> contexts;
@JsonProperty
private boolean strict;
@JsonProperty
private String url;
public Collection<String> getContexts() {
return contexts;
}
public String getUrl() {
return url;
}
public boolean isRequiresBranchUpToDate() {
return strict;
}
}
public static class Restrictions {
@JsonProperty
private Collection<GHTeam> teams;
@JsonProperty("teams_url")
private String teamsUrl;
@JsonProperty
private String url;
@JsonProperty
private Collection<GHUser> users;
@JsonProperty("users_url")
private String usersUrl;
public Collection<GHTeam> getTeams() {
return teams;
}
public String getTeamsUrl() {
return teamsUrl;
}
public String getUrl() {
return url;
}
public Collection<GHUser> getUsers() {
return users;
}
public String getUsersUrl() {
return usersUrl;
}
}
}

View File

@@ -0,0 +1,203 @@
package org.kohsuke.github;
import static org.kohsuke.github.Previews.LOKI;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
/**
* Builder to configure the branch protection settings.
*
* @see GHBranch#enableProtection()
*/
@SuppressFBWarnings(value = { "UWF_UNWRITTEN_PUBLIC_OR_PROTECTED_FIELD", "UWF_UNWRITTEN_FIELD", "NP_UNWRITTEN_FIELD",
"URF_UNREAD_FIELD" }, justification = "JSON API")
public class GHBranchProtectionBuilder {
private final GHBranch branch;
private boolean enforceAdmins;
private Map<String, Object> prReviews;
private Restrictions restrictions;
private StatusChecks statusChecks;
GHBranchProtectionBuilder(GHBranch branch) {
this.branch = branch;
}
public GHBranchProtectionBuilder addRequiredChecks(Collection<String> checks) {
getStatusChecks().contexts.addAll(checks);
return this;
}
public GHBranchProtectionBuilder addRequiredChecks(String... checks) {
addRequiredChecks(Arrays.asList(checks));
return this;
}
public GHBranchProtectionBuilder dismissStaleReviews() {
getPrReviews().put("dismiss_stale_reviews", true);
return this;
}
public GHBranchProtection enable() throws IOException {
return requester().method("PUT")
.withNullable("required_status_checks", statusChecks)
.withNullable("required_pull_request_reviews", prReviews)
.withNullable("restrictions", restrictions)
.withNullable("enforce_admins", enforceAdmins)
.to(branch.getProtectionUrl().toString(), GHBranchProtection.class);
}
public GHBranchProtectionBuilder includeAdmins() {
return includeAdmins(true);
}
public GHBranchProtectionBuilder includeAdmins(boolean v) {
enforceAdmins = v;
return this;
}
public GHBranchProtectionBuilder requireBranchIsUpToDate() {
return requireBranchIsUpToDate(true);
}
public GHBranchProtectionBuilder requireBranchIsUpToDate(boolean v) {
getStatusChecks().strict = v;
return this;
}
public GHBranchProtectionBuilder requireCodeOwnReviews() {
return requireCodeOwnReviews(true);
}
public GHBranchProtectionBuilder requireCodeOwnReviews(boolean v) {
getPrReviews().put("require_code_owner_reviews", v);
return this;
}
public GHBranchProtectionBuilder requireReviews() {
getPrReviews();
return this;
}
public GHBranchProtectionBuilder restrictPushAccess() {
getRestrictions();
return this;
}
public GHBranchProtectionBuilder teamPushAccess(Collection<GHTeam> teams) {
for (GHTeam team : teams) {
teamPushAccess(team);
}
return this;
}
public GHBranchProtectionBuilder teamPushAccess(GHTeam... teams) {
for (GHTeam team : teams) {
getRestrictions().teams.add(team.getSlug());
}
return this;
}
public GHBranchProtectionBuilder teamReviewDismissals(Collection<GHTeam> teams) {
for (GHTeam team : teams) {
teamReviewDismissals(team);
}
return this;
}
public GHBranchProtectionBuilder teamReviewDismissals(GHTeam... teams) {
for (GHTeam team : teams) {
addReviewRestriction(team.getSlug(), true);
}
return this;
}
public GHBranchProtectionBuilder userPushAccess(Collection<GHUser> users) {
for (GHUser user : users) {
userPushAccess(user);
}
return this;
}
public GHBranchProtectionBuilder userPushAccess(GHUser... users) {
for (GHUser user : users) {
getRestrictions().users.add(user.getLogin());
}
return this;
}
public GHBranchProtectionBuilder userReviewDismissals(Collection<GHUser> users) {
for (GHUser team : users) {
userReviewDismissals(team);
}
return this;
}
public GHBranchProtectionBuilder userReviewDismissals(GHUser... users) {
for (GHUser user : users) {
addReviewRestriction(user.getLogin(), false);
}
return this;
}
private void addReviewRestriction(String restriction, boolean isTeam) {
getPrReviews();
if (!prReviews.containsKey("dismissal_restrictions")) {
prReviews.put("dismissal_restrictions", new Restrictions());
}
Restrictions restrictions = (Restrictions) prReviews.get("dismissal_restrictions");
if (isTeam) {
restrictions.teams.add(restriction);
} else {
restrictions.users.add(restriction);
}
}
private Map<String, Object> getPrReviews() {
if (prReviews == null) {
prReviews = new HashMap<String, Object>();
}
return prReviews;
}
private Restrictions getRestrictions() {
if (restrictions == null) {
restrictions = new Restrictions();
}
return restrictions;
}
private StatusChecks getStatusChecks() {
if (statusChecks == null) {
statusChecks = new StatusChecks();
}
return statusChecks;
}
private Requester requester() {
return new Requester(branch.getRoot()).withPreview(LOKI);
}
private static class Restrictions {
private Set<String> teams = new HashSet<String>();
private Set<String> users = new HashSet<String>();
}
private static class StatusChecks {
final List<String> contexts = new ArrayList<String>();
boolean strict;
}
}

View File

@@ -0,0 +1,137 @@
package org.kohsuke.github;
import java.io.IOException;
import org.apache.commons.lang.StringUtils;
/**
* Search commits.
*
* @author Marc de Verdelhan
* @see GitHub#searchCommits()
*/
@Preview @Deprecated
public class GHCommitSearchBuilder extends GHSearchBuilder<GHCommit> {
/*package*/ GHCommitSearchBuilder(GitHub root) {
super(root,CommitSearchResult.class);
req.withPreview(Previews.CLOAK);
}
/**
* Search terms.
*/
public GHCommitSearchBuilder q(String term) {
super.q(term);
return this;
}
public GHCommitSearchBuilder author(String v) {
return q("author:"+v);
}
public GHCommitSearchBuilder committer(String v) {
return q("committer:"+v);
}
public GHCommitSearchBuilder authorName(String v) {
return q("author-name:"+v);
}
public GHCommitSearchBuilder committerName(String v) {
return q("committer-name:"+v);
}
public GHCommitSearchBuilder authorEmail(String v) {
return q("author-email:"+v);
}
public GHCommitSearchBuilder committerEmail(String v) {
return q("committer-email:"+v);
}
public GHCommitSearchBuilder authorDate(String v) {
return q("author-date:"+v);
}
public GHCommitSearchBuilder committerDate(String v) {
return q("committer-date:"+v);
}
public GHCommitSearchBuilder merge(boolean merge) {
return q("merge:"+Boolean.valueOf(merge).toString().toLowerCase());
}
public GHCommitSearchBuilder hash(String v) {
return q("hash:"+v);
}
public GHCommitSearchBuilder parent(String v) {
return q("parent:"+v);
}
public GHCommitSearchBuilder tree(String v) {
return q("tree:"+v);
}
public GHCommitSearchBuilder is(String v) {
return q("is:"+v);
}
public GHCommitSearchBuilder user(String v) {
return q("user:"+v);
}
public GHCommitSearchBuilder org(String v) {
return q("org:"+v);
}
public GHCommitSearchBuilder repo(String v) {
return q("repo:"+v);
}
public GHCommitSearchBuilder order(GHDirection v) {
req.with("order",v);
return this;
}
public GHCommitSearchBuilder sort(Sort sort) {
req.with("sort",sort);
return this;
}
public enum Sort { AUTHOR_DATE, COMMITTER_DATE }
private static class CommitSearchResult extends SearchResult<GHCommit> {
private GHCommit[] items;
@Override
/*package*/ GHCommit[] getItems(GitHub root) {
for (GHCommit commit : items) {
String repoName = getRepoName(commit.url);
try {
GHRepository repo = root.getRepository(repoName);
commit.wrapUp(repo);
} catch (IOException ioe) {}
}
return items;
}
}
/**
* @param commitUrl a commit URL
* @return the repo name ("username/reponame")
*/
private static String getRepoName(String commitUrl) {
if (StringUtils.isBlank(commitUrl)) {
return null;
}
int indexOfUsername = (GitHub.GITHUB_URL + "/repos/").length();
String[] tokens = commitUrl.substring(indexOfUsername).split("/", 3);
return tokens[0] + '/' + tokens[1];
}
@Override
protected String getApiUrl() {
return "/search/commits";
}
}

View File

@@ -21,17 +21,30 @@ public enum GHEvent {
FORK_APPLY,
GIST,
GOLLUM,
INSTALLATION,
INSTALLATION_REPOSITORIES,
ISSUE_COMMENT,
ISSUES,
LABEL,
MARKETPLACE_PURCHASE,
MEMBER,
MEMBERSHIP,
MILESTONE,
ORGANIZATION,
ORG_BLOCK,
PAGE_BUILD,
PROJECT_CARD,
PROJECT_COLUMN,
PROJECT,
PUBLIC,
PULL_REQUEST,
PULL_REQUEST_REVIEW,
PULL_REQUEST_REVIEW_COMMENT,
PUSH,
RELEASE,
REPOSITORY, // only valid for org hooks
STATUS,
TEAM,
TEAM_ADD,
WATCH,
PING,

View File

@@ -41,6 +41,13 @@ public abstract class GHHook extends GHObject {
return Collections.unmodifiableMap(config);
}
/**
* @see <a href="https://developer.github.com/v3/repos/hooks/#ping-a-hook">Ping hook</a>
*/
public void ping() throws IOException {
new Requester(getRoot()).method("POST").to(getApiRoute() + "/pings");
}
/**
* Deletes this hook.
*/

View File

@@ -25,8 +25,14 @@ package org.kohsuke.github;
import java.io.IOException;
import java.net.URL;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Date;
import java.util.List;
import javax.annotation.CheckForNull;
import static org.kohsuke.github.Previews.BLACK_CAT;
/**
* A pull request.
@@ -208,7 +214,7 @@ public class GHPullRequest extends GHIssue {
}
/**
* Retrieves all the commits associated to this pull request.
* Retrieves all the files associated to this pull request.
*/
public PagedIterable<GHPullRequestFileDetail> listFiles() {
return new PagedIterable<GHPullRequestFileDetail>() {
@@ -223,6 +229,27 @@ public class GHPullRequest extends GHIssue {
};
}
/**
* Retrieves all the reviews associated to this pull request.
*/
public PagedIterable<GHPullRequestReview> listReviews() {
return new PagedIterable<GHPullRequestReview>() {
public PagedIterator<GHPullRequestReview> _iterator(int pageSize) {
return new PagedIterator<GHPullRequestReview>(root.retrieve()
.withPreview(BLACK_CAT)
.asIterator(String.format("%s/reviews", getApiRoute()),
GHPullRequestReview[].class, pageSize)) {
@Override
protected void wrapUp(GHPullRequestReview[] page) {
for (GHPullRequestReview r: page) {
r.wrapUp(GHPullRequest.this);
}
}
};
}
};
}
/**
* Obtains all the review comments associated with this pull request.
*/
@@ -259,6 +286,34 @@ public class GHPullRequest extends GHIssue {
};
}
@Preview
@Deprecated
public GHPullRequestReview createReview(String body, @CheckForNull GHPullRequestReviewState event,
GHPullRequestReviewComment... comments)
throws IOException {
return createReview(body, event, Arrays.asList(comments));
}
@Preview
@Deprecated
public GHPullRequestReview createReview(String body, @CheckForNull GHPullRequestReviewState event,
List<GHPullRequestReviewComment> comments)
throws IOException {
// if (event == null) {
// event = GHPullRequestReviewState.PENDING;
// }
List<DraftReviewComment> draftComments = new ArrayList<DraftReviewComment>(comments.size());
for (GHPullRequestReviewComment c : comments) {
draftComments.add(new DraftReviewComment(c.getBody(), c.getPath(), c.getPosition()));
}
return new Requester(root).method("POST")
.with("body", body)
//.with("event", event.name())
._with("comments", draftComments)
.withPreview(BLACK_CAT)
.to(getApiRoute() + "/reviews", GHPullRequestReview.class).wrapUp(this);
}
public GHPullRequestReviewComment createReviewComment(String body, String sha, String path, int position) throws IOException {
return new Requester(root).method("POST")
.with("body", body)
@@ -300,4 +355,28 @@ public class GHPullRequest extends GHIssue {
fetchedIssueDetails = true;
}
}
private static class DraftReviewComment {
private String body;
private String path;
private int position;
public DraftReviewComment(String body, String path, int position) {
this.body = body;
this.path = path;
this.position = position;
}
public String getBody() {
return body;
}
public String getPath() {
return path;
}
public int getPosition() {
return position;
}
}
}

View File

@@ -0,0 +1,149 @@
/*
* The MIT License
*
* Copyright (c) 2017, CloudBees, Inc.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
package org.kohsuke.github;
import java.io.IOException;
import java.net.URL;
import static org.kohsuke.github.Previews.BLACK_CAT;
/**
* Review to the pull request
*
* @see GHPullRequest#listReviews()
* @see GHPullRequest#createReview(String, GHPullRequestReviewState, GHPullRequestReviewComment...)
*/
public class GHPullRequestReview extends GHObject {
GHPullRequest owner;
private String body;
private GHUser user;
private String commit_id;
private GHPullRequestReviewState state;
/*package*/ GHPullRequestReview wrapUp(GHPullRequest owner) {
this.owner = owner;
return this;
}
/**
* Gets the pull request to which this review is associated.
*/
public GHPullRequest getParent() {
return owner;
}
/**
* The comment itself.
*/
public String getBody() {
return body;
}
/**
* Gets the user who posted this review.
*/
public GHUser getUser() throws IOException {
return owner.root.getUser(user.getLogin());
}
public String getCommitId() {
return commit_id;
}
public GHPullRequestReviewState getState() {
return state;
}
@Override
public URL getHtmlUrl() {
return null;
}
protected String getApiRoute() {
return owner.getApiRoute()+"/reviews/"+id;
}
/**
* Updates the comment.
*/
@Preview
@Deprecated
public void submit(String body, GHPullRequestReviewState event) throws IOException {
new Requester(owner.root).method("POST")
.with("body", body)
.with("event", event.action())
.withPreview("application/vnd.github.black-cat-preview+json")
.to(getApiRoute()+"/events",this);
this.body = body;
this.state = event;
}
/**
* Deletes this review.
*/
@Preview
@Deprecated
public void delete() throws IOException {
new Requester(owner.root).method("DELETE")
.withPreview(BLACK_CAT)
.to(getApiRoute());
}
/**
* Dismisses this review.
*/
@Preview
@Deprecated
public void dismiss(String message) throws IOException {
new Requester(owner.root).method("PUT")
.with("message", message)
.withPreview(BLACK_CAT)
.to(getApiRoute()+"/dismissals");
state = GHPullRequestReviewState.DISMISSED;
}
/**
* Obtains all the review comments associated with this pull request review.
*/
@Preview
@Deprecated
public PagedIterable<GHPullRequestReviewComment> listReviewComments() throws IOException {
return new PagedIterable<GHPullRequestReviewComment>() {
public PagedIterator<GHPullRequestReviewComment> _iterator(int pageSize) {
return new PagedIterator<GHPullRequestReviewComment>(
owner.root.retrieve()
.withPreview(BLACK_CAT)
.asIterator(getApiRoute() + "/comments",
GHPullRequestReviewComment[].class, pageSize)) {
protected void wrapUp(GHPullRequestReviewComment[] page) {
for (GHPullRequestReviewComment c : page)
c.wrapUp(owner);
}
};
}
};
}
}

View File

@@ -44,6 +44,14 @@ public class GHPullRequestReviewComment extends GHObject implements Reactable {
private int position;
private int originalPosition;
public static GHPullRequestReviewComment draft(String body, String path, int position) {
GHPullRequestReviewComment result = new GHPullRequestReviewComment();
result.body = body;
result.path = path;
result.position = position;
return result;
}
/*package*/ GHPullRequestReviewComment wrapUp(GHPullRequest owner) {
this.owner = owner;
return this;

View File

@@ -0,0 +1,19 @@
package org.kohsuke.github;
public enum GHPullRequestReviewState {
PENDING(null),
APPROVED("APPROVE"),
REQUEST_CHANGES("REQUEST_CHANGES"),
COMMENTED("COMMENT"),
DISMISSED(null);
private final String _action;
GHPullRequestReviewState(String action) {
_action = action;
}
public String action() {
return _action;
}
}

View File

@@ -60,7 +60,7 @@ import static org.kohsuke.github.Previews.*;
* @author Kohsuke Kawaguchi
*/
@SuppressWarnings({"UnusedDeclaration"})
@SuppressFBWarnings(value = {"UWF_UNWRITTEN_PUBLIC_OR_PROTECTED_FIELD", "UWF_UNWRITTEN_FIELD",
@SuppressFBWarnings(value = {"UWF_UNWRITTEN_PUBLIC_OR_PROTECTED_FIELD", "UWF_UNWRITTEN_FIELD",
"NP_UNWRITTEN_FIELD"}, justification = "JSON API")
public class GHRepository extends GHObject {
/*package almost final*/ GitHub root;
@@ -298,6 +298,14 @@ public class GHRepository extends GHObject {
public List<GHRelease> getReleases() throws IOException {
return listReleases().asList();
}
public GHRelease getLatestRelease() throws IOException {
try {
return root.retrieve().to(getApiTailUrl("releases/latest"), GHRelease.class).wrap(this);
} catch (FileNotFoundException e) {
return null; // no latest release
}
}
public PagedIterable<GHRelease> listReleases() throws IOException {
return new PagedIterable<GHRelease>() {
@@ -434,8 +442,8 @@ public class GHRepository extends GHObject {
public int getSize() {
return size;
}
/**
* Gets the collaborators on this repository.
* This set always appear to include the owner.
@@ -486,9 +494,8 @@ public class GHRepository extends GHObject {
* @throws FileNotFoundException under some conditions (e.g., private repo you can see but are not an admin of); treat as unknown
* @throws HttpException with a 403 under other conditions (e.g., public repo you have no special rights to); treat as unknown
*/
@Deprecated @Preview
public GHPermissionType getPermission(String user) throws IOException {
GHPermission perm = root.retrieve().withPreview(KORRA).to(getApiTailUrl("collaborators/" + user + "/permission"), GHPermission.class);
GHPermission perm = root.retrieve().to(getApiTailUrl("collaborators/" + user + "/permission"), GHPermission.class);
perm.wrapUp(root);
return perm.getPermissionType();
}
@@ -498,7 +505,6 @@ public class GHRepository extends GHObject {
* @throws FileNotFoundException under some conditions (e.g., private repo you can see but are not an admin of); treat as unknown
* @throws HttpException with a 403 under other conditions (e.g., public repo you have no special rights to); treat as unknown
*/
@Deprecated @Preview
public GHPermissionType getPermission(GHUser u) throws IOException {
return getPermission(u.getLogin());
}
@@ -784,6 +790,26 @@ public class GHRepository extends GHObject {
return GHRef.wrap(root.retrieve().to(String.format("/repos/%s/%s/git/refs", getOwnerName(), name), GHRef[].class), root);
}
/**
* Retrieves all refs for the github repository.
*
* @return paged iterable of all refs
* @throws IOException on failure communicating with GitHub, potentially due to an invalid ref type being requested
*/
public PagedIterable<GHRef> listRefs() throws IOException {
final String url = String.format("/repos/%s/%s/git/refs", getOwnerName(), name);
return new PagedIterable<GHRef>() {
public PagedIterator<GHRef> _iterator(int pageSize) {
return new PagedIterator<GHRef>(root.retrieve().asIterator(url, GHRef[].class, pageSize)) {
protected void wrapUp(GHRef[] page) {
// no-op
}
};
}
};
}
/**
* Retrieves all refs of the given type for the current GitHub repository.
* @param refType the type of reg to search for e.g. <tt>tags</tt> or <tt>commits</tt>
@@ -793,6 +819,27 @@ public class GHRepository extends GHObject {
public GHRef[] getRefs(String refType) throws IOException {
return GHRef.wrap(root.retrieve().to(String.format("/repos/%s/%s/git/refs/%s", getOwnerName(), name, refType), GHRef[].class),root);
}
/**
* Retrieves all refs of the given type for the current GitHub repository.
*
* @param refType the type of reg to search for e.g. <tt>tags</tt> or <tt>commits</tt>
* @return paged iterable of all refs of the specified type
* @throws IOException on failure communicating with GitHub, potentially due to an invalid ref type being requested
*/
public PagedIterable<GHRef> listRefs(String refType) throws IOException {
final String url = String.format("/repos/%s/%s/git/refs/%s", getOwnerName(), name, refType);
return new PagedIterable<GHRef>() {
public PagedIterator<GHRef> _iterator(int pageSize) {
return new PagedIterator<GHRef>(root.retrieve().asIterator(url, GHRef[].class, pageSize)) {
protected void wrapUp(GHRef[] page) {
// no-op
}
};
}
};
}
/**
* Retrive a ref of the given type for the current GitHub repository.
*
@@ -810,6 +857,18 @@ public class GHRepository extends GHObject {
refName = refName.replaceAll("#", "%23");
return root.retrieve().to(String.format("/repos/%s/%s/git/refs/%s", getOwnerName(), name, refName), GHRef.class).wrap(root);
}
/**
* Returns the <strong>annotated</strong> tag object. Only valid if the {@link GHRef#getObject()} has a
* {@link GHRef.GHObject#getType()} of {@code tag}.
*
* @param sha the sha of the tag object
* @return the annotated tag object
*/
public GHTagObject getTagObject(String sha) throws IOException {
return root.retrieve().to(getApiTailUrl("git/tags/" + sha), GHTagObject.class).wrap(this);
}
/**
* Retrive a tree of the given type for the current GitHub repository.
*
@@ -1146,7 +1205,7 @@ public class GHRepository extends GHObject {
* @deprecated
* Use {@link #getHooks()} and {@link #createHook(String, Map, Collection, boolean)}
*/
@SuppressFBWarnings(value = "DMI_COLLECTION_OF_URLS",
@SuppressFBWarnings(value = "DMI_COLLECTION_OF_URLS",
justification = "It causes a performance degradation, but we have already exposed it to the API")
public Set<URL> getPostCommitHooks() {
return postCommitHooks;
@@ -1155,7 +1214,7 @@ public class GHRepository extends GHObject {
/**
* Live set view of the post-commit hook.
*/
@SuppressFBWarnings(value = "DMI_COLLECTION_OF_URLS",
@SuppressFBWarnings(value = "DMI_COLLECTION_OF_URLS",
justification = "It causes a performance degradation, but we have already exposed it to the API")
@SkipFromToString
private final Set<URL> postCommitHooks = new AbstractSet<URL>() {
@@ -1223,7 +1282,7 @@ public class GHRepository extends GHObject {
*/
public Map<String,GHBranch> getBranches() throws IOException {
Map<String,GHBranch> r = new TreeMap<String,GHBranch>();
for (GHBranch p : root.retrieve().to(getApiTailUrl("branches"), GHBranch[].class)) {
for (GHBranch p : root.retrieve().withPreview(LOKI).to(getApiTailUrl("branches"), GHBranch[].class)) {
p.wrap(this);
r.put(p.getName(),p);
}
@@ -1231,7 +1290,7 @@ public class GHRepository extends GHObject {
}
public GHBranch getBranch(String name) throws IOException {
return root.retrieve().to(getApiTailUrl("branches/"+name),GHBranch.class).wrap(this);
return root.retrieve().withPreview(LOKI).to(getApiTailUrl("branches/"+name),GHBranch.class).wrap(this);
}
/**
@@ -1453,7 +1512,7 @@ public class GHRepository extends GHObject {
public boolean equals(Object obj) {
// We ignore contributions in the calculation
return super.equals(obj);
}
}
}
/**

View File

@@ -0,0 +1,60 @@
package org.kohsuke.github;
import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
/**
* Represents an annotated tag in a {@link GHRepository}
*
* @see GHRepository#getAnnotatedTag()
*/
@SuppressFBWarnings(value = {"UWF_UNWRITTEN_PUBLIC_OR_PROTECTED_FIELD", "UWF_UNWRITTEN_FIELD",
"NP_UNWRITTEN_FIELD"}, justification = "JSON API")
public class GHTagObject {
private GHRepository owner;
private GitHub root;
private String tag;
private String sha;
private String url;
private String message;
private GitUser tagger;
private GHRef.GHObject object;
/*package*/ GHTagObject wrap(GHRepository owner) {
this.owner = owner;
this.root = owner.root;
return this;
}
public GHRepository getOwner() {
return owner;
}
public GitHub getRoot() {
return root;
}
public String getTag() {
return tag;
}
public String getSha() {
return sha;
}
public String getUrl() {
return url;
}
public String getMessage() {
return message;
}
public GitUser getTagger() {
return tagger;
}
public GHRef.GHObject getObject() {
return object;
}
}

View File

@@ -719,6 +719,14 @@ public class GitHub {
}
}
/**
* Search commits.
*/
@Preview @Deprecated
public GHCommitSearchBuilder searchCommits() {
return new GHCommitSearchBuilder(this);
}
/**
* Search issues.
*/

View File

@@ -7,5 +7,6 @@ package org.kohsuke.github;
static final String LOKI = "application/vnd.github.loki-preview+json";
static final String DRAX = "application/vnd.github.drax-preview+json";
static final String SQUIRREL_GIRL = "application/vnd.github.squirrel-girl-preview";
static final String KORRA = "application/vnd.github.korra-preview";
static final String CLOAK = "application/vnd.github.cloak-preview";
static final String BLACK_CAT = "application/vnd.github.black-cat-preview+json";
}

View File

@@ -170,6 +170,11 @@ class Requester {
return this;
}
public Requester withNullable(String key, Object value) {
args.add(new Entry(key, value));
return this;
}
public Requester _with(String key, Object value) {
if (value!=null) {
args.add(new Entry(key,value));
@@ -314,7 +319,7 @@ class Requester {
setupConnection(root.getApiURL(tailApiUrl));
buildRequest();
try {
return wrapStream(uc.getInputStream());
} catch (IOException e) {

View File

@@ -1,5 +1,8 @@
package org.kohsuke.github;
import java.io.FileInputStream;
import java.util.Properties;
import org.apache.commons.io.IOUtils;
import org.junit.Assert;
import org.junit.Assume;
import org.junit.Before;
@@ -19,9 +22,17 @@ public abstract class AbstractGitHubApiTestBase extends Assert {
public void setUp() throws Exception {
File f = new File(System.getProperty("user.home"), ".github.kohsuke2");
if (f.exists()) {
Properties props = new Properties();
FileInputStream in = null;
try {
in = new FileInputStream(f);
props.load(in);
} finally {
IOUtils.closeQuietly(in);
}
// use the non-standard credential preferentially, so that developers of this library do not have
// to clutter their event stream.
gitHub = GitHubBuilder.fromPropertyFile(f.getPath()).withRateLimitHandler(RateLimitHandler.FAIL).build();
gitHub = GitHubBuilder.fromProperties(props).withRateLimitHandler(RateLimitHandler.FAIL).build();
} else {
gitHub = GitHubBuilder.fromCredentials().withRateLimitHandler(RateLimitHandler.FAIL).build();
}

View File

@@ -685,6 +685,15 @@ public class AppTest extends AbstractGitHubApiTestBase {
assertFalse(all.isEmpty());
}
@Test
public void testCommitSearch() throws IOException {
PagedSearchIterable<GHCommit> r = gitHub.searchCommits().author("kohsuke").list();
assertTrue(r.getTotalCount() > 0);
GHCommit firstCommit = r.iterator().next();
assertTrue(firstCommit.getFiles().size() > 0);
}
@Test
public void testIssueSearch() throws IOException {
PagedSearchIterable<GHIssue> r = gitHub.searchIssues().mentions("kohsuke").isOpen().list();

View File

@@ -0,0 +1,82 @@
package org.kohsuke.github;
import org.junit.Before;
import org.junit.Test;
import org.kohsuke.github.GHBranchProtection.EnforceAdmins;
import org.kohsuke.github.GHBranchProtection.RequiredReviews;
import org.kohsuke.github.GHBranchProtection.RequiredStatusChecks;
import java.io.FileNotFoundException;
public class GHBranchProtectionTest extends AbstractGitHubApiTestBase {
private static final String BRANCH = "bp-test";
private static final String BRANCH_REF = "heads/" + BRANCH;
private GHBranch branch;
private GHRepository repo;
@Before
@Override
public void setUp() throws Exception {
super.setUp();
repo = gitHub.getRepository("github-api-test-org/GHContentIntegrationTest").fork();
try {
repo.getRef(BRANCH_REF);
} catch (FileNotFoundException e) {
repo.createRef("refs/" + BRANCH_REF, repo.getBranch("master").getSHA1());
}
branch = repo.getBranch(BRANCH);
if (branch.isProtected()) {
branch.disableProtection();
}
branch = repo.getBranch(BRANCH);
assertFalse(branch.isProtected());
}
@Test
public void testEnableBranchProtections() throws Exception {
// team/user restrictions require an organization repo to test against
GHBranchProtection protection = branch.enableProtection()
.addRequiredChecks("test-status-check")
.requireBranchIsUpToDate()
.requireCodeOwnReviews()
.dismissStaleReviews()
.includeAdmins()
.enable();
RequiredStatusChecks statusChecks = protection.getRequiredStatusChecks();
assertNotNull(statusChecks);
assertTrue(statusChecks.isRequiresBranchUpToDate());
assertTrue(statusChecks.getContexts().contains("test-status-check"));
RequiredReviews requiredReviews = protection.getRequiredReviews();
assertNotNull(requiredReviews);
assertTrue(requiredReviews.isDismissStaleReviews());
assertTrue(requiredReviews.isRequireCodeOwnerReviews());
EnforceAdmins enforceAdmins = protection.getEnforceAdmins();
assertNotNull(enforceAdmins);
assertTrue(enforceAdmins.isEnabled());
}
@Test
public void testEnableProtectionOnly() throws Exception {
branch.enableProtection().enable();
assertTrue(repo.getBranch(BRANCH).isProtected());
}
@Test
public void testEnableRequireReviewsOnly() throws Exception {
GHBranchProtection protection = branch.enableProtection()
.requireReviews()
.enable();
assertNotNull(protection.getRequiredReviews());
}
}

View File

@@ -20,13 +20,6 @@ public class GHContentIntegrationTest extends AbstractGitHubApiTestBase {
repo = gitHub.getRepository("github-api-test-org/GHContentIntegrationTest").fork();
}
@Test
public void testBranchProtection() throws Exception {
GHBranch b = repo.getBranch("master");
b.enableProtection(EnforcementLevel.NON_ADMINS, "foo/bar");
b.disableProtection();
}
@Test
public void testGetFileContent() throws Exception {
GHContent content = repo.getFileContent("ghcontent-ro/a-file-with-content");

View File

@@ -7,6 +7,9 @@ import java.io.IOException;
import java.util.Collection;
import java.util.List;
import static org.hamcrest.CoreMatchers.is;
import static org.hamcrest.CoreMatchers.notNullValue;
/**
* @author Kohsuke Kawaguchi
*/
@@ -26,6 +29,33 @@ public class PullRequestTest extends AbstractGitHubApiTestBase {
p.comment("Some comment");
}
@Test
public void testPullRequestReviews() throws Exception {
String name = rnd.next();
GHPullRequest p = getRepository().createPullRequest(name, "stable", "master", "## test");
GHPullRequestReview draftReview = p.createReview("Some draft review", null,
GHPullRequestReviewComment.draft("Some niggle", "changelog.html", 1)
);
assertThat(draftReview.getState(), is(GHPullRequestReviewState.PENDING));
assertThat(draftReview.getBody(), is("Some draft review"));
assertThat(draftReview.getCommitId(), notNullValue());
List<GHPullRequestReview> reviews = p.listReviews().asList();
assertThat(reviews.size(), is(1));
GHPullRequestReview review = reviews.get(0);
assertThat(review.getState(), is(GHPullRequestReviewState.PENDING));
assertThat(review.getBody(), is("Some draft review"));
assertThat(review.getCommitId(), notNullValue());
review.submit("Some review comment", GHPullRequestReviewState.COMMENTED);
List<GHPullRequestReviewComment> comments = review.listReviewComments().asList();
assertEquals(1, comments.size());
GHPullRequestReviewComment comment = comments.get(0);
assertEquals("Some niggle", comment.getBody());
review = p.createReview("Some new review", null,
GHPullRequestReviewComment.draft("Some niggle", "changelog.html", 1)
);
review.delete();
}
@Test
public void testPullRequestReviewComments() throws Exception {
String name = rnd.next();

View File

@@ -67,6 +67,32 @@ public class RepositoryTest extends AbstractGitHubApiTestBase {
}
}
}
@Test
public void LatestRepositoryExist() {
try {
// add the repository that have latest release
GHRelease release = gitHub.getRepository("kamontat/CheckIDNumber").getLatestRelease();
assertEquals("v3.0", release.getTagName());
} catch (IOException e) {
e.printStackTrace();
fail();
}
}
@Test
public void LatestRepositoryNotExist() {
try {
// add the repository that `NOT` have latest release
GHRelease release = gitHub.getRepository("kamontat/Java8Example").getLatestRelease();
assertNull(release);
} catch (IOException e) {
e.printStackTrace();
fail();
}
}
private GHRepository getRepository() throws IOException {
return gitHub.getOrganization("github-api-test-org").getRepository("jenkins");