From 90301ae9ee43208d9210dd1de7d3d51482d405be Mon Sep 17 00:00:00 2001 From: Vaughn Date: Thu, 23 Jan 2020 13:37:35 -0600 Subject: [PATCH 01/11] Added ability to specify permissions for collaborators --- .../java/org/kohsuke/github/GHRepository.java | 5382 +++++++++-------- 1 file changed, 2697 insertions(+), 2685 deletions(-) diff --git a/src/main/java/org/kohsuke/github/GHRepository.java b/src/main/java/org/kohsuke/github/GHRepository.java index 47424fe50e..b0a423ad04 100644 --- a/src/main/java/org/kohsuke/github/GHRepository.java +++ b/src/main/java/org/kohsuke/github/GHRepository.java @@ -1,2685 +1,2697 @@ -/* - * The MIT License - * - * Copyright (c) 2010, Kohsuke Kawaguchi - * - * 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 com.fasterxml.jackson.annotation.JsonProperty; -import com.infradna.tool.bridge_method_injector.WithBridgeMethods; -import edu.umd.cs.findbugs.annotations.SuppressFBWarnings; -import org.apache.commons.lang3.StringUtils; - -import java.io.FileNotFoundException; -import java.io.IOException; -import java.io.InputStream; -import java.io.InputStreamReader; -import java.io.InterruptedIOException; -import java.io.Reader; -import java.net.URL; -import java.util.AbstractSet; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collection; -import java.util.Collections; -import java.util.Date; -import java.util.HashMap; -import java.util.HashSet; -import java.util.Iterator; -import java.util.List; -import java.util.Map; -import java.util.Set; -import java.util.TreeMap; -import java.util.WeakHashMap; - -import static java.util.Arrays.*; -import static org.kohsuke.github.Previews.*; - -/** - * A repository on GitHub. - * - * @author Kohsuke Kawaguchi - */ -@SuppressWarnings({ "UnusedDeclaration" }) -@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; - - private String description, homepage, name, full_name; - private String html_url; // this is the UI - /* - * The license information makes use of the preview API. - * - * See: https://developer.github.com/v3/licenses/ - */ - private GHLicense license; - - private String git_url, ssh_url, clone_url, svn_url, mirror_url; - private GHUser owner; // not fully populated. beware. - private boolean has_issues, has_wiki, fork, has_downloads, has_pages, archived; - - private boolean allow_squash_merge; - private boolean allow_merge_commit; - private boolean allow_rebase_merge; - - @JsonProperty("private") - private boolean _private; - private int forks_count, stargazers_count, watchers_count, size, open_issues_count, subscribers_count; - private String pushed_at; - private Map milestones = new WeakHashMap(); - - private String default_branch, language; - private Map commits = new WeakHashMap(); - - @SkipFromToString - private GHRepoPermission permissions; - - private GHRepository source, parent; - - /** - * Create deployment gh deployment builder. - * - * @param ref - * the ref - * @return the gh deployment builder - */ - public GHDeploymentBuilder createDeployment(String ref) { - return new GHDeploymentBuilder(this, ref); - } - - /** - * Gets deployment statuses. - * - * @param id - * the id - * @return the deployment statuses - * @throws IOException - * the io exception - * @deprecated Use {@code getDeployment(id).listStatuses()} - */ - public PagedIterable getDeploymentStatuses(final int id) throws IOException { - return getDeployment(id).listStatuses(); - } - - /** - * List deployments paged iterable. - * - * @param sha - * the sha - * @param ref - * the ref - * @param task - * the task - * @param environment - * the environment - * @return the paged iterable - */ - public PagedIterable listDeployments(String sha, String ref, String task, String environment) { - return root.createRequest() - .with("sha", sha) - .with("ref", ref) - .with("task", task) - .with("environment", environment) - .withUrlPath(getApiTailUrl("deployments")) - .toIterable(GHDeployment[].class, item -> item.wrap(this)); - } - - /** - * Obtains a single {@link GHDeployment} by its ID. - * - * @param id - * the id - * @return the deployment - * @throws IOException - * the io exception - */ - public GHDeployment getDeployment(long id) throws IOException { - return root.createRequest() - .withUrlPath(getApiTailUrl("deployments/" + id)) - .fetch(GHDeployment.class) - .wrap(this); - } - - /** - * Gets deploy status. - * - * @param deploymentId - * the deployment id - * @param ghDeploymentState - * the gh deployment state - * @return the deploy status - * @throws IOException - * the io exception - * @deprecated Use {@code getDeployment(deploymentId).createStatus(ghDeploymentState)} - */ - public GHDeploymentStatusBuilder createDeployStatus(int deploymentId, GHDeploymentState ghDeploymentState) - throws IOException { - return getDeployment(deploymentId).createStatus(ghDeploymentState); - } - - private static class GHRepoPermission { - boolean pull, push, admin; - } - - /** - * Gets description. - * - * @return the description - */ - public String getDescription() { - return description; - } - - /** - * Gets homepage. - * - * @return the homepage - */ - public String getHomepage() { - return homepage; - } - - /** - * Gets the git:// URL to this repository, such as "git://github.com/kohsuke/jenkins.git" This URL is read-only. - * - * @return the git transport url - */ - public String getGitTransportUrl() { - return git_url; - } - - /** - * Gets the HTTPS URL to this repository, such as "https://github.com/kohsuke/jenkins.git" This URL is read-only. - * - * @return the http transport url - */ - public String getHttpTransportUrl() { - return clone_url; - } - - /** - * Git http transport url string. - * - * @return the string - * @deprecated Typo of {@link #getHttpTransportUrl()} - */ - public String gitHttpTransportUrl() { - return clone_url; - } - - /** - * Gets the Subversion URL to access this repository: https://github.com/rails/rails - * - * @return the svn url - */ - public String getSvnUrl() { - return svn_url; - } - - /** - * Gets the Mirror URL to access this repository: https://github.com/apache/tomee mirrored from - * git://git.apache.org/tomee.git - * - * @return the mirror url - */ - public String getMirrorUrl() { - return mirror_url; - } - - /** - * Gets the SSH URL to access this repository, such as git@github.com:rails/rails.git - * - * @return the ssh url - */ - public String getSshUrl() { - return ssh_url; - } - - public URL getHtmlUrl() { - return GitHub.parseURL(html_url); - } - - /** - * Short repository name without the owner. For example 'jenkins' in case of http://github.com/jenkinsci/jenkins - * - * @return the name - */ - public String getName() { - return name; - } - - /** - * Full repository name including the owner or organization. For example 'jenkinsci/jenkins' in case of - * http://github.com/jenkinsci/jenkins - * - * @return the full name - */ - public String getFullName() { - return full_name; - } - - /** - * Has pull access boolean. - * - * @return the boolean - */ - public boolean hasPullAccess() { - return permissions != null && permissions.pull; - } - - /** - * Has push access boolean. - * - * @return the boolean - */ - public boolean hasPushAccess() { - return permissions != null && permissions.push; - } - - /** - * Has admin access boolean. - * - * @return the boolean - */ - public boolean hasAdminAccess() { - return permissions != null && permissions.admin; - } - - /** - * Gets the primary programming language. - * - * @return the language - */ - public String getLanguage() { - return language; - } - - /** - * Gets owner. - * - * @return the owner - * @throws IOException - * the io exception - */ - public GHUser getOwner() throws IOException { - return root.isOffline() ? owner : root.getUser(getOwnerName()); // because 'owner' isn't fully populated - } - - /** - * Gets issue. - * - * @param id - * the id - * @return the issue - * @throws IOException - * the io exception - */ - public GHIssue getIssue(int id) throws IOException { - return root.createRequest().withUrlPath(getApiTailUrl("issues/" + id)).fetch(GHIssue.class).wrap(this); - } - - /** - * Create issue gh issue builder. - * - * @param title - * the title - * @return the gh issue builder - */ - public GHIssueBuilder createIssue(String title) { - return new GHIssueBuilder(this, title); - } - - /** - * Gets issues. - * - * @param state - * the state - * @return the issues - * @throws IOException - * the io exception - */ - public List getIssues(GHIssueState state) throws IOException { - return listIssues(state).asList(); - } - - /** - * Gets issues. - * - * @param state - * the state - * @param milestone - * the milestone - * @return the issues - * @throws IOException - * the io exception - */ - public List getIssues(GHIssueState state, GHMilestone milestone) throws IOException { - Requester requester = root.createRequest() - .with("state", state) - .with("milestone", milestone == null ? "none" : "" + milestone.getNumber()); - return Arrays - .asList(GHIssue.wrap(requester.withUrlPath(getApiTailUrl("issues")).fetchArray(GHIssue[].class), this)); - } - - /** - * Lists up all the issues in this repository. - * - * @param state - * the state - * @return the paged iterable - */ - public PagedIterable listIssues(final GHIssueState state) { - return root.createRequest() - .with("state", state) - .withUrlPath(getApiTailUrl("issues")) - .toIterable(GHIssue[].class, item -> item.wrap(this)); - } - - /** - * Create release gh release builder. - * - * @param tag - * the tag - * @return the gh release builder - */ - public GHReleaseBuilder createRelease(String tag) { - return new GHReleaseBuilder(this, tag); - } - - /** - * Creates a named ref, such as tag, branch, etc. - * - * @param name - * The name of the fully qualified reference (ie: refs/heads/master). If it doesn't start with 'refs' and - * have at least two slashes, it will be rejected. - * @param sha - * The SHA1 value to set this reference to - * @return the gh ref - * @throws IOException - * the io exception - */ - public GHRef createRef(String name, String sha) throws IOException { - return root.createRequest() - .method("POST") - .with("ref", name) - .with("sha", sha) - .withUrlPath(getApiTailUrl("git/refs")) - .fetch(GHRef.class) - .wrap(root); - } - - /** - * Gets releases. - * - * @return the releases - * @throws IOException - * the io exception - * @deprecated use {@link #listReleases()} - */ - public List getReleases() throws IOException { - return listReleases().asList(); - } - - /** - * Gets release. - * - * @param id - * the id - * @return the release - * @throws IOException - * the io exception - */ - public GHRelease getRelease(long id) throws IOException { - try { - return root.createRequest().withUrlPath(getApiTailUrl("releases/" + id)).fetch(GHRelease.class).wrap(this); - } catch (FileNotFoundException e) { - return null; // no release for this id - } - } - - /** - * Gets release by tag name. - * - * @param tag - * the tag - * @return the release by tag name - * @throws IOException - * the io exception - */ - public GHRelease getReleaseByTagName(String tag) throws IOException { - try { - return root.createRequest() - .withUrlPath(getApiTailUrl("releases/tags/" + tag)) - .fetch(GHRelease.class) - .wrap(this); - } catch (FileNotFoundException e) { - return null; // no release for this tag - } - } - - /** - * Gets latest release. - * - * @return the latest release - * @throws IOException - * the io exception - */ - public GHRelease getLatestRelease() throws IOException { - try { - return root.createRequest().withUrlPath(getApiTailUrl("releases/latest")).fetch(GHRelease.class).wrap(this); - } catch (FileNotFoundException e) { - return null; // no latest release - } - } - - /** - * List releases paged iterable. - * - * @return the paged iterable - * @throws IOException - * the io exception - */ - public PagedIterable listReleases() throws IOException { - return root.createRequest() - .withUrlPath(getApiTailUrl("releases")) - .toIterable(GHRelease[].class, item -> item.wrap(this)); - } - - /** - * List tags paged iterable. - * - * @return the paged iterable - * @throws IOException - * the io exception - */ - public PagedIterable listTags() throws IOException { - return root.createRequest() - .withUrlPath(getApiTailUrl("tags")) - .toIterable(GHTag[].class, item -> item.wrap(this)); - } - - /** - * List languages for the specified repository. The value on the right of a language is the number of bytes of code - * written in that language. { "C": 78769, "Python": 7769 } - * - * @return the map - * @throws IOException - * the io exception - */ - public Map listLanguages() throws IOException { - return root.createRequest().withUrlPath(getApiTailUrl("languages")).fetch(HashMap.class); - } - - /** - * Gets owner name. - * - * @return the owner name - */ - public String getOwnerName() { - // consistency of the GitHub API is super... some serialized forms of GHRepository populate - // a full GHUser while others populate only the owner and email. This later form is super helpful - // in putting the login in owner.name not owner.login... thankfully we can easily identify this - // second set because owner.login will be null - return owner.login != null ? owner.login : owner.name; - } - - /** - * Has issues boolean. - * - * @return the boolean - */ - public boolean hasIssues() { - return has_issues; - } - - /** - * Has wiki boolean. - * - * @return the boolean - */ - public boolean hasWiki() { - return has_wiki; - } - - /** - * Is fork boolean. - * - * @return the boolean - */ - public boolean isFork() { - return fork; - } - - /** - * Is archived boolean. - * - * @return the boolean - */ - public boolean isArchived() { - return archived; - } - - /** - * Is allow squash merge boolean. - * - * @return the boolean - */ - public boolean isAllowSquashMerge() { - return allow_squash_merge; - } - - /** - * Is allow merge commit boolean. - * - * @return the boolean - */ - public boolean isAllowMergeCommit() { - return allow_merge_commit; - } - - /** - * Is allow rebase merge boolean. - * - * @return the boolean - */ - public boolean isAllowRebaseMerge() { - return allow_rebase_merge; - } - - /** - * Returns the number of all forks of this repository. This not only counts direct forks, but also forks of forks, - * and so on. - * - * @return the forks - */ - public int getForks() { - return forks_count; - } - - /** - * Gets stargazers count. - * - * @return the stargazers count - */ - public int getStargazersCount() { - return stargazers_count; - } - - /** - * Is private boolean. - * - * @return the boolean - */ - public boolean isPrivate() { - return _private; - } - - /** - * Has downloads boolean. - * - * @return the boolean - */ - public boolean hasDownloads() { - return has_downloads; - } - - /** - * Has pages boolean. - * - * @return the boolean - */ - public boolean hasPages() { - return has_pages; - } - - /** - * Gets watchers. - * - * @return the watchers - */ - public int getWatchers() { - return watchers_count; - } - - /** - * Gets open issue count. - * - * @return the open issue count - */ - public int getOpenIssueCount() { - return open_issues_count; - } - - /** - * Gets network count. - * - * @return the network count - * @deprecated This no longer exists in the official API documentation. Use {@link #getForks()} - */ - public int getNetworkCount() { - return forks_count; - } - - /** - * Gets subscribers count. - * - * @return the subscribers count - */ - public int getSubscribersCount() { - return subscribers_count; - } - - /** - * Gets pushed at. - * - * @return null if the repository was never pushed at. - */ - public Date getPushedAt() { - return GitHub.parseDate(pushed_at); - } - - /** - * Returns the primary branch you'll configure in the "Admin > Options" config page. - * - * @return This field is null until the user explicitly configures the master branch. - */ - public String getDefaultBranch() { - return default_branch; - } - - /** - * Gets master branch. - * - * @return the master branch - * @deprecated Renamed to {@link #getDefaultBranch()} - */ - public String getMasterBranch() { - return default_branch; - } - - /** - * Gets size. - * - * @return the size - */ - public int getSize() { - return size; - } - - /** - * Gets the collaborators on this repository. This set always appear to include the owner. - * - * @return the collaborators - * @throws IOException - * the io exception - */ - @WithBridgeMethods(Set.class) - public GHPersonSet getCollaborators() throws IOException { - return new GHPersonSet(listCollaborators().asList()); - } - - /** - * Lists up the collaborators on this repository. - * - * @return Users paged iterable - * @throws IOException - * the io exception - */ - public PagedIterable listCollaborators() throws IOException { - return listUsers("collaborators"); - } - - /** - * Lists all - * the - * available assignees to which issues may be assigned. - * - * @return the paged iterable - * @throws IOException - * the io exception - */ - public PagedIterable listAssignees() throws IOException { - return listUsers("assignees"); - } - - /** - * Checks if the given user is an assignee for this repository. - * - * @param u - * the u - * @return the boolean - * @throws IOException - * the io exception - */ - public boolean hasAssignee(GHUser u) throws IOException { - return root.createRequest().withUrlPath(getApiTailUrl("assignees/" + u.getLogin())).fetchHttpStatusCode() - / 100 == 2; - } - - /** - * Gets the names of the collaborators on this repository. This method deviates from the principle of this library - * but it works a lot faster than {@link #getCollaborators()}. - * - * @return the collaborator names - * @throws IOException - * the io exception - */ - public Set getCollaboratorNames() throws IOException { - Set r = new HashSet(); - for (GHUser u : GHUser.wrap( - root.createRequest().withUrlPath(getApiTailUrl("collaborators")).fetchArray(GHUser[].class), - root)) - r.add(u.login); - return r; - } - - /** - * Obtain permission for a given user in this repository. - * - * @param user - * a {@link GHUser#getLogin} - * @return the permission - * @throws IOException - * the io exception - */ - public GHPermissionType getPermission(String user) throws IOException { - GHPermission perm = root.createRequest() - .withUrlPath(getApiTailUrl("collaborators/" + user + "/permission")) - .fetch(GHPermission.class); - perm.wrapUp(root); - return perm.getPermissionType(); - } - - /** - * Obtain permission for a given user in this repository. - * - * @param u - * the u - * @return the permission - * @throws IOException - * the io exception - */ - public GHPermissionType getPermission(GHUser u) throws IOException { - return getPermission(u.getLogin()); - } - - /** - * If this repository belongs to an organization, return a set of teams. - * - * @return the teams - * @throws IOException - * the io exception - */ - public Set getTeams() throws IOException { - return Collections.unmodifiableSet(new HashSet(Arrays.asList( - GHTeam.wrapUp(root.createRequest().withUrlPath(getApiTailUrl("teams")).fetchArray(GHTeam[].class), - root.getOrganization(getOwnerName()))))); - } - - /** - * Add collaborators. - * - * @param users - * the users - * @throws IOException - * the io exception - */ - public void addCollaborators(GHUser... users) throws IOException { - addCollaborators(asList(users)); - } - - /** - * Add collaborators. - * - * @param users - * the users - * @throws IOException - * the io exception - */ - public void addCollaborators(Collection users) throws IOException { - modifyCollaborators(users, "PUT"); - } - - /** - * Remove collaborators. - * - * @param users - * the users - * @throws IOException - * the io exception - */ - public void removeCollaborators(GHUser... users) throws IOException { - removeCollaborators(asList(users)); - } - - /** - * Remove collaborators. - * - * @param users - * the users - * @throws IOException - * the io exception - */ - public void removeCollaborators(Collection users) throws IOException { - modifyCollaborators(users, "DELETE"); - } - - private void modifyCollaborators(Collection users, String method) throws IOException { - for (GHUser user : users) { - root.createRequest().method(method).withUrlPath(getApiTailUrl("collaborators/" + user.getLogin())).send(); - } - } - - /** - * Sets email service hook. - * - * @param address - * the address - * @throws IOException - * the io exception - */ - public void setEmailServiceHook(String address) throws IOException { - Map config = new HashMap(); - config.put("address", address); - root.createRequest() - .method("POST") - .with("name", "email") - .with("config", config) - .with("active", true) - .withUrlPath(getApiTailUrl("hooks")) - .send(); - } - - private void edit(String key, String value) throws IOException { - Requester requester = root.createRequest(); - if (!key.equals("name")) - requester.with("name", name); // even when we don't change the name, we need to send it in - requester.with(key, value).method("PATCH").withUrlPath(getApiTailUrl("")).send(); - } - - /** - * Enables or disables the issue tracker for this repository. - * - * @param v - * the v - * @throws IOException - * the io exception - */ - public void enableIssueTracker(boolean v) throws IOException { - edit("has_issues", String.valueOf(v)); - } - - /** - * Enables or disables Wiki for this repository. - * - * @param v - * the v - * @throws IOException - * the io exception - */ - public void enableWiki(boolean v) throws IOException { - edit("has_wiki", String.valueOf(v)); - } - - /** - * Enable downloads. - * - * @param v - * the v - * @throws IOException - * the io exception - */ - public void enableDownloads(boolean v) throws IOException { - edit("has_downloads", String.valueOf(v)); - } - - /** - * Rename this repository. - * - * @param name - * the name - * @throws IOException - * the io exception - */ - public void renameTo(String name) throws IOException { - edit("name", name); - } - - /** - * Sets description. - * - * @param value - * the value - * @throws IOException - * the io exception - */ - public void setDescription(String value) throws IOException { - edit("description", value); - } - - /** - * Sets homepage. - * - * @param value - * the value - * @throws IOException - * the io exception - */ - public void setHomepage(String value) throws IOException { - edit("homepage", value); - } - - /** - * Sets default branch. - * - * @param value - * the value - * @throws IOException - * the io exception - */ - public void setDefaultBranch(String value) throws IOException { - edit("default_branch", value); - } - - /** - * Sets private. - * - * @param value - * the value - * @throws IOException - * the io exception - */ - public void setPrivate(boolean value) throws IOException { - edit("private", Boolean.toString(value)); - } - - /** - * Allow squash merge. - * - * @param value - * the value - * @throws IOException - * the io exception - */ - public void allowSquashMerge(boolean value) throws IOException { - edit("allow_squash_merge", Boolean.toString(value)); - } - - /** - * Allow merge commit. - * - * @param value - * the value - * @throws IOException - * the io exception - */ - public void allowMergeCommit(boolean value) throws IOException { - edit("allow_merge_commit", Boolean.toString(value)); - } - - /** - * Allow rebase merge. - * - * @param value - * the value - * @throws IOException - * the io exception - */ - public void allowRebaseMerge(boolean value) throws IOException { - edit("allow_rebase_merge", Boolean.toString(value)); - } - - /** - * Deletes this repository. - * - * @throws IOException - * the io exception - */ - public void delete() throws IOException { - try { - root.createRequest().method("DELETE").withUrlPath(getApiTailUrl("")).send(); - } catch (FileNotFoundException x) { - throw (FileNotFoundException) new FileNotFoundException("Failed to delete " + getOwnerName() + "/" + name - + "; might not exist, or you might need the delete_repo scope in your token: http://stackoverflow.com/a/19327004/12916") - .initCause(x); - } - } - - /** - * Will archive and this repository as read-only. When a repository is archived, any operation that can change its - * state is forbidden. This applies symmetrically if trying to unarchive it. - * - *

- * When you try to do any operation that modifies a read-only repository, it returns the response: - * - *

-     * org.kohsuke.github.HttpException: {
-     *     "message":"Repository was archived so is read-only.",
-     *     "documentation_url":"https://developer.github.com/v3/repos/#edit"
-     * }
-     * 
- * - * @throws IOException - * In case of any networking error or error from the server. - */ - public void archive() throws IOException { - edit("archived", "true"); - // Generall would not update this record, - // but do so here since this will result in any other update actions failing - archived = true; - } - - /** - * Sort orders for listing forks - */ - public enum ForkSort { - NEWEST, OLDEST, STARGAZERS - } - - /** - * Lists all the direct forks of this repository, sorted by github api default, currently {@link ForkSort#NEWEST - * ForkSort.NEWEST}*. - * - * @return the paged iterable - */ - public PagedIterable listForks() { - return listForks(null); - } - - /** - * Lists all the direct forks of this repository, sorted by the given sort order. - * - * @param sort - * the sort order. If null, defaults to github api default, currently {@link ForkSort#NEWEST - * ForkSort.NEWEST}. - * @return the paged iterable - */ - public PagedIterable listForks(final ForkSort sort) { - return root.createRequest() - .with("sort", sort) - .withUrlPath(getApiTailUrl("forks")) - .toIterable(GHRepository[].class, item -> item.wrap(root)); - } - - /** - * Forks this repository as your repository. - * - * @return Newly forked repository that belong to you. - * @throws IOException - * the io exception - */ - public GHRepository fork() throws IOException { - root.createRequest().method("POST").withUrlPath(getApiTailUrl("forks")).send(); - - // this API is asynchronous. we need to wait for a bit - for (int i = 0; i < 10; i++) { - GHRepository r = root.getMyself().getRepository(name); - if (r != null) - return r; - try { - Thread.sleep(3000); - } catch (InterruptedException e) { - throw (IOException) new InterruptedIOException().initCause(e); - } - } - throw new IOException(this + " was forked but can't find the new repository"); - } - - /** - * Forks this repository into an organization. - * - * @param org - * the org - * @return Newly forked repository that belong to you. - * @throws IOException - * the io exception - */ - public GHRepository forkTo(GHOrganization org) throws IOException { - root.createRequest() - .method("POST") - .with("organization", org.getLogin()) - .withUrlPath(getApiTailUrl("forks")) - .send(); - - // this API is asynchronous. we need to wait for a bit - for (int i = 0; i < 10; i++) { - GHRepository r = org.getRepository(name); - if (r != null) - return r; - try { - Thread.sleep(3000); - } catch (InterruptedException e) { - throw (IOException) new InterruptedIOException().initCause(e); - } - } - throw new IOException(this + " was forked into " + org.getLogin() + " but can't find the new repository"); - } - - /** - * Retrieves a specified pull request. - * - * @param i - * the - * @return the pull request - * @throws IOException - * the io exception - */ - public GHPullRequest getPullRequest(int i) throws IOException { - return root.createRequest() - .withPreview(SHADOW_CAT) - .withUrlPath(getApiTailUrl("pulls/" + i)) - .fetch(GHPullRequest.class) - .wrapUp(this); - } - - /** - * Retrieves all the pull requests of a particular state. - * - * @param state - * the state - * @return the pull requests - * @throws IOException - * the io exception - * @see #listPullRequests(GHIssueState) #listPullRequests(GHIssueState) - */ - public List getPullRequests(GHIssueState state) throws IOException { - return queryPullRequests().state(state).list().asList(); - } - - /** - * Retrieves all the pull requests of a particular state. - * - * @param state - * the state - * @return the paged iterable - * @deprecated Use {@link #queryPullRequests()} - */ - public PagedIterable listPullRequests(GHIssueState state) { - return queryPullRequests().state(state).list(); - } - - /** - * Retrieves pull requests. - * - * @return the gh pull request query builder - */ - public GHPullRequestQueryBuilder queryPullRequests() { - return new GHPullRequestQueryBuilder(this); - } - - /** - * Creates a new pull request. - * - * @param title - * Required. The title of the pull request. - * @param head - * Required. The name of the branch where your changes are implemented. For cross-repository pull - * requests in the same network, namespace head with a user like this: username:branch. - * @param base - * Required. The name of the branch you want your changes pulled into. This should be an existing branch - * on the current repository. - * @param body - * The contents of the pull request. This is the markdown description of a pull request. - * @return the gh pull request - * @throws IOException - * the io exception - */ - public GHPullRequest createPullRequest(String title, String head, String base, String body) throws IOException { - return createPullRequest(title, head, base, body, true); - } - - /** - * Creates a new pull request. Maintainer's permissions aware. - * - * @param title - * Required. The title of the pull request. - * @param head - * Required. The name of the branch where your changes are implemented. For cross-repository pull - * requests in the same network, namespace head with a user like this: username:branch. - * @param base - * Required. The name of the branch you want your changes pulled into. This should be an existing branch - * on the current repository. - * @param body - * The contents of the pull request. This is the markdown description of a pull request. - * @param maintainerCanModify - * Indicates whether maintainers can modify the pull request. - * @return the gh pull request - * @throws IOException - * the io exception - */ - public GHPullRequest createPullRequest(String title, - String head, - String base, - String body, - boolean maintainerCanModify) throws IOException { - return createPullRequest(title, head, base, body, maintainerCanModify, false); - } - - /** - * Creates a new pull request. Maintainer's permissions and draft aware. - * - * @param title - * Required. The title of the pull request. - * @param head - * Required. The name of the branch where your changes are implemented. For cross-repository pull - * requests in the same network, namespace head with a user like this: username:branch. - * @param base - * Required. The name of the branch you want your changes pulled into. This should be an existing branch - * on the current repository. - * @param body - * The contents of the pull request. This is the markdown description of a pull request. - * @param maintainerCanModify - * Indicates whether maintainers can modify the pull request. - * @param draft - * Indicates whether to create a draft pull request or not. - * @return the gh pull request - * @throws IOException - * the io exception - */ - public GHPullRequest createPullRequest(String title, - String head, - String base, - String body, - boolean maintainerCanModify, - boolean draft) throws IOException { - return root.createRequest() - .method("POST") - .withPreview(SHADOW_CAT) - .with("title", title) - .with("head", head) - .with("base", base) - .with("body", body) - .with("maintainer_can_modify", maintainerCanModify) - .with("draft", draft) - .withUrlPath(getApiTailUrl("pulls")) - .fetch(GHPullRequest.class) - .wrapUp(this); - } - - /** - * Retrieves the currently configured hooks. - * - * @return the hooks - * @throws IOException - * the io exception - */ - public List getHooks() throws IOException { - return GHHooks.repoContext(this, owner).getHooks(); - } - - /** - * Gets hook. - * - * @param id - * the id - * @return the hook - * @throws IOException - * the io exception - */ - public GHHook getHook(int id) throws IOException { - return GHHooks.repoContext(this, owner).getHook(id); - } - - /** - * Gets a comparison between 2 points in the repository. This would be similar to calling - * git log id1...id2 against a local repository. - * - * @param id1 - * an identifier for the first point to compare from, this can be a sha1 ID (for a commit, tag etc) or a - * direct tag name - * @param id2 - * an identifier for the second point to compare to. Can be the same as the first point. - * @return the comparison output - * @throws IOException - * on failure communicating with GitHub - */ - public GHCompare getCompare(String id1, String id2) throws IOException { - GHCompare compare = root.createRequest() - .withUrlPath(getApiTailUrl(String.format("compare/%s...%s", id1, id2))) - .fetch(GHCompare.class); - return compare.wrap(this); - } - - /** - * Gets compare. - * - * @param id1 - * the id 1 - * @param id2 - * the id 2 - * @return the compare - * @throws IOException - * the io exception - */ - public GHCompare getCompare(GHCommit id1, GHCommit id2) throws IOException { - return getCompare(id1.getSHA1(), id2.getSHA1()); - } - - /** - * Gets compare. - * - * @param id1 - * the id 1 - * @param id2 - * the id 2 - * @return the compare - * @throws IOException - * the io exception - */ - public GHCompare getCompare(GHBranch id1, GHBranch id2) throws IOException { - - GHRepository owner1 = id1.getOwner(); - GHRepository owner2 = id2.getOwner(); - - // If the owner of the branches is different, we have a cross-fork compare. - if (owner1 != null && owner2 != null) { - String ownerName1 = owner1.getOwnerName(); - String ownerName2 = owner2.getOwnerName(); - if (!StringUtils.equals(ownerName1, ownerName2)) { - String qualifiedName1 = String.format("%s:%s", ownerName1, id1.getName()); - String qualifiedName2 = String.format("%s:%s", ownerName2, id2.getName()); - return getCompare(qualifiedName1, qualifiedName2); - } - } - - return getCompare(id1.getName(), id2.getName()); - - } - - /** - * Retrieves all refs for the github repository. - * - * @return an array of GHRef elements coresponding with the refs in the remote repository. - * @throws IOException - * on failure communicating with GitHub - */ - public GHRef[] getRefs() throws IOException { - return GHRef.wrap(root.createRequest() - .withUrlPath(String.format("/repos/%s/%s/git/refs", getOwnerName(), name)) - .fetchArray(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 listRefs() throws IOException { - final String url = String.format("/repos/%s/%s/git/refs", getOwnerName(), name); - return root.createRequest().withUrlPath(url).toIterable(GHRef[].class, item -> item.wrap(root)); - } - - /** - * Retrieves all refs of the given type for the current GitHub repository. - * - * @param refType - * the type of reg to search for e.g. tags or commits - * @return an array of all refs matching the request type - * @throws IOException - * on failure communicating with GitHub, potentially due to an invalid ref type being requested - */ - public GHRef[] getRefs(String refType) throws IOException { - return GHRef.wrap(root.createRequest() - .withUrlPath(String.format("/repos/%s/%s/git/refs/%s", getOwnerName(), name, refType)) - .fetchArray(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. tags or commits - * @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 listRefs(String refType) throws IOException { - final String url = String.format("/repos/%s/%s/git/refs/%s", getOwnerName(), name, refType); - return root.createRequest().withUrlPath(url).toIterable(GHRef[].class, item -> item.wrap(root)); - } - - /** - * Retrive a ref of the given type for the current GitHub repository. - * - * @param refName - * eg: heads/branch - * @return refs matching the request type - * @throws IOException - * on failure communicating with GitHub, potentially due to an invalid ref type being requested - */ - public GHRef getRef(String refName) throws IOException { - return root.createRequest() - .withUrlPath(getApiTailUrl(String.format("git/refs/%s", refName))) - .fetch(GHRef.class) - .wrap(root); - } - - /** - * Returns the annotated 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 - * @throws IOException - * the io exception - */ - public GHTagObject getTagObject(String sha) throws IOException { - return root.createRequest().withUrlPath(getApiTailUrl("git/tags/" + sha)).fetch(GHTagObject.class).wrap(this); - } - - /** - * Retrive a tree of the given type for the current GitHub repository. - * - * @param sha - * sha number or branch name ex: "master" - * @return refs matching the request type - * @throws IOException - * on failure communicating with GitHub, potentially due to an invalid tree type being requested - */ - public GHTree getTree(String sha) throws IOException { - String url = String.format("/repos/%s/%s/git/trees/%s", getOwnerName(), name, sha); - return root.createRequest().withUrlPath(url).fetch(GHTree.class).wrap(this); - } - - /** - * Create tree gh tree builder. - * - * @return the gh tree builder - */ - public GHTreeBuilder createTree() { - return new GHTreeBuilder(this); - } - - /** - * Retrieves the tree for the current GitHub repository, recursively as described in here: - * https://developer.github.com/v3/git/trees/#get-a-tree-recursively - * - * @param sha - * sha number or branch name ex: "master" - * @param recursive - * use 1 - * @return the tree recursive - * @throws IOException - * on failure communicating with GitHub, potentially due to an invalid tree type being requested - */ - public GHTree getTreeRecursive(String sha, int recursive) throws IOException { - String url = String.format("/repos/%s/%s/git/trees/%s", getOwnerName(), name, sha); - return root.createRequest().with("recursive", recursive).withUrlPath(url).fetch(GHTree.class).wrap(this); - } - - /** - * Obtains the metadata & the content of a blob. - * - *

- * This method retrieves the whole content in memory, so beware when you are dealing with large BLOB. - * - * @param blobSha - * the blob sha - * @return the blob - * @throws IOException - * the io exception - * @see Get a blob - * @see #readBlob(String) #readBlob(String) - */ - public GHBlob getBlob(String blobSha) throws IOException { - String target = getApiTailUrl("git/blobs/" + blobSha); - return root.createRequest().withUrlPath(target).fetch(GHBlob.class); - } - - /** - * Create blob gh blob builder. - * - * @return the gh blob builder - */ - public GHBlobBuilder createBlob() { - return new GHBlobBuilder(this); - } - - /** - * Reads the content of a blob as a stream for better efficiency. - * - * @param blobSha - * the blob sha - * @return the input stream - * @throws IOException - * the io exception - * @see Get a blob - * @see #getBlob(String) #getBlob(String) - */ - public InputStream readBlob(String blobSha) throws IOException { - String target = getApiTailUrl("git/blobs/" + blobSha); - - // https://developer.github.com/v3/media/ describes this media type - return root.createRequest() - .withHeader("Accept", "application/vnd.github.v3.raw") - .withUrlPath(target) - .fetchStream(); - } - - /** - * Gets a commit object in this repository. - * - * @param sha1 - * the sha 1 - * @return the commit - * @throws IOException - * the io exception - */ - public GHCommit getCommit(String sha1) throws IOException { - GHCommit c = commits.get(sha1); - if (c == null) { - c = root.createRequest() - .withUrlPath(String.format("/repos/%s/%s/commits/%s", getOwnerName(), name, sha1)) - .fetch(GHCommit.class) - .wrapUp(this); - commits.put(sha1, c); - } - return c; - } - - /** - * Create commit gh commit builder. - * - * @return the gh commit builder - */ - public GHCommitBuilder createCommit() { - return new GHCommitBuilder(this); - } - - /** - * Lists all the commits. - * - * @return the paged iterable - */ - public PagedIterable listCommits() { - return root.createRequest() - .withUrlPath(String.format("/repos/%s/%s/commits", getOwnerName(), name)) - .toIterable(GHCommit[].class, item -> item.wrapUp(this)); - } - - /** - * Search commits by specifying filters through a builder pattern. - * - * @return the gh commit query builder - */ - public GHCommitQueryBuilder queryCommits() { - return new GHCommitQueryBuilder(this); - } - - /** - * Lists up all the commit comments in this repository. - * - * @return the paged iterable - */ - public PagedIterable listCommitComments() { - return root.createRequest() - .withUrlPath(String.format("/repos/%s/%s/comments", getOwnerName(), name)) - .toIterable(GHCommitComment[].class, item -> item.wrap(this)); - } - - /** - * Gets the basic license details for the repository. - *

- * - * @return null if there's no license. - * @throws IOException - * as usual but also if you don't use the preview connector - */ - public GHLicense getLicense() throws IOException { - GHContentWithLicense lic = getLicenseContent_(); - return lic != null ? lic.license : null; - } - - /** - * Retrieves the contents of the repository's license file - makes an additional API call - *

- * - * @return details regarding the license contents, or null if there's no license. - * @throws IOException - * as usual but also if you don't use the preview connector - */ - public GHContent getLicenseContent() throws IOException { - return getLicenseContent_(); - } - - private GHContentWithLicense getLicenseContent_() throws IOException { - try { - return root.createRequest() - .withUrlPath(getApiTailUrl("license")) - .fetch(GHContentWithLicense.class) - .wrap(this); - } catch (FileNotFoundException e) { - return null; - } - } - - /** - * /** Lists all the commit statues attached to the given commit, newer ones first. - * - * @param sha1 - * the sha 1 - * @return the paged iterable - * @throws IOException - * the io exception - */ - public PagedIterable listCommitStatuses(final String sha1) throws IOException { - return root.createRequest() - .withUrlPath(String.format("/repos/%s/%s/statuses/%s", getOwnerName(), name, sha1)) - .toIterable(GHCommitStatus[].class, item -> item.wrapUp(root)); - } - - /** - * Gets the last status of this commit, which is what gets shown in the UI. - * - * @param sha1 - * the sha 1 - * @return the last commit status - * @throws IOException - * the io exception - */ - public GHCommitStatus getLastCommitStatus(String sha1) throws IOException { - List v = listCommitStatuses(sha1).asList(); - return v.isEmpty() ? null : v.get(0); - } - - /** - * Creates a commit status - * - * @param sha1 - * the sha 1 - * @param state - * the state - * @param targetUrl - * Optional parameter that points to the URL that has more details. - * @param description - * Optional short description. - * @param context - * Optinal commit status context. - * @return the gh commit status - * @throws IOException - * the io exception - */ - public GHCommitStatus createCommitStatus(String sha1, - GHCommitState state, - String targetUrl, - String description, - String context) throws IOException { - return root.createRequest() - .method("POST") - .with("state", state) - .with("target_url", targetUrl) - .with("description", description) - .with("context", context) - .withUrlPath(String.format("/repos/%s/%s/statuses/%s", getOwnerName(), this.name, sha1)) - .fetch(GHCommitStatus.class) - .wrapUp(root); - } - - /** - * Create commit status gh commit status. - * - * @param sha1 - * the sha 1 - * @param state - * the state - * @param targetUrl - * the target url - * @param description - * the description - * @return the gh commit status - * @throws IOException - * the io exception - * @see #createCommitStatus(String, GHCommitState, String, String, String) #createCommitStatus(String, - * GHCommitState,String,String,String) - */ - public GHCommitStatus createCommitStatus(String sha1, GHCommitState state, String targetUrl, String description) - throws IOException { - return createCommitStatus(sha1, state, targetUrl, description, null); - } - - /** - * Lists repository events. - * - * @return the paged iterable - * @throws IOException - * the io exception - */ - public PagedIterable listEvents() throws IOException { - return root.createRequest() - .withUrlPath(String.format("/repos/%s/%s/events", getOwnerName(), name)) - .toIterable(GHEventInfo[].class, item -> item.wrapUp(root)); - } - - /** - * Lists labels in this repository. - *

- * https://developer.github.com/v3/issues/labels/#list-all-labels-for-this-repository - * - * @return the paged iterable - * @throws IOException - * the io exception - */ - public PagedIterable listLabels() throws IOException { - return root.createRequest() - .withUrlPath(getApiTailUrl("labels")) - .toIterable(GHLabel[].class, item -> item.wrapUp(this)); - } - - /** - * Gets label. - * - * @param name - * the name - * @return the label - * @throws IOException - * the io exception - */ - public GHLabel getLabel(String name) throws IOException { - return root.createRequest().withUrlPath(getApiTailUrl("labels/" + name)).fetch(GHLabel.class).wrapUp(this); - } - - /** - * Create label gh label. - * - * @param name - * the name - * @param color - * the color - * @return the gh label - * @throws IOException - * the io exception - */ - public GHLabel createLabel(String name, String color) throws IOException { - return createLabel(name, color, ""); - } - - /** - * Description is still in preview. - * - * @param name - * the name - * @param color - * the color - * @param description - * the description - * @return gh label - * @throws IOException - * the io exception - */ - public GHLabel createLabel(String name, String color, String description) throws IOException { - return root.createRequest() - .method("POST") - .with("name", name) - .with("color", color) - .with("description", description) - .withUrlPath(getApiTailUrl("labels")) - .fetch(GHLabel.class) - .wrapUp(this); - } - - /** - * Lists all the invitations. - * - * @return the paged iterable - */ - public PagedIterable listInvitations() { - return root.createRequest() - .withUrlPath(String.format("/repos/%s/%s/invitations", getOwnerName(), name)) - .toIterable(GHInvitation[].class, item -> item.wrapUp(root)); - } - - /** - * Lists all the subscribers (aka watchers.) - *

- * https://developer.github.com/v3/activity/watching/ - * - * @return the paged iterable - */ - public PagedIterable listSubscribers() { - return listUsers("subscribers"); - } - - /** - * Lists all the users who have starred this repo based on the old version of the API. For additional information, - * like date when the repository was starred, see {@link #listStargazers2()} - * - * @return the paged iterable - */ - public PagedIterable listStargazers() { - return listUsers("stargazers"); - } - - /** - * Lists all the users who have starred this repo based on new version of the API, having extended information like - * the time when the repository was starred. For compatibility with the old API see {@link #listStargazers()} - * - * @return the paged iterable - */ - public PagedIterable listStargazers2() { - return root.createRequest() - .withPreview("application/vnd.github.v3.star+json") - .withUrlPath(getApiTailUrl("stargazers")) - .toIterable(GHStargazer[].class, item -> item.wrapUp(this)); - } - - private PagedIterable listUsers(final String suffix) { - return root.createRequest() - .withUrlPath(getApiTailUrl(suffix)) - .toIterable(GHUser[].class, item -> item.wrapUp(root)); - } - - /** - * See https://api.github.com/hooks for possible names and their configuration scheme. TODO: produce type-safe - * binding - * - * @param name - * Type of the hook to be created. See https://api.github.com/hooks for possible names. - * @param config - * The configuration hash. - * @param events - * Can be null. Types of events to hook into. - * @param active - * the active - * @return the gh hook - * @throws IOException - * the io exception - */ - public GHHook createHook(String name, Map config, Collection events, boolean active) - throws IOException { - return GHHooks.repoContext(this, owner).createHook(name, config, events, active); - } - - /** - * Create web hook gh hook. - * - * @param url - * the url - * @param events - * the events - * @return the gh hook - * @throws IOException - * the io exception - */ - public GHHook createWebHook(URL url, Collection events) throws IOException { - return createHook("web", Collections.singletonMap("url", url.toExternalForm()), events, true); - } - - /** - * Create web hook gh hook. - * - * @param url - * the url - * @return the gh hook - * @throws IOException - * the io exception - */ - public GHHook createWebHook(URL url) throws IOException { - return createWebHook(url, null); - } - - // this is no different from getPullRequests(OPEN) - // /** - // * Retrieves all the pull requests. - // */ - // public List getPullRequests() throws IOException { - // return root.retrieveWithAuth("/pulls/"+owner+'/'+name,JsonPullRequests.class).wrap(root); - // } - - /** - * Returns a set that represents the post-commit hook URLs. The returned set is live, and changes made to them are - * reflected to GitHub. - * - * @return the post commit hooks - * @deprecated Use {@link #getHooks()} and {@link #createHook(String, Map, Collection, boolean)} - */ - @SuppressFBWarnings(value = "DMI_COLLECTION_OF_URLS", - justification = "It causes a performance degradation, but we have already exposed it to the API") - public Set getPostCommitHooks() { - return postCommitHooks; - } - - /** - * Live set view of the post-commit hook. - */ - @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 postCommitHooks = new AbstractSet() { - private List getPostCommitHooks() { - try { - List r = new ArrayList(); - for (GHHook h : getHooks()) { - if (h.getName().equals("web")) { - r.add(new URL(h.getConfig().get("url"))); - } - } - return r; - } catch (IOException e) { - throw new GHException("Failed to retrieve post-commit hooks", e); - } - } - - @Override - public Iterator iterator() { - return getPostCommitHooks().iterator(); - } - - @Override - public int size() { - return getPostCommitHooks().size(); - } - - @Override - public boolean add(URL url) { - try { - createWebHook(url); - return true; - } catch (IOException e) { - throw new GHException("Failed to update post-commit hooks", e); - } - } - - @Override - public boolean remove(Object url) { - try { - String _url = ((URL) url).toExternalForm(); - for (GHHook h : getHooks()) { - if (h.getName().equals("web") && h.getConfig().get("url").equals(_url)) { - h.delete(); - return true; - } - } - return false; - } catch (IOException e) { - throw new GHException("Failed to update post-commit hooks", e); - } - } - }; - - GHRepository wrap(GitHub root) { - this.root = root; - if (root.isOffline()) { - owner.wrapUp(root); - } - return this; - } - - /** - * Gets branches by {@linkplain GHBranch#getName() their names}. - * - * @return the branches - * @throws IOException - * the io exception - */ - public Map getBranches() throws IOException { - Map r = new TreeMap(); - for (GHBranch p : root.createRequest().withUrlPath(getApiTailUrl("branches")).fetchArray(GHBranch[].class)) { - p.wrap(this); - r.put(p.getName(), p); - } - return r; - } - - /** - * Gets branch. - * - * @param name - * the name - * @return the branch - * @throws IOException - * the io exception - */ - public GHBranch getBranch(String name) throws IOException { - return root.createRequest().withUrlPath(getApiTailUrl("branches/" + name)).fetch(GHBranch.class).wrap(this); - } - - /** - * Gets milestones. - * - * @return the milestones - * @throws IOException - * the io exception - * @deprecated Use {@link #listMilestones(GHIssueState)} - */ - public Map getMilestones() throws IOException { - Map milestones = new TreeMap(); - for (GHMilestone m : listMilestones(GHIssueState.OPEN)) { - milestones.put(m.getNumber(), m); - } - return milestones; - } - - /** - * Lists up all the milestones in this repository. - * - * @param state - * the state - * @return the paged iterable - */ - public PagedIterable listMilestones(final GHIssueState state) { - return root.createRequest() - .with("state", state) - .withUrlPath(getApiTailUrl("milestones")) - .toIterable(GHMilestone[].class, item -> item.wrap(this)); - } - - /** - * Gets milestone. - * - * @param number - * the number - * @return the milestone - * @throws IOException - * the io exception - */ - public GHMilestone getMilestone(int number) throws IOException { - GHMilestone m = milestones.get(number); - if (m == null) { - m = root.createRequest().withUrlPath(getApiTailUrl("milestones/" + number)).fetch(GHMilestone.class); - m.owner = this; - m.root = root; - milestones.put(m.getNumber(), m); - } - return m; - } - - /** - * Gets file content. - * - * @param path - * the path - * @return the file content - * @throws IOException - * the io exception - */ - public GHContent getFileContent(String path) throws IOException { - return getFileContent(path, null); - } - - /** - * Gets file content. - * - * @param path - * the path - * @param ref - * the ref - * @return the file content - * @throws IOException - * the io exception - */ - public GHContent getFileContent(String path, String ref) throws IOException { - Requester requester = root.createRequest(); - String target = getApiTailUrl("contents/" + path); - - return requester.with("ref", ref).withUrlPath(target).fetch(GHContent.class).wrap(this); - } - - /** - * Gets directory content. - * - * @param path - * the path - * @return the directory content - * @throws IOException - * the io exception - */ - public List getDirectoryContent(String path) throws IOException { - return getDirectoryContent(path, null); - } - - /** - * Gets directory content. - * - * @param path - * the path - * @param ref - * the ref - * @return the directory content - * @throws IOException - * the io exception - */ - public List getDirectoryContent(String path, String ref) throws IOException { - Requester requester = root.createRequest(); - while (path.endsWith("/")) { - path = path.substring(0, path.length() - 1); - } - String target = getApiTailUrl("contents/" + path); - - GHContent[] files = requester.with("ref", ref).withUrlPath(target).fetchArray(GHContent[].class); - - GHContent.wrap(files, this); - - return Arrays.asList(files); - } - - /** - * https://developer.github.com/v3/repos/contents/#get-the-readme - * - * @return the readme - * @throws IOException - * the io exception - */ - public GHContent getReadme() throws IOException { - Requester requester = root.createRequest(); - return requester.withUrlPath(getApiTailUrl("readme")).fetch(GHContent.class).wrap(this); - } - - /** - * Creates a new content, or update an existing content. - * - * @return the gh content builder - */ - public GHContentBuilder createContent() { - return new GHContentBuilder(this); - } - - /** - * Use {@link #createContent()}. - * - * @param content - * the content - * @param commitMessage - * the commit message - * @param path - * the path - * @return the gh content update response - * @throws IOException - * the io exception - */ - @Deprecated - public GHContentUpdateResponse createContent(String content, String commitMessage, String path) throws IOException { - return createContent().content(content).message(commitMessage).path(path).commit(); - } - - /** - * Use {@link #createContent()}. - * - * @param content - * the content - * @param commitMessage - * the commit message - * @param path - * the path - * @param branch - * the branch - * @return the gh content update response - * @throws IOException - * the io exception - */ - @Deprecated - public GHContentUpdateResponse createContent(String content, String commitMessage, String path, String branch) - throws IOException { - return createContent().content(content).message(commitMessage).path(path).branch(branch).commit(); - } - - /** - * Use {@link #createContent()}. - * - * @param contentBytes - * the content bytes - * @param commitMessage - * the commit message - * @param path - * the path - * @return the gh content update response - * @throws IOException - * the io exception - */ - @Deprecated - public GHContentUpdateResponse createContent(byte[] contentBytes, String commitMessage, String path) - throws IOException { - return createContent().content(contentBytes).message(commitMessage).path(path).commit(); - } - - /** - * Use {@link #createContent()}. - * - * @param contentBytes - * the content bytes - * @param commitMessage - * the commit message - * @param path - * the path - * @param branch - * the branch - * @return the gh content update response - * @throws IOException - * the io exception - */ - @Deprecated - public GHContentUpdateResponse createContent(byte[] contentBytes, String commitMessage, String path, String branch) - throws IOException { - return createContent().content(contentBytes).message(commitMessage).path(path).branch(branch).commit(); - } - - /** - * Create milestone gh milestone. - * - * @param title - * the title - * @param description - * the description - * @return the gh milestone - * @throws IOException - * the io exception - */ - public GHMilestone createMilestone(String title, String description) throws IOException { - return root.createRequest() - .method("POST") - .with("title", title) - .with("description", description) - .withUrlPath(getApiTailUrl("milestones")) - .fetch(GHMilestone.class) - .wrap(this); - } - - /** - * Add deploy key gh deploy key. - * - * @param title - * the title - * @param key - * the key - * @return the gh deploy key - * @throws IOException - * the io exception - */ - public GHDeployKey addDeployKey(String title, String key) throws IOException { - return root.createRequest() - .method("POST") - .with("title", title) - .with("key", key) - .withUrlPath(getApiTailUrl("keys")) - .fetch(GHDeployKey.class) - .wrap(this); - - } - - /** - * Gets deploy keys. - * - * @return the deploy keys - * @throws IOException - * the io exception - */ - public List getDeployKeys() throws IOException { - List list = new ArrayList( - Arrays.asList(root.createRequest().withUrlPath(getApiTailUrl("keys")).fetchArray(GHDeployKey[].class))); - for (GHDeployKey h : list) - h.wrap(this); - return list; - } - - /** - * Forked repositories have a 'source' attribute that specifies the ultimate source of the forking chain. - * - * @return {@link GHRepository} that points to the root repository where this repository is forked (indirectly or - * directly) from. Otherwise null. - * @throws IOException - * the io exception - * @see #getParent() #getParent() - */ - public GHRepository getSource() throws IOException { - if (source == null) - return null; - if (source.root == null) - source = root.getRepository(source.getFullName()); - return source; - } - - /** - * Forked repositories have a 'parent' attribute that specifies the repository this repository is directly forked - * from. If we keep traversing {@link #getParent()} until it returns null, that is {@link #getSource()}. - * - * @return {@link GHRepository} that points to the repository where this repository is forked directly from. - * Otherwise null. - * @throws IOException - * the io exception - * @see #getSource() #getSource() - */ - public GHRepository getParent() throws IOException { - if (parent == null) - return null; - if (parent.root == null) - parent = root.getRepository(parent.getFullName()); - return parent; - } - - /** - * Subscribes to this repository to get notifications. - * - * @param subscribed - * the subscribed - * @param ignored - * the ignored - * @return the gh subscription - * @throws IOException - * the io exception - */ - public GHSubscription subscribe(boolean subscribed, boolean ignored) throws IOException { - return root.createRequest() - .method("PUT") - .with("subscribed", subscribed) - .with("ignored", ignored) - .withUrlPath(getApiTailUrl("subscription")) - .fetch(GHSubscription.class) - .wrapUp(this); - } - - /** - * Returns the current subscription. - * - * @return null if no subscription exists. - * @throws IOException - * the io exception - */ - public GHSubscription getSubscription() throws IOException { - try { - return root.createRequest() - .withUrlPath(getApiTailUrl("subscription")) - .fetch(GHSubscription.class) - .wrapUp(this); - } catch (FileNotFoundException e) { - return null; - } - } - - /** - * List contributors paged iterable. - * - * @return the paged iterable - * @throws IOException - * the io exception - */ - public PagedIterable listContributors() throws IOException { - return root.createRequest() - .withUrlPath(getApiTailUrl("contributors")) - .toIterable(Contributor[].class, item -> item.wrapUp(root)); - } - - /** - * The type Contributor. - */ - public static class Contributor extends GHUser { - private int contributions; - - /** - * Gets contributions. - * - * @return the contributions - */ - public int getContributions() { - return contributions; - } - - @Override - public int hashCode() { - // We ignore contributions in the calculation - return super.hashCode(); - } - - @Override - public boolean equals(Object obj) { - // We ignore contributions in the calculation - return super.equals(obj); - } - } - - /** - * Returns the statistics for this repository. - * - * @return the statistics - */ - public GHRepositoryStatistics getStatistics() { - // TODO: Use static object and introduce refresh() method, - // instead of returning new object each time. - return new GHRepositoryStatistics(this); - } - - /** - * Create a project for this repository. - * - * @param name - * the name - * @param body - * the body - * @return the gh project - * @throws IOException - * the io exception - */ - public GHProject createProject(String name, String body) throws IOException { - return root.createRequest() - .method("POST") - .withPreview(INERTIA) - .with("name", name) - .with("body", body) - .withUrlPath(getApiTailUrl("projects")) - .fetch(GHProject.class) - .wrap(this); - } - - /** - * Returns the projects for this repository. - * - * @param status - * The status filter (all, open or closed). - * @return the paged iterable - * @throws IOException - * the io exception - */ - public PagedIterable listProjects(final GHProject.ProjectStateFilter status) throws IOException { - return root.createRequest() - .withPreview(INERTIA) - .with("state", status) - .withUrlPath(getApiTailUrl("projects")) - .toIterable(GHProject[].class, item -> item.wrap(this)); - } - - /** - * Returns open projects for this repository. - * - * @return the paged iterable - * @throws IOException - * the io exception - */ - public PagedIterable listProjects() throws IOException { - return listProjects(GHProject.ProjectStateFilter.OPEN); - } - - /** - * Render a Markdown document. - *

- * In {@linkplain MarkdownMode#GFM GFM mode}, issue numbers and user mentions are linked accordingly. - * - * @param text - * the text - * @param mode - * the mode - * @return the reader - * @throws IOException - * the io exception - * @see GitHub#renderMarkdown(String) GitHub#renderMarkdown(String) - */ - public Reader renderMarkdown(String text, MarkdownMode mode) throws IOException { - return new InputStreamReader( - root.createRequest() - .method("POST") - .with("text", text) - .with("mode", mode == null ? null : mode.toString()) - .with("context", getFullName()) - .withUrlPath("/markdown") - .fetchStream(), - "UTF-8"); - } - - /** - * List all the notifications in a repository for the current user. - * - * @return the gh notification stream - */ - public GHNotificationStream listNotifications() { - return new GHNotificationStream(root, getApiTailUrl("/notifications")); - } - - /** - * https://developer.github.com/v3/repos/traffic/#views - * - * @return the view traffic - * @throws IOException - * the io exception - */ - public GHRepositoryViewTraffic getViewTraffic() throws IOException { - return root.createRequest().withUrlPath(getApiTailUrl("/traffic/views")).fetch(GHRepositoryViewTraffic.class); - } - - /** - * https://developer.github.com/v3/repos/traffic/#clones - * - * @return the clone traffic - * @throws IOException - * the io exception - */ - public GHRepositoryCloneTraffic getCloneTraffic() throws IOException { - return root.createRequest().withUrlPath(getApiTailUrl("/traffic/clones")).fetch(GHRepositoryCloneTraffic.class); - } - - @Override - public int hashCode() { - return ("Repository:" + getOwnerName() + ":" + name).hashCode(); - } - - @Override - public boolean equals(Object obj) { - if (obj instanceof GHRepository) { - GHRepository that = (GHRepository) obj; - return this.getOwnerName().equals(that.getOwnerName()) && this.name.equals(that.name); - } - return false; - } - - String getApiTailUrl(String tail) { - if (tail.length() > 0 && !tail.startsWith("/")) - tail = '/' + tail; - return "/repos/" + getOwnerName() + "/" + name + tail; - } - - /** - * Get all issue events for this repository. See - * https://developer.github.com/v3/issues/events/#list-events-for-a-repository - * - * @return the paged iterable - * @throws IOException - * the io exception - */ - public PagedIterable listIssueEvents() throws IOException { - return root.createRequest() - .withUrlPath(getApiTailUrl("issues/events")) - .toIterable(GHIssueEvent[].class, item -> item.wrapUp(root)); - } - - /** - * Get a single issue event. See https://developer.github.com/v3/issues/events/#get-a-single-event - * - * @param id - * the id - * @return the issue event - * @throws IOException - * the io exception - */ - public GHIssueEvent getIssueEvent(long id) throws IOException { - return root.createRequest() - .withUrlPath(getApiTailUrl("issues/events/" + id)) - .fetch(GHIssueEvent.class) - .wrapUp(root); - } - - // Only used within listTopics(). - private static class Topics { - public List names; - } - - /** - * Return the topics for this repository. See - * https://developer.github.com/v3/repos/#list-all-topics-for-a-repository - * - * @return the list - * @throws IOException - * the io exception - */ - public List listTopics() throws IOException { - Topics topics = root.createRequest() - .withPreview(MERCY) - .withUrlPath(getApiTailUrl("topics")) - .fetch(Topics.class); - return topics.names; - } - - /** - * Set the topics for this repository. See - * https://developer.github.com/v3/repos/#replace-all-topics-for-a-repository - * - * @param topics - * the topics - * @throws IOException - * the io exception - */ - public void setTopics(List topics) throws IOException { - root.createRequest() - .method("PUT") - .with("names", topics) - .withPreview(MERCY) - .withUrlPath(getApiTailUrl("topics")) - .send(); - } - - /** - * Create a tag. See https://developer.github.com/v3/git/tags/#create-a-tag-object - * - * @param tag - * The tag's name. - * @param message - * The tag message. - * @param object - * The SHA of the git object this is tagging. - * @param type - * The type of the object we're tagging: "commit", "tree" or "blob". - * @return The newly created tag. - * @throws java.io.IOException - * The IO exception. - */ - public GHTagObject createTag(String tag, String message, String object, String type) throws IOException { - return root.createRequest() - .method("POST") - .with("tag", tag) - .with("message", message) - .with("object", object) - .with("type", type) - .withUrlPath(getApiTailUrl("git/tags")) - .fetch(GHTagObject.class) - .wrap(this); - } -} +/* + * The MIT License + * + * Copyright (c) 2010, Kohsuke Kawaguchi + * + * 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 com.fasterxml.jackson.annotation.JsonProperty; +import com.infradna.tool.bridge_method_injector.WithBridgeMethods; +import edu.umd.cs.findbugs.annotations.SuppressFBWarnings; +import org.apache.commons.lang3.StringUtils; + +import java.io.FileNotFoundException; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.io.InterruptedIOException; +import java.io.Reader; +import java.net.URL; +import java.util.AbstractSet; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; +import java.util.Collections; +import java.util.Date; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.TreeMap; +import java.util.WeakHashMap; + +import static java.util.Arrays.*; +import static org.kohsuke.github.Previews.*; + +/** + * A repository on GitHub. + * + * @author Kohsuke Kawaguchi + */ +@SuppressWarnings({ "UnusedDeclaration" }) +@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; + + private String description, homepage, name, full_name; + private String html_url; // this is the UI + /* + * The license information makes use of the preview API. + * + * See: https://developer.github.com/v3/licenses/ + */ + private GHLicense license; + + private String git_url, ssh_url, clone_url, svn_url, mirror_url; + private GHUser owner; // not fully populated. beware. + private boolean has_issues, has_wiki, fork, has_downloads, has_pages, archived; + + private boolean allow_squash_merge; + private boolean allow_merge_commit; + private boolean allow_rebase_merge; + + @JsonProperty("private") + private boolean _private; + private int forks_count, stargazers_count, watchers_count, size, open_issues_count, subscribers_count; + private String pushed_at; + private Map milestones = new WeakHashMap(); + + private String default_branch, language; + private Map commits = new WeakHashMap(); + + @SkipFromToString + private GHRepoPermission permissions; + + private GHRepository source, parent; + + /** + * Create deployment gh deployment builder. + * + * @param ref + * the ref + * @return the gh deployment builder + */ + public GHDeploymentBuilder createDeployment(String ref) { + return new GHDeploymentBuilder(this, ref); + } + + /** + * Gets deployment statuses. + * + * @param id + * the id + * @return the deployment statuses + * @throws IOException + * the io exception + * @deprecated Use {@code getDeployment(id).listStatuses()} + */ + public PagedIterable getDeploymentStatuses(final int id) throws IOException { + return getDeployment(id).listStatuses(); + } + + /** + * List deployments paged iterable. + * + * @param sha + * the sha + * @param ref + * the ref + * @param task + * the task + * @param environment + * the environment + * @return the paged iterable + */ + public PagedIterable listDeployments(String sha, String ref, String task, String environment) { + return root.createRequest() + .with("sha", sha) + .with("ref", ref) + .with("task", task) + .with("environment", environment) + .withUrlPath(getApiTailUrl("deployments")) + .toIterable(GHDeployment[].class, item -> item.wrap(this)); + } + + /** + * Obtains a single {@link GHDeployment} by its ID. + * + * @param id + * the id + * @return the deployment + * @throws IOException + * the io exception + */ + public GHDeployment getDeployment(long id) throws IOException { + return root.createRequest() + .withUrlPath(getApiTailUrl("deployments/" + id)) + .fetch(GHDeployment.class) + .wrap(this); + } + + /** + * Gets deploy status. + * + * @param deploymentId + * the deployment id + * @param ghDeploymentState + * the gh deployment state + * @return the deploy status + * @throws IOException + * the io exception + * @deprecated Use {@code getDeployment(deploymentId).createStatus(ghDeploymentState)} + */ + public GHDeploymentStatusBuilder createDeployStatus(int deploymentId, GHDeploymentState ghDeploymentState) + throws IOException { + return getDeployment(deploymentId).createStatus(ghDeploymentState); + } + + private static class GHRepoPermission { + boolean pull, push, admin; + } + + /** + * Gets description. + * + * @return the description + */ + public String getDescription() { + return description; + } + + /** + * Gets homepage. + * + * @return the homepage + */ + public String getHomepage() { + return homepage; + } + + /** + * Gets the git:// URL to this repository, such as "git://github.com/kohsuke/jenkins.git" This URL is read-only. + * + * @return the git transport url + */ + public String getGitTransportUrl() { + return git_url; + } + + /** + * Gets the HTTPS URL to this repository, such as "https://github.com/kohsuke/jenkins.git" This URL is read-only. + * + * @return the http transport url + */ + public String getHttpTransportUrl() { + return clone_url; + } + + /** + * Git http transport url string. + * + * @return the string + * @deprecated Typo of {@link #getHttpTransportUrl()} + */ + public String gitHttpTransportUrl() { + return clone_url; + } + + /** + * Gets the Subversion URL to access this repository: https://github.com/rails/rails + * + * @return the svn url + */ + public String getSvnUrl() { + return svn_url; + } + + /** + * Gets the Mirror URL to access this repository: https://github.com/apache/tomee mirrored from + * git://git.apache.org/tomee.git + * + * @return the mirror url + */ + public String getMirrorUrl() { + return mirror_url; + } + + /** + * Gets the SSH URL to access this repository, such as git@github.com:rails/rails.git + * + * @return the ssh url + */ + public String getSshUrl() { + return ssh_url; + } + + public URL getHtmlUrl() { + return GitHub.parseURL(html_url); + } + + /** + * Short repository name without the owner. For example 'jenkins' in case of http://github.com/jenkinsci/jenkins + * + * @return the name + */ + public String getName() { + return name; + } + + /** + * Full repository name including the owner or organization. For example 'jenkinsci/jenkins' in case of + * http://github.com/jenkinsci/jenkins + * + * @return the full name + */ + public String getFullName() { + return full_name; + } + + /** + * Has pull access boolean. + * + * @return the boolean + */ + public boolean hasPullAccess() { + return permissions != null && permissions.pull; + } + + /** + * Has push access boolean. + * + * @return the boolean + */ + public boolean hasPushAccess() { + return permissions != null && permissions.push; + } + + /** + * Has admin access boolean. + * + * @return the boolean + */ + public boolean hasAdminAccess() { + return permissions != null && permissions.admin; + } + + /** + * Gets the primary programming language. + * + * @return the language + */ + public String getLanguage() { + return language; + } + + /** + * Gets owner. + * + * @return the owner + * @throws IOException + * the io exception + */ + public GHUser getOwner() throws IOException { + return root.isOffline() ? owner : root.getUser(getOwnerName()); // because 'owner' isn't fully populated + } + + /** + * Gets issue. + * + * @param id + * the id + * @return the issue + * @throws IOException + * the io exception + */ + public GHIssue getIssue(int id) throws IOException { + return root.createRequest().withUrlPath(getApiTailUrl("issues/" + id)).fetch(GHIssue.class).wrap(this); + } + + /** + * Create issue gh issue builder. + * + * @param title + * the title + * @return the gh issue builder + */ + public GHIssueBuilder createIssue(String title) { + return new GHIssueBuilder(this, title); + } + + /** + * Gets issues. + * + * @param state + * the state + * @return the issues + * @throws IOException + * the io exception + */ + public List getIssues(GHIssueState state) throws IOException { + return listIssues(state).asList(); + } + + /** + * Gets issues. + * + * @param state + * the state + * @param milestone + * the milestone + * @return the issues + * @throws IOException + * the io exception + */ + public List getIssues(GHIssueState state, GHMilestone milestone) throws IOException { + Requester requester = root.createRequest() + .with("state", state) + .with("milestone", milestone == null ? "none" : "" + milestone.getNumber()); + return Arrays + .asList(GHIssue.wrap(requester.withUrlPath(getApiTailUrl("issues")).fetchArray(GHIssue[].class), this)); + } + + /** + * Lists up all the issues in this repository. + * + * @param state + * the state + * @return the paged iterable + */ + public PagedIterable listIssues(final GHIssueState state) { + return root.createRequest() + .with("state", state) + .withUrlPath(getApiTailUrl("issues")) + .toIterable(GHIssue[].class, item -> item.wrap(this)); + } + + /** + * Create release gh release builder. + * + * @param tag + * the tag + * @return the gh release builder + */ + public GHReleaseBuilder createRelease(String tag) { + return new GHReleaseBuilder(this, tag); + } + + /** + * Creates a named ref, such as tag, branch, etc. + * + * @param name + * The name of the fully qualified reference (ie: refs/heads/master). If it doesn't start with 'refs' and + * have at least two slashes, it will be rejected. + * @param sha + * The SHA1 value to set this reference to + * @return the gh ref + * @throws IOException + * the io exception + */ + public GHRef createRef(String name, String sha) throws IOException { + return root.createRequest() + .method("POST") + .with("ref", name) + .with("sha", sha) + .withUrlPath(getApiTailUrl("git/refs")) + .fetch(GHRef.class) + .wrap(root); + } + + /** + * Gets releases. + * + * @return the releases + * @throws IOException + * the io exception + * @deprecated use {@link #listReleases()} + */ + public List getReleases() throws IOException { + return listReleases().asList(); + } + + /** + * Gets release. + * + * @param id + * the id + * @return the release + * @throws IOException + * the io exception + */ + public GHRelease getRelease(long id) throws IOException { + try { + return root.createRequest().withUrlPath(getApiTailUrl("releases/" + id)).fetch(GHRelease.class).wrap(this); + } catch (FileNotFoundException e) { + return null; // no release for this id + } + } + + /** + * Gets release by tag name. + * + * @param tag + * the tag + * @return the release by tag name + * @throws IOException + * the io exception + */ + public GHRelease getReleaseByTagName(String tag) throws IOException { + try { + return root.createRequest() + .withUrlPath(getApiTailUrl("releases/tags/" + tag)) + .fetch(GHRelease.class) + .wrap(this); + } catch (FileNotFoundException e) { + return null; // no release for this tag + } + } + + /** + * Gets latest release. + * + * @return the latest release + * @throws IOException + * the io exception + */ + public GHRelease getLatestRelease() throws IOException { + try { + return root.createRequest().withUrlPath(getApiTailUrl("releases/latest")).fetch(GHRelease.class).wrap(this); + } catch (FileNotFoundException e) { + return null; // no latest release + } + } + + /** + * List releases paged iterable. + * + * @return the paged iterable + * @throws IOException + * the io exception + */ + public PagedIterable listReleases() throws IOException { + return root.createRequest() + .withUrlPath(getApiTailUrl("releases")) + .toIterable(GHRelease[].class, item -> item.wrap(this)); + } + + /** + * List tags paged iterable. + * + * @return the paged iterable + * @throws IOException + * the io exception + */ + public PagedIterable listTags() throws IOException { + return root.createRequest() + .withUrlPath(getApiTailUrl("tags")) + .toIterable(GHTag[].class, item -> item.wrap(this)); + } + + /** + * List languages for the specified repository. The value on the right of a language is the number of bytes of code + * written in that language. { "C": 78769, "Python": 7769 } + * + * @return the map + * @throws IOException + * the io exception + */ + public Map listLanguages() throws IOException { + return root.createRequest().withUrlPath(getApiTailUrl("languages")).fetch(HashMap.class); + } + + /** + * Gets owner name. + * + * @return the owner name + */ + public String getOwnerName() { + // consistency of the GitHub API is super... some serialized forms of GHRepository populate + // a full GHUser while others populate only the owner and email. This later form is super helpful + // in putting the login in owner.name not owner.login... thankfully we can easily identify this + // second set because owner.login will be null + return owner.login != null ? owner.login : owner.name; + } + + /** + * Has issues boolean. + * + * @return the boolean + */ + public boolean hasIssues() { + return has_issues; + } + + /** + * Has wiki boolean. + * + * @return the boolean + */ + public boolean hasWiki() { + return has_wiki; + } + + /** + * Is fork boolean. + * + * @return the boolean + */ + public boolean isFork() { + return fork; + } + + /** + * Is archived boolean. + * + * @return the boolean + */ + public boolean isArchived() { + return archived; + } + + /** + * Is allow squash merge boolean. + * + * @return the boolean + */ + public boolean isAllowSquashMerge() { + return allow_squash_merge; + } + + /** + * Is allow merge commit boolean. + * + * @return the boolean + */ + public boolean isAllowMergeCommit() { + return allow_merge_commit; + } + + /** + * Is allow rebase merge boolean. + * + * @return the boolean + */ + public boolean isAllowRebaseMerge() { + return allow_rebase_merge; + } + + /** + * Returns the number of all forks of this repository. This not only counts direct forks, but also forks of forks, + * and so on. + * + * @return the forks + */ + public int getForks() { + return forks_count; + } + + /** + * Gets stargazers count. + * + * @return the stargazers count + */ + public int getStargazersCount() { + return stargazers_count; + } + + /** + * Is private boolean. + * + * @return the boolean + */ + public boolean isPrivate() { + return _private; + } + + /** + * Has downloads boolean. + * + * @return the boolean + */ + public boolean hasDownloads() { + return has_downloads; + } + + /** + * Has pages boolean. + * + * @return the boolean + */ + public boolean hasPages() { + return has_pages; + } + + /** + * Gets watchers. + * + * @return the watchers + */ + public int getWatchers() { + return watchers_count; + } + + /** + * Gets open issue count. + * + * @return the open issue count + */ + public int getOpenIssueCount() { + return open_issues_count; + } + + /** + * Gets network count. + * + * @return the network count + * @deprecated This no longer exists in the official API documentation. Use {@link #getForks()} + */ + public int getNetworkCount() { + return forks_count; + } + + /** + * Gets subscribers count. + * + * @return the subscribers count + */ + public int getSubscribersCount() { + return subscribers_count; + } + + /** + * Gets pushed at. + * + * @return null if the repository was never pushed at. + */ + public Date getPushedAt() { + return GitHub.parseDate(pushed_at); + } + + /** + * Returns the primary branch you'll configure in the "Admin > Options" config page. + * + * @return This field is null until the user explicitly configures the master branch. + */ + public String getDefaultBranch() { + return default_branch; + } + + /** + * Gets master branch. + * + * @return the master branch + * @deprecated Renamed to {@link #getDefaultBranch()} + */ + public String getMasterBranch() { + return default_branch; + } + + /** + * Gets size. + * + * @return the size + */ + public int getSize() { + return size; + } + + /** + * Gets the collaborators on this repository. This set always appear to include the owner. + * + * @return the collaborators + * @throws IOException + * the io exception + */ + @WithBridgeMethods(Set.class) + public GHPersonSet getCollaborators() throws IOException { + return new GHPersonSet(listCollaborators().asList()); + } + + /** + * Lists up the collaborators on this repository. + * + * @return Users paged iterable + * @throws IOException + * the io exception + */ + public PagedIterable listCollaborators() throws IOException { + return listUsers("collaborators"); + } + + /** + * Lists all + * the + * available assignees to which issues may be assigned. + * + * @return the paged iterable + * @throws IOException + * the io exception + */ + public PagedIterable listAssignees() throws IOException { + return listUsers("assignees"); + } + + /** + * Checks if the given user is an assignee for this repository. + * + * @param u + * the u + * @return the boolean + * @throws IOException + * the io exception + */ + public boolean hasAssignee(GHUser u) throws IOException { + return root.createRequest().withUrlPath(getApiTailUrl("assignees/" + u.getLogin())).fetchHttpStatusCode() + / 100 == 2; + } + + /** + * Gets the names of the collaborators on this repository. This method deviates from the principle of this library + * but it works a lot faster than {@link #getCollaborators()}. + * + * @return the collaborator names + * @throws IOException + * the io exception + */ + public Set getCollaboratorNames() throws IOException { + Set r = new HashSet(); + for (GHUser u : GHUser.wrap( + root.createRequest().withUrlPath(getApiTailUrl("collaborators")).fetchArray(GHUser[].class), + root)) + r.add(u.login); + return r; + } + + /** + * Obtain permission for a given user in this repository. + * + * @param user + * a {@link GHUser#getLogin} + * @return the permission + * @throws IOException + * the io exception + */ + public GHPermissionType getPermission(String user) throws IOException { + GHPermission perm = root.createRequest() + .withUrlPath(getApiTailUrl("collaborators/" + user + "/permission")) + .fetch(GHPermission.class); + perm.wrapUp(root); + return perm.getPermissionType(); + } + + /** + * Obtain permission for a given user in this repository. + * + * @param u + * the u + * @return the permission + * @throws IOException + * the io exception + */ + public GHPermissionType getPermission(GHUser u) throws IOException { + return getPermission(u.getLogin()); + } + + /** + * If this repository belongs to an organization, return a set of teams. + * + * @return the teams + * @throws IOException + * the io exception + */ + public Set getTeams() throws IOException { + return Collections.unmodifiableSet(new HashSet(Arrays.asList( + GHTeam.wrapUp(root.createRequest().withUrlPath(getApiTailUrl("teams")).fetchArray(GHTeam[].class), + root.getOrganization(getOwnerName()))))); + } + + /** + * Add collaborators. + * + * @param users + * the users + * @throws IOException + * the io exception + */ + public void addCollaborators(GHOrganization.Permission perm, GHUser... users) throws IOException { + addCollaborators(perm, asList(users)); + } + + /** + * Add collaborators. + * + * @param users + * the users + * @throws IOException + * the io exception + */ + public void addCollaborators(GHOrganization.Permission perm, Collection users) throws IOException { + modifyCollaborators(perm, users, "PUT"); + } + + /** + * Remove collaborators. + * + * @param users + * the users + * @throws IOException + * the io exception + */ + public void removeCollaborators(GHUser... users) throws IOException { + removeCollaborators(asList(users)); + } + + /** + * Remove collaborators. + * + * @param users + * the users + * @throws IOException + * the io exception + */ + public void removeCollaborators(Collection users) throws IOException { + modifyCollaborators(users, "DELETE"); + } + + private void modifyCollaborators(Collection users, String method) throws IOException { + for (GHUser user : users) { + root.createRequest().method(method).withUrlPath(getApiTailUrl("collaborators/" + user.getLogin())).send(); + } + } + + private void modifyCollaborators(GHOrganization.Permission perm, Collection users, String method) + throws IOException { + for (GHUser user : users) { + root.createRequest() + .method(method) + .with("permission", perm) + .inBody() + .withUrlPath(getApiTailUrl("collaborators/" + user.getLogin())) + .send(); + } + } + + /** + * Sets email service hook. + * + * @param address + * the address + * @throws IOException + * the io exception + */ + public void setEmailServiceHook(String address) throws IOException { + Map config = new HashMap(); + config.put("address", address); + root.createRequest() + .method("POST") + .with("name", "email") + .with("config", config) + .with("active", true) + .withUrlPath(getApiTailUrl("hooks")) + .send(); + } + + private void edit(String key, String value) throws IOException { + Requester requester = root.createRequest(); + if (!key.equals("name")) + requester.with("name", name); // even when we don't change the name, we need to send it in + requester.with(key, value).method("PATCH").withUrlPath(getApiTailUrl("")).send(); + } + + /** + * Enables or disables the issue tracker for this repository. + * + * @param v + * the v + * @throws IOException + * the io exception + */ + public void enableIssueTracker(boolean v) throws IOException { + edit("has_issues", String.valueOf(v)); + } + + /** + * Enables or disables Wiki for this repository. + * + * @param v + * the v + * @throws IOException + * the io exception + */ + public void enableWiki(boolean v) throws IOException { + edit("has_wiki", String.valueOf(v)); + } + + /** + * Enable downloads. + * + * @param v + * the v + * @throws IOException + * the io exception + */ + public void enableDownloads(boolean v) throws IOException { + edit("has_downloads", String.valueOf(v)); + } + + /** + * Rename this repository. + * + * @param name + * the name + * @throws IOException + * the io exception + */ + public void renameTo(String name) throws IOException { + edit("name", name); + } + + /** + * Sets description. + * + * @param value + * the value + * @throws IOException + * the io exception + */ + public void setDescription(String value) throws IOException { + edit("description", value); + } + + /** + * Sets homepage. + * + * @param value + * the value + * @throws IOException + * the io exception + */ + public void setHomepage(String value) throws IOException { + edit("homepage", value); + } + + /** + * Sets default branch. + * + * @param value + * the value + * @throws IOException + * the io exception + */ + public void setDefaultBranch(String value) throws IOException { + edit("default_branch", value); + } + + /** + * Sets private. + * + * @param value + * the value + * @throws IOException + * the io exception + */ + public void setPrivate(boolean value) throws IOException { + edit("private", Boolean.toString(value)); + } + + /** + * Allow squash merge. + * + * @param value + * the value + * @throws IOException + * the io exception + */ + public void allowSquashMerge(boolean value) throws IOException { + edit("allow_squash_merge", Boolean.toString(value)); + } + + /** + * Allow merge commit. + * + * @param value + * the value + * @throws IOException + * the io exception + */ + public void allowMergeCommit(boolean value) throws IOException { + edit("allow_merge_commit", Boolean.toString(value)); + } + + /** + * Allow rebase merge. + * + * @param value + * the value + * @throws IOException + * the io exception + */ + public void allowRebaseMerge(boolean value) throws IOException { + edit("allow_rebase_merge", Boolean.toString(value)); + } + + /** + * Deletes this repository. + * + * @throws IOException + * the io exception + */ + public void delete() throws IOException { + try { + root.createRequest().method("DELETE").withUrlPath(getApiTailUrl("")).send(); + } catch (FileNotFoundException x) { + throw (FileNotFoundException) new FileNotFoundException("Failed to delete " + getOwnerName() + "/" + name + + "; might not exist, or you might need the delete_repo scope in your token: http://stackoverflow.com/a/19327004/12916") + .initCause(x); + } + } + + /** + * Will archive and this repository as read-only. When a repository is archived, any operation that can change its + * state is forbidden. This applies symmetrically if trying to unarchive it. + * + *

+ * When you try to do any operation that modifies a read-only repository, it returns the response: + * + *

+     * org.kohsuke.github.HttpException: {
+     *     "message":"Repository was archived so is read-only.",
+     *     "documentation_url":"https://developer.github.com/v3/repos/#edit"
+     * }
+     * 
+ * + * @throws IOException + * In case of any networking error or error from the server. + */ + public void archive() throws IOException { + edit("archived", "true"); + // Generall would not update this record, + // but do so here since this will result in any other update actions failing + archived = true; + } + + /** + * Sort orders for listing forks + */ + public enum ForkSort { + NEWEST, OLDEST, STARGAZERS + } + + /** + * Lists all the direct forks of this repository, sorted by github api default, currently {@link ForkSort#NEWEST + * ForkSort.NEWEST}*. + * + * @return the paged iterable + */ + public PagedIterable listForks() { + return listForks(null); + } + + /** + * Lists all the direct forks of this repository, sorted by the given sort order. + * + * @param sort + * the sort order. If null, defaults to github api default, currently {@link ForkSort#NEWEST + * ForkSort.NEWEST}. + * @return the paged iterable + */ + public PagedIterable listForks(final ForkSort sort) { + return root.createRequest() + .with("sort", sort) + .withUrlPath(getApiTailUrl("forks")) + .toIterable(GHRepository[].class, item -> item.wrap(root)); + } + + /** + * Forks this repository as your repository. + * + * @return Newly forked repository that belong to you. + * @throws IOException + * the io exception + */ + public GHRepository fork() throws IOException { + root.createRequest().method("POST").withUrlPath(getApiTailUrl("forks")).send(); + + // this API is asynchronous. we need to wait for a bit + for (int i = 0; i < 10; i++) { + GHRepository r = root.getMyself().getRepository(name); + if (r != null) + return r; + try { + Thread.sleep(3000); + } catch (InterruptedException e) { + throw (IOException) new InterruptedIOException().initCause(e); + } + } + throw new IOException(this + " was forked but can't find the new repository"); + } + + /** + * Forks this repository into an organization. + * + * @param org + * the org + * @return Newly forked repository that belong to you. + * @throws IOException + * the io exception + */ + public GHRepository forkTo(GHOrganization org) throws IOException { + root.createRequest() + .method("POST") + .with("organization", org.getLogin()) + .withUrlPath(getApiTailUrl("forks")) + .send(); + + // this API is asynchronous. we need to wait for a bit + for (int i = 0; i < 10; i++) { + GHRepository r = org.getRepository(name); + if (r != null) + return r; + try { + Thread.sleep(3000); + } catch (InterruptedException e) { + throw (IOException) new InterruptedIOException().initCause(e); + } + } + throw new IOException(this + " was forked into " + org.getLogin() + " but can't find the new repository"); + } + + /** + * Retrieves a specified pull request. + * + * @param i + * the + * @return the pull request + * @throws IOException + * the io exception + */ + public GHPullRequest getPullRequest(int i) throws IOException { + return root.createRequest() + .withPreview(SHADOW_CAT) + .withUrlPath(getApiTailUrl("pulls/" + i)) + .fetch(GHPullRequest.class) + .wrapUp(this); + } + + /** + * Retrieves all the pull requests of a particular state. + * + * @param state + * the state + * @return the pull requests + * @throws IOException + * the io exception + * @see #listPullRequests(GHIssueState) #listPullRequests(GHIssueState) + */ + public List getPullRequests(GHIssueState state) throws IOException { + return queryPullRequests().state(state).list().asList(); + } + + /** + * Retrieves all the pull requests of a particular state. + * + * @param state + * the state + * @return the paged iterable + * @deprecated Use {@link #queryPullRequests()} + */ + public PagedIterable listPullRequests(GHIssueState state) { + return queryPullRequests().state(state).list(); + } + + /** + * Retrieves pull requests. + * + * @return the gh pull request query builder + */ + public GHPullRequestQueryBuilder queryPullRequests() { + return new GHPullRequestQueryBuilder(this); + } + + /** + * Creates a new pull request. + * + * @param title + * Required. The title of the pull request. + * @param head + * Required. The name of the branch where your changes are implemented. For cross-repository pull + * requests in the same network, namespace head with a user like this: username:branch. + * @param base + * Required. The name of the branch you want your changes pulled into. This should be an existing branch + * on the current repository. + * @param body + * The contents of the pull request. This is the markdown description of a pull request. + * @return the gh pull request + * @throws IOException + * the io exception + */ + public GHPullRequest createPullRequest(String title, String head, String base, String body) throws IOException { + return createPullRequest(title, head, base, body, true); + } + + /** + * Creates a new pull request. Maintainer's permissions aware. + * + * @param title + * Required. The title of the pull request. + * @param head + * Required. The name of the branch where your changes are implemented. For cross-repository pull + * requests in the same network, namespace head with a user like this: username:branch. + * @param base + * Required. The name of the branch you want your changes pulled into. This should be an existing branch + * on the current repository. + * @param body + * The contents of the pull request. This is the markdown description of a pull request. + * @param maintainerCanModify + * Indicates whether maintainers can modify the pull request. + * @return the gh pull request + * @throws IOException + * the io exception + */ + public GHPullRequest createPullRequest(String title, + String head, + String base, + String body, + boolean maintainerCanModify) throws IOException { + return createPullRequest(title, head, base, body, maintainerCanModify, false); + } + + /** + * Creates a new pull request. Maintainer's permissions and draft aware. + * + * @param title + * Required. The title of the pull request. + * @param head + * Required. The name of the branch where your changes are implemented. For cross-repository pull + * requests in the same network, namespace head with a user like this: username:branch. + * @param base + * Required. The name of the branch you want your changes pulled into. This should be an existing branch + * on the current repository. + * @param body + * The contents of the pull request. This is the markdown description of a pull request. + * @param maintainerCanModify + * Indicates whether maintainers can modify the pull request. + * @param draft + * Indicates whether to create a draft pull request or not. + * @return the gh pull request + * @throws IOException + * the io exception + */ + public GHPullRequest createPullRequest(String title, + String head, + String base, + String body, + boolean maintainerCanModify, + boolean draft) throws IOException { + return root.createRequest() + .method("POST") + .withPreview(SHADOW_CAT) + .with("title", title) + .with("head", head) + .with("base", base) + .with("body", body) + .with("maintainer_can_modify", maintainerCanModify) + .with("draft", draft) + .withUrlPath(getApiTailUrl("pulls")) + .fetch(GHPullRequest.class) + .wrapUp(this); + } + + /** + * Retrieves the currently configured hooks. + * + * @return the hooks + * @throws IOException + * the io exception + */ + public List getHooks() throws IOException { + return GHHooks.repoContext(this, owner).getHooks(); + } + + /** + * Gets hook. + * + * @param id + * the id + * @return the hook + * @throws IOException + * the io exception + */ + public GHHook getHook(int id) throws IOException { + return GHHooks.repoContext(this, owner).getHook(id); + } + + /** + * Gets a comparison between 2 points in the repository. This would be similar to calling + * git log id1...id2 against a local repository. + * + * @param id1 + * an identifier for the first point to compare from, this can be a sha1 ID (for a commit, tag etc) or a + * direct tag name + * @param id2 + * an identifier for the second point to compare to. Can be the same as the first point. + * @return the comparison output + * @throws IOException + * on failure communicating with GitHub + */ + public GHCompare getCompare(String id1, String id2) throws IOException { + GHCompare compare = root.createRequest() + .withUrlPath(getApiTailUrl(String.format("compare/%s...%s", id1, id2))) + .fetch(GHCompare.class); + return compare.wrap(this); + } + + /** + * Gets compare. + * + * @param id1 + * the id 1 + * @param id2 + * the id 2 + * @return the compare + * @throws IOException + * the io exception + */ + public GHCompare getCompare(GHCommit id1, GHCommit id2) throws IOException { + return getCompare(id1.getSHA1(), id2.getSHA1()); + } + + /** + * Gets compare. + * + * @param id1 + * the id 1 + * @param id2 + * the id 2 + * @return the compare + * @throws IOException + * the io exception + */ + public GHCompare getCompare(GHBranch id1, GHBranch id2) throws IOException { + + GHRepository owner1 = id1.getOwner(); + GHRepository owner2 = id2.getOwner(); + + // If the owner of the branches is different, we have a cross-fork compare. + if (owner1 != null && owner2 != null) { + String ownerName1 = owner1.getOwnerName(); + String ownerName2 = owner2.getOwnerName(); + if (!StringUtils.equals(ownerName1, ownerName2)) { + String qualifiedName1 = String.format("%s:%s", ownerName1, id1.getName()); + String qualifiedName2 = String.format("%s:%s", ownerName2, id2.getName()); + return getCompare(qualifiedName1, qualifiedName2); + } + } + + return getCompare(id1.getName(), id2.getName()); + + } + + /** + * Retrieves all refs for the github repository. + * + * @return an array of GHRef elements coresponding with the refs in the remote repository. + * @throws IOException + * on failure communicating with GitHub + */ + public GHRef[] getRefs() throws IOException { + return GHRef.wrap(root.createRequest() + .withUrlPath(String.format("/repos/%s/%s/git/refs", getOwnerName(), name)) + .fetchArray(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 listRefs() throws IOException { + final String url = String.format("/repos/%s/%s/git/refs", getOwnerName(), name); + return root.createRequest().withUrlPath(url).toIterable(GHRef[].class, item -> item.wrap(root)); + } + + /** + * Retrieves all refs of the given type for the current GitHub repository. + * + * @param refType + * the type of reg to search for e.g. tags or commits + * @return an array of all refs matching the request type + * @throws IOException + * on failure communicating with GitHub, potentially due to an invalid ref type being requested + */ + public GHRef[] getRefs(String refType) throws IOException { + return GHRef.wrap(root.createRequest() + .withUrlPath(String.format("/repos/%s/%s/git/refs/%s", getOwnerName(), name, refType)) + .fetchArray(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. tags or commits + * @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 listRefs(String refType) throws IOException { + final String url = String.format("/repos/%s/%s/git/refs/%s", getOwnerName(), name, refType); + return root.createRequest().withUrlPath(url).toIterable(GHRef[].class, item -> item.wrap(root)); + } + + /** + * Retrive a ref of the given type for the current GitHub repository. + * + * @param refName + * eg: heads/branch + * @return refs matching the request type + * @throws IOException + * on failure communicating with GitHub, potentially due to an invalid ref type being requested + */ + public GHRef getRef(String refName) throws IOException { + return root.createRequest() + .withUrlPath(getApiTailUrl(String.format("git/refs/%s", refName))) + .fetch(GHRef.class) + .wrap(root); + } + + /** + * Returns the annotated 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 + * @throws IOException + * the io exception + */ + public GHTagObject getTagObject(String sha) throws IOException { + return root.createRequest().withUrlPath(getApiTailUrl("git/tags/" + sha)).fetch(GHTagObject.class).wrap(this); + } + + /** + * Retrive a tree of the given type for the current GitHub repository. + * + * @param sha + * sha number or branch name ex: "master" + * @return refs matching the request type + * @throws IOException + * on failure communicating with GitHub, potentially due to an invalid tree type being requested + */ + public GHTree getTree(String sha) throws IOException { + String url = String.format("/repos/%s/%s/git/trees/%s", getOwnerName(), name, sha); + return root.createRequest().withUrlPath(url).fetch(GHTree.class).wrap(this); + } + + /** + * Create tree gh tree builder. + * + * @return the gh tree builder + */ + public GHTreeBuilder createTree() { + return new GHTreeBuilder(this); + } + + /** + * Retrieves the tree for the current GitHub repository, recursively as described in here: + * https://developer.github.com/v3/git/trees/#get-a-tree-recursively + * + * @param sha + * sha number or branch name ex: "master" + * @param recursive + * use 1 + * @return the tree recursive + * @throws IOException + * on failure communicating with GitHub, potentially due to an invalid tree type being requested + */ + public GHTree getTreeRecursive(String sha, int recursive) throws IOException { + String url = String.format("/repos/%s/%s/git/trees/%s", getOwnerName(), name, sha); + return root.createRequest().with("recursive", recursive).withUrlPath(url).fetch(GHTree.class).wrap(this); + } + + /** + * Obtains the metadata & the content of a blob. + * + *

+ * This method retrieves the whole content in memory, so beware when you are dealing with large BLOB. + * + * @param blobSha + * the blob sha + * @return the blob + * @throws IOException + * the io exception + * @see Get a blob + * @see #readBlob(String) #readBlob(String) + */ + public GHBlob getBlob(String blobSha) throws IOException { + String target = getApiTailUrl("git/blobs/" + blobSha); + return root.createRequest().withUrlPath(target).fetch(GHBlob.class); + } + + /** + * Create blob gh blob builder. + * + * @return the gh blob builder + */ + public GHBlobBuilder createBlob() { + return new GHBlobBuilder(this); + } + + /** + * Reads the content of a blob as a stream for better efficiency. + * + * @param blobSha + * the blob sha + * @return the input stream + * @throws IOException + * the io exception + * @see Get a blob + * @see #getBlob(String) #getBlob(String) + */ + public InputStream readBlob(String blobSha) throws IOException { + String target = getApiTailUrl("git/blobs/" + blobSha); + + // https://developer.github.com/v3/media/ describes this media type + return root.createRequest() + .withHeader("Accept", "application/vnd.github.v3.raw") + .withUrlPath(target) + .fetchStream(); + } + + /** + * Gets a commit object in this repository. + * + * @param sha1 + * the sha 1 + * @return the commit + * @throws IOException + * the io exception + */ + public GHCommit getCommit(String sha1) throws IOException { + GHCommit c = commits.get(sha1); + if (c == null) { + c = root.createRequest() + .withUrlPath(String.format("/repos/%s/%s/commits/%s", getOwnerName(), name, sha1)) + .fetch(GHCommit.class) + .wrapUp(this); + commits.put(sha1, c); + } + return c; + } + + /** + * Create commit gh commit builder. + * + * @return the gh commit builder + */ + public GHCommitBuilder createCommit() { + return new GHCommitBuilder(this); + } + + /** + * Lists all the commits. + * + * @return the paged iterable + */ + public PagedIterable listCommits() { + return root.createRequest() + .withUrlPath(String.format("/repos/%s/%s/commits", getOwnerName(), name)) + .toIterable(GHCommit[].class, item -> item.wrapUp(this)); + } + + /** + * Search commits by specifying filters through a builder pattern. + * + * @return the gh commit query builder + */ + public GHCommitQueryBuilder queryCommits() { + return new GHCommitQueryBuilder(this); + } + + /** + * Lists up all the commit comments in this repository. + * + * @return the paged iterable + */ + public PagedIterable listCommitComments() { + return root.createRequest() + .withUrlPath(String.format("/repos/%s/%s/comments", getOwnerName(), name)) + .toIterable(GHCommitComment[].class, item -> item.wrap(this)); + } + + /** + * Gets the basic license details for the repository. + *

+ * + * @return null if there's no license. + * @throws IOException + * as usual but also if you don't use the preview connector + */ + public GHLicense getLicense() throws IOException { + GHContentWithLicense lic = getLicenseContent_(); + return lic != null ? lic.license : null; + } + + /** + * Retrieves the contents of the repository's license file - makes an additional API call + *

+ * + * @return details regarding the license contents, or null if there's no license. + * @throws IOException + * as usual but also if you don't use the preview connector + */ + public GHContent getLicenseContent() throws IOException { + return getLicenseContent_(); + } + + private GHContentWithLicense getLicenseContent_() throws IOException { + try { + return root.createRequest() + .withUrlPath(getApiTailUrl("license")) + .fetch(GHContentWithLicense.class) + .wrap(this); + } catch (FileNotFoundException e) { + return null; + } + } + + /** + * /** Lists all the commit statues attached to the given commit, newer ones first. + * + * @param sha1 + * the sha 1 + * @return the paged iterable + * @throws IOException + * the io exception + */ + public PagedIterable listCommitStatuses(final String sha1) throws IOException { + return root.createRequest() + .withUrlPath(String.format("/repos/%s/%s/statuses/%s", getOwnerName(), name, sha1)) + .toIterable(GHCommitStatus[].class, item -> item.wrapUp(root)); + } + + /** + * Gets the last status of this commit, which is what gets shown in the UI. + * + * @param sha1 + * the sha 1 + * @return the last commit status + * @throws IOException + * the io exception + */ + public GHCommitStatus getLastCommitStatus(String sha1) throws IOException { + List v = listCommitStatuses(sha1).asList(); + return v.isEmpty() ? null : v.get(0); + } + + /** + * Creates a commit status + * + * @param sha1 + * the sha 1 + * @param state + * the state + * @param targetUrl + * Optional parameter that points to the URL that has more details. + * @param description + * Optional short description. + * @param context + * Optinal commit status context. + * @return the gh commit status + * @throws IOException + * the io exception + */ + public GHCommitStatus createCommitStatus(String sha1, + GHCommitState state, + String targetUrl, + String description, + String context) throws IOException { + return root.createRequest() + .method("POST") + .with("state", state) + .with("target_url", targetUrl) + .with("description", description) + .with("context", context) + .withUrlPath(String.format("/repos/%s/%s/statuses/%s", getOwnerName(), this.name, sha1)) + .fetch(GHCommitStatus.class) + .wrapUp(root); + } + + /** + * Create commit status gh commit status. + * + * @param sha1 + * the sha 1 + * @param state + * the state + * @param targetUrl + * the target url + * @param description + * the description + * @return the gh commit status + * @throws IOException + * the io exception + * @see #createCommitStatus(String, GHCommitState, String, String, String) #createCommitStatus(String, + * GHCommitState,String,String,String) + */ + public GHCommitStatus createCommitStatus(String sha1, GHCommitState state, String targetUrl, String description) + throws IOException { + return createCommitStatus(sha1, state, targetUrl, description, null); + } + + /** + * Lists repository events. + * + * @return the paged iterable + * @throws IOException + * the io exception + */ + public PagedIterable listEvents() throws IOException { + return root.createRequest() + .withUrlPath(String.format("/repos/%s/%s/events", getOwnerName(), name)) + .toIterable(GHEventInfo[].class, item -> item.wrapUp(root)); + } + + /** + * Lists labels in this repository. + *

+ * https://developer.github.com/v3/issues/labels/#list-all-labels-for-this-repository + * + * @return the paged iterable + * @throws IOException + * the io exception + */ + public PagedIterable listLabels() throws IOException { + return root.createRequest() + .withUrlPath(getApiTailUrl("labels")) + .toIterable(GHLabel[].class, item -> item.wrapUp(this)); + } + + /** + * Gets label. + * + * @param name + * the name + * @return the label + * @throws IOException + * the io exception + */ + public GHLabel getLabel(String name) throws IOException { + return root.createRequest().withUrlPath(getApiTailUrl("labels/" + name)).fetch(GHLabel.class).wrapUp(this); + } + + /** + * Create label gh label. + * + * @param name + * the name + * @param color + * the color + * @return the gh label + * @throws IOException + * the io exception + */ + public GHLabel createLabel(String name, String color) throws IOException { + return createLabel(name, color, ""); + } + + /** + * Description is still in preview. + * + * @param name + * the name + * @param color + * the color + * @param description + * the description + * @return gh label + * @throws IOException + * the io exception + */ + public GHLabel createLabel(String name, String color, String description) throws IOException { + return root.createRequest() + .method("POST") + .with("name", name) + .with("color", color) + .with("description", description) + .withUrlPath(getApiTailUrl("labels")) + .fetch(GHLabel.class) + .wrapUp(this); + } + + /** + * Lists all the invitations. + * + * @return the paged iterable + */ + public PagedIterable listInvitations() { + return root.createRequest() + .withUrlPath(String.format("/repos/%s/%s/invitations", getOwnerName(), name)) + .toIterable(GHInvitation[].class, item -> item.wrapUp(root)); + } + + /** + * Lists all the subscribers (aka watchers.) + *

+ * https://developer.github.com/v3/activity/watching/ + * + * @return the paged iterable + */ + public PagedIterable listSubscribers() { + return listUsers("subscribers"); + } + + /** + * Lists all the users who have starred this repo based on the old version of the API. For additional information, + * like date when the repository was starred, see {@link #listStargazers2()} + * + * @return the paged iterable + */ + public PagedIterable listStargazers() { + return listUsers("stargazers"); + } + + /** + * Lists all the users who have starred this repo based on new version of the API, having extended information like + * the time when the repository was starred. For compatibility with the old API see {@link #listStargazers()} + * + * @return the paged iterable + */ + public PagedIterable listStargazers2() { + return root.createRequest() + .withPreview("application/vnd.github.v3.star+json") + .withUrlPath(getApiTailUrl("stargazers")) + .toIterable(GHStargazer[].class, item -> item.wrapUp(this)); + } + + private PagedIterable listUsers(final String suffix) { + return root.createRequest() + .withUrlPath(getApiTailUrl(suffix)) + .toIterable(GHUser[].class, item -> item.wrapUp(root)); + } + + /** + * See https://api.github.com/hooks for possible names and their configuration scheme. TODO: produce type-safe + * binding + * + * @param name + * Type of the hook to be created. See https://api.github.com/hooks for possible names. + * @param config + * The configuration hash. + * @param events + * Can be null. Types of events to hook into. + * @param active + * the active + * @return the gh hook + * @throws IOException + * the io exception + */ + public GHHook createHook(String name, Map config, Collection events, boolean active) + throws IOException { + return GHHooks.repoContext(this, owner).createHook(name, config, events, active); + } + + /** + * Create web hook gh hook. + * + * @param url + * the url + * @param events + * the events + * @return the gh hook + * @throws IOException + * the io exception + */ + public GHHook createWebHook(URL url, Collection events) throws IOException { + return createHook("web", Collections.singletonMap("url", url.toExternalForm()), events, true); + } + + /** + * Create web hook gh hook. + * + * @param url + * the url + * @return the gh hook + * @throws IOException + * the io exception + */ + public GHHook createWebHook(URL url) throws IOException { + return createWebHook(url, null); + } + + // this is no different from getPullRequests(OPEN) + // /** + // * Retrieves all the pull requests. + // */ + // public List getPullRequests() throws IOException { + // return root.retrieveWithAuth("/pulls/"+owner+'/'+name,JsonPullRequests.class).wrap(root); + // } + + /** + * Returns a set that represents the post-commit hook URLs. The returned set is live, and changes made to them are + * reflected to GitHub. + * + * @return the post commit hooks + * @deprecated Use {@link #getHooks()} and {@link #createHook(String, Map, Collection, boolean)} + */ + @SuppressFBWarnings(value = "DMI_COLLECTION_OF_URLS", + justification = "It causes a performance degradation, but we have already exposed it to the API") + public Set getPostCommitHooks() { + return postCommitHooks; + } + + /** + * Live set view of the post-commit hook. + */ + @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 postCommitHooks = new AbstractSet() { + private List getPostCommitHooks() { + try { + List r = new ArrayList(); + for (GHHook h : getHooks()) { + if (h.getName().equals("web")) { + r.add(new URL(h.getConfig().get("url"))); + } + } + return r; + } catch (IOException e) { + throw new GHException("Failed to retrieve post-commit hooks", e); + } + } + + @Override + public Iterator iterator() { + return getPostCommitHooks().iterator(); + } + + @Override + public int size() { + return getPostCommitHooks().size(); + } + + @Override + public boolean add(URL url) { + try { + createWebHook(url); + return true; + } catch (IOException e) { + throw new GHException("Failed to update post-commit hooks", e); + } + } + + @Override + public boolean remove(Object url) { + try { + String _url = ((URL) url).toExternalForm(); + for (GHHook h : getHooks()) { + if (h.getName().equals("web") && h.getConfig().get("url").equals(_url)) { + h.delete(); + return true; + } + } + return false; + } catch (IOException e) { + throw new GHException("Failed to update post-commit hooks", e); + } + } + }; + + GHRepository wrap(GitHub root) { + this.root = root; + if (root.isOffline()) { + owner.wrapUp(root); + } + return this; + } + + /** + * Gets branches by {@linkplain GHBranch#getName() their names}. + * + * @return the branches + * @throws IOException + * the io exception + */ + public Map getBranches() throws IOException { + Map r = new TreeMap(); + for (GHBranch p : root.createRequest().withUrlPath(getApiTailUrl("branches")).fetchArray(GHBranch[].class)) { + p.wrap(this); + r.put(p.getName(), p); + } + return r; + } + + /** + * Gets branch. + * + * @param name + * the name + * @return the branch + * @throws IOException + * the io exception + */ + public GHBranch getBranch(String name) throws IOException { + return root.createRequest().withUrlPath(getApiTailUrl("branches/" + name)).fetch(GHBranch.class).wrap(this); + } + + /** + * Gets milestones. + * + * @return the milestones + * @throws IOException + * the io exception + * @deprecated Use {@link #listMilestones(GHIssueState)} + */ + public Map getMilestones() throws IOException { + Map milestones = new TreeMap(); + for (GHMilestone m : listMilestones(GHIssueState.OPEN)) { + milestones.put(m.getNumber(), m); + } + return milestones; + } + + /** + * Lists up all the milestones in this repository. + * + * @param state + * the state + * @return the paged iterable + */ + public PagedIterable listMilestones(final GHIssueState state) { + return root.createRequest() + .with("state", state) + .withUrlPath(getApiTailUrl("milestones")) + .toIterable(GHMilestone[].class, item -> item.wrap(this)); + } + + /** + * Gets milestone. + * + * @param number + * the number + * @return the milestone + * @throws IOException + * the io exception + */ + public GHMilestone getMilestone(int number) throws IOException { + GHMilestone m = milestones.get(number); + if (m == null) { + m = root.createRequest().withUrlPath(getApiTailUrl("milestones/" + number)).fetch(GHMilestone.class); + m.owner = this; + m.root = root; + milestones.put(m.getNumber(), m); + } + return m; + } + + /** + * Gets file content. + * + * @param path + * the path + * @return the file content + * @throws IOException + * the io exception + */ + public GHContent getFileContent(String path) throws IOException { + return getFileContent(path, null); + } + + /** + * Gets file content. + * + * @param path + * the path + * @param ref + * the ref + * @return the file content + * @throws IOException + * the io exception + */ + public GHContent getFileContent(String path, String ref) throws IOException { + Requester requester = root.createRequest(); + String target = getApiTailUrl("contents/" + path); + + return requester.with("ref", ref).withUrlPath(target).fetch(GHContent.class).wrap(this); + } + + /** + * Gets directory content. + * + * @param path + * the path + * @return the directory content + * @throws IOException + * the io exception + */ + public List getDirectoryContent(String path) throws IOException { + return getDirectoryContent(path, null); + } + + /** + * Gets directory content. + * + * @param path + * the path + * @param ref + * the ref + * @return the directory content + * @throws IOException + * the io exception + */ + public List getDirectoryContent(String path, String ref) throws IOException { + Requester requester = root.createRequest(); + while (path.endsWith("/")) { + path = path.substring(0, path.length() - 1); + } + String target = getApiTailUrl("contents/" + path); + + GHContent[] files = requester.with("ref", ref).withUrlPath(target).fetchArray(GHContent[].class); + + GHContent.wrap(files, this); + + return Arrays.asList(files); + } + + /** + * https://developer.github.com/v3/repos/contents/#get-the-readme + * + * @return the readme + * @throws IOException + * the io exception + */ + public GHContent getReadme() throws IOException { + Requester requester = root.createRequest(); + return requester.withUrlPath(getApiTailUrl("readme")).fetch(GHContent.class).wrap(this); + } + + /** + * Creates a new content, or update an existing content. + * + * @return the gh content builder + */ + public GHContentBuilder createContent() { + return new GHContentBuilder(this); + } + + /** + * Use {@link #createContent()}. + * + * @param content + * the content + * @param commitMessage + * the commit message + * @param path + * the path + * @return the gh content update response + * @throws IOException + * the io exception + */ + @Deprecated + public GHContentUpdateResponse createContent(String content, String commitMessage, String path) throws IOException { + return createContent().content(content).message(commitMessage).path(path).commit(); + } + + /** + * Use {@link #createContent()}. + * + * @param content + * the content + * @param commitMessage + * the commit message + * @param path + * the path + * @param branch + * the branch + * @return the gh content update response + * @throws IOException + * the io exception + */ + @Deprecated + public GHContentUpdateResponse createContent(String content, String commitMessage, String path, String branch) + throws IOException { + return createContent().content(content).message(commitMessage).path(path).branch(branch).commit(); + } + + /** + * Use {@link #createContent()}. + * + * @param contentBytes + * the content bytes + * @param commitMessage + * the commit message + * @param path + * the path + * @return the gh content update response + * @throws IOException + * the io exception + */ + @Deprecated + public GHContentUpdateResponse createContent(byte[] contentBytes, String commitMessage, String path) + throws IOException { + return createContent().content(contentBytes).message(commitMessage).path(path).commit(); + } + + /** + * Use {@link #createContent()}. + * + * @param contentBytes + * the content bytes + * @param commitMessage + * the commit message + * @param path + * the path + * @param branch + * the branch + * @return the gh content update response + * @throws IOException + * the io exception + */ + @Deprecated + public GHContentUpdateResponse createContent(byte[] contentBytes, String commitMessage, String path, String branch) + throws IOException { + return createContent().content(contentBytes).message(commitMessage).path(path).branch(branch).commit(); + } + + /** + * Create milestone gh milestone. + * + * @param title + * the title + * @param description + * the description + * @return the gh milestone + * @throws IOException + * the io exception + */ + public GHMilestone createMilestone(String title, String description) throws IOException { + return root.createRequest() + .method("POST") + .with("title", title) + .with("description", description) + .withUrlPath(getApiTailUrl("milestones")) + .fetch(GHMilestone.class) + .wrap(this); + } + + /** + * Add deploy key gh deploy key. + * + * @param title + * the title + * @param key + * the key + * @return the gh deploy key + * @throws IOException + * the io exception + */ + public GHDeployKey addDeployKey(String title, String key) throws IOException { + return root.createRequest() + .method("POST") + .with("title", title) + .with("key", key) + .withUrlPath(getApiTailUrl("keys")) + .fetch(GHDeployKey.class) + .wrap(this); + + } + + /** + * Gets deploy keys. + * + * @return the deploy keys + * @throws IOException + * the io exception + */ + public List getDeployKeys() throws IOException { + List list = new ArrayList( + Arrays.asList(root.createRequest().withUrlPath(getApiTailUrl("keys")).fetchArray(GHDeployKey[].class))); + for (GHDeployKey h : list) + h.wrap(this); + return list; + } + + /** + * Forked repositories have a 'source' attribute that specifies the ultimate source of the forking chain. + * + * @return {@link GHRepository} that points to the root repository where this repository is forked (indirectly or + * directly) from. Otherwise null. + * @throws IOException + * the io exception + * @see #getParent() #getParent() + */ + public GHRepository getSource() throws IOException { + if (source == null) + return null; + if (source.root == null) + source = root.getRepository(source.getFullName()); + return source; + } + + /** + * Forked repositories have a 'parent' attribute that specifies the repository this repository is directly forked + * from. If we keep traversing {@link #getParent()} until it returns null, that is {@link #getSource()}. + * + * @return {@link GHRepository} that points to the repository where this repository is forked directly from. + * Otherwise null. + * @throws IOException + * the io exception + * @see #getSource() #getSource() + */ + public GHRepository getParent() throws IOException { + if (parent == null) + return null; + if (parent.root == null) + parent = root.getRepository(parent.getFullName()); + return parent; + } + + /** + * Subscribes to this repository to get notifications. + * + * @param subscribed + * the subscribed + * @param ignored + * the ignored + * @return the gh subscription + * @throws IOException + * the io exception + */ + public GHSubscription subscribe(boolean subscribed, boolean ignored) throws IOException { + return root.createRequest() + .method("PUT") + .with("subscribed", subscribed) + .with("ignored", ignored) + .withUrlPath(getApiTailUrl("subscription")) + .fetch(GHSubscription.class) + .wrapUp(this); + } + + /** + * Returns the current subscription. + * + * @return null if no subscription exists. + * @throws IOException + * the io exception + */ + public GHSubscription getSubscription() throws IOException { + try { + return root.createRequest() + .withUrlPath(getApiTailUrl("subscription")) + .fetch(GHSubscription.class) + .wrapUp(this); + } catch (FileNotFoundException e) { + return null; + } + } + + /** + * List contributors paged iterable. + * + * @return the paged iterable + * @throws IOException + * the io exception + */ + public PagedIterable listContributors() throws IOException { + return root.createRequest() + .withUrlPath(getApiTailUrl("contributors")) + .toIterable(Contributor[].class, item -> item.wrapUp(root)); + } + + /** + * The type Contributor. + */ + public static class Contributor extends GHUser { + private int contributions; + + /** + * Gets contributions. + * + * @return the contributions + */ + public int getContributions() { + return contributions; + } + + @Override + public int hashCode() { + // We ignore contributions in the calculation + return super.hashCode(); + } + + @Override + public boolean equals(Object obj) { + // We ignore contributions in the calculation + return super.equals(obj); + } + } + + /** + * Returns the statistics for this repository. + * + * @return the statistics + */ + public GHRepositoryStatistics getStatistics() { + // TODO: Use static object and introduce refresh() method, + // instead of returning new object each time. + return new GHRepositoryStatistics(this); + } + + /** + * Create a project for this repository. + * + * @param name + * the name + * @param body + * the body + * @return the gh project + * @throws IOException + * the io exception + */ + public GHProject createProject(String name, String body) throws IOException { + return root.createRequest() + .method("POST") + .withPreview(INERTIA) + .with("name", name) + .with("body", body) + .withUrlPath(getApiTailUrl("projects")) + .fetch(GHProject.class) + .wrap(this); + } + + /** + * Returns the projects for this repository. + * + * @param status + * The status filter (all, open or closed). + * @return the paged iterable + * @throws IOException + * the io exception + */ + public PagedIterable listProjects(final GHProject.ProjectStateFilter status) throws IOException { + return root.createRequest() + .withPreview(INERTIA) + .with("state", status) + .withUrlPath(getApiTailUrl("projects")) + .toIterable(GHProject[].class, item -> item.wrap(this)); + } + + /** + * Returns open projects for this repository. + * + * @return the paged iterable + * @throws IOException + * the io exception + */ + public PagedIterable listProjects() throws IOException { + return listProjects(GHProject.ProjectStateFilter.OPEN); + } + + /** + * Render a Markdown document. + *

+ * In {@linkplain MarkdownMode#GFM GFM mode}, issue numbers and user mentions are linked accordingly. + * + * @param text + * the text + * @param mode + * the mode + * @return the reader + * @throws IOException + * the io exception + * @see GitHub#renderMarkdown(String) GitHub#renderMarkdown(String) + */ + public Reader renderMarkdown(String text, MarkdownMode mode) throws IOException { + return new InputStreamReader( + root.createRequest() + .method("POST") + .with("text", text) + .with("mode", mode == null ? null : mode.toString()) + .with("context", getFullName()) + .withUrlPath("/markdown") + .fetchStream(), + "UTF-8"); + } + + /** + * List all the notifications in a repository for the current user. + * + * @return the gh notification stream + */ + public GHNotificationStream listNotifications() { + return new GHNotificationStream(root, getApiTailUrl("/notifications")); + } + + /** + * https://developer.github.com/v3/repos/traffic/#views + * + * @return the view traffic + * @throws IOException + * the io exception + */ + public GHRepositoryViewTraffic getViewTraffic() throws IOException { + return root.createRequest().withUrlPath(getApiTailUrl("/traffic/views")).fetch(GHRepositoryViewTraffic.class); + } + + /** + * https://developer.github.com/v3/repos/traffic/#clones + * + * @return the clone traffic + * @throws IOException + * the io exception + */ + public GHRepositoryCloneTraffic getCloneTraffic() throws IOException { + return root.createRequest().withUrlPath(getApiTailUrl("/traffic/clones")).fetch(GHRepositoryCloneTraffic.class); + } + + @Override + public int hashCode() { + return ("Repository:" + getOwnerName() + ":" + name).hashCode(); + } + + @Override + public boolean equals(Object obj) { + if (obj instanceof GHRepository) { + GHRepository that = (GHRepository) obj; + return this.getOwnerName().equals(that.getOwnerName()) && this.name.equals(that.name); + } + return false; + } + + String getApiTailUrl(String tail) { + if (tail.length() > 0 && !tail.startsWith("/")) + tail = '/' + tail; + return "/repos/" + getOwnerName() + "/" + name + tail; + } + + /** + * Get all issue events for this repository. See + * https://developer.github.com/v3/issues/events/#list-events-for-a-repository + * + * @return the paged iterable + * @throws IOException + * the io exception + */ + public PagedIterable listIssueEvents() throws IOException { + return root.createRequest() + .withUrlPath(getApiTailUrl("issues/events")) + .toIterable(GHIssueEvent[].class, item -> item.wrapUp(root)); + } + + /** + * Get a single issue event. See https://developer.github.com/v3/issues/events/#get-a-single-event + * + * @param id + * the id + * @return the issue event + * @throws IOException + * the io exception + */ + public GHIssueEvent getIssueEvent(long id) throws IOException { + return root.createRequest() + .withUrlPath(getApiTailUrl("issues/events/" + id)) + .fetch(GHIssueEvent.class) + .wrapUp(root); + } + + // Only used within listTopics(). + private static class Topics { + public List names; + } + + /** + * Return the topics for this repository. See + * https://developer.github.com/v3/repos/#list-all-topics-for-a-repository + * + * @return the list + * @throws IOException + * the io exception + */ + public List listTopics() throws IOException { + Topics topics = root.createRequest() + .withPreview(MERCY) + .withUrlPath(getApiTailUrl("topics")) + .fetch(Topics.class); + return topics.names; + } + + /** + * Set the topics for this repository. See + * https://developer.github.com/v3/repos/#replace-all-topics-for-a-repository + * + * @param topics + * the topics + * @throws IOException + * the io exception + */ + public void setTopics(List topics) throws IOException { + root.createRequest() + .method("PUT") + .with("names", topics) + .withPreview(MERCY) + .withUrlPath(getApiTailUrl("topics")) + .send(); + } + + /** + * Create a tag. See https://developer.github.com/v3/git/tags/#create-a-tag-object + * + * @param tag + * The tag's name. + * @param message + * The tag message. + * @param object + * The SHA of the git object this is tagging. + * @param type + * The type of the object we're tagging: "commit", "tree" or "blob". + * @return The newly created tag. + * @throws java.io.IOException + * The IO exception. + */ + public GHTagObject createTag(String tag, String message, String object, String type) throws IOException { + return root.createRequest() + .method("POST") + .with("tag", tag) + .with("message", message) + .with("object", object) + .with("type", type) + .withUrlPath(getApiTailUrl("git/tags")) + .fetch(GHTagObject.class) + .wrap(this); + } +} From 9ab8bdfe4ace551eade1238434169585dc8bb64b Mon Sep 17 00:00:00 2001 From: Vaughn Date: Thu, 23 Jan 2020 14:45:24 -0600 Subject: [PATCH 02/11] formatted file --- .../java/org/kohsuke/github/GHRepository.java | 316 ++++++------------ 1 file changed, 93 insertions(+), 223 deletions(-) diff --git a/src/main/java/org/kohsuke/github/GHRepository.java b/src/main/java/org/kohsuke/github/GHRepository.java index b0a423ad04..02379bc44e 100644 --- a/src/main/java/org/kohsuke/github/GHRepository.java +++ b/src/main/java/org/kohsuke/github/GHRepository.java @@ -59,8 +59,8 @@ * @author Kohsuke Kawaguchi */ @SuppressWarnings({ "UnusedDeclaration" }) -@SuppressFBWarnings(value = { "UWF_UNWRITTEN_PUBLIC_OR_PROTECTED_FIELD", "UWF_UNWRITTEN_FIELD", "NP_UNWRITTEN_FIELD" }, - justification = "JSON API") +@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; @@ -134,12 +134,8 @@ public PagedIterable getDeploymentStatuses(final int id) thr * @return the paged iterable */ public PagedIterable listDeployments(String sha, String ref, String task, String environment) { - return root.createRequest() - .with("sha", sha) - .with("ref", ref) - .with("task", task) - .with("environment", environment) - .withUrlPath(getApiTailUrl("deployments")) + return root.createRequest().with("sha", sha).with("ref", ref).with("task", task) + .with("environment", environment).withUrlPath(getApiTailUrl("deployments")) .toIterable(GHDeployment[].class, item -> item.wrap(this)); } @@ -153,9 +149,7 @@ public PagedIterable listDeployments(String sha, String ref, Strin * the io exception */ public GHDeployment getDeployment(long id) throws IOException { - return root.createRequest() - .withUrlPath(getApiTailUrl("deployments/" + id)) - .fetch(GHDeployment.class) + return root.createRequest().withUrlPath(getApiTailUrl("deployments/" + id)).fetch(GHDeployment.class) .wrap(this); } @@ -373,9 +367,8 @@ public List getIssues(GHIssueState state) throws IOException { * the io exception */ public List getIssues(GHIssueState state, GHMilestone milestone) throws IOException { - Requester requester = root.createRequest() - .with("state", state) - .with("milestone", milestone == null ? "none" : "" + milestone.getNumber()); + Requester requester = root.createRequest().with("state", state).with("milestone", + milestone == null ? "none" : "" + milestone.getNumber()); return Arrays .asList(GHIssue.wrap(requester.withUrlPath(getApiTailUrl("issues")).fetchArray(GHIssue[].class), this)); } @@ -388,9 +381,7 @@ public List getIssues(GHIssueState state, GHMilestone milestone) throws * @return the paged iterable */ public PagedIterable listIssues(final GHIssueState state) { - return root.createRequest() - .with("state", state) - .withUrlPath(getApiTailUrl("issues")) + return root.createRequest().with("state", state).withUrlPath(getApiTailUrl("issues")) .toIterable(GHIssue[].class, item -> item.wrap(this)); } @@ -418,13 +409,8 @@ public GHReleaseBuilder createRelease(String tag) { * the io exception */ public GHRef createRef(String name, String sha) throws IOException { - return root.createRequest() - .method("POST") - .with("ref", name) - .with("sha", sha) - .withUrlPath(getApiTailUrl("git/refs")) - .fetch(GHRef.class) - .wrap(root); + return root.createRequest().method("POST").with("ref", name).with("sha", sha) + .withUrlPath(getApiTailUrl("git/refs")).fetch(GHRef.class).wrap(root); } /** @@ -467,9 +453,7 @@ public GHRelease getRelease(long id) throws IOException { */ public GHRelease getReleaseByTagName(String tag) throws IOException { try { - return root.createRequest() - .withUrlPath(getApiTailUrl("releases/tags/" + tag)) - .fetch(GHRelease.class) + return root.createRequest().withUrlPath(getApiTailUrl("releases/tags/" + tag)).fetch(GHRelease.class) .wrap(this); } catch (FileNotFoundException e) { return null; // no release for this tag @@ -499,9 +483,8 @@ public GHRelease getLatestRelease() throws IOException { * the io exception */ public PagedIterable listReleases() throws IOException { - return root.createRequest() - .withUrlPath(getApiTailUrl("releases")) - .toIterable(GHRelease[].class, item -> item.wrap(this)); + return root.createRequest().withUrlPath(getApiTailUrl("releases")).toIterable(GHRelease[].class, + item -> item.wrap(this)); } /** @@ -512,9 +495,8 @@ public PagedIterable listReleases() throws IOException { * the io exception */ public PagedIterable listTags() throws IOException { - return root.createRequest() - .withUrlPath(getApiTailUrl("tags")) - .toIterable(GHTag[].class, item -> item.wrap(this)); + return root.createRequest().withUrlPath(getApiTailUrl("tags")).toIterable(GHTag[].class, + item -> item.wrap(this)); } /** @@ -535,9 +517,12 @@ public Map listLanguages() throws IOException { * @return the owner name */ public String getOwnerName() { - // consistency of the GitHub API is super... some serialized forms of GHRepository populate - // a full GHUser while others populate only the owner and email. This later form is super helpful - // in putting the login in owner.name not owner.login... thankfully we can easily identify this + // consistency of the GitHub API is super... some serialized forms of + // GHRepository populate + // a full GHUser while others populate only the owner and email. This later form + // is super helpful + // in putting the login in owner.name not owner.login... thankfully we can + // easily identify this // second set because owner.login will be null return owner.login != null ? owner.login : owner.name; } @@ -750,7 +735,7 @@ public PagedIterable listCollaborators() throws IOException { /** * Lists all - * the + * the * available assignees to which issues may be assigned. * * @return the paged iterable @@ -786,8 +771,7 @@ public boolean hasAssignee(GHUser u) throws IOException { public Set getCollaboratorNames() throws IOException { Set r = new HashSet(); for (GHUser u : GHUser.wrap( - root.createRequest().withUrlPath(getApiTailUrl("collaborators")).fetchArray(GHUser[].class), - root)) + root.createRequest().withUrlPath(getApiTailUrl("collaborators")).fetchArray(GHUser[].class), root)) r.add(u.login); return r; } @@ -802,8 +786,7 @@ public Set getCollaboratorNames() throws IOException { * the io exception */ public GHPermissionType getPermission(String user) throws IOException { - GHPermission perm = root.createRequest() - .withUrlPath(getApiTailUrl("collaborators/" + user + "/permission")) + GHPermission perm = root.createRequest().withUrlPath(getApiTailUrl("collaborators/" + user + "/permission")) .fetch(GHPermission.class); perm.wrapUp(root); return perm.getPermissionType(); @@ -840,6 +823,8 @@ public Set getTeams() throws IOException { * * @param users * the users + * @param perm + * the permission level * @throws IOException * the io exception */ @@ -852,6 +837,8 @@ public void addCollaborators(GHOrganization.Permission perm, GHUser... users) th * * @param users * the users + * @param perm + * the permission level * @throws IOException * the io exception */ @@ -892,12 +879,8 @@ private void modifyCollaborators(Collection users, String method) throws private void modifyCollaborators(GHOrganization.Permission perm, Collection users, String method) throws IOException { for (GHUser user : users) { - root.createRequest() - .method(method) - .with("permission", perm) - .inBody() - .withUrlPath(getApiTailUrl("collaborators/" + user.getLogin())) - .send(); + root.createRequest().method(method).with("permission", perm).inBody() + .withUrlPath(getApiTailUrl("collaborators/" + user.getLogin())).send(); } } @@ -912,13 +895,8 @@ private void modifyCollaborators(GHOrganization.Permission perm, Collection config = new HashMap(); config.put("address", address); - root.createRequest() - .method("POST") - .with("name", "email") - .with("config", config) - .with("active", true) - .withUrlPath(getApiTailUrl("hooks")) - .send(); + root.createRequest().method("POST").with("name", "email").with("config", config).with("active", true) + .withUrlPath(getApiTailUrl("hooks")).send(); } private void edit(String key, String value) throws IOException { @@ -1126,9 +1104,7 @@ public PagedIterable listForks() { * @return the paged iterable */ public PagedIterable listForks(final ForkSort sort) { - return root.createRequest() - .with("sort", sort) - .withUrlPath(getApiTailUrl("forks")) + return root.createRequest().with("sort", sort).withUrlPath(getApiTailUrl("forks")) .toIterable(GHRepository[].class, item -> item.wrap(root)); } @@ -1166,10 +1142,7 @@ public GHRepository fork() throws IOException { * the io exception */ public GHRepository forkTo(GHOrganization org) throws IOException { - root.createRequest() - .method("POST") - .with("organization", org.getLogin()) - .withUrlPath(getApiTailUrl("forks")) + root.createRequest().method("POST").with("organization", org.getLogin()).withUrlPath(getApiTailUrl("forks")) .send(); // this API is asynchronous. we need to wait for a bit @@ -1196,11 +1169,8 @@ public GHRepository forkTo(GHOrganization org) throws IOException { * the io exception */ public GHPullRequest getPullRequest(int i) throws IOException { - return root.createRequest() - .withPreview(SHADOW_CAT) - .withUrlPath(getApiTailUrl("pulls/" + i)) - .fetch(GHPullRequest.class) - .wrapUp(this); + return root.createRequest().withPreview(SHADOW_CAT).withUrlPath(getApiTailUrl("pulls/" + i)) + .fetch(GHPullRequest.class).wrapUp(this); } /** @@ -1278,10 +1248,7 @@ public GHPullRequest createPullRequest(String title, String head, String base, S * @throws IOException * the io exception */ - public GHPullRequest createPullRequest(String title, - String head, - String base, - String body, + public GHPullRequest createPullRequest(String title, String head, String base, String body, boolean maintainerCanModify) throws IOException { return createPullRequest(title, head, base, body, maintainerCanModify, false); } @@ -1307,24 +1274,11 @@ public GHPullRequest createPullRequest(String title, * @throws IOException * the io exception */ - public GHPullRequest createPullRequest(String title, - String head, - String base, - String body, - boolean maintainerCanModify, - boolean draft) throws IOException { - return root.createRequest() - .method("POST") - .withPreview(SHADOW_CAT) - .with("title", title) - .with("head", head) - .with("base", base) - .with("body", body) - .with("maintainer_can_modify", maintainerCanModify) - .with("draft", draft) - .withUrlPath(getApiTailUrl("pulls")) - .fetch(GHPullRequest.class) - .wrapUp(this); + public GHPullRequest createPullRequest(String title, String head, String base, String body, + boolean maintainerCanModify, boolean draft) throws IOException { + return root.createRequest().method("POST").withPreview(SHADOW_CAT).with("title", title).with("head", head) + .with("base", base).with("body", body).with("maintainer_can_modify", maintainerCanModify) + .with("draft", draft).withUrlPath(getApiTailUrl("pulls")).fetch(GHPullRequest.class).wrapUp(this); } /** @@ -1365,8 +1319,7 @@ public GHHook getHook(int id) throws IOException { * on failure communicating with GitHub */ public GHCompare getCompare(String id1, String id2) throws IOException { - GHCompare compare = root.createRequest() - .withUrlPath(getApiTailUrl(String.format("compare/%s...%s", id1, id2))) + GHCompare compare = root.createRequest().withUrlPath(getApiTailUrl(String.format("compare/%s...%s", id1, id2))) .fetch(GHCompare.class); return compare.wrap(this); } @@ -1425,8 +1378,7 @@ public GHCompare getCompare(GHBranch id1, GHBranch id2) throws IOException { * on failure communicating with GitHub */ public GHRef[] getRefs() throws IOException { - return GHRef.wrap(root.createRequest() - .withUrlPath(String.format("/repos/%s/%s/git/refs", getOwnerName(), name)) + return GHRef.wrap(root.createRequest().withUrlPath(String.format("/repos/%s/%s/git/refs", getOwnerName(), name)) .fetchArray(GHRef[].class), root); } @@ -1481,9 +1433,7 @@ public PagedIterable listRefs(String refType) throws IOException { * on failure communicating with GitHub, potentially due to an invalid ref type being requested */ public GHRef getRef(String refName) throws IOException { - return root.createRequest() - .withUrlPath(getApiTailUrl(String.format("git/refs/%s", refName))) - .fetch(GHRef.class) + return root.createRequest().withUrlPath(getApiTailUrl(String.format("git/refs/%s", refName))).fetch(GHRef.class) .wrap(root); } @@ -1584,9 +1534,7 @@ public InputStream readBlob(String blobSha) throws IOException { String target = getApiTailUrl("git/blobs/" + blobSha); // https://developer.github.com/v3/media/ describes this media type - return root.createRequest() - .withHeader("Accept", "application/vnd.github.v3.raw") - .withUrlPath(target) + return root.createRequest().withHeader("Accept", "application/vnd.github.v3.raw").withUrlPath(target) .fetchStream(); } @@ -1602,10 +1550,8 @@ public InputStream readBlob(String blobSha) throws IOException { public GHCommit getCommit(String sha1) throws IOException { GHCommit c = commits.get(sha1); if (c == null) { - c = root.createRequest() - .withUrlPath(String.format("/repos/%s/%s/commits/%s", getOwnerName(), name, sha1)) - .fetch(GHCommit.class) - .wrapUp(this); + c = root.createRequest().withUrlPath(String.format("/repos/%s/%s/commits/%s", getOwnerName(), name, sha1)) + .fetch(GHCommit.class).wrapUp(this); commits.put(sha1, c); } return c; @@ -1626,8 +1572,7 @@ public GHCommitBuilder createCommit() { * @return the paged iterable */ public PagedIterable listCommits() { - return root.createRequest() - .withUrlPath(String.format("/repos/%s/%s/commits", getOwnerName(), name)) + return root.createRequest().withUrlPath(String.format("/repos/%s/%s/commits", getOwnerName(), name)) .toIterable(GHCommit[].class, item -> item.wrapUp(this)); } @@ -1646,8 +1591,7 @@ public GHCommitQueryBuilder queryCommits() { * @return the paged iterable */ public PagedIterable listCommitComments() { - return root.createRequest() - .withUrlPath(String.format("/repos/%s/%s/comments", getOwnerName(), name)) + return root.createRequest().withUrlPath(String.format("/repos/%s/%s/comments", getOwnerName(), name)) .toIterable(GHCommitComment[].class, item -> item.wrap(this)); } @@ -1678,9 +1622,7 @@ public GHContent getLicenseContent() throws IOException { private GHContentWithLicense getLicenseContent_() throws IOException { try { - return root.createRequest() - .withUrlPath(getApiTailUrl("license")) - .fetch(GHContentWithLicense.class) + return root.createRequest().withUrlPath(getApiTailUrl("license")).fetch(GHContentWithLicense.class) .wrap(this); } catch (FileNotFoundException e) { return null; @@ -1697,8 +1639,7 @@ private GHContentWithLicense getLicenseContent_() throws IOException { * the io exception */ public PagedIterable listCommitStatuses(final String sha1) throws IOException { - return root.createRequest() - .withUrlPath(String.format("/repos/%s/%s/statuses/%s", getOwnerName(), name, sha1)) + return root.createRequest().withUrlPath(String.format("/repos/%s/%s/statuses/%s", getOwnerName(), name, sha1)) .toIterable(GHCommitStatus[].class, item -> item.wrapUp(root)); } @@ -1733,20 +1674,12 @@ public GHCommitStatus getLastCommitStatus(String sha1) throws IOException { * @throws IOException * the io exception */ - public GHCommitStatus createCommitStatus(String sha1, - GHCommitState state, - String targetUrl, - String description, + public GHCommitStatus createCommitStatus(String sha1, GHCommitState state, String targetUrl, String description, String context) throws IOException { - return root.createRequest() - .method("POST") - .with("state", state) - .with("target_url", targetUrl) - .with("description", description) - .with("context", context) + return root.createRequest().method("POST").with("state", state).with("target_url", targetUrl) + .with("description", description).with("context", context) .withUrlPath(String.format("/repos/%s/%s/statuses/%s", getOwnerName(), this.name, sha1)) - .fetch(GHCommitStatus.class) - .wrapUp(root); + .fetch(GHCommitStatus.class).wrapUp(root); } /** @@ -1779,8 +1712,7 @@ public GHCommitStatus createCommitStatus(String sha1, GHCommitState state, Strin * the io exception */ public PagedIterable listEvents() throws IOException { - return root.createRequest() - .withUrlPath(String.format("/repos/%s/%s/events", getOwnerName(), name)) + return root.createRequest().withUrlPath(String.format("/repos/%s/%s/events", getOwnerName(), name)) .toIterable(GHEventInfo[].class, item -> item.wrapUp(root)); } @@ -1794,9 +1726,8 @@ public PagedIterable listEvents() throws IOException { * the io exception */ public PagedIterable listLabels() throws IOException { - return root.createRequest() - .withUrlPath(getApiTailUrl("labels")) - .toIterable(GHLabel[].class, item -> item.wrapUp(this)); + return root.createRequest().withUrlPath(getApiTailUrl("labels")).toIterable(GHLabel[].class, + item -> item.wrapUp(this)); } /** @@ -1841,13 +1772,8 @@ public GHLabel createLabel(String name, String color) throws IOException { * the io exception */ public GHLabel createLabel(String name, String color, String description) throws IOException { - return root.createRequest() - .method("POST") - .with("name", name) - .with("color", color) - .with("description", description) - .withUrlPath(getApiTailUrl("labels")) - .fetch(GHLabel.class) + return root.createRequest().method("POST").with("name", name).with("color", color) + .with("description", description).withUrlPath(getApiTailUrl("labels")).fetch(GHLabel.class) .wrapUp(this); } @@ -1857,8 +1783,7 @@ public GHLabel createLabel(String name, String color, String description) throws * @return the paged iterable */ public PagedIterable listInvitations() { - return root.createRequest() - .withUrlPath(String.format("/repos/%s/%s/invitations", getOwnerName(), name)) + return root.createRequest().withUrlPath(String.format("/repos/%s/%s/invitations", getOwnerName(), name)) .toIterable(GHInvitation[].class, item -> item.wrapUp(root)); } @@ -1890,16 +1815,13 @@ public PagedIterable listStargazers() { * @return the paged iterable */ public PagedIterable listStargazers2() { - return root.createRequest() - .withPreview("application/vnd.github.v3.star+json") - .withUrlPath(getApiTailUrl("stargazers")) - .toIterable(GHStargazer[].class, item -> item.wrapUp(this)); + return root.createRequest().withPreview("application/vnd.github.v3.star+json") + .withUrlPath(getApiTailUrl("stargazers")).toIterable(GHStargazer[].class, item -> item.wrapUp(this)); } private PagedIterable listUsers(final String suffix) { - return root.createRequest() - .withUrlPath(getApiTailUrl(suffix)) - .toIterable(GHUser[].class, item -> item.wrapUp(root)); + return root.createRequest().withUrlPath(getApiTailUrl(suffix)).toIterable(GHUser[].class, + item -> item.wrapUp(root)); } /** @@ -1956,7 +1878,8 @@ public GHHook createWebHook(URL url) throws IOException { // * Retrieves all the pull requests. // */ // public List getPullRequests() throws IOException { - // return root.retrieveWithAuth("/pulls/"+owner+'/'+name,JsonPullRequests.class).wrap(root); + // return + // root.retrieveWithAuth("/pulls/"+owner+'/'+name,JsonPullRequests.class).wrap(root); // } /** @@ -1966,8 +1889,7 @@ public GHHook createWebHook(URL url) throws IOException { * @return the post commit hooks * @deprecated Use {@link #getHooks()} and {@link #createHook(String, Map, Collection, boolean)} */ - @SuppressFBWarnings(value = "DMI_COLLECTION_OF_URLS", - justification = "It causes a performance degradation, but we have already exposed it to the API") + @SuppressFBWarnings(value = "DMI_COLLECTION_OF_URLS", justification = "It causes a performance degradation, but we have already exposed it to the API") public Set getPostCommitHooks() { return postCommitHooks; } @@ -1975,8 +1897,7 @@ public Set getPostCommitHooks() { /** * Live set view of the post-commit hook. */ - @SuppressFBWarnings(value = "DMI_COLLECTION_OF_URLS", - justification = "It causes a performance degradation, but we have already exposed it to the API") + @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 postCommitHooks = new AbstractSet() { private List getPostCommitHooks() { @@ -2091,9 +2012,7 @@ public Map getMilestones() throws IOException { * @return the paged iterable */ public PagedIterable listMilestones(final GHIssueState state) { - return root.createRequest() - .with("state", state) - .withUrlPath(getApiTailUrl("milestones")) + return root.createRequest().with("state", state).withUrlPath(getApiTailUrl("milestones")) .toIterable(GHMilestone[].class, item -> item.wrap(this)); } @@ -2298,13 +2217,8 @@ public GHContentUpdateResponse createContent(byte[] contentBytes, String commitM * the io exception */ public GHMilestone createMilestone(String title, String description) throws IOException { - return root.createRequest() - .method("POST") - .with("title", title) - .with("description", description) - .withUrlPath(getApiTailUrl("milestones")) - .fetch(GHMilestone.class) - .wrap(this); + return root.createRequest().method("POST").with("title", title).with("description", description) + .withUrlPath(getApiTailUrl("milestones")).fetch(GHMilestone.class).wrap(this); } /** @@ -2319,13 +2233,8 @@ public GHMilestone createMilestone(String title, String description) throws IOEx * the io exception */ public GHDeployKey addDeployKey(String title, String key) throws IOException { - return root.createRequest() - .method("POST") - .with("title", title) - .with("key", key) - .withUrlPath(getApiTailUrl("keys")) - .fetch(GHDeployKey.class) - .wrap(this); + return root.createRequest().method("POST").with("title", title).with("key", key) + .withUrlPath(getApiTailUrl("keys")).fetch(GHDeployKey.class).wrap(this); } @@ -2391,13 +2300,8 @@ public GHRepository getParent() throws IOException { * the io exception */ public GHSubscription subscribe(boolean subscribed, boolean ignored) throws IOException { - return root.createRequest() - .method("PUT") - .with("subscribed", subscribed) - .with("ignored", ignored) - .withUrlPath(getApiTailUrl("subscription")) - .fetch(GHSubscription.class) - .wrapUp(this); + return root.createRequest().method("PUT").with("subscribed", subscribed).with("ignored", ignored) + .withUrlPath(getApiTailUrl("subscription")).fetch(GHSubscription.class).wrapUp(this); } /** @@ -2409,9 +2313,7 @@ public GHSubscription subscribe(boolean subscribed, boolean ignored) throws IOEx */ public GHSubscription getSubscription() throws IOException { try { - return root.createRequest() - .withUrlPath(getApiTailUrl("subscription")) - .fetch(GHSubscription.class) + return root.createRequest().withUrlPath(getApiTailUrl("subscription")).fetch(GHSubscription.class) .wrapUp(this); } catch (FileNotFoundException e) { return null; @@ -2426,9 +2328,8 @@ public GHSubscription getSubscription() throws IOException { * the io exception */ public PagedIterable listContributors() throws IOException { - return root.createRequest() - .withUrlPath(getApiTailUrl("contributors")) - .toIterable(Contributor[].class, item -> item.wrapUp(root)); + return root.createRequest().withUrlPath(getApiTailUrl("contributors")).toIterable(Contributor[].class, + item -> item.wrapUp(root)); } /** @@ -2482,14 +2383,8 @@ public GHRepositoryStatistics getStatistics() { * the io exception */ public GHProject createProject(String name, String body) throws IOException { - return root.createRequest() - .method("POST") - .withPreview(INERTIA) - .with("name", name) - .with("body", body) - .withUrlPath(getApiTailUrl("projects")) - .fetch(GHProject.class) - .wrap(this); + return root.createRequest().method("POST").withPreview(INERTIA).with("name", name).with("body", body) + .withUrlPath(getApiTailUrl("projects")).fetch(GHProject.class).wrap(this); } /** @@ -2502,10 +2397,7 @@ public GHProject createProject(String name, String body) throws IOException { * the io exception */ public PagedIterable listProjects(final GHProject.ProjectStateFilter status) throws IOException { - return root.createRequest() - .withPreview(INERTIA) - .with("state", status) - .withUrlPath(getApiTailUrl("projects")) + return root.createRequest().withPreview(INERTIA).with("state", status).withUrlPath(getApiTailUrl("projects")) .toIterable(GHProject[].class, item -> item.wrap(this)); } @@ -2535,15 +2427,9 @@ public PagedIterable listProjects() throws IOException { * @see GitHub#renderMarkdown(String) GitHub#renderMarkdown(String) */ public Reader renderMarkdown(String text, MarkdownMode mode) throws IOException { - return new InputStreamReader( - root.createRequest() - .method("POST") - .with("text", text) - .with("mode", mode == null ? null : mode.toString()) - .with("context", getFullName()) - .withUrlPath("/markdown") - .fetchStream(), - "UTF-8"); + return new InputStreamReader(root.createRequest().method("POST").with("text", text) + .with("mode", mode == null ? null : mode.toString()).with("context", getFullName()) + .withUrlPath("/markdown").fetchStream(), "UTF-8"); } /** @@ -2608,9 +2494,8 @@ String getApiTailUrl(String tail) { * the io exception */ public PagedIterable listIssueEvents() throws IOException { - return root.createRequest() - .withUrlPath(getApiTailUrl("issues/events")) - .toIterable(GHIssueEvent[].class, item -> item.wrapUp(root)); + return root.createRequest().withUrlPath(getApiTailUrl("issues/events")).toIterable(GHIssueEvent[].class, + item -> item.wrapUp(root)); } /** @@ -2623,9 +2508,7 @@ public PagedIterable listIssueEvents() throws IOException { * the io exception */ public GHIssueEvent getIssueEvent(long id) throws IOException { - return root.createRequest() - .withUrlPath(getApiTailUrl("issues/events/" + id)) - .fetch(GHIssueEvent.class) + return root.createRequest().withUrlPath(getApiTailUrl("issues/events/" + id)).fetch(GHIssueEvent.class) .wrapUp(root); } @@ -2643,9 +2526,7 @@ private static class Topics { * the io exception */ public List listTopics() throws IOException { - Topics topics = root.createRequest() - .withPreview(MERCY) - .withUrlPath(getApiTailUrl("topics")) + Topics topics = root.createRequest().withPreview(MERCY).withUrlPath(getApiTailUrl("topics")) .fetch(Topics.class); return topics.names; } @@ -2660,11 +2541,7 @@ public List listTopics() throws IOException { * the io exception */ public void setTopics(List topics) throws IOException { - root.createRequest() - .method("PUT") - .with("names", topics) - .withPreview(MERCY) - .withUrlPath(getApiTailUrl("topics")) + root.createRequest().method("PUT").with("names", topics).withPreview(MERCY).withUrlPath(getApiTailUrl("topics")) .send(); } @@ -2684,14 +2561,7 @@ public void setTopics(List topics) throws IOException { * The IO exception. */ public GHTagObject createTag(String tag, String message, String object, String type) throws IOException { - return root.createRequest() - .method("POST") - .with("tag", tag) - .with("message", message) - .with("object", object) - .with("type", type) - .withUrlPath(getApiTailUrl("git/tags")) - .fetch(GHTagObject.class) - .wrap(this); + return root.createRequest().method("POST").with("tag", tag).with("message", message).with("object", object) + .with("type", type).withUrlPath(getApiTailUrl("git/tags")).fetch(GHTagObject.class).wrap(this); } } From 8792213594f590f937601be05f758ee986253247 Mon Sep 17 00:00:00 2001 From: Vaughn Date: Thu, 23 Jan 2020 15:16:36 -0600 Subject: [PATCH 03/11] tried formatting the file once again. --- src/main/java/org/kohsuke/github/GHRepository.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/org/kohsuke/github/GHRepository.java b/src/main/java/org/kohsuke/github/GHRepository.java index 02379bc44e..fca88bafdd 100644 --- a/src/main/java/org/kohsuke/github/GHRepository.java +++ b/src/main/java/org/kohsuke/github/GHRepository.java @@ -1,4 +1,4 @@ -/* +/* * The MIT License * * Copyright (c) 2010, Kohsuke Kawaguchi From 3bf8baee8588e53bdc4339577b5f6b15dd917f27 Mon Sep 17 00:00:00 2001 From: James Vaughn Date: Thu, 23 Jan 2020 18:32:37 -0600 Subject: [PATCH 04/11] format fixed and validation passed --- .../java/org/kohsuke/github/GHRepository.java | 5134 ++++++++--------- 1 file changed, 2567 insertions(+), 2567 deletions(-) diff --git a/src/main/java/org/kohsuke/github/GHRepository.java b/src/main/java/org/kohsuke/github/GHRepository.java index fca88bafdd..54bfc15f79 100644 --- a/src/main/java/org/kohsuke/github/GHRepository.java +++ b/src/main/java/org/kohsuke/github/GHRepository.java @@ -1,2567 +1,2567 @@ -/* - * The MIT License - * - * Copyright (c) 2010, Kohsuke Kawaguchi - * - * 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 com.fasterxml.jackson.annotation.JsonProperty; -import com.infradna.tool.bridge_method_injector.WithBridgeMethods; -import edu.umd.cs.findbugs.annotations.SuppressFBWarnings; -import org.apache.commons.lang3.StringUtils; - -import java.io.FileNotFoundException; -import java.io.IOException; -import java.io.InputStream; -import java.io.InputStreamReader; -import java.io.InterruptedIOException; -import java.io.Reader; -import java.net.URL; -import java.util.AbstractSet; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collection; -import java.util.Collections; -import java.util.Date; -import java.util.HashMap; -import java.util.HashSet; -import java.util.Iterator; -import java.util.List; -import java.util.Map; -import java.util.Set; -import java.util.TreeMap; -import java.util.WeakHashMap; - -import static java.util.Arrays.*; -import static org.kohsuke.github.Previews.*; - -/** - * A repository on GitHub. - * - * @author Kohsuke Kawaguchi - */ -@SuppressWarnings({ "UnusedDeclaration" }) -@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; - - private String description, homepage, name, full_name; - private String html_url; // this is the UI - /* - * The license information makes use of the preview API. - * - * See: https://developer.github.com/v3/licenses/ - */ - private GHLicense license; - - private String git_url, ssh_url, clone_url, svn_url, mirror_url; - private GHUser owner; // not fully populated. beware. - private boolean has_issues, has_wiki, fork, has_downloads, has_pages, archived; - - private boolean allow_squash_merge; - private boolean allow_merge_commit; - private boolean allow_rebase_merge; - - @JsonProperty("private") - private boolean _private; - private int forks_count, stargazers_count, watchers_count, size, open_issues_count, subscribers_count; - private String pushed_at; - private Map milestones = new WeakHashMap(); - - private String default_branch, language; - private Map commits = new WeakHashMap(); - - @SkipFromToString - private GHRepoPermission permissions; - - private GHRepository source, parent; - - /** - * Create deployment gh deployment builder. - * - * @param ref - * the ref - * @return the gh deployment builder - */ - public GHDeploymentBuilder createDeployment(String ref) { - return new GHDeploymentBuilder(this, ref); - } - - /** - * Gets deployment statuses. - * - * @param id - * the id - * @return the deployment statuses - * @throws IOException - * the io exception - * @deprecated Use {@code getDeployment(id).listStatuses()} - */ - public PagedIterable getDeploymentStatuses(final int id) throws IOException { - return getDeployment(id).listStatuses(); - } - - /** - * List deployments paged iterable. - * - * @param sha - * the sha - * @param ref - * the ref - * @param task - * the task - * @param environment - * the environment - * @return the paged iterable - */ - public PagedIterable listDeployments(String sha, String ref, String task, String environment) { - return root.createRequest().with("sha", sha).with("ref", ref).with("task", task) - .with("environment", environment).withUrlPath(getApiTailUrl("deployments")) - .toIterable(GHDeployment[].class, item -> item.wrap(this)); - } - - /** - * Obtains a single {@link GHDeployment} by its ID. - * - * @param id - * the id - * @return the deployment - * @throws IOException - * the io exception - */ - public GHDeployment getDeployment(long id) throws IOException { - return root.createRequest().withUrlPath(getApiTailUrl("deployments/" + id)).fetch(GHDeployment.class) - .wrap(this); - } - - /** - * Gets deploy status. - * - * @param deploymentId - * the deployment id - * @param ghDeploymentState - * the gh deployment state - * @return the deploy status - * @throws IOException - * the io exception - * @deprecated Use {@code getDeployment(deploymentId).createStatus(ghDeploymentState)} - */ - public GHDeploymentStatusBuilder createDeployStatus(int deploymentId, GHDeploymentState ghDeploymentState) - throws IOException { - return getDeployment(deploymentId).createStatus(ghDeploymentState); - } - - private static class GHRepoPermission { - boolean pull, push, admin; - } - - /** - * Gets description. - * - * @return the description - */ - public String getDescription() { - return description; - } - - /** - * Gets homepage. - * - * @return the homepage - */ - public String getHomepage() { - return homepage; - } - - /** - * Gets the git:// URL to this repository, such as "git://github.com/kohsuke/jenkins.git" This URL is read-only. - * - * @return the git transport url - */ - public String getGitTransportUrl() { - return git_url; - } - - /** - * Gets the HTTPS URL to this repository, such as "https://github.com/kohsuke/jenkins.git" This URL is read-only. - * - * @return the http transport url - */ - public String getHttpTransportUrl() { - return clone_url; - } - - /** - * Git http transport url string. - * - * @return the string - * @deprecated Typo of {@link #getHttpTransportUrl()} - */ - public String gitHttpTransportUrl() { - return clone_url; - } - - /** - * Gets the Subversion URL to access this repository: https://github.com/rails/rails - * - * @return the svn url - */ - public String getSvnUrl() { - return svn_url; - } - - /** - * Gets the Mirror URL to access this repository: https://github.com/apache/tomee mirrored from - * git://git.apache.org/tomee.git - * - * @return the mirror url - */ - public String getMirrorUrl() { - return mirror_url; - } - - /** - * Gets the SSH URL to access this repository, such as git@github.com:rails/rails.git - * - * @return the ssh url - */ - public String getSshUrl() { - return ssh_url; - } - - public URL getHtmlUrl() { - return GitHub.parseURL(html_url); - } - - /** - * Short repository name without the owner. For example 'jenkins' in case of http://github.com/jenkinsci/jenkins - * - * @return the name - */ - public String getName() { - return name; - } - - /** - * Full repository name including the owner or organization. For example 'jenkinsci/jenkins' in case of - * http://github.com/jenkinsci/jenkins - * - * @return the full name - */ - public String getFullName() { - return full_name; - } - - /** - * Has pull access boolean. - * - * @return the boolean - */ - public boolean hasPullAccess() { - return permissions != null && permissions.pull; - } - - /** - * Has push access boolean. - * - * @return the boolean - */ - public boolean hasPushAccess() { - return permissions != null && permissions.push; - } - - /** - * Has admin access boolean. - * - * @return the boolean - */ - public boolean hasAdminAccess() { - return permissions != null && permissions.admin; - } - - /** - * Gets the primary programming language. - * - * @return the language - */ - public String getLanguage() { - return language; - } - - /** - * Gets owner. - * - * @return the owner - * @throws IOException - * the io exception - */ - public GHUser getOwner() throws IOException { - return root.isOffline() ? owner : root.getUser(getOwnerName()); // because 'owner' isn't fully populated - } - - /** - * Gets issue. - * - * @param id - * the id - * @return the issue - * @throws IOException - * the io exception - */ - public GHIssue getIssue(int id) throws IOException { - return root.createRequest().withUrlPath(getApiTailUrl("issues/" + id)).fetch(GHIssue.class).wrap(this); - } - - /** - * Create issue gh issue builder. - * - * @param title - * the title - * @return the gh issue builder - */ - public GHIssueBuilder createIssue(String title) { - return new GHIssueBuilder(this, title); - } - - /** - * Gets issues. - * - * @param state - * the state - * @return the issues - * @throws IOException - * the io exception - */ - public List getIssues(GHIssueState state) throws IOException { - return listIssues(state).asList(); - } - - /** - * Gets issues. - * - * @param state - * the state - * @param milestone - * the milestone - * @return the issues - * @throws IOException - * the io exception - */ - public List getIssues(GHIssueState state, GHMilestone milestone) throws IOException { - Requester requester = root.createRequest().with("state", state).with("milestone", - milestone == null ? "none" : "" + milestone.getNumber()); - return Arrays - .asList(GHIssue.wrap(requester.withUrlPath(getApiTailUrl("issues")).fetchArray(GHIssue[].class), this)); - } - - /** - * Lists up all the issues in this repository. - * - * @param state - * the state - * @return the paged iterable - */ - public PagedIterable listIssues(final GHIssueState state) { - return root.createRequest().with("state", state).withUrlPath(getApiTailUrl("issues")) - .toIterable(GHIssue[].class, item -> item.wrap(this)); - } - - /** - * Create release gh release builder. - * - * @param tag - * the tag - * @return the gh release builder - */ - public GHReleaseBuilder createRelease(String tag) { - return new GHReleaseBuilder(this, tag); - } - - /** - * Creates a named ref, such as tag, branch, etc. - * - * @param name - * The name of the fully qualified reference (ie: refs/heads/master). If it doesn't start with 'refs' and - * have at least two slashes, it will be rejected. - * @param sha - * The SHA1 value to set this reference to - * @return the gh ref - * @throws IOException - * the io exception - */ - public GHRef createRef(String name, String sha) throws IOException { - return root.createRequest().method("POST").with("ref", name).with("sha", sha) - .withUrlPath(getApiTailUrl("git/refs")).fetch(GHRef.class).wrap(root); - } - - /** - * Gets releases. - * - * @return the releases - * @throws IOException - * the io exception - * @deprecated use {@link #listReleases()} - */ - public List getReleases() throws IOException { - return listReleases().asList(); - } - - /** - * Gets release. - * - * @param id - * the id - * @return the release - * @throws IOException - * the io exception - */ - public GHRelease getRelease(long id) throws IOException { - try { - return root.createRequest().withUrlPath(getApiTailUrl("releases/" + id)).fetch(GHRelease.class).wrap(this); - } catch (FileNotFoundException e) { - return null; // no release for this id - } - } - - /** - * Gets release by tag name. - * - * @param tag - * the tag - * @return the release by tag name - * @throws IOException - * the io exception - */ - public GHRelease getReleaseByTagName(String tag) throws IOException { - try { - return root.createRequest().withUrlPath(getApiTailUrl("releases/tags/" + tag)).fetch(GHRelease.class) - .wrap(this); - } catch (FileNotFoundException e) { - return null; // no release for this tag - } - } - - /** - * Gets latest release. - * - * @return the latest release - * @throws IOException - * the io exception - */ - public GHRelease getLatestRelease() throws IOException { - try { - return root.createRequest().withUrlPath(getApiTailUrl("releases/latest")).fetch(GHRelease.class).wrap(this); - } catch (FileNotFoundException e) { - return null; // no latest release - } - } - - /** - * List releases paged iterable. - * - * @return the paged iterable - * @throws IOException - * the io exception - */ - public PagedIterable listReleases() throws IOException { - return root.createRequest().withUrlPath(getApiTailUrl("releases")).toIterable(GHRelease[].class, - item -> item.wrap(this)); - } - - /** - * List tags paged iterable. - * - * @return the paged iterable - * @throws IOException - * the io exception - */ - public PagedIterable listTags() throws IOException { - return root.createRequest().withUrlPath(getApiTailUrl("tags")).toIterable(GHTag[].class, - item -> item.wrap(this)); - } - - /** - * List languages for the specified repository. The value on the right of a language is the number of bytes of code - * written in that language. { "C": 78769, "Python": 7769 } - * - * @return the map - * @throws IOException - * the io exception - */ - public Map listLanguages() throws IOException { - return root.createRequest().withUrlPath(getApiTailUrl("languages")).fetch(HashMap.class); - } - - /** - * Gets owner name. - * - * @return the owner name - */ - public String getOwnerName() { - // consistency of the GitHub API is super... some serialized forms of - // GHRepository populate - // a full GHUser while others populate only the owner and email. This later form - // is super helpful - // in putting the login in owner.name not owner.login... thankfully we can - // easily identify this - // second set because owner.login will be null - return owner.login != null ? owner.login : owner.name; - } - - /** - * Has issues boolean. - * - * @return the boolean - */ - public boolean hasIssues() { - return has_issues; - } - - /** - * Has wiki boolean. - * - * @return the boolean - */ - public boolean hasWiki() { - return has_wiki; - } - - /** - * Is fork boolean. - * - * @return the boolean - */ - public boolean isFork() { - return fork; - } - - /** - * Is archived boolean. - * - * @return the boolean - */ - public boolean isArchived() { - return archived; - } - - /** - * Is allow squash merge boolean. - * - * @return the boolean - */ - public boolean isAllowSquashMerge() { - return allow_squash_merge; - } - - /** - * Is allow merge commit boolean. - * - * @return the boolean - */ - public boolean isAllowMergeCommit() { - return allow_merge_commit; - } - - /** - * Is allow rebase merge boolean. - * - * @return the boolean - */ - public boolean isAllowRebaseMerge() { - return allow_rebase_merge; - } - - /** - * Returns the number of all forks of this repository. This not only counts direct forks, but also forks of forks, - * and so on. - * - * @return the forks - */ - public int getForks() { - return forks_count; - } - - /** - * Gets stargazers count. - * - * @return the stargazers count - */ - public int getStargazersCount() { - return stargazers_count; - } - - /** - * Is private boolean. - * - * @return the boolean - */ - public boolean isPrivate() { - return _private; - } - - /** - * Has downloads boolean. - * - * @return the boolean - */ - public boolean hasDownloads() { - return has_downloads; - } - - /** - * Has pages boolean. - * - * @return the boolean - */ - public boolean hasPages() { - return has_pages; - } - - /** - * Gets watchers. - * - * @return the watchers - */ - public int getWatchers() { - return watchers_count; - } - - /** - * Gets open issue count. - * - * @return the open issue count - */ - public int getOpenIssueCount() { - return open_issues_count; - } - - /** - * Gets network count. - * - * @return the network count - * @deprecated This no longer exists in the official API documentation. Use {@link #getForks()} - */ - public int getNetworkCount() { - return forks_count; - } - - /** - * Gets subscribers count. - * - * @return the subscribers count - */ - public int getSubscribersCount() { - return subscribers_count; - } - - /** - * Gets pushed at. - * - * @return null if the repository was never pushed at. - */ - public Date getPushedAt() { - return GitHub.parseDate(pushed_at); - } - - /** - * Returns the primary branch you'll configure in the "Admin > Options" config page. - * - * @return This field is null until the user explicitly configures the master branch. - */ - public String getDefaultBranch() { - return default_branch; - } - - /** - * Gets master branch. - * - * @return the master branch - * @deprecated Renamed to {@link #getDefaultBranch()} - */ - public String getMasterBranch() { - return default_branch; - } - - /** - * Gets size. - * - * @return the size - */ - public int getSize() { - return size; - } - - /** - * Gets the collaborators on this repository. This set always appear to include the owner. - * - * @return the collaborators - * @throws IOException - * the io exception - */ - @WithBridgeMethods(Set.class) - public GHPersonSet getCollaborators() throws IOException { - return new GHPersonSet(listCollaborators().asList()); - } - - /** - * Lists up the collaborators on this repository. - * - * @return Users paged iterable - * @throws IOException - * the io exception - */ - public PagedIterable listCollaborators() throws IOException { - return listUsers("collaborators"); - } - - /** - * Lists all - * the - * available assignees to which issues may be assigned. - * - * @return the paged iterable - * @throws IOException - * the io exception - */ - public PagedIterable listAssignees() throws IOException { - return listUsers("assignees"); - } - - /** - * Checks if the given user is an assignee for this repository. - * - * @param u - * the u - * @return the boolean - * @throws IOException - * the io exception - */ - public boolean hasAssignee(GHUser u) throws IOException { - return root.createRequest().withUrlPath(getApiTailUrl("assignees/" + u.getLogin())).fetchHttpStatusCode() - / 100 == 2; - } - - /** - * Gets the names of the collaborators on this repository. This method deviates from the principle of this library - * but it works a lot faster than {@link #getCollaborators()}. - * - * @return the collaborator names - * @throws IOException - * the io exception - */ - public Set getCollaboratorNames() throws IOException { - Set r = new HashSet(); - for (GHUser u : GHUser.wrap( - root.createRequest().withUrlPath(getApiTailUrl("collaborators")).fetchArray(GHUser[].class), root)) - r.add(u.login); - return r; - } - - /** - * Obtain permission for a given user in this repository. - * - * @param user - * a {@link GHUser#getLogin} - * @return the permission - * @throws IOException - * the io exception - */ - public GHPermissionType getPermission(String user) throws IOException { - GHPermission perm = root.createRequest().withUrlPath(getApiTailUrl("collaborators/" + user + "/permission")) - .fetch(GHPermission.class); - perm.wrapUp(root); - return perm.getPermissionType(); - } - - /** - * Obtain permission for a given user in this repository. - * - * @param u - * the u - * @return the permission - * @throws IOException - * the io exception - */ - public GHPermissionType getPermission(GHUser u) throws IOException { - return getPermission(u.getLogin()); - } - - /** - * If this repository belongs to an organization, return a set of teams. - * - * @return the teams - * @throws IOException - * the io exception - */ - public Set getTeams() throws IOException { - return Collections.unmodifiableSet(new HashSet(Arrays.asList( - GHTeam.wrapUp(root.createRequest().withUrlPath(getApiTailUrl("teams")).fetchArray(GHTeam[].class), - root.getOrganization(getOwnerName()))))); - } - - /** - * Add collaborators. - * - * @param users - * the users - * @param perm - * the permission level - * @throws IOException - * the io exception - */ - public void addCollaborators(GHOrganization.Permission perm, GHUser... users) throws IOException { - addCollaborators(perm, asList(users)); - } - - /** - * Add collaborators. - * - * @param users - * the users - * @param perm - * the permission level - * @throws IOException - * the io exception - */ - public void addCollaborators(GHOrganization.Permission perm, Collection users) throws IOException { - modifyCollaborators(perm, users, "PUT"); - } - - /** - * Remove collaborators. - * - * @param users - * the users - * @throws IOException - * the io exception - */ - public void removeCollaborators(GHUser... users) throws IOException { - removeCollaborators(asList(users)); - } - - /** - * Remove collaborators. - * - * @param users - * the users - * @throws IOException - * the io exception - */ - public void removeCollaborators(Collection users) throws IOException { - modifyCollaborators(users, "DELETE"); - } - - private void modifyCollaborators(Collection users, String method) throws IOException { - for (GHUser user : users) { - root.createRequest().method(method).withUrlPath(getApiTailUrl("collaborators/" + user.getLogin())).send(); - } - } - - private void modifyCollaborators(GHOrganization.Permission perm, Collection users, String method) - throws IOException { - for (GHUser user : users) { - root.createRequest().method(method).with("permission", perm).inBody() - .withUrlPath(getApiTailUrl("collaborators/" + user.getLogin())).send(); - } - } - - /** - * Sets email service hook. - * - * @param address - * the address - * @throws IOException - * the io exception - */ - public void setEmailServiceHook(String address) throws IOException { - Map config = new HashMap(); - config.put("address", address); - root.createRequest().method("POST").with("name", "email").with("config", config).with("active", true) - .withUrlPath(getApiTailUrl("hooks")).send(); - } - - private void edit(String key, String value) throws IOException { - Requester requester = root.createRequest(); - if (!key.equals("name")) - requester.with("name", name); // even when we don't change the name, we need to send it in - requester.with(key, value).method("PATCH").withUrlPath(getApiTailUrl("")).send(); - } - - /** - * Enables or disables the issue tracker for this repository. - * - * @param v - * the v - * @throws IOException - * the io exception - */ - public void enableIssueTracker(boolean v) throws IOException { - edit("has_issues", String.valueOf(v)); - } - - /** - * Enables or disables Wiki for this repository. - * - * @param v - * the v - * @throws IOException - * the io exception - */ - public void enableWiki(boolean v) throws IOException { - edit("has_wiki", String.valueOf(v)); - } - - /** - * Enable downloads. - * - * @param v - * the v - * @throws IOException - * the io exception - */ - public void enableDownloads(boolean v) throws IOException { - edit("has_downloads", String.valueOf(v)); - } - - /** - * Rename this repository. - * - * @param name - * the name - * @throws IOException - * the io exception - */ - public void renameTo(String name) throws IOException { - edit("name", name); - } - - /** - * Sets description. - * - * @param value - * the value - * @throws IOException - * the io exception - */ - public void setDescription(String value) throws IOException { - edit("description", value); - } - - /** - * Sets homepage. - * - * @param value - * the value - * @throws IOException - * the io exception - */ - public void setHomepage(String value) throws IOException { - edit("homepage", value); - } - - /** - * Sets default branch. - * - * @param value - * the value - * @throws IOException - * the io exception - */ - public void setDefaultBranch(String value) throws IOException { - edit("default_branch", value); - } - - /** - * Sets private. - * - * @param value - * the value - * @throws IOException - * the io exception - */ - public void setPrivate(boolean value) throws IOException { - edit("private", Boolean.toString(value)); - } - - /** - * Allow squash merge. - * - * @param value - * the value - * @throws IOException - * the io exception - */ - public void allowSquashMerge(boolean value) throws IOException { - edit("allow_squash_merge", Boolean.toString(value)); - } - - /** - * Allow merge commit. - * - * @param value - * the value - * @throws IOException - * the io exception - */ - public void allowMergeCommit(boolean value) throws IOException { - edit("allow_merge_commit", Boolean.toString(value)); - } - - /** - * Allow rebase merge. - * - * @param value - * the value - * @throws IOException - * the io exception - */ - public void allowRebaseMerge(boolean value) throws IOException { - edit("allow_rebase_merge", Boolean.toString(value)); - } - - /** - * Deletes this repository. - * - * @throws IOException - * the io exception - */ - public void delete() throws IOException { - try { - root.createRequest().method("DELETE").withUrlPath(getApiTailUrl("")).send(); - } catch (FileNotFoundException x) { - throw (FileNotFoundException) new FileNotFoundException("Failed to delete " + getOwnerName() + "/" + name - + "; might not exist, or you might need the delete_repo scope in your token: http://stackoverflow.com/a/19327004/12916") - .initCause(x); - } - } - - /** - * Will archive and this repository as read-only. When a repository is archived, any operation that can change its - * state is forbidden. This applies symmetrically if trying to unarchive it. - * - *

- * When you try to do any operation that modifies a read-only repository, it returns the response: - * - *

-     * org.kohsuke.github.HttpException: {
-     *     "message":"Repository was archived so is read-only.",
-     *     "documentation_url":"https://developer.github.com/v3/repos/#edit"
-     * }
-     * 
- * - * @throws IOException - * In case of any networking error or error from the server. - */ - public void archive() throws IOException { - edit("archived", "true"); - // Generall would not update this record, - // but do so here since this will result in any other update actions failing - archived = true; - } - - /** - * Sort orders for listing forks - */ - public enum ForkSort { - NEWEST, OLDEST, STARGAZERS - } - - /** - * Lists all the direct forks of this repository, sorted by github api default, currently {@link ForkSort#NEWEST - * ForkSort.NEWEST}*. - * - * @return the paged iterable - */ - public PagedIterable listForks() { - return listForks(null); - } - - /** - * Lists all the direct forks of this repository, sorted by the given sort order. - * - * @param sort - * the sort order. If null, defaults to github api default, currently {@link ForkSort#NEWEST - * ForkSort.NEWEST}. - * @return the paged iterable - */ - public PagedIterable listForks(final ForkSort sort) { - return root.createRequest().with("sort", sort).withUrlPath(getApiTailUrl("forks")) - .toIterable(GHRepository[].class, item -> item.wrap(root)); - } - - /** - * Forks this repository as your repository. - * - * @return Newly forked repository that belong to you. - * @throws IOException - * the io exception - */ - public GHRepository fork() throws IOException { - root.createRequest().method("POST").withUrlPath(getApiTailUrl("forks")).send(); - - // this API is asynchronous. we need to wait for a bit - for (int i = 0; i < 10; i++) { - GHRepository r = root.getMyself().getRepository(name); - if (r != null) - return r; - try { - Thread.sleep(3000); - } catch (InterruptedException e) { - throw (IOException) new InterruptedIOException().initCause(e); - } - } - throw new IOException(this + " was forked but can't find the new repository"); - } - - /** - * Forks this repository into an organization. - * - * @param org - * the org - * @return Newly forked repository that belong to you. - * @throws IOException - * the io exception - */ - public GHRepository forkTo(GHOrganization org) throws IOException { - root.createRequest().method("POST").with("organization", org.getLogin()).withUrlPath(getApiTailUrl("forks")) - .send(); - - // this API is asynchronous. we need to wait for a bit - for (int i = 0; i < 10; i++) { - GHRepository r = org.getRepository(name); - if (r != null) - return r; - try { - Thread.sleep(3000); - } catch (InterruptedException e) { - throw (IOException) new InterruptedIOException().initCause(e); - } - } - throw new IOException(this + " was forked into " + org.getLogin() + " but can't find the new repository"); - } - - /** - * Retrieves a specified pull request. - * - * @param i - * the - * @return the pull request - * @throws IOException - * the io exception - */ - public GHPullRequest getPullRequest(int i) throws IOException { - return root.createRequest().withPreview(SHADOW_CAT).withUrlPath(getApiTailUrl("pulls/" + i)) - .fetch(GHPullRequest.class).wrapUp(this); - } - - /** - * Retrieves all the pull requests of a particular state. - * - * @param state - * the state - * @return the pull requests - * @throws IOException - * the io exception - * @see #listPullRequests(GHIssueState) #listPullRequests(GHIssueState) - */ - public List getPullRequests(GHIssueState state) throws IOException { - return queryPullRequests().state(state).list().asList(); - } - - /** - * Retrieves all the pull requests of a particular state. - * - * @param state - * the state - * @return the paged iterable - * @deprecated Use {@link #queryPullRequests()} - */ - public PagedIterable listPullRequests(GHIssueState state) { - return queryPullRequests().state(state).list(); - } - - /** - * Retrieves pull requests. - * - * @return the gh pull request query builder - */ - public GHPullRequestQueryBuilder queryPullRequests() { - return new GHPullRequestQueryBuilder(this); - } - - /** - * Creates a new pull request. - * - * @param title - * Required. The title of the pull request. - * @param head - * Required. The name of the branch where your changes are implemented. For cross-repository pull - * requests in the same network, namespace head with a user like this: username:branch. - * @param base - * Required. The name of the branch you want your changes pulled into. This should be an existing branch - * on the current repository. - * @param body - * The contents of the pull request. This is the markdown description of a pull request. - * @return the gh pull request - * @throws IOException - * the io exception - */ - public GHPullRequest createPullRequest(String title, String head, String base, String body) throws IOException { - return createPullRequest(title, head, base, body, true); - } - - /** - * Creates a new pull request. Maintainer's permissions aware. - * - * @param title - * Required. The title of the pull request. - * @param head - * Required. The name of the branch where your changes are implemented. For cross-repository pull - * requests in the same network, namespace head with a user like this: username:branch. - * @param base - * Required. The name of the branch you want your changes pulled into. This should be an existing branch - * on the current repository. - * @param body - * The contents of the pull request. This is the markdown description of a pull request. - * @param maintainerCanModify - * Indicates whether maintainers can modify the pull request. - * @return the gh pull request - * @throws IOException - * the io exception - */ - public GHPullRequest createPullRequest(String title, String head, String base, String body, - boolean maintainerCanModify) throws IOException { - return createPullRequest(title, head, base, body, maintainerCanModify, false); - } - - /** - * Creates a new pull request. Maintainer's permissions and draft aware. - * - * @param title - * Required. The title of the pull request. - * @param head - * Required. The name of the branch where your changes are implemented. For cross-repository pull - * requests in the same network, namespace head with a user like this: username:branch. - * @param base - * Required. The name of the branch you want your changes pulled into. This should be an existing branch - * on the current repository. - * @param body - * The contents of the pull request. This is the markdown description of a pull request. - * @param maintainerCanModify - * Indicates whether maintainers can modify the pull request. - * @param draft - * Indicates whether to create a draft pull request or not. - * @return the gh pull request - * @throws IOException - * the io exception - */ - public GHPullRequest createPullRequest(String title, String head, String base, String body, - boolean maintainerCanModify, boolean draft) throws IOException { - return root.createRequest().method("POST").withPreview(SHADOW_CAT).with("title", title).with("head", head) - .with("base", base).with("body", body).with("maintainer_can_modify", maintainerCanModify) - .with("draft", draft).withUrlPath(getApiTailUrl("pulls")).fetch(GHPullRequest.class).wrapUp(this); - } - - /** - * Retrieves the currently configured hooks. - * - * @return the hooks - * @throws IOException - * the io exception - */ - public List getHooks() throws IOException { - return GHHooks.repoContext(this, owner).getHooks(); - } - - /** - * Gets hook. - * - * @param id - * the id - * @return the hook - * @throws IOException - * the io exception - */ - public GHHook getHook(int id) throws IOException { - return GHHooks.repoContext(this, owner).getHook(id); - } - - /** - * Gets a comparison between 2 points in the repository. This would be similar to calling - * git log id1...id2 against a local repository. - * - * @param id1 - * an identifier for the first point to compare from, this can be a sha1 ID (for a commit, tag etc) or a - * direct tag name - * @param id2 - * an identifier for the second point to compare to. Can be the same as the first point. - * @return the comparison output - * @throws IOException - * on failure communicating with GitHub - */ - public GHCompare getCompare(String id1, String id2) throws IOException { - GHCompare compare = root.createRequest().withUrlPath(getApiTailUrl(String.format("compare/%s...%s", id1, id2))) - .fetch(GHCompare.class); - return compare.wrap(this); - } - - /** - * Gets compare. - * - * @param id1 - * the id 1 - * @param id2 - * the id 2 - * @return the compare - * @throws IOException - * the io exception - */ - public GHCompare getCompare(GHCommit id1, GHCommit id2) throws IOException { - return getCompare(id1.getSHA1(), id2.getSHA1()); - } - - /** - * Gets compare. - * - * @param id1 - * the id 1 - * @param id2 - * the id 2 - * @return the compare - * @throws IOException - * the io exception - */ - public GHCompare getCompare(GHBranch id1, GHBranch id2) throws IOException { - - GHRepository owner1 = id1.getOwner(); - GHRepository owner2 = id2.getOwner(); - - // If the owner of the branches is different, we have a cross-fork compare. - if (owner1 != null && owner2 != null) { - String ownerName1 = owner1.getOwnerName(); - String ownerName2 = owner2.getOwnerName(); - if (!StringUtils.equals(ownerName1, ownerName2)) { - String qualifiedName1 = String.format("%s:%s", ownerName1, id1.getName()); - String qualifiedName2 = String.format("%s:%s", ownerName2, id2.getName()); - return getCompare(qualifiedName1, qualifiedName2); - } - } - - return getCompare(id1.getName(), id2.getName()); - - } - - /** - * Retrieves all refs for the github repository. - * - * @return an array of GHRef elements coresponding with the refs in the remote repository. - * @throws IOException - * on failure communicating with GitHub - */ - public GHRef[] getRefs() throws IOException { - return GHRef.wrap(root.createRequest().withUrlPath(String.format("/repos/%s/%s/git/refs", getOwnerName(), name)) - .fetchArray(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 listRefs() throws IOException { - final String url = String.format("/repos/%s/%s/git/refs", getOwnerName(), name); - return root.createRequest().withUrlPath(url).toIterable(GHRef[].class, item -> item.wrap(root)); - } - - /** - * Retrieves all refs of the given type for the current GitHub repository. - * - * @param refType - * the type of reg to search for e.g. tags or commits - * @return an array of all refs matching the request type - * @throws IOException - * on failure communicating with GitHub, potentially due to an invalid ref type being requested - */ - public GHRef[] getRefs(String refType) throws IOException { - return GHRef.wrap(root.createRequest() - .withUrlPath(String.format("/repos/%s/%s/git/refs/%s", getOwnerName(), name, refType)) - .fetchArray(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. tags or commits - * @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 listRefs(String refType) throws IOException { - final String url = String.format("/repos/%s/%s/git/refs/%s", getOwnerName(), name, refType); - return root.createRequest().withUrlPath(url).toIterable(GHRef[].class, item -> item.wrap(root)); - } - - /** - * Retrive a ref of the given type for the current GitHub repository. - * - * @param refName - * eg: heads/branch - * @return refs matching the request type - * @throws IOException - * on failure communicating with GitHub, potentially due to an invalid ref type being requested - */ - public GHRef getRef(String refName) throws IOException { - return root.createRequest().withUrlPath(getApiTailUrl(String.format("git/refs/%s", refName))).fetch(GHRef.class) - .wrap(root); - } - - /** - * Returns the annotated 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 - * @throws IOException - * the io exception - */ - public GHTagObject getTagObject(String sha) throws IOException { - return root.createRequest().withUrlPath(getApiTailUrl("git/tags/" + sha)).fetch(GHTagObject.class).wrap(this); - } - - /** - * Retrive a tree of the given type for the current GitHub repository. - * - * @param sha - * sha number or branch name ex: "master" - * @return refs matching the request type - * @throws IOException - * on failure communicating with GitHub, potentially due to an invalid tree type being requested - */ - public GHTree getTree(String sha) throws IOException { - String url = String.format("/repos/%s/%s/git/trees/%s", getOwnerName(), name, sha); - return root.createRequest().withUrlPath(url).fetch(GHTree.class).wrap(this); - } - - /** - * Create tree gh tree builder. - * - * @return the gh tree builder - */ - public GHTreeBuilder createTree() { - return new GHTreeBuilder(this); - } - - /** - * Retrieves the tree for the current GitHub repository, recursively as described in here: - * https://developer.github.com/v3/git/trees/#get-a-tree-recursively - * - * @param sha - * sha number or branch name ex: "master" - * @param recursive - * use 1 - * @return the tree recursive - * @throws IOException - * on failure communicating with GitHub, potentially due to an invalid tree type being requested - */ - public GHTree getTreeRecursive(String sha, int recursive) throws IOException { - String url = String.format("/repos/%s/%s/git/trees/%s", getOwnerName(), name, sha); - return root.createRequest().with("recursive", recursive).withUrlPath(url).fetch(GHTree.class).wrap(this); - } - - /** - * Obtains the metadata & the content of a blob. - * - *

- * This method retrieves the whole content in memory, so beware when you are dealing with large BLOB. - * - * @param blobSha - * the blob sha - * @return the blob - * @throws IOException - * the io exception - * @see Get a blob - * @see #readBlob(String) #readBlob(String) - */ - public GHBlob getBlob(String blobSha) throws IOException { - String target = getApiTailUrl("git/blobs/" + blobSha); - return root.createRequest().withUrlPath(target).fetch(GHBlob.class); - } - - /** - * Create blob gh blob builder. - * - * @return the gh blob builder - */ - public GHBlobBuilder createBlob() { - return new GHBlobBuilder(this); - } - - /** - * Reads the content of a blob as a stream for better efficiency. - * - * @param blobSha - * the blob sha - * @return the input stream - * @throws IOException - * the io exception - * @see Get a blob - * @see #getBlob(String) #getBlob(String) - */ - public InputStream readBlob(String blobSha) throws IOException { - String target = getApiTailUrl("git/blobs/" + blobSha); - - // https://developer.github.com/v3/media/ describes this media type - return root.createRequest().withHeader("Accept", "application/vnd.github.v3.raw").withUrlPath(target) - .fetchStream(); - } - - /** - * Gets a commit object in this repository. - * - * @param sha1 - * the sha 1 - * @return the commit - * @throws IOException - * the io exception - */ - public GHCommit getCommit(String sha1) throws IOException { - GHCommit c = commits.get(sha1); - if (c == null) { - c = root.createRequest().withUrlPath(String.format("/repos/%s/%s/commits/%s", getOwnerName(), name, sha1)) - .fetch(GHCommit.class).wrapUp(this); - commits.put(sha1, c); - } - return c; - } - - /** - * Create commit gh commit builder. - * - * @return the gh commit builder - */ - public GHCommitBuilder createCommit() { - return new GHCommitBuilder(this); - } - - /** - * Lists all the commits. - * - * @return the paged iterable - */ - public PagedIterable listCommits() { - return root.createRequest().withUrlPath(String.format("/repos/%s/%s/commits", getOwnerName(), name)) - .toIterable(GHCommit[].class, item -> item.wrapUp(this)); - } - - /** - * Search commits by specifying filters through a builder pattern. - * - * @return the gh commit query builder - */ - public GHCommitQueryBuilder queryCommits() { - return new GHCommitQueryBuilder(this); - } - - /** - * Lists up all the commit comments in this repository. - * - * @return the paged iterable - */ - public PagedIterable listCommitComments() { - return root.createRequest().withUrlPath(String.format("/repos/%s/%s/comments", getOwnerName(), name)) - .toIterable(GHCommitComment[].class, item -> item.wrap(this)); - } - - /** - * Gets the basic license details for the repository. - *

- * - * @return null if there's no license. - * @throws IOException - * as usual but also if you don't use the preview connector - */ - public GHLicense getLicense() throws IOException { - GHContentWithLicense lic = getLicenseContent_(); - return lic != null ? lic.license : null; - } - - /** - * Retrieves the contents of the repository's license file - makes an additional API call - *

- * - * @return details regarding the license contents, or null if there's no license. - * @throws IOException - * as usual but also if you don't use the preview connector - */ - public GHContent getLicenseContent() throws IOException { - return getLicenseContent_(); - } - - private GHContentWithLicense getLicenseContent_() throws IOException { - try { - return root.createRequest().withUrlPath(getApiTailUrl("license")).fetch(GHContentWithLicense.class) - .wrap(this); - } catch (FileNotFoundException e) { - return null; - } - } - - /** - * /** Lists all the commit statues attached to the given commit, newer ones first. - * - * @param sha1 - * the sha 1 - * @return the paged iterable - * @throws IOException - * the io exception - */ - public PagedIterable listCommitStatuses(final String sha1) throws IOException { - return root.createRequest().withUrlPath(String.format("/repos/%s/%s/statuses/%s", getOwnerName(), name, sha1)) - .toIterable(GHCommitStatus[].class, item -> item.wrapUp(root)); - } - - /** - * Gets the last status of this commit, which is what gets shown in the UI. - * - * @param sha1 - * the sha 1 - * @return the last commit status - * @throws IOException - * the io exception - */ - public GHCommitStatus getLastCommitStatus(String sha1) throws IOException { - List v = listCommitStatuses(sha1).asList(); - return v.isEmpty() ? null : v.get(0); - } - - /** - * Creates a commit status - * - * @param sha1 - * the sha 1 - * @param state - * the state - * @param targetUrl - * Optional parameter that points to the URL that has more details. - * @param description - * Optional short description. - * @param context - * Optinal commit status context. - * @return the gh commit status - * @throws IOException - * the io exception - */ - public GHCommitStatus createCommitStatus(String sha1, GHCommitState state, String targetUrl, String description, - String context) throws IOException { - return root.createRequest().method("POST").with("state", state).with("target_url", targetUrl) - .with("description", description).with("context", context) - .withUrlPath(String.format("/repos/%s/%s/statuses/%s", getOwnerName(), this.name, sha1)) - .fetch(GHCommitStatus.class).wrapUp(root); - } - - /** - * Create commit status gh commit status. - * - * @param sha1 - * the sha 1 - * @param state - * the state - * @param targetUrl - * the target url - * @param description - * the description - * @return the gh commit status - * @throws IOException - * the io exception - * @see #createCommitStatus(String, GHCommitState, String, String, String) #createCommitStatus(String, - * GHCommitState,String,String,String) - */ - public GHCommitStatus createCommitStatus(String sha1, GHCommitState state, String targetUrl, String description) - throws IOException { - return createCommitStatus(sha1, state, targetUrl, description, null); - } - - /** - * Lists repository events. - * - * @return the paged iterable - * @throws IOException - * the io exception - */ - public PagedIterable listEvents() throws IOException { - return root.createRequest().withUrlPath(String.format("/repos/%s/%s/events", getOwnerName(), name)) - .toIterable(GHEventInfo[].class, item -> item.wrapUp(root)); - } - - /** - * Lists labels in this repository. - *

- * https://developer.github.com/v3/issues/labels/#list-all-labels-for-this-repository - * - * @return the paged iterable - * @throws IOException - * the io exception - */ - public PagedIterable listLabels() throws IOException { - return root.createRequest().withUrlPath(getApiTailUrl("labels")).toIterable(GHLabel[].class, - item -> item.wrapUp(this)); - } - - /** - * Gets label. - * - * @param name - * the name - * @return the label - * @throws IOException - * the io exception - */ - public GHLabel getLabel(String name) throws IOException { - return root.createRequest().withUrlPath(getApiTailUrl("labels/" + name)).fetch(GHLabel.class).wrapUp(this); - } - - /** - * Create label gh label. - * - * @param name - * the name - * @param color - * the color - * @return the gh label - * @throws IOException - * the io exception - */ - public GHLabel createLabel(String name, String color) throws IOException { - return createLabel(name, color, ""); - } - - /** - * Description is still in preview. - * - * @param name - * the name - * @param color - * the color - * @param description - * the description - * @return gh label - * @throws IOException - * the io exception - */ - public GHLabel createLabel(String name, String color, String description) throws IOException { - return root.createRequest().method("POST").with("name", name).with("color", color) - .with("description", description).withUrlPath(getApiTailUrl("labels")).fetch(GHLabel.class) - .wrapUp(this); - } - - /** - * Lists all the invitations. - * - * @return the paged iterable - */ - public PagedIterable listInvitations() { - return root.createRequest().withUrlPath(String.format("/repos/%s/%s/invitations", getOwnerName(), name)) - .toIterable(GHInvitation[].class, item -> item.wrapUp(root)); - } - - /** - * Lists all the subscribers (aka watchers.) - *

- * https://developer.github.com/v3/activity/watching/ - * - * @return the paged iterable - */ - public PagedIterable listSubscribers() { - return listUsers("subscribers"); - } - - /** - * Lists all the users who have starred this repo based on the old version of the API. For additional information, - * like date when the repository was starred, see {@link #listStargazers2()} - * - * @return the paged iterable - */ - public PagedIterable listStargazers() { - return listUsers("stargazers"); - } - - /** - * Lists all the users who have starred this repo based on new version of the API, having extended information like - * the time when the repository was starred. For compatibility with the old API see {@link #listStargazers()} - * - * @return the paged iterable - */ - public PagedIterable listStargazers2() { - return root.createRequest().withPreview("application/vnd.github.v3.star+json") - .withUrlPath(getApiTailUrl("stargazers")).toIterable(GHStargazer[].class, item -> item.wrapUp(this)); - } - - private PagedIterable listUsers(final String suffix) { - return root.createRequest().withUrlPath(getApiTailUrl(suffix)).toIterable(GHUser[].class, - item -> item.wrapUp(root)); - } - - /** - * See https://api.github.com/hooks for possible names and their configuration scheme. TODO: produce type-safe - * binding - * - * @param name - * Type of the hook to be created. See https://api.github.com/hooks for possible names. - * @param config - * The configuration hash. - * @param events - * Can be null. Types of events to hook into. - * @param active - * the active - * @return the gh hook - * @throws IOException - * the io exception - */ - public GHHook createHook(String name, Map config, Collection events, boolean active) - throws IOException { - return GHHooks.repoContext(this, owner).createHook(name, config, events, active); - } - - /** - * Create web hook gh hook. - * - * @param url - * the url - * @param events - * the events - * @return the gh hook - * @throws IOException - * the io exception - */ - public GHHook createWebHook(URL url, Collection events) throws IOException { - return createHook("web", Collections.singletonMap("url", url.toExternalForm()), events, true); - } - - /** - * Create web hook gh hook. - * - * @param url - * the url - * @return the gh hook - * @throws IOException - * the io exception - */ - public GHHook createWebHook(URL url) throws IOException { - return createWebHook(url, null); - } - - // this is no different from getPullRequests(OPEN) - // /** - // * Retrieves all the pull requests. - // */ - // public List getPullRequests() throws IOException { - // return - // root.retrieveWithAuth("/pulls/"+owner+'/'+name,JsonPullRequests.class).wrap(root); - // } - - /** - * Returns a set that represents the post-commit hook URLs. The returned set is live, and changes made to them are - * reflected to GitHub. - * - * @return the post commit hooks - * @deprecated Use {@link #getHooks()} and {@link #createHook(String, Map, Collection, boolean)} - */ - @SuppressFBWarnings(value = "DMI_COLLECTION_OF_URLS", justification = "It causes a performance degradation, but we have already exposed it to the API") - public Set getPostCommitHooks() { - return postCommitHooks; - } - - /** - * Live set view of the post-commit hook. - */ - @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 postCommitHooks = new AbstractSet() { - private List getPostCommitHooks() { - try { - List r = new ArrayList(); - for (GHHook h : getHooks()) { - if (h.getName().equals("web")) { - r.add(new URL(h.getConfig().get("url"))); - } - } - return r; - } catch (IOException e) { - throw new GHException("Failed to retrieve post-commit hooks", e); - } - } - - @Override - public Iterator iterator() { - return getPostCommitHooks().iterator(); - } - - @Override - public int size() { - return getPostCommitHooks().size(); - } - - @Override - public boolean add(URL url) { - try { - createWebHook(url); - return true; - } catch (IOException e) { - throw new GHException("Failed to update post-commit hooks", e); - } - } - - @Override - public boolean remove(Object url) { - try { - String _url = ((URL) url).toExternalForm(); - for (GHHook h : getHooks()) { - if (h.getName().equals("web") && h.getConfig().get("url").equals(_url)) { - h.delete(); - return true; - } - } - return false; - } catch (IOException e) { - throw new GHException("Failed to update post-commit hooks", e); - } - } - }; - - GHRepository wrap(GitHub root) { - this.root = root; - if (root.isOffline()) { - owner.wrapUp(root); - } - return this; - } - - /** - * Gets branches by {@linkplain GHBranch#getName() their names}. - * - * @return the branches - * @throws IOException - * the io exception - */ - public Map getBranches() throws IOException { - Map r = new TreeMap(); - for (GHBranch p : root.createRequest().withUrlPath(getApiTailUrl("branches")).fetchArray(GHBranch[].class)) { - p.wrap(this); - r.put(p.getName(), p); - } - return r; - } - - /** - * Gets branch. - * - * @param name - * the name - * @return the branch - * @throws IOException - * the io exception - */ - public GHBranch getBranch(String name) throws IOException { - return root.createRequest().withUrlPath(getApiTailUrl("branches/" + name)).fetch(GHBranch.class).wrap(this); - } - - /** - * Gets milestones. - * - * @return the milestones - * @throws IOException - * the io exception - * @deprecated Use {@link #listMilestones(GHIssueState)} - */ - public Map getMilestones() throws IOException { - Map milestones = new TreeMap(); - for (GHMilestone m : listMilestones(GHIssueState.OPEN)) { - milestones.put(m.getNumber(), m); - } - return milestones; - } - - /** - * Lists up all the milestones in this repository. - * - * @param state - * the state - * @return the paged iterable - */ - public PagedIterable listMilestones(final GHIssueState state) { - return root.createRequest().with("state", state).withUrlPath(getApiTailUrl("milestones")) - .toIterable(GHMilestone[].class, item -> item.wrap(this)); - } - - /** - * Gets milestone. - * - * @param number - * the number - * @return the milestone - * @throws IOException - * the io exception - */ - public GHMilestone getMilestone(int number) throws IOException { - GHMilestone m = milestones.get(number); - if (m == null) { - m = root.createRequest().withUrlPath(getApiTailUrl("milestones/" + number)).fetch(GHMilestone.class); - m.owner = this; - m.root = root; - milestones.put(m.getNumber(), m); - } - return m; - } - - /** - * Gets file content. - * - * @param path - * the path - * @return the file content - * @throws IOException - * the io exception - */ - public GHContent getFileContent(String path) throws IOException { - return getFileContent(path, null); - } - - /** - * Gets file content. - * - * @param path - * the path - * @param ref - * the ref - * @return the file content - * @throws IOException - * the io exception - */ - public GHContent getFileContent(String path, String ref) throws IOException { - Requester requester = root.createRequest(); - String target = getApiTailUrl("contents/" + path); - - return requester.with("ref", ref).withUrlPath(target).fetch(GHContent.class).wrap(this); - } - - /** - * Gets directory content. - * - * @param path - * the path - * @return the directory content - * @throws IOException - * the io exception - */ - public List getDirectoryContent(String path) throws IOException { - return getDirectoryContent(path, null); - } - - /** - * Gets directory content. - * - * @param path - * the path - * @param ref - * the ref - * @return the directory content - * @throws IOException - * the io exception - */ - public List getDirectoryContent(String path, String ref) throws IOException { - Requester requester = root.createRequest(); - while (path.endsWith("/")) { - path = path.substring(0, path.length() - 1); - } - String target = getApiTailUrl("contents/" + path); - - GHContent[] files = requester.with("ref", ref).withUrlPath(target).fetchArray(GHContent[].class); - - GHContent.wrap(files, this); - - return Arrays.asList(files); - } - - /** - * https://developer.github.com/v3/repos/contents/#get-the-readme - * - * @return the readme - * @throws IOException - * the io exception - */ - public GHContent getReadme() throws IOException { - Requester requester = root.createRequest(); - return requester.withUrlPath(getApiTailUrl("readme")).fetch(GHContent.class).wrap(this); - } - - /** - * Creates a new content, or update an existing content. - * - * @return the gh content builder - */ - public GHContentBuilder createContent() { - return new GHContentBuilder(this); - } - - /** - * Use {@link #createContent()}. - * - * @param content - * the content - * @param commitMessage - * the commit message - * @param path - * the path - * @return the gh content update response - * @throws IOException - * the io exception - */ - @Deprecated - public GHContentUpdateResponse createContent(String content, String commitMessage, String path) throws IOException { - return createContent().content(content).message(commitMessage).path(path).commit(); - } - - /** - * Use {@link #createContent()}. - * - * @param content - * the content - * @param commitMessage - * the commit message - * @param path - * the path - * @param branch - * the branch - * @return the gh content update response - * @throws IOException - * the io exception - */ - @Deprecated - public GHContentUpdateResponse createContent(String content, String commitMessage, String path, String branch) - throws IOException { - return createContent().content(content).message(commitMessage).path(path).branch(branch).commit(); - } - - /** - * Use {@link #createContent()}. - * - * @param contentBytes - * the content bytes - * @param commitMessage - * the commit message - * @param path - * the path - * @return the gh content update response - * @throws IOException - * the io exception - */ - @Deprecated - public GHContentUpdateResponse createContent(byte[] contentBytes, String commitMessage, String path) - throws IOException { - return createContent().content(contentBytes).message(commitMessage).path(path).commit(); - } - - /** - * Use {@link #createContent()}. - * - * @param contentBytes - * the content bytes - * @param commitMessage - * the commit message - * @param path - * the path - * @param branch - * the branch - * @return the gh content update response - * @throws IOException - * the io exception - */ - @Deprecated - public GHContentUpdateResponse createContent(byte[] contentBytes, String commitMessage, String path, String branch) - throws IOException { - return createContent().content(contentBytes).message(commitMessage).path(path).branch(branch).commit(); - } - - /** - * Create milestone gh milestone. - * - * @param title - * the title - * @param description - * the description - * @return the gh milestone - * @throws IOException - * the io exception - */ - public GHMilestone createMilestone(String title, String description) throws IOException { - return root.createRequest().method("POST").with("title", title).with("description", description) - .withUrlPath(getApiTailUrl("milestones")).fetch(GHMilestone.class).wrap(this); - } - - /** - * Add deploy key gh deploy key. - * - * @param title - * the title - * @param key - * the key - * @return the gh deploy key - * @throws IOException - * the io exception - */ - public GHDeployKey addDeployKey(String title, String key) throws IOException { - return root.createRequest().method("POST").with("title", title).with("key", key) - .withUrlPath(getApiTailUrl("keys")).fetch(GHDeployKey.class).wrap(this); - - } - - /** - * Gets deploy keys. - * - * @return the deploy keys - * @throws IOException - * the io exception - */ - public List getDeployKeys() throws IOException { - List list = new ArrayList( - Arrays.asList(root.createRequest().withUrlPath(getApiTailUrl("keys")).fetchArray(GHDeployKey[].class))); - for (GHDeployKey h : list) - h.wrap(this); - return list; - } - - /** - * Forked repositories have a 'source' attribute that specifies the ultimate source of the forking chain. - * - * @return {@link GHRepository} that points to the root repository where this repository is forked (indirectly or - * directly) from. Otherwise null. - * @throws IOException - * the io exception - * @see #getParent() #getParent() - */ - public GHRepository getSource() throws IOException { - if (source == null) - return null; - if (source.root == null) - source = root.getRepository(source.getFullName()); - return source; - } - - /** - * Forked repositories have a 'parent' attribute that specifies the repository this repository is directly forked - * from. If we keep traversing {@link #getParent()} until it returns null, that is {@link #getSource()}. - * - * @return {@link GHRepository} that points to the repository where this repository is forked directly from. - * Otherwise null. - * @throws IOException - * the io exception - * @see #getSource() #getSource() - */ - public GHRepository getParent() throws IOException { - if (parent == null) - return null; - if (parent.root == null) - parent = root.getRepository(parent.getFullName()); - return parent; - } - - /** - * Subscribes to this repository to get notifications. - * - * @param subscribed - * the subscribed - * @param ignored - * the ignored - * @return the gh subscription - * @throws IOException - * the io exception - */ - public GHSubscription subscribe(boolean subscribed, boolean ignored) throws IOException { - return root.createRequest().method("PUT").with("subscribed", subscribed).with("ignored", ignored) - .withUrlPath(getApiTailUrl("subscription")).fetch(GHSubscription.class).wrapUp(this); - } - - /** - * Returns the current subscription. - * - * @return null if no subscription exists. - * @throws IOException - * the io exception - */ - public GHSubscription getSubscription() throws IOException { - try { - return root.createRequest().withUrlPath(getApiTailUrl("subscription")).fetch(GHSubscription.class) - .wrapUp(this); - } catch (FileNotFoundException e) { - return null; - } - } - - /** - * List contributors paged iterable. - * - * @return the paged iterable - * @throws IOException - * the io exception - */ - public PagedIterable listContributors() throws IOException { - return root.createRequest().withUrlPath(getApiTailUrl("contributors")).toIterable(Contributor[].class, - item -> item.wrapUp(root)); - } - - /** - * The type Contributor. - */ - public static class Contributor extends GHUser { - private int contributions; - - /** - * Gets contributions. - * - * @return the contributions - */ - public int getContributions() { - return contributions; - } - - @Override - public int hashCode() { - // We ignore contributions in the calculation - return super.hashCode(); - } - - @Override - public boolean equals(Object obj) { - // We ignore contributions in the calculation - return super.equals(obj); - } - } - - /** - * Returns the statistics for this repository. - * - * @return the statistics - */ - public GHRepositoryStatistics getStatistics() { - // TODO: Use static object and introduce refresh() method, - // instead of returning new object each time. - return new GHRepositoryStatistics(this); - } - - /** - * Create a project for this repository. - * - * @param name - * the name - * @param body - * the body - * @return the gh project - * @throws IOException - * the io exception - */ - public GHProject createProject(String name, String body) throws IOException { - return root.createRequest().method("POST").withPreview(INERTIA).with("name", name).with("body", body) - .withUrlPath(getApiTailUrl("projects")).fetch(GHProject.class).wrap(this); - } - - /** - * Returns the projects for this repository. - * - * @param status - * The status filter (all, open or closed). - * @return the paged iterable - * @throws IOException - * the io exception - */ - public PagedIterable listProjects(final GHProject.ProjectStateFilter status) throws IOException { - return root.createRequest().withPreview(INERTIA).with("state", status).withUrlPath(getApiTailUrl("projects")) - .toIterable(GHProject[].class, item -> item.wrap(this)); - } - - /** - * Returns open projects for this repository. - * - * @return the paged iterable - * @throws IOException - * the io exception - */ - public PagedIterable listProjects() throws IOException { - return listProjects(GHProject.ProjectStateFilter.OPEN); - } - - /** - * Render a Markdown document. - *

- * In {@linkplain MarkdownMode#GFM GFM mode}, issue numbers and user mentions are linked accordingly. - * - * @param text - * the text - * @param mode - * the mode - * @return the reader - * @throws IOException - * the io exception - * @see GitHub#renderMarkdown(String) GitHub#renderMarkdown(String) - */ - public Reader renderMarkdown(String text, MarkdownMode mode) throws IOException { - return new InputStreamReader(root.createRequest().method("POST").with("text", text) - .with("mode", mode == null ? null : mode.toString()).with("context", getFullName()) - .withUrlPath("/markdown").fetchStream(), "UTF-8"); - } - - /** - * List all the notifications in a repository for the current user. - * - * @return the gh notification stream - */ - public GHNotificationStream listNotifications() { - return new GHNotificationStream(root, getApiTailUrl("/notifications")); - } - - /** - * https://developer.github.com/v3/repos/traffic/#views - * - * @return the view traffic - * @throws IOException - * the io exception - */ - public GHRepositoryViewTraffic getViewTraffic() throws IOException { - return root.createRequest().withUrlPath(getApiTailUrl("/traffic/views")).fetch(GHRepositoryViewTraffic.class); - } - - /** - * https://developer.github.com/v3/repos/traffic/#clones - * - * @return the clone traffic - * @throws IOException - * the io exception - */ - public GHRepositoryCloneTraffic getCloneTraffic() throws IOException { - return root.createRequest().withUrlPath(getApiTailUrl("/traffic/clones")).fetch(GHRepositoryCloneTraffic.class); - } - - @Override - public int hashCode() { - return ("Repository:" + getOwnerName() + ":" + name).hashCode(); - } - - @Override - public boolean equals(Object obj) { - if (obj instanceof GHRepository) { - GHRepository that = (GHRepository) obj; - return this.getOwnerName().equals(that.getOwnerName()) && this.name.equals(that.name); - } - return false; - } - - String getApiTailUrl(String tail) { - if (tail.length() > 0 && !tail.startsWith("/")) - tail = '/' + tail; - return "/repos/" + getOwnerName() + "/" + name + tail; - } - - /** - * Get all issue events for this repository. See - * https://developer.github.com/v3/issues/events/#list-events-for-a-repository - * - * @return the paged iterable - * @throws IOException - * the io exception - */ - public PagedIterable listIssueEvents() throws IOException { - return root.createRequest().withUrlPath(getApiTailUrl("issues/events")).toIterable(GHIssueEvent[].class, - item -> item.wrapUp(root)); - } - - /** - * Get a single issue event. See https://developer.github.com/v3/issues/events/#get-a-single-event - * - * @param id - * the id - * @return the issue event - * @throws IOException - * the io exception - */ - public GHIssueEvent getIssueEvent(long id) throws IOException { - return root.createRequest().withUrlPath(getApiTailUrl("issues/events/" + id)).fetch(GHIssueEvent.class) - .wrapUp(root); - } - - // Only used within listTopics(). - private static class Topics { - public List names; - } - - /** - * Return the topics for this repository. See - * https://developer.github.com/v3/repos/#list-all-topics-for-a-repository - * - * @return the list - * @throws IOException - * the io exception - */ - public List listTopics() throws IOException { - Topics topics = root.createRequest().withPreview(MERCY).withUrlPath(getApiTailUrl("topics")) - .fetch(Topics.class); - return topics.names; - } - - /** - * Set the topics for this repository. See - * https://developer.github.com/v3/repos/#replace-all-topics-for-a-repository - * - * @param topics - * the topics - * @throws IOException - * the io exception - */ - public void setTopics(List topics) throws IOException { - root.createRequest().method("PUT").with("names", topics).withPreview(MERCY).withUrlPath(getApiTailUrl("topics")) - .send(); - } - - /** - * Create a tag. See https://developer.github.com/v3/git/tags/#create-a-tag-object - * - * @param tag - * The tag's name. - * @param message - * The tag message. - * @param object - * The SHA of the git object this is tagging. - * @param type - * The type of the object we're tagging: "commit", "tree" or "blob". - * @return The newly created tag. - * @throws java.io.IOException - * The IO exception. - */ - public GHTagObject createTag(String tag, String message, String object, String type) throws IOException { - return root.createRequest().method("POST").with("tag", tag).with("message", message).with("object", object) - .with("type", type).withUrlPath(getApiTailUrl("git/tags")).fetch(GHTagObject.class).wrap(this); - } -} +/* + * The MIT License + * + * Copyright (c) 2010, Kohsuke Kawaguchi + * + * 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 com.fasterxml.jackson.annotation.JsonProperty; +import com.infradna.tool.bridge_method_injector.WithBridgeMethods; +import edu.umd.cs.findbugs.annotations.SuppressFBWarnings; +import org.apache.commons.lang3.StringUtils; + +import java.io.FileNotFoundException; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.io.InterruptedIOException; +import java.io.Reader; +import java.net.URL; +import java.util.AbstractSet; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; +import java.util.Collections; +import java.util.Date; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.TreeMap; +import java.util.WeakHashMap; + +import static java.util.Arrays.*; +import static org.kohsuke.github.Previews.*; + +/** + * A repository on GitHub. + * + * @author Kohsuke Kawaguchi + */ +@SuppressWarnings({ "UnusedDeclaration" }) +@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; + + private String description, homepage, name, full_name; + private String html_url; // this is the UI + /* + * The license information makes use of the preview API. + * + * See: https://developer.github.com/v3/licenses/ + */ + private GHLicense license; + + private String git_url, ssh_url, clone_url, svn_url, mirror_url; + private GHUser owner; // not fully populated. beware. + private boolean has_issues, has_wiki, fork, has_downloads, has_pages, archived; + + private boolean allow_squash_merge; + private boolean allow_merge_commit; + private boolean allow_rebase_merge; + + @JsonProperty("private") + private boolean _private; + private int forks_count, stargazers_count, watchers_count, size, open_issues_count, subscribers_count; + private String pushed_at; + private Map milestones = new WeakHashMap(); + + private String default_branch, language; + private Map commits = new WeakHashMap(); + + @SkipFromToString + private GHRepoPermission permissions; + + private GHRepository source, parent; + + /** + * Create deployment gh deployment builder. + * + * @param ref + * the ref + * @return the gh deployment builder + */ + public GHDeploymentBuilder createDeployment(String ref) { + return new GHDeploymentBuilder(this, ref); + } + + /** + * Gets deployment statuses. + * + * @param id + * the id + * @return the deployment statuses + * @throws IOException + * the io exception + * @deprecated Use {@code getDeployment(id).listStatuses()} + */ + public PagedIterable getDeploymentStatuses(final int id) throws IOException { + return getDeployment(id).listStatuses(); + } + + /** + * List deployments paged iterable. + * + * @param sha + * the sha + * @param ref + * the ref + * @param task + * the task + * @param environment + * the environment + * @return the paged iterable + */ + public PagedIterable listDeployments(String sha, String ref, String task, String environment) { + return root.createRequest().with("sha", sha).with("ref", ref).with("task", task) + .with("environment", environment).withUrlPath(getApiTailUrl("deployments")) + .toIterable(GHDeployment[].class, item -> item.wrap(this)); + } + + /** + * Obtains a single {@link GHDeployment} by its ID. + * + * @param id + * the id + * @return the deployment + * @throws IOException + * the io exception + */ + public GHDeployment getDeployment(long id) throws IOException { + return root.createRequest().withUrlPath(getApiTailUrl("deployments/" + id)).fetch(GHDeployment.class) + .wrap(this); + } + + /** + * Gets deploy status. + * + * @param deploymentId + * the deployment id + * @param ghDeploymentState + * the gh deployment state + * @return the deploy status + * @throws IOException + * the io exception + * @deprecated Use {@code getDeployment(deploymentId).createStatus(ghDeploymentState)} + */ + public GHDeploymentStatusBuilder createDeployStatus(int deploymentId, GHDeploymentState ghDeploymentState) + throws IOException { + return getDeployment(deploymentId).createStatus(ghDeploymentState); + } + + private static class GHRepoPermission { + boolean pull, push, admin; + } + + /** + * Gets description. + * + * @return the description + */ + public String getDescription() { + return description; + } + + /** + * Gets homepage. + * + * @return the homepage + */ + public String getHomepage() { + return homepage; + } + + /** + * Gets the git:// URL to this repository, such as "git://github.com/kohsuke/jenkins.git" This URL is read-only. + * + * @return the git transport url + */ + public String getGitTransportUrl() { + return git_url; + } + + /** + * Gets the HTTPS URL to this repository, such as "https://github.com/kohsuke/jenkins.git" This URL is read-only. + * + * @return the http transport url + */ + public String getHttpTransportUrl() { + return clone_url; + } + + /** + * Git http transport url string. + * + * @return the string + * @deprecated Typo of {@link #getHttpTransportUrl()} + */ + public String gitHttpTransportUrl() { + return clone_url; + } + + /** + * Gets the Subversion URL to access this repository: https://github.com/rails/rails + * + * @return the svn url + */ + public String getSvnUrl() { + return svn_url; + } + + /** + * Gets the Mirror URL to access this repository: https://github.com/apache/tomee mirrored from + * git://git.apache.org/tomee.git + * + * @return the mirror url + */ + public String getMirrorUrl() { + return mirror_url; + } + + /** + * Gets the SSH URL to access this repository, such as git@github.com:rails/rails.git + * + * @return the ssh url + */ + public String getSshUrl() { + return ssh_url; + } + + public URL getHtmlUrl() { + return GitHub.parseURL(html_url); + } + + /** + * Short repository name without the owner. For example 'jenkins' in case of http://github.com/jenkinsci/jenkins + * + * @return the name + */ + public String getName() { + return name; + } + + /** + * Full repository name including the owner or organization. For example 'jenkinsci/jenkins' in case of + * http://github.com/jenkinsci/jenkins + * + * @return the full name + */ + public String getFullName() { + return full_name; + } + + /** + * Has pull access boolean. + * + * @return the boolean + */ + public boolean hasPullAccess() { + return permissions != null && permissions.pull; + } + + /** + * Has push access boolean. + * + * @return the boolean + */ + public boolean hasPushAccess() { + return permissions != null && permissions.push; + } + + /** + * Has admin access boolean. + * + * @return the boolean + */ + public boolean hasAdminAccess() { + return permissions != null && permissions.admin; + } + + /** + * Gets the primary programming language. + * + * @return the language + */ + public String getLanguage() { + return language; + } + + /** + * Gets owner. + * + * @return the owner + * @throws IOException + * the io exception + */ + public GHUser getOwner() throws IOException { + return root.isOffline() ? owner : root.getUser(getOwnerName()); // because 'owner' isn't fully populated + } + + /** + * Gets issue. + * + * @param id + * the id + * @return the issue + * @throws IOException + * the io exception + */ + public GHIssue getIssue(int id) throws IOException { + return root.createRequest().withUrlPath(getApiTailUrl("issues/" + id)).fetch(GHIssue.class).wrap(this); + } + + /** + * Create issue gh issue builder. + * + * @param title + * the title + * @return the gh issue builder + */ + public GHIssueBuilder createIssue(String title) { + return new GHIssueBuilder(this, title); + } + + /** + * Gets issues. + * + * @param state + * the state + * @return the issues + * @throws IOException + * the io exception + */ + public List getIssues(GHIssueState state) throws IOException { + return listIssues(state).asList(); + } + + /** + * Gets issues. + * + * @param state + * the state + * @param milestone + * the milestone + * @return the issues + * @throws IOException + * the io exception + */ + public List getIssues(GHIssueState state, GHMilestone milestone) throws IOException { + Requester requester = root.createRequest().with("state", state).with("milestone", + milestone == null ? "none" : "" + milestone.getNumber()); + return Arrays + .asList(GHIssue.wrap(requester.withUrlPath(getApiTailUrl("issues")).fetchArray(GHIssue[].class), this)); + } + + /** + * Lists up all the issues in this repository. + * + * @param state + * the state + * @return the paged iterable + */ + public PagedIterable listIssues(final GHIssueState state) { + return root.createRequest().with("state", state).withUrlPath(getApiTailUrl("issues")) + .toIterable(GHIssue[].class, item -> item.wrap(this)); + } + + /** + * Create release gh release builder. + * + * @param tag + * the tag + * @return the gh release builder + */ + public GHReleaseBuilder createRelease(String tag) { + return new GHReleaseBuilder(this, tag); + } + + /** + * Creates a named ref, such as tag, branch, etc. + * + * @param name + * The name of the fully qualified reference (ie: refs/heads/master). If it doesn't start with 'refs' and + * have at least two slashes, it will be rejected. + * @param sha + * The SHA1 value to set this reference to + * @return the gh ref + * @throws IOException + * the io exception + */ + public GHRef createRef(String name, String sha) throws IOException { + return root.createRequest().method("POST").with("ref", name).with("sha", sha) + .withUrlPath(getApiTailUrl("git/refs")).fetch(GHRef.class).wrap(root); + } + + /** + * Gets releases. + * + * @return the releases + * @throws IOException + * the io exception + * @deprecated use {@link #listReleases()} + */ + public List getReleases() throws IOException { + return listReleases().asList(); + } + + /** + * Gets release. + * + * @param id + * the id + * @return the release + * @throws IOException + * the io exception + */ + public GHRelease getRelease(long id) throws IOException { + try { + return root.createRequest().withUrlPath(getApiTailUrl("releases/" + id)).fetch(GHRelease.class).wrap(this); + } catch (FileNotFoundException e) { + return null; // no release for this id + } + } + + /** + * Gets release by tag name. + * + * @param tag + * the tag + * @return the release by tag name + * @throws IOException + * the io exception + */ + public GHRelease getReleaseByTagName(String tag) throws IOException { + try { + return root.createRequest().withUrlPath(getApiTailUrl("releases/tags/" + tag)).fetch(GHRelease.class) + .wrap(this); + } catch (FileNotFoundException e) { + return null; // no release for this tag + } + } + + /** + * Gets latest release. + * + * @return the latest release + * @throws IOException + * the io exception + */ + public GHRelease getLatestRelease() throws IOException { + try { + return root.createRequest().withUrlPath(getApiTailUrl("releases/latest")).fetch(GHRelease.class).wrap(this); + } catch (FileNotFoundException e) { + return null; // no latest release + } + } + + /** + * List releases paged iterable. + * + * @return the paged iterable + * @throws IOException + * the io exception + */ + public PagedIterable listReleases() throws IOException { + return root.createRequest().withUrlPath(getApiTailUrl("releases")).toIterable(GHRelease[].class, + item -> item.wrap(this)); + } + + /** + * List tags paged iterable. + * + * @return the paged iterable + * @throws IOException + * the io exception + */ + public PagedIterable listTags() throws IOException { + return root.createRequest().withUrlPath(getApiTailUrl("tags")).toIterable(GHTag[].class, + item -> item.wrap(this)); + } + + /** + * List languages for the specified repository. The value on the right of a language is the number of bytes of code + * written in that language. { "C": 78769, "Python": 7769 } + * + * @return the map + * @throws IOException + * the io exception + */ + public Map listLanguages() throws IOException { + return root.createRequest().withUrlPath(getApiTailUrl("languages")).fetch(HashMap.class); + } + + /** + * Gets owner name. + * + * @return the owner name + */ + public String getOwnerName() { + // consistency of the GitHub API is super... some serialized forms of + // GHRepository populate + // a full GHUser while others populate only the owner and email. This later form + // is super helpful + // in putting the login in owner.name not owner.login... thankfully we can + // easily identify this + // second set because owner.login will be null + return owner.login != null ? owner.login : owner.name; + } + + /** + * Has issues boolean. + * + * @return the boolean + */ + public boolean hasIssues() { + return has_issues; + } + + /** + * Has wiki boolean. + * + * @return the boolean + */ + public boolean hasWiki() { + return has_wiki; + } + + /** + * Is fork boolean. + * + * @return the boolean + */ + public boolean isFork() { + return fork; + } + + /** + * Is archived boolean. + * + * @return the boolean + */ + public boolean isArchived() { + return archived; + } + + /** + * Is allow squash merge boolean. + * + * @return the boolean + */ + public boolean isAllowSquashMerge() { + return allow_squash_merge; + } + + /** + * Is allow merge commit boolean. + * + * @return the boolean + */ + public boolean isAllowMergeCommit() { + return allow_merge_commit; + } + + /** + * Is allow rebase merge boolean. + * + * @return the boolean + */ + public boolean isAllowRebaseMerge() { + return allow_rebase_merge; + } + + /** + * Returns the number of all forks of this repository. This not only counts direct forks, but also forks of forks, + * and so on. + * + * @return the forks + */ + public int getForks() { + return forks_count; + } + + /** + * Gets stargazers count. + * + * @return the stargazers count + */ + public int getStargazersCount() { + return stargazers_count; + } + + /** + * Is private boolean. + * + * @return the boolean + */ + public boolean isPrivate() { + return _private; + } + + /** + * Has downloads boolean. + * + * @return the boolean + */ + public boolean hasDownloads() { + return has_downloads; + } + + /** + * Has pages boolean. + * + * @return the boolean + */ + public boolean hasPages() { + return has_pages; + } + + /** + * Gets watchers. + * + * @return the watchers + */ + public int getWatchers() { + return watchers_count; + } + + /** + * Gets open issue count. + * + * @return the open issue count + */ + public int getOpenIssueCount() { + return open_issues_count; + } + + /** + * Gets network count. + * + * @return the network count + * @deprecated This no longer exists in the official API documentation. Use {@link #getForks()} + */ + public int getNetworkCount() { + return forks_count; + } + + /** + * Gets subscribers count. + * + * @return the subscribers count + */ + public int getSubscribersCount() { + return subscribers_count; + } + + /** + * Gets pushed at. + * + * @return null if the repository was never pushed at. + */ + public Date getPushedAt() { + return GitHub.parseDate(pushed_at); + } + + /** + * Returns the primary branch you'll configure in the "Admin > Options" config page. + * + * @return This field is null until the user explicitly configures the master branch. + */ + public String getDefaultBranch() { + return default_branch; + } + + /** + * Gets master branch. + * + * @return the master branch + * @deprecated Renamed to {@link #getDefaultBranch()} + */ + public String getMasterBranch() { + return default_branch; + } + + /** + * Gets size. + * + * @return the size + */ + public int getSize() { + return size; + } + + /** + * Gets the collaborators on this repository. This set always appear to include the owner. + * + * @return the collaborators + * @throws IOException + * the io exception + */ + @WithBridgeMethods(Set.class) + public GHPersonSet getCollaborators() throws IOException { + return new GHPersonSet(listCollaborators().asList()); + } + + /** + * Lists up the collaborators on this repository. + * + * @return Users paged iterable + * @throws IOException + * the io exception + */ + public PagedIterable listCollaborators() throws IOException { + return listUsers("collaborators"); + } + + /** + * Lists all + * the + * available assignees to which issues may be assigned. + * + * @return the paged iterable + * @throws IOException + * the io exception + */ + public PagedIterable listAssignees() throws IOException { + return listUsers("assignees"); + } + + /** + * Checks if the given user is an assignee for this repository. + * + * @param u + * the u + * @return the boolean + * @throws IOException + * the io exception + */ + public boolean hasAssignee(GHUser u) throws IOException { + return root.createRequest().withUrlPath(getApiTailUrl("assignees/" + u.getLogin())).fetchHttpStatusCode() + / 100 == 2; + } + + /** + * Gets the names of the collaborators on this repository. This method deviates from the principle of this library + * but it works a lot faster than {@link #getCollaborators()}. + * + * @return the collaborator names + * @throws IOException + * the io exception + */ + public Set getCollaboratorNames() throws IOException { + Set r = new HashSet(); + for (GHUser u : GHUser.wrap( + root.createRequest().withUrlPath(getApiTailUrl("collaborators")).fetchArray(GHUser[].class), root)) + r.add(u.login); + return r; + } + + /** + * Obtain permission for a given user in this repository. + * + * @param user + * a {@link GHUser#getLogin} + * @return the permission + * @throws IOException + * the io exception + */ + public GHPermissionType getPermission(String user) throws IOException { + GHPermission perm = root.createRequest().withUrlPath(getApiTailUrl("collaborators/" + user + "/permission")) + .fetch(GHPermission.class); + perm.wrapUp(root); + return perm.getPermissionType(); + } + + /** + * Obtain permission for a given user in this repository. + * + * @param u + * the u + * @return the permission + * @throws IOException + * the io exception + */ + public GHPermissionType getPermission(GHUser u) throws IOException { + return getPermission(u.getLogin()); + } + + /** + * If this repository belongs to an organization, return a set of teams. + * + * @return the teams + * @throws IOException + * the io exception + */ + public Set getTeams() throws IOException { + return Collections.unmodifiableSet(new HashSet(Arrays.asList( + GHTeam.wrapUp(root.createRequest().withUrlPath(getApiTailUrl("teams")).fetchArray(GHTeam[].class), + root.getOrganization(getOwnerName()))))); + } + + /** + * Add collaborators. + * + * @param users + * the users + * @param perm + * the permission level + * @throws IOException + * the io exception + */ + public void addCollaborators(GHOrganization.Permission perm, GHUser... users) throws IOException { + addCollaborators(perm, asList(users)); + } + + /** + * Add collaborators. + * + * @param users + * the users + * @param perm + * the permission level + * @throws IOException + * the io exception + */ + public void addCollaborators(GHOrganization.Permission perm, Collection users) throws IOException { + modifyCollaborators(perm, users, "PUT"); + } + + /** + * Remove collaborators. + * + * @param users + * the users + * @throws IOException + * the io exception + */ + public void removeCollaborators(GHUser... users) throws IOException { + removeCollaborators(asList(users)); + } + + /** + * Remove collaborators. + * + * @param users + * the users + * @throws IOException + * the io exception + */ + public void removeCollaborators(Collection users) throws IOException { + modifyCollaborators(users, "DELETE"); + } + + private void modifyCollaborators(Collection users, String method) throws IOException { + for (GHUser user : users) { + root.createRequest().method(method).withUrlPath(getApiTailUrl("collaborators/" + user.getLogin())).send(); + } + } + + private void modifyCollaborators(GHOrganization.Permission perm, Collection users, String method) + throws IOException { + for (GHUser user : users) { + root.createRequest().method(method).with("permission", perm).inBody() + .withUrlPath(getApiTailUrl("collaborators/" + user.getLogin())).send(); + } + } + + /** + * Sets email service hook. + * + * @param address + * the address + * @throws IOException + * the io exception + */ + public void setEmailServiceHook(String address) throws IOException { + Map config = new HashMap(); + config.put("address", address); + root.createRequest().method("POST").with("name", "email").with("config", config).with("active", true) + .withUrlPath(getApiTailUrl("hooks")).send(); + } + + private void edit(String key, String value) throws IOException { + Requester requester = root.createRequest(); + if (!key.equals("name")) + requester.with("name", name); // even when we don't change the name, we need to send it in + requester.with(key, value).method("PATCH").withUrlPath(getApiTailUrl("")).send(); + } + + /** + * Enables or disables the issue tracker for this repository. + * + * @param v + * the v + * @throws IOException + * the io exception + */ + public void enableIssueTracker(boolean v) throws IOException { + edit("has_issues", String.valueOf(v)); + } + + /** + * Enables or disables Wiki for this repository. + * + * @param v + * the v + * @throws IOException + * the io exception + */ + public void enableWiki(boolean v) throws IOException { + edit("has_wiki", String.valueOf(v)); + } + + /** + * Enable downloads. + * + * @param v + * the v + * @throws IOException + * the io exception + */ + public void enableDownloads(boolean v) throws IOException { + edit("has_downloads", String.valueOf(v)); + } + + /** + * Rename this repository. + * + * @param name + * the name + * @throws IOException + * the io exception + */ + public void renameTo(String name) throws IOException { + edit("name", name); + } + + /** + * Sets description. + * + * @param value + * the value + * @throws IOException + * the io exception + */ + public void setDescription(String value) throws IOException { + edit("description", value); + } + + /** + * Sets homepage. + * + * @param value + * the value + * @throws IOException + * the io exception + */ + public void setHomepage(String value) throws IOException { + edit("homepage", value); + } + + /** + * Sets default branch. + * + * @param value + * the value + * @throws IOException + * the io exception + */ + public void setDefaultBranch(String value) throws IOException { + edit("default_branch", value); + } + + /** + * Sets private. + * + * @param value + * the value + * @throws IOException + * the io exception + */ + public void setPrivate(boolean value) throws IOException { + edit("private", Boolean.toString(value)); + } + + /** + * Allow squash merge. + * + * @param value + * the value + * @throws IOException + * the io exception + */ + public void allowSquashMerge(boolean value) throws IOException { + edit("allow_squash_merge", Boolean.toString(value)); + } + + /** + * Allow merge commit. + * + * @param value + * the value + * @throws IOException + * the io exception + */ + public void allowMergeCommit(boolean value) throws IOException { + edit("allow_merge_commit", Boolean.toString(value)); + } + + /** + * Allow rebase merge. + * + * @param value + * the value + * @throws IOException + * the io exception + */ + public void allowRebaseMerge(boolean value) throws IOException { + edit("allow_rebase_merge", Boolean.toString(value)); + } + + /** + * Deletes this repository. + * + * @throws IOException + * the io exception + */ + public void delete() throws IOException { + try { + root.createRequest().method("DELETE").withUrlPath(getApiTailUrl("")).send(); + } catch (FileNotFoundException x) { + throw (FileNotFoundException) new FileNotFoundException("Failed to delete " + getOwnerName() + "/" + name + + "; might not exist, or you might need the delete_repo scope in your token: http://stackoverflow.com/a/19327004/12916") + .initCause(x); + } + } + + /** + * Will archive and this repository as read-only. When a repository is archived, any operation that can change its + * state is forbidden. This applies symmetrically if trying to unarchive it. + * + *

+ * When you try to do any operation that modifies a read-only repository, it returns the response: + * + *

+     * org.kohsuke.github.HttpException: {
+     *     "message":"Repository was archived so is read-only.",
+     *     "documentation_url":"https://developer.github.com/v3/repos/#edit"
+     * }
+     * 
+ * + * @throws IOException + * In case of any networking error or error from the server. + */ + public void archive() throws IOException { + edit("archived", "true"); + // Generall would not update this record, + // but do so here since this will result in any other update actions failing + archived = true; + } + + /** + * Sort orders for listing forks + */ + public enum ForkSort { + NEWEST, OLDEST, STARGAZERS + } + + /** + * Lists all the direct forks of this repository, sorted by github api default, currently {@link ForkSort#NEWEST + * ForkSort.NEWEST}*. + * + * @return the paged iterable + */ + public PagedIterable listForks() { + return listForks(null); + } + + /** + * Lists all the direct forks of this repository, sorted by the given sort order. + * + * @param sort + * the sort order. If null, defaults to github api default, currently {@link ForkSort#NEWEST + * ForkSort.NEWEST}. + * @return the paged iterable + */ + public PagedIterable listForks(final ForkSort sort) { + return root.createRequest().with("sort", sort).withUrlPath(getApiTailUrl("forks")) + .toIterable(GHRepository[].class, item -> item.wrap(root)); + } + + /** + * Forks this repository as your repository. + * + * @return Newly forked repository that belong to you. + * @throws IOException + * the io exception + */ + public GHRepository fork() throws IOException { + root.createRequest().method("POST").withUrlPath(getApiTailUrl("forks")).send(); + + // this API is asynchronous. we need to wait for a bit + for (int i = 0; i < 10; i++) { + GHRepository r = root.getMyself().getRepository(name); + if (r != null) + return r; + try { + Thread.sleep(3000); + } catch (InterruptedException e) { + throw (IOException) new InterruptedIOException().initCause(e); + } + } + throw new IOException(this + " was forked but can't find the new repository"); + } + + /** + * Forks this repository into an organization. + * + * @param org + * the org + * @return Newly forked repository that belong to you. + * @throws IOException + * the io exception + */ + public GHRepository forkTo(GHOrganization org) throws IOException { + root.createRequest().method("POST").with("organization", org.getLogin()).withUrlPath(getApiTailUrl("forks")) + .send(); + + // this API is asynchronous. we need to wait for a bit + for (int i = 0; i < 10; i++) { + GHRepository r = org.getRepository(name); + if (r != null) + return r; + try { + Thread.sleep(3000); + } catch (InterruptedException e) { + throw (IOException) new InterruptedIOException().initCause(e); + } + } + throw new IOException(this + " was forked into " + org.getLogin() + " but can't find the new repository"); + } + + /** + * Retrieves a specified pull request. + * + * @param i + * the + * @return the pull request + * @throws IOException + * the io exception + */ + public GHPullRequest getPullRequest(int i) throws IOException { + return root.createRequest().withPreview(SHADOW_CAT).withUrlPath(getApiTailUrl("pulls/" + i)) + .fetch(GHPullRequest.class).wrapUp(this); + } + + /** + * Retrieves all the pull requests of a particular state. + * + * @param state + * the state + * @return the pull requests + * @throws IOException + * the io exception + * @see #listPullRequests(GHIssueState) #listPullRequests(GHIssueState) + */ + public List getPullRequests(GHIssueState state) throws IOException { + return queryPullRequests().state(state).list().asList(); + } + + /** + * Retrieves all the pull requests of a particular state. + * + * @param state + * the state + * @return the paged iterable + * @deprecated Use {@link #queryPullRequests()} + */ + public PagedIterable listPullRequests(GHIssueState state) { + return queryPullRequests().state(state).list(); + } + + /** + * Retrieves pull requests. + * + * @return the gh pull request query builder + */ + public GHPullRequestQueryBuilder queryPullRequests() { + return new GHPullRequestQueryBuilder(this); + } + + /** + * Creates a new pull request. + * + * @param title + * Required. The title of the pull request. + * @param head + * Required. The name of the branch where your changes are implemented. For cross-repository pull + * requests in the same network, namespace head with a user like this: username:branch. + * @param base + * Required. The name of the branch you want your changes pulled into. This should be an existing branch + * on the current repository. + * @param body + * The contents of the pull request. This is the markdown description of a pull request. + * @return the gh pull request + * @throws IOException + * the io exception + */ + public GHPullRequest createPullRequest(String title, String head, String base, String body) throws IOException { + return createPullRequest(title, head, base, body, true); + } + + /** + * Creates a new pull request. Maintainer's permissions aware. + * + * @param title + * Required. The title of the pull request. + * @param head + * Required. The name of the branch where your changes are implemented. For cross-repository pull + * requests in the same network, namespace head with a user like this: username:branch. + * @param base + * Required. The name of the branch you want your changes pulled into. This should be an existing branch + * on the current repository. + * @param body + * The contents of the pull request. This is the markdown description of a pull request. + * @param maintainerCanModify + * Indicates whether maintainers can modify the pull request. + * @return the gh pull request + * @throws IOException + * the io exception + */ + public GHPullRequest createPullRequest(String title, String head, String base, String body, + boolean maintainerCanModify) throws IOException { + return createPullRequest(title, head, base, body, maintainerCanModify, false); + } + + /** + * Creates a new pull request. Maintainer's permissions and draft aware. + * + * @param title + * Required. The title of the pull request. + * @param head + * Required. The name of the branch where your changes are implemented. For cross-repository pull + * requests in the same network, namespace head with a user like this: username:branch. + * @param base + * Required. The name of the branch you want your changes pulled into. This should be an existing branch + * on the current repository. + * @param body + * The contents of the pull request. This is the markdown description of a pull request. + * @param maintainerCanModify + * Indicates whether maintainers can modify the pull request. + * @param draft + * Indicates whether to create a draft pull request or not. + * @return the gh pull request + * @throws IOException + * the io exception + */ + public GHPullRequest createPullRequest(String title, String head, String base, String body, + boolean maintainerCanModify, boolean draft) throws IOException { + return root.createRequest().method("POST").withPreview(SHADOW_CAT).with("title", title).with("head", head) + .with("base", base).with("body", body).with("maintainer_can_modify", maintainerCanModify) + .with("draft", draft).withUrlPath(getApiTailUrl("pulls")).fetch(GHPullRequest.class).wrapUp(this); + } + + /** + * Retrieves the currently configured hooks. + * + * @return the hooks + * @throws IOException + * the io exception + */ + public List getHooks() throws IOException { + return GHHooks.repoContext(this, owner).getHooks(); + } + + /** + * Gets hook. + * + * @param id + * the id + * @return the hook + * @throws IOException + * the io exception + */ + public GHHook getHook(int id) throws IOException { + return GHHooks.repoContext(this, owner).getHook(id); + } + + /** + * Gets a comparison between 2 points in the repository. This would be similar to calling + * git log id1...id2 against a local repository. + * + * @param id1 + * an identifier for the first point to compare from, this can be a sha1 ID (for a commit, tag etc) or a + * direct tag name + * @param id2 + * an identifier for the second point to compare to. Can be the same as the first point. + * @return the comparison output + * @throws IOException + * on failure communicating with GitHub + */ + public GHCompare getCompare(String id1, String id2) throws IOException { + GHCompare compare = root.createRequest().withUrlPath(getApiTailUrl(String.format("compare/%s...%s", id1, id2))) + .fetch(GHCompare.class); + return compare.wrap(this); + } + + /** + * Gets compare. + * + * @param id1 + * the id 1 + * @param id2 + * the id 2 + * @return the compare + * @throws IOException + * the io exception + */ + public GHCompare getCompare(GHCommit id1, GHCommit id2) throws IOException { + return getCompare(id1.getSHA1(), id2.getSHA1()); + } + + /** + * Gets compare. + * + * @param id1 + * the id 1 + * @param id2 + * the id 2 + * @return the compare + * @throws IOException + * the io exception + */ + public GHCompare getCompare(GHBranch id1, GHBranch id2) throws IOException { + + GHRepository owner1 = id1.getOwner(); + GHRepository owner2 = id2.getOwner(); + + // If the owner of the branches is different, we have a cross-fork compare. + if (owner1 != null && owner2 != null) { + String ownerName1 = owner1.getOwnerName(); + String ownerName2 = owner2.getOwnerName(); + if (!StringUtils.equals(ownerName1, ownerName2)) { + String qualifiedName1 = String.format("%s:%s", ownerName1, id1.getName()); + String qualifiedName2 = String.format("%s:%s", ownerName2, id2.getName()); + return getCompare(qualifiedName1, qualifiedName2); + } + } + + return getCompare(id1.getName(), id2.getName()); + + } + + /** + * Retrieves all refs for the github repository. + * + * @return an array of GHRef elements coresponding with the refs in the remote repository. + * @throws IOException + * on failure communicating with GitHub + */ + public GHRef[] getRefs() throws IOException { + return GHRef.wrap(root.createRequest().withUrlPath(String.format("/repos/%s/%s/git/refs", getOwnerName(), name)) + .fetchArray(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 listRefs() throws IOException { + final String url = String.format("/repos/%s/%s/git/refs", getOwnerName(), name); + return root.createRequest().withUrlPath(url).toIterable(GHRef[].class, item -> item.wrap(root)); + } + + /** + * Retrieves all refs of the given type for the current GitHub repository. + * + * @param refType + * the type of reg to search for e.g. tags or commits + * @return an array of all refs matching the request type + * @throws IOException + * on failure communicating with GitHub, potentially due to an invalid ref type being requested + */ + public GHRef[] getRefs(String refType) throws IOException { + return GHRef.wrap(root.createRequest() + .withUrlPath(String.format("/repos/%s/%s/git/refs/%s", getOwnerName(), name, refType)) + .fetchArray(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. tags or commits + * @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 listRefs(String refType) throws IOException { + final String url = String.format("/repos/%s/%s/git/refs/%s", getOwnerName(), name, refType); + return root.createRequest().withUrlPath(url).toIterable(GHRef[].class, item -> item.wrap(root)); + } + + /** + * Retrive a ref of the given type for the current GitHub repository. + * + * @param refName + * eg: heads/branch + * @return refs matching the request type + * @throws IOException + * on failure communicating with GitHub, potentially due to an invalid ref type being requested + */ + public GHRef getRef(String refName) throws IOException { + return root.createRequest().withUrlPath(getApiTailUrl(String.format("git/refs/%s", refName))).fetch(GHRef.class) + .wrap(root); + } + + /** + * Returns the annotated 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 + * @throws IOException + * the io exception + */ + public GHTagObject getTagObject(String sha) throws IOException { + return root.createRequest().withUrlPath(getApiTailUrl("git/tags/" + sha)).fetch(GHTagObject.class).wrap(this); + } + + /** + * Retrive a tree of the given type for the current GitHub repository. + * + * @param sha + * sha number or branch name ex: "master" + * @return refs matching the request type + * @throws IOException + * on failure communicating with GitHub, potentially due to an invalid tree type being requested + */ + public GHTree getTree(String sha) throws IOException { + String url = String.format("/repos/%s/%s/git/trees/%s", getOwnerName(), name, sha); + return root.createRequest().withUrlPath(url).fetch(GHTree.class).wrap(this); + } + + /** + * Create tree gh tree builder. + * + * @return the gh tree builder + */ + public GHTreeBuilder createTree() { + return new GHTreeBuilder(this); + } + + /** + * Retrieves the tree for the current GitHub repository, recursively as described in here: + * https://developer.github.com/v3/git/trees/#get-a-tree-recursively + * + * @param sha + * sha number or branch name ex: "master" + * @param recursive + * use 1 + * @return the tree recursive + * @throws IOException + * on failure communicating with GitHub, potentially due to an invalid tree type being requested + */ + public GHTree getTreeRecursive(String sha, int recursive) throws IOException { + String url = String.format("/repos/%s/%s/git/trees/%s", getOwnerName(), name, sha); + return root.createRequest().with("recursive", recursive).withUrlPath(url).fetch(GHTree.class).wrap(this); + } + + /** + * Obtains the metadata & the content of a blob. + * + *

+ * This method retrieves the whole content in memory, so beware when you are dealing with large BLOB. + * + * @param blobSha + * the blob sha + * @return the blob + * @throws IOException + * the io exception + * @see Get a blob + * @see #readBlob(String) #readBlob(String) + */ + public GHBlob getBlob(String blobSha) throws IOException { + String target = getApiTailUrl("git/blobs/" + blobSha); + return root.createRequest().withUrlPath(target).fetch(GHBlob.class); + } + + /** + * Create blob gh blob builder. + * + * @return the gh blob builder + */ + public GHBlobBuilder createBlob() { + return new GHBlobBuilder(this); + } + + /** + * Reads the content of a blob as a stream for better efficiency. + * + * @param blobSha + * the blob sha + * @return the input stream + * @throws IOException + * the io exception + * @see Get a blob + * @see #getBlob(String) #getBlob(String) + */ + public InputStream readBlob(String blobSha) throws IOException { + String target = getApiTailUrl("git/blobs/" + blobSha); + + // https://developer.github.com/v3/media/ describes this media type + return root.createRequest().withHeader("Accept", "application/vnd.github.v3.raw").withUrlPath(target) + .fetchStream(); + } + + /** + * Gets a commit object in this repository. + * + * @param sha1 + * the sha 1 + * @return the commit + * @throws IOException + * the io exception + */ + public GHCommit getCommit(String sha1) throws IOException { + GHCommit c = commits.get(sha1); + if (c == null) { + c = root.createRequest().withUrlPath(String.format("/repos/%s/%s/commits/%s", getOwnerName(), name, sha1)) + .fetch(GHCommit.class).wrapUp(this); + commits.put(sha1, c); + } + return c; + } + + /** + * Create commit gh commit builder. + * + * @return the gh commit builder + */ + public GHCommitBuilder createCommit() { + return new GHCommitBuilder(this); + } + + /** + * Lists all the commits. + * + * @return the paged iterable + */ + public PagedIterable listCommits() { + return root.createRequest().withUrlPath(String.format("/repos/%s/%s/commits", getOwnerName(), name)) + .toIterable(GHCommit[].class, item -> item.wrapUp(this)); + } + + /** + * Search commits by specifying filters through a builder pattern. + * + * @return the gh commit query builder + */ + public GHCommitQueryBuilder queryCommits() { + return new GHCommitQueryBuilder(this); + } + + /** + * Lists up all the commit comments in this repository. + * + * @return the paged iterable + */ + public PagedIterable listCommitComments() { + return root.createRequest().withUrlPath(String.format("/repos/%s/%s/comments", getOwnerName(), name)) + .toIterable(GHCommitComment[].class, item -> item.wrap(this)); + } + + /** + * Gets the basic license details for the repository. + *

+ * + * @return null if there's no license. + * @throws IOException + * as usual but also if you don't use the preview connector + */ + public GHLicense getLicense() throws IOException { + GHContentWithLicense lic = getLicenseContent_(); + return lic != null ? lic.license : null; + } + + /** + * Retrieves the contents of the repository's license file - makes an additional API call + *

+ * + * @return details regarding the license contents, or null if there's no license. + * @throws IOException + * as usual but also if you don't use the preview connector + */ + public GHContent getLicenseContent() throws IOException { + return getLicenseContent_(); + } + + private GHContentWithLicense getLicenseContent_() throws IOException { + try { + return root.createRequest().withUrlPath(getApiTailUrl("license")).fetch(GHContentWithLicense.class) + .wrap(this); + } catch (FileNotFoundException e) { + return null; + } + } + + /** + * /** Lists all the commit statues attached to the given commit, newer ones first. + * + * @param sha1 + * the sha 1 + * @return the paged iterable + * @throws IOException + * the io exception + */ + public PagedIterable listCommitStatuses(final String sha1) throws IOException { + return root.createRequest().withUrlPath(String.format("/repos/%s/%s/statuses/%s", getOwnerName(), name, sha1)) + .toIterable(GHCommitStatus[].class, item -> item.wrapUp(root)); + } + + /** + * Gets the last status of this commit, which is what gets shown in the UI. + * + * @param sha1 + * the sha 1 + * @return the last commit status + * @throws IOException + * the io exception + */ + public GHCommitStatus getLastCommitStatus(String sha1) throws IOException { + List v = listCommitStatuses(sha1).asList(); + return v.isEmpty() ? null : v.get(0); + } + + /** + * Creates a commit status + * + * @param sha1 + * the sha 1 + * @param state + * the state + * @param targetUrl + * Optional parameter that points to the URL that has more details. + * @param description + * Optional short description. + * @param context + * Optinal commit status context. + * @return the gh commit status + * @throws IOException + * the io exception + */ + public GHCommitStatus createCommitStatus(String sha1, GHCommitState state, String targetUrl, String description, + String context) throws IOException { + return root.createRequest().method("POST").with("state", state).with("target_url", targetUrl) + .with("description", description).with("context", context) + .withUrlPath(String.format("/repos/%s/%s/statuses/%s", getOwnerName(), this.name, sha1)) + .fetch(GHCommitStatus.class).wrapUp(root); + } + + /** + * Create commit status gh commit status. + * + * @param sha1 + * the sha 1 + * @param state + * the state + * @param targetUrl + * the target url + * @param description + * the description + * @return the gh commit status + * @throws IOException + * the io exception + * @see #createCommitStatus(String, GHCommitState, String, String, String) #createCommitStatus(String, + * GHCommitState,String,String,String) + */ + public GHCommitStatus createCommitStatus(String sha1, GHCommitState state, String targetUrl, String description) + throws IOException { + return createCommitStatus(sha1, state, targetUrl, description, null); + } + + /** + * Lists repository events. + * + * @return the paged iterable + * @throws IOException + * the io exception + */ + public PagedIterable listEvents() throws IOException { + return root.createRequest().withUrlPath(String.format("/repos/%s/%s/events", getOwnerName(), name)) + .toIterable(GHEventInfo[].class, item -> item.wrapUp(root)); + } + + /** + * Lists labels in this repository. + *

+ * https://developer.github.com/v3/issues/labels/#list-all-labels-for-this-repository + * + * @return the paged iterable + * @throws IOException + * the io exception + */ + public PagedIterable listLabels() throws IOException { + return root.createRequest().withUrlPath(getApiTailUrl("labels")).toIterable(GHLabel[].class, + item -> item.wrapUp(this)); + } + + /** + * Gets label. + * + * @param name + * the name + * @return the label + * @throws IOException + * the io exception + */ + public GHLabel getLabel(String name) throws IOException { + return root.createRequest().withUrlPath(getApiTailUrl("labels/" + name)).fetch(GHLabel.class).wrapUp(this); + } + + /** + * Create label gh label. + * + * @param name + * the name + * @param color + * the color + * @return the gh label + * @throws IOException + * the io exception + */ + public GHLabel createLabel(String name, String color) throws IOException { + return createLabel(name, color, ""); + } + + /** + * Description is still in preview. + * + * @param name + * the name + * @param color + * the color + * @param description + * the description + * @return gh label + * @throws IOException + * the io exception + */ + public GHLabel createLabel(String name, String color, String description) throws IOException { + return root.createRequest().method("POST").with("name", name).with("color", color) + .with("description", description).withUrlPath(getApiTailUrl("labels")).fetch(GHLabel.class) + .wrapUp(this); + } + + /** + * Lists all the invitations. + * + * @return the paged iterable + */ + public PagedIterable listInvitations() { + return root.createRequest().withUrlPath(String.format("/repos/%s/%s/invitations", getOwnerName(), name)) + .toIterable(GHInvitation[].class, item -> item.wrapUp(root)); + } + + /** + * Lists all the subscribers (aka watchers.) + *

+ * https://developer.github.com/v3/activity/watching/ + * + * @return the paged iterable + */ + public PagedIterable listSubscribers() { + return listUsers("subscribers"); + } + + /** + * Lists all the users who have starred this repo based on the old version of the API. For additional information, + * like date when the repository was starred, see {@link #listStargazers2()} + * + * @return the paged iterable + */ + public PagedIterable listStargazers() { + return listUsers("stargazers"); + } + + /** + * Lists all the users who have starred this repo based on new version of the API, having extended information like + * the time when the repository was starred. For compatibility with the old API see {@link #listStargazers()} + * + * @return the paged iterable + */ + public PagedIterable listStargazers2() { + return root.createRequest().withPreview("application/vnd.github.v3.star+json") + .withUrlPath(getApiTailUrl("stargazers")).toIterable(GHStargazer[].class, item -> item.wrapUp(this)); + } + + private PagedIterable listUsers(final String suffix) { + return root.createRequest().withUrlPath(getApiTailUrl(suffix)).toIterable(GHUser[].class, + item -> item.wrapUp(root)); + } + + /** + * See https://api.github.com/hooks for possible names and their configuration scheme. TODO: produce type-safe + * binding + * + * @param name + * Type of the hook to be created. See https://api.github.com/hooks for possible names. + * @param config + * The configuration hash. + * @param events + * Can be null. Types of events to hook into. + * @param active + * the active + * @return the gh hook + * @throws IOException + * the io exception + */ + public GHHook createHook(String name, Map config, Collection events, boolean active) + throws IOException { + return GHHooks.repoContext(this, owner).createHook(name, config, events, active); + } + + /** + * Create web hook gh hook. + * + * @param url + * the url + * @param events + * the events + * @return the gh hook + * @throws IOException + * the io exception + */ + public GHHook createWebHook(URL url, Collection events) throws IOException { + return createHook("web", Collections.singletonMap("url", url.toExternalForm()), events, true); + } + + /** + * Create web hook gh hook. + * + * @param url + * the url + * @return the gh hook + * @throws IOException + * the io exception + */ + public GHHook createWebHook(URL url) throws IOException { + return createWebHook(url, null); + } + + // this is no different from getPullRequests(OPEN) + // /** + // * Retrieves all the pull requests. + // */ + // public List getPullRequests() throws IOException { + // return + // root.retrieveWithAuth("/pulls/"+owner+'/'+name,JsonPullRequests.class).wrap(root); + // } + + /** + * Returns a set that represents the post-commit hook URLs. The returned set is live, and changes made to them are + * reflected to GitHub. + * + * @return the post commit hooks + * @deprecated Use {@link #getHooks()} and {@link #createHook(String, Map, Collection, boolean)} + */ + @SuppressFBWarnings(value = "DMI_COLLECTION_OF_URLS", justification = "It causes a performance degradation, but we have already exposed it to the API") + public Set getPostCommitHooks() { + return postCommitHooks; + } + + /** + * Live set view of the post-commit hook. + */ + @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 postCommitHooks = new AbstractSet() { + private List getPostCommitHooks() { + try { + List r = new ArrayList(); + for (GHHook h : getHooks()) { + if (h.getName().equals("web")) { + r.add(new URL(h.getConfig().get("url"))); + } + } + return r; + } catch (IOException e) { + throw new GHException("Failed to retrieve post-commit hooks", e); + } + } + + @Override + public Iterator iterator() { + return getPostCommitHooks().iterator(); + } + + @Override + public int size() { + return getPostCommitHooks().size(); + } + + @Override + public boolean add(URL url) { + try { + createWebHook(url); + return true; + } catch (IOException e) { + throw new GHException("Failed to update post-commit hooks", e); + } + } + + @Override + public boolean remove(Object url) { + try { + String _url = ((URL) url).toExternalForm(); + for (GHHook h : getHooks()) { + if (h.getName().equals("web") && h.getConfig().get("url").equals(_url)) { + h.delete(); + return true; + } + } + return false; + } catch (IOException e) { + throw new GHException("Failed to update post-commit hooks", e); + } + } + }; + + GHRepository wrap(GitHub root) { + this.root = root; + if (root.isOffline()) { + owner.wrapUp(root); + } + return this; + } + + /** + * Gets branches by {@linkplain GHBranch#getName() their names}. + * + * @return the branches + * @throws IOException + * the io exception + */ + public Map getBranches() throws IOException { + Map r = new TreeMap(); + for (GHBranch p : root.createRequest().withUrlPath(getApiTailUrl("branches")).fetchArray(GHBranch[].class)) { + p.wrap(this); + r.put(p.getName(), p); + } + return r; + } + + /** + * Gets branch. + * + * @param name + * the name + * @return the branch + * @throws IOException + * the io exception + */ + public GHBranch getBranch(String name) throws IOException { + return root.createRequest().withUrlPath(getApiTailUrl("branches/" + name)).fetch(GHBranch.class).wrap(this); + } + + /** + * Gets milestones. + * + * @return the milestones + * @throws IOException + * the io exception + * @deprecated Use {@link #listMilestones(GHIssueState)} + */ + public Map getMilestones() throws IOException { + Map milestones = new TreeMap(); + for (GHMilestone m : listMilestones(GHIssueState.OPEN)) { + milestones.put(m.getNumber(), m); + } + return milestones; + } + + /** + * Lists up all the milestones in this repository. + * + * @param state + * the state + * @return the paged iterable + */ + public PagedIterable listMilestones(final GHIssueState state) { + return root.createRequest().with("state", state).withUrlPath(getApiTailUrl("milestones")) + .toIterable(GHMilestone[].class, item -> item.wrap(this)); + } + + /** + * Gets milestone. + * + * @param number + * the number + * @return the milestone + * @throws IOException + * the io exception + */ + public GHMilestone getMilestone(int number) throws IOException { + GHMilestone m = milestones.get(number); + if (m == null) { + m = root.createRequest().withUrlPath(getApiTailUrl("milestones/" + number)).fetch(GHMilestone.class); + m.owner = this; + m.root = root; + milestones.put(m.getNumber(), m); + } + return m; + } + + /** + * Gets file content. + * + * @param path + * the path + * @return the file content + * @throws IOException + * the io exception + */ + public GHContent getFileContent(String path) throws IOException { + return getFileContent(path, null); + } + + /** + * Gets file content. + * + * @param path + * the path + * @param ref + * the ref + * @return the file content + * @throws IOException + * the io exception + */ + public GHContent getFileContent(String path, String ref) throws IOException { + Requester requester = root.createRequest(); + String target = getApiTailUrl("contents/" + path); + + return requester.with("ref", ref).withUrlPath(target).fetch(GHContent.class).wrap(this); + } + + /** + * Gets directory content. + * + * @param path + * the path + * @return the directory content + * @throws IOException + * the io exception + */ + public List getDirectoryContent(String path) throws IOException { + return getDirectoryContent(path, null); + } + + /** + * Gets directory content. + * + * @param path + * the path + * @param ref + * the ref + * @return the directory content + * @throws IOException + * the io exception + */ + public List getDirectoryContent(String path, String ref) throws IOException { + Requester requester = root.createRequest(); + while (path.endsWith("/")) { + path = path.substring(0, path.length() - 1); + } + String target = getApiTailUrl("contents/" + path); + + GHContent[] files = requester.with("ref", ref).withUrlPath(target).fetchArray(GHContent[].class); + + GHContent.wrap(files, this); + + return Arrays.asList(files); + } + + /** + * https://developer.github.com/v3/repos/contents/#get-the-readme + * + * @return the readme + * @throws IOException + * the io exception + */ + public GHContent getReadme() throws IOException { + Requester requester = root.createRequest(); + return requester.withUrlPath(getApiTailUrl("readme")).fetch(GHContent.class).wrap(this); + } + + /** + * Creates a new content, or update an existing content. + * + * @return the gh content builder + */ + public GHContentBuilder createContent() { + return new GHContentBuilder(this); + } + + /** + * Use {@link #createContent()}. + * + * @param content + * the content + * @param commitMessage + * the commit message + * @param path + * the path + * @return the gh content update response + * @throws IOException + * the io exception + */ + @Deprecated + public GHContentUpdateResponse createContent(String content, String commitMessage, String path) throws IOException { + return createContent().content(content).message(commitMessage).path(path).commit(); + } + + /** + * Use {@link #createContent()}. + * + * @param content + * the content + * @param commitMessage + * the commit message + * @param path + * the path + * @param branch + * the branch + * @return the gh content update response + * @throws IOException + * the io exception + */ + @Deprecated + public GHContentUpdateResponse createContent(String content, String commitMessage, String path, String branch) + throws IOException { + return createContent().content(content).message(commitMessage).path(path).branch(branch).commit(); + } + + /** + * Use {@link #createContent()}. + * + * @param contentBytes + * the content bytes + * @param commitMessage + * the commit message + * @param path + * the path + * @return the gh content update response + * @throws IOException + * the io exception + */ + @Deprecated + public GHContentUpdateResponse createContent(byte[] contentBytes, String commitMessage, String path) + throws IOException { + return createContent().content(contentBytes).message(commitMessage).path(path).commit(); + } + + /** + * Use {@link #createContent()}. + * + * @param contentBytes + * the content bytes + * @param commitMessage + * the commit message + * @param path + * the path + * @param branch + * the branch + * @return the gh content update response + * @throws IOException + * the io exception + */ + @Deprecated + public GHContentUpdateResponse createContent(byte[] contentBytes, String commitMessage, String path, String branch) + throws IOException { + return createContent().content(contentBytes).message(commitMessage).path(path).branch(branch).commit(); + } + + /** + * Create milestone gh milestone. + * + * @param title + * the title + * @param description + * the description + * @return the gh milestone + * @throws IOException + * the io exception + */ + public GHMilestone createMilestone(String title, String description) throws IOException { + return root.createRequest().method("POST").with("title", title).with("description", description) + .withUrlPath(getApiTailUrl("milestones")).fetch(GHMilestone.class).wrap(this); + } + + /** + * Add deploy key gh deploy key. + * + * @param title + * the title + * @param key + * the key + * @return the gh deploy key + * @throws IOException + * the io exception + */ + public GHDeployKey addDeployKey(String title, String key) throws IOException { + return root.createRequest().method("POST").with("title", title).with("key", key) + .withUrlPath(getApiTailUrl("keys")).fetch(GHDeployKey.class).wrap(this); + + } + + /** + * Gets deploy keys. + * + * @return the deploy keys + * @throws IOException + * the io exception + */ + public List getDeployKeys() throws IOException { + List list = new ArrayList( + Arrays.asList(root.createRequest().withUrlPath(getApiTailUrl("keys")).fetchArray(GHDeployKey[].class))); + for (GHDeployKey h : list) + h.wrap(this); + return list; + } + + /** + * Forked repositories have a 'source' attribute that specifies the ultimate source of the forking chain. + * + * @return {@link GHRepository} that points to the root repository where this repository is forked (indirectly or + * directly) from. Otherwise null. + * @throws IOException + * the io exception + * @see #getParent() #getParent() + */ + public GHRepository getSource() throws IOException { + if (source == null) + return null; + if (source.root == null) + source = root.getRepository(source.getFullName()); + return source; + } + + /** + * Forked repositories have a 'parent' attribute that specifies the repository this repository is directly forked + * from. If we keep traversing {@link #getParent()} until it returns null, that is {@link #getSource()}. + * + * @return {@link GHRepository} that points to the repository where this repository is forked directly from. + * Otherwise null. + * @throws IOException + * the io exception + * @see #getSource() #getSource() + */ + public GHRepository getParent() throws IOException { + if (parent == null) + return null; + if (parent.root == null) + parent = root.getRepository(parent.getFullName()); + return parent; + } + + /** + * Subscribes to this repository to get notifications. + * + * @param subscribed + * the subscribed + * @param ignored + * the ignored + * @return the gh subscription + * @throws IOException + * the io exception + */ + public GHSubscription subscribe(boolean subscribed, boolean ignored) throws IOException { + return root.createRequest().method("PUT").with("subscribed", subscribed).with("ignored", ignored) + .withUrlPath(getApiTailUrl("subscription")).fetch(GHSubscription.class).wrapUp(this); + } + + /** + * Returns the current subscription. + * + * @return null if no subscription exists. + * @throws IOException + * the io exception + */ + public GHSubscription getSubscription() throws IOException { + try { + return root.createRequest().withUrlPath(getApiTailUrl("subscription")).fetch(GHSubscription.class) + .wrapUp(this); + } catch (FileNotFoundException e) { + return null; + } + } + + /** + * List contributors paged iterable. + * + * @return the paged iterable + * @throws IOException + * the io exception + */ + public PagedIterable listContributors() throws IOException { + return root.createRequest().withUrlPath(getApiTailUrl("contributors")).toIterable(Contributor[].class, + item -> item.wrapUp(root)); + } + + /** + * The type Contributor. + */ + public static class Contributor extends GHUser { + private int contributions; + + /** + * Gets contributions. + * + * @return the contributions + */ + public int getContributions() { + return contributions; + } + + @Override + public int hashCode() { + // We ignore contributions in the calculation + return super.hashCode(); + } + + @Override + public boolean equals(Object obj) { + // We ignore contributions in the calculation + return super.equals(obj); + } + } + + /** + * Returns the statistics for this repository. + * + * @return the statistics + */ + public GHRepositoryStatistics getStatistics() { + // TODO: Use static object and introduce refresh() method, + // instead of returning new object each time. + return new GHRepositoryStatistics(this); + } + + /** + * Create a project for this repository. + * + * @param name + * the name + * @param body + * the body + * @return the gh project + * @throws IOException + * the io exception + */ + public GHProject createProject(String name, String body) throws IOException { + return root.createRequest().method("POST").withPreview(INERTIA).with("name", name).with("body", body) + .withUrlPath(getApiTailUrl("projects")).fetch(GHProject.class).wrap(this); + } + + /** + * Returns the projects for this repository. + * + * @param status + * The status filter (all, open or closed). + * @return the paged iterable + * @throws IOException + * the io exception + */ + public PagedIterable listProjects(final GHProject.ProjectStateFilter status) throws IOException { + return root.createRequest().withPreview(INERTIA).with("state", status).withUrlPath(getApiTailUrl("projects")) + .toIterable(GHProject[].class, item -> item.wrap(this)); + } + + /** + * Returns open projects for this repository. + * + * @return the paged iterable + * @throws IOException + * the io exception + */ + public PagedIterable listProjects() throws IOException { + return listProjects(GHProject.ProjectStateFilter.OPEN); + } + + /** + * Render a Markdown document. + *

+ * In {@linkplain MarkdownMode#GFM GFM mode}, issue numbers and user mentions are linked accordingly. + * + * @param text + * the text + * @param mode + * the mode + * @return the reader + * @throws IOException + * the io exception + * @see GitHub#renderMarkdown(String) GitHub#renderMarkdown(String) + */ + public Reader renderMarkdown(String text, MarkdownMode mode) throws IOException { + return new InputStreamReader(root.createRequest().method("POST").with("text", text) + .with("mode", mode == null ? null : mode.toString()).with("context", getFullName()) + .withUrlPath("/markdown").fetchStream(), "UTF-8"); + } + + /** + * List all the notifications in a repository for the current user. + * + * @return the gh notification stream + */ + public GHNotificationStream listNotifications() { + return new GHNotificationStream(root, getApiTailUrl("/notifications")); + } + + /** + * https://developer.github.com/v3/repos/traffic/#views + * + * @return the view traffic + * @throws IOException + * the io exception + */ + public GHRepositoryViewTraffic getViewTraffic() throws IOException { + return root.createRequest().withUrlPath(getApiTailUrl("/traffic/views")).fetch(GHRepositoryViewTraffic.class); + } + + /** + * https://developer.github.com/v3/repos/traffic/#clones + * + * @return the clone traffic + * @throws IOException + * the io exception + */ + public GHRepositoryCloneTraffic getCloneTraffic() throws IOException { + return root.createRequest().withUrlPath(getApiTailUrl("/traffic/clones")).fetch(GHRepositoryCloneTraffic.class); + } + + @Override + public int hashCode() { + return ("Repository:" + getOwnerName() + ":" + name).hashCode(); + } + + @Override + public boolean equals(Object obj) { + if (obj instanceof GHRepository) { + GHRepository that = (GHRepository) obj; + return this.getOwnerName().equals(that.getOwnerName()) && this.name.equals(that.name); + } + return false; + } + + String getApiTailUrl(String tail) { + if (tail.length() > 0 && !tail.startsWith("/")) + tail = '/' + tail; + return "/repos/" + getOwnerName() + "/" + name + tail; + } + + /** + * Get all issue events for this repository. See + * https://developer.github.com/v3/issues/events/#list-events-for-a-repository + * + * @return the paged iterable + * @throws IOException + * the io exception + */ + public PagedIterable listIssueEvents() throws IOException { + return root.createRequest().withUrlPath(getApiTailUrl("issues/events")).toIterable(GHIssueEvent[].class, + item -> item.wrapUp(root)); + } + + /** + * Get a single issue event. See https://developer.github.com/v3/issues/events/#get-a-single-event + * + * @param id + * the id + * @return the issue event + * @throws IOException + * the io exception + */ + public GHIssueEvent getIssueEvent(long id) throws IOException { + return root.createRequest().withUrlPath(getApiTailUrl("issues/events/" + id)).fetch(GHIssueEvent.class) + .wrapUp(root); + } + + // Only used within listTopics(). + private static class Topics { + public List names; + } + + /** + * Return the topics for this repository. See + * https://developer.github.com/v3/repos/#list-all-topics-for-a-repository + * + * @return the list + * @throws IOException + * the io exception + */ + public List listTopics() throws IOException { + Topics topics = root.createRequest().withPreview(MERCY).withUrlPath(getApiTailUrl("topics")) + .fetch(Topics.class); + return topics.names; + } + + /** + * Set the topics for this repository. See + * https://developer.github.com/v3/repos/#replace-all-topics-for-a-repository + * + * @param topics + * the topics + * @throws IOException + * the io exception + */ + public void setTopics(List topics) throws IOException { + root.createRequest().method("PUT").with("names", topics).withPreview(MERCY).withUrlPath(getApiTailUrl("topics")) + .send(); + } + + /** + * Create a tag. See https://developer.github.com/v3/git/tags/#create-a-tag-object + * + * @param tag + * The tag's name. + * @param message + * The tag message. + * @param object + * The SHA of the git object this is tagging. + * @param type + * The type of the object we're tagging: "commit", "tree" or "blob". + * @return The newly created tag. + * @throws java.io.IOException + * The IO exception. + */ + public GHTagObject createTag(String tag, String message, String object, String type) throws IOException { + return root.createRequest().method("POST").with("tag", tag).with("message", message).with("object", object) + .with("type", type).withUrlPath(getApiTailUrl("git/tags")).fetch(GHTagObject.class).wrap(this); + } +} From 3e4f160c5db33d9eba299502ff73903ba0078a98 Mon Sep 17 00:00:00 2001 From: James Vaughn Date: Fri, 24 Jan 2020 18:23:59 -0600 Subject: [PATCH 05/11] ran mvn clean install then the build commmand and build was successful --- .../java/org/kohsuke/github/GHRepository.java | 298 +++++++++++++----- 1 file changed, 218 insertions(+), 80 deletions(-) diff --git a/src/main/java/org/kohsuke/github/GHRepository.java b/src/main/java/org/kohsuke/github/GHRepository.java index 54bfc15f79..454843b78b 100644 --- a/src/main/java/org/kohsuke/github/GHRepository.java +++ b/src/main/java/org/kohsuke/github/GHRepository.java @@ -59,8 +59,8 @@ * @author Kohsuke Kawaguchi */ @SuppressWarnings({ "UnusedDeclaration" }) -@SuppressFBWarnings(value = { "UWF_UNWRITTEN_PUBLIC_OR_PROTECTED_FIELD", "UWF_UNWRITTEN_FIELD", - "NP_UNWRITTEN_FIELD" }, justification = "JSON API") +@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; @@ -134,8 +134,12 @@ public PagedIterable getDeploymentStatuses(final int id) thr * @return the paged iterable */ public PagedIterable listDeployments(String sha, String ref, String task, String environment) { - return root.createRequest().with("sha", sha).with("ref", ref).with("task", task) - .with("environment", environment).withUrlPath(getApiTailUrl("deployments")) + return root.createRequest() + .with("sha", sha) + .with("ref", ref) + .with("task", task) + .with("environment", environment) + .withUrlPath(getApiTailUrl("deployments")) .toIterable(GHDeployment[].class, item -> item.wrap(this)); } @@ -149,7 +153,9 @@ public PagedIterable listDeployments(String sha, String ref, Strin * the io exception */ public GHDeployment getDeployment(long id) throws IOException { - return root.createRequest().withUrlPath(getApiTailUrl("deployments/" + id)).fetch(GHDeployment.class) + return root.createRequest() + .withUrlPath(getApiTailUrl("deployments/" + id)) + .fetch(GHDeployment.class) .wrap(this); } @@ -367,8 +373,9 @@ public List getIssues(GHIssueState state) throws IOException { * the io exception */ public List getIssues(GHIssueState state, GHMilestone milestone) throws IOException { - Requester requester = root.createRequest().with("state", state).with("milestone", - milestone == null ? "none" : "" + milestone.getNumber()); + Requester requester = root.createRequest() + .with("state", state) + .with("milestone", milestone == null ? "none" : "" + milestone.getNumber()); return Arrays .asList(GHIssue.wrap(requester.withUrlPath(getApiTailUrl("issues")).fetchArray(GHIssue[].class), this)); } @@ -381,7 +388,9 @@ public List getIssues(GHIssueState state, GHMilestone milestone) throws * @return the paged iterable */ public PagedIterable listIssues(final GHIssueState state) { - return root.createRequest().with("state", state).withUrlPath(getApiTailUrl("issues")) + return root.createRequest() + .with("state", state) + .withUrlPath(getApiTailUrl("issues")) .toIterable(GHIssue[].class, item -> item.wrap(this)); } @@ -409,8 +418,13 @@ public GHReleaseBuilder createRelease(String tag) { * the io exception */ public GHRef createRef(String name, String sha) throws IOException { - return root.createRequest().method("POST").with("ref", name).with("sha", sha) - .withUrlPath(getApiTailUrl("git/refs")).fetch(GHRef.class).wrap(root); + return root.createRequest() + .method("POST") + .with("ref", name) + .with("sha", sha) + .withUrlPath(getApiTailUrl("git/refs")) + .fetch(GHRef.class) + .wrap(root); } /** @@ -453,7 +467,9 @@ public GHRelease getRelease(long id) throws IOException { */ public GHRelease getReleaseByTagName(String tag) throws IOException { try { - return root.createRequest().withUrlPath(getApiTailUrl("releases/tags/" + tag)).fetch(GHRelease.class) + return root.createRequest() + .withUrlPath(getApiTailUrl("releases/tags/" + tag)) + .fetch(GHRelease.class) .wrap(this); } catch (FileNotFoundException e) { return null; // no release for this tag @@ -483,8 +499,9 @@ public GHRelease getLatestRelease() throws IOException { * the io exception */ public PagedIterable listReleases() throws IOException { - return root.createRequest().withUrlPath(getApiTailUrl("releases")).toIterable(GHRelease[].class, - item -> item.wrap(this)); + return root.createRequest() + .withUrlPath(getApiTailUrl("releases")) + .toIterable(GHRelease[].class, item -> item.wrap(this)); } /** @@ -495,8 +512,9 @@ public PagedIterable listReleases() throws IOException { * the io exception */ public PagedIterable listTags() throws IOException { - return root.createRequest().withUrlPath(getApiTailUrl("tags")).toIterable(GHTag[].class, - item -> item.wrap(this)); + return root.createRequest() + .withUrlPath(getApiTailUrl("tags")) + .toIterable(GHTag[].class, item -> item.wrap(this)); } /** @@ -771,7 +789,8 @@ public boolean hasAssignee(GHUser u) throws IOException { public Set getCollaboratorNames() throws IOException { Set r = new HashSet(); for (GHUser u : GHUser.wrap( - root.createRequest().withUrlPath(getApiTailUrl("collaborators")).fetchArray(GHUser[].class), root)) + root.createRequest().withUrlPath(getApiTailUrl("collaborators")).fetchArray(GHUser[].class), + root)) r.add(u.login); return r; } @@ -786,7 +805,8 @@ public Set getCollaboratorNames() throws IOException { * the io exception */ public GHPermissionType getPermission(String user) throws IOException { - GHPermission perm = root.createRequest().withUrlPath(getApiTailUrl("collaborators/" + user + "/permission")) + GHPermission perm = root.createRequest() + .withUrlPath(getApiTailUrl("collaborators/" + user + "/permission")) .fetch(GHPermission.class); perm.wrapUp(root); return perm.getPermissionType(); @@ -879,8 +899,12 @@ private void modifyCollaborators(Collection users, String method) throws private void modifyCollaborators(GHOrganization.Permission perm, Collection users, String method) throws IOException { for (GHUser user : users) { - root.createRequest().method(method).with("permission", perm).inBody() - .withUrlPath(getApiTailUrl("collaborators/" + user.getLogin())).send(); + root.createRequest() + .method(method) + .with("permission", perm) + .inBody() + .withUrlPath(getApiTailUrl("collaborators/" + user.getLogin())) + .send(); } } @@ -895,8 +919,13 @@ private void modifyCollaborators(GHOrganization.Permission perm, Collection config = new HashMap(); config.put("address", address); - root.createRequest().method("POST").with("name", "email").with("config", config).with("active", true) - .withUrlPath(getApiTailUrl("hooks")).send(); + root.createRequest() + .method("POST") + .with("name", "email") + .with("config", config) + .with("active", true) + .withUrlPath(getApiTailUrl("hooks")) + .send(); } private void edit(String key, String value) throws IOException { @@ -1104,7 +1133,9 @@ public PagedIterable listForks() { * @return the paged iterable */ public PagedIterable listForks(final ForkSort sort) { - return root.createRequest().with("sort", sort).withUrlPath(getApiTailUrl("forks")) + return root.createRequest() + .with("sort", sort) + .withUrlPath(getApiTailUrl("forks")) .toIterable(GHRepository[].class, item -> item.wrap(root)); } @@ -1142,7 +1173,10 @@ public GHRepository fork() throws IOException { * the io exception */ public GHRepository forkTo(GHOrganization org) throws IOException { - root.createRequest().method("POST").with("organization", org.getLogin()).withUrlPath(getApiTailUrl("forks")) + root.createRequest() + .method("POST") + .with("organization", org.getLogin()) + .withUrlPath(getApiTailUrl("forks")) .send(); // this API is asynchronous. we need to wait for a bit @@ -1169,8 +1203,11 @@ public GHRepository forkTo(GHOrganization org) throws IOException { * the io exception */ public GHPullRequest getPullRequest(int i) throws IOException { - return root.createRequest().withPreview(SHADOW_CAT).withUrlPath(getApiTailUrl("pulls/" + i)) - .fetch(GHPullRequest.class).wrapUp(this); + return root.createRequest() + .withPreview(SHADOW_CAT) + .withUrlPath(getApiTailUrl("pulls/" + i)) + .fetch(GHPullRequest.class) + .wrapUp(this); } /** @@ -1248,7 +1285,10 @@ public GHPullRequest createPullRequest(String title, String head, String base, S * @throws IOException * the io exception */ - public GHPullRequest createPullRequest(String title, String head, String base, String body, + public GHPullRequest createPullRequest(String title, + String head, + String base, + String body, boolean maintainerCanModify) throws IOException { return createPullRequest(title, head, base, body, maintainerCanModify, false); } @@ -1274,11 +1314,24 @@ public GHPullRequest createPullRequest(String title, String head, String base, S * @throws IOException * the io exception */ - public GHPullRequest createPullRequest(String title, String head, String base, String body, - boolean maintainerCanModify, boolean draft) throws IOException { - return root.createRequest().method("POST").withPreview(SHADOW_CAT).with("title", title).with("head", head) - .with("base", base).with("body", body).with("maintainer_can_modify", maintainerCanModify) - .with("draft", draft).withUrlPath(getApiTailUrl("pulls")).fetch(GHPullRequest.class).wrapUp(this); + public GHPullRequest createPullRequest(String title, + String head, + String base, + String body, + boolean maintainerCanModify, + boolean draft) throws IOException { + return root.createRequest() + .method("POST") + .withPreview(SHADOW_CAT) + .with("title", title) + .with("head", head) + .with("base", base) + .with("body", body) + .with("maintainer_can_modify", maintainerCanModify) + .with("draft", draft) + .withUrlPath(getApiTailUrl("pulls")) + .fetch(GHPullRequest.class) + .wrapUp(this); } /** @@ -1319,7 +1372,8 @@ public GHHook getHook(int id) throws IOException { * on failure communicating with GitHub */ public GHCompare getCompare(String id1, String id2) throws IOException { - GHCompare compare = root.createRequest().withUrlPath(getApiTailUrl(String.format("compare/%s...%s", id1, id2))) + GHCompare compare = root.createRequest() + .withUrlPath(getApiTailUrl(String.format("compare/%s...%s", id1, id2))) .fetch(GHCompare.class); return compare.wrap(this); } @@ -1378,7 +1432,8 @@ public GHCompare getCompare(GHBranch id1, GHBranch id2) throws IOException { * on failure communicating with GitHub */ public GHRef[] getRefs() throws IOException { - return GHRef.wrap(root.createRequest().withUrlPath(String.format("/repos/%s/%s/git/refs", getOwnerName(), name)) + return GHRef.wrap(root.createRequest() + .withUrlPath(String.format("/repos/%s/%s/git/refs", getOwnerName(), name)) .fetchArray(GHRef[].class), root); } @@ -1433,7 +1488,9 @@ public PagedIterable listRefs(String refType) throws IOException { * on failure communicating with GitHub, potentially due to an invalid ref type being requested */ public GHRef getRef(String refName) throws IOException { - return root.createRequest().withUrlPath(getApiTailUrl(String.format("git/refs/%s", refName))).fetch(GHRef.class) + return root.createRequest() + .withUrlPath(getApiTailUrl(String.format("git/refs/%s", refName))) + .fetch(GHRef.class) .wrap(root); } @@ -1534,7 +1591,9 @@ public InputStream readBlob(String blobSha) throws IOException { String target = getApiTailUrl("git/blobs/" + blobSha); // https://developer.github.com/v3/media/ describes this media type - return root.createRequest().withHeader("Accept", "application/vnd.github.v3.raw").withUrlPath(target) + return root.createRequest() + .withHeader("Accept", "application/vnd.github.v3.raw") + .withUrlPath(target) .fetchStream(); } @@ -1550,8 +1609,10 @@ public InputStream readBlob(String blobSha) throws IOException { public GHCommit getCommit(String sha1) throws IOException { GHCommit c = commits.get(sha1); if (c == null) { - c = root.createRequest().withUrlPath(String.format("/repos/%s/%s/commits/%s", getOwnerName(), name, sha1)) - .fetch(GHCommit.class).wrapUp(this); + c = root.createRequest() + .withUrlPath(String.format("/repos/%s/%s/commits/%s", getOwnerName(), name, sha1)) + .fetch(GHCommit.class) + .wrapUp(this); commits.put(sha1, c); } return c; @@ -1572,7 +1633,8 @@ public GHCommitBuilder createCommit() { * @return the paged iterable */ public PagedIterable listCommits() { - return root.createRequest().withUrlPath(String.format("/repos/%s/%s/commits", getOwnerName(), name)) + return root.createRequest() + .withUrlPath(String.format("/repos/%s/%s/commits", getOwnerName(), name)) .toIterable(GHCommit[].class, item -> item.wrapUp(this)); } @@ -1591,7 +1653,8 @@ public GHCommitQueryBuilder queryCommits() { * @return the paged iterable */ public PagedIterable listCommitComments() { - return root.createRequest().withUrlPath(String.format("/repos/%s/%s/comments", getOwnerName(), name)) + return root.createRequest() + .withUrlPath(String.format("/repos/%s/%s/comments", getOwnerName(), name)) .toIterable(GHCommitComment[].class, item -> item.wrap(this)); } @@ -1622,7 +1685,9 @@ public GHContent getLicenseContent() throws IOException { private GHContentWithLicense getLicenseContent_() throws IOException { try { - return root.createRequest().withUrlPath(getApiTailUrl("license")).fetch(GHContentWithLicense.class) + return root.createRequest() + .withUrlPath(getApiTailUrl("license")) + .fetch(GHContentWithLicense.class) .wrap(this); } catch (FileNotFoundException e) { return null; @@ -1639,7 +1704,8 @@ private GHContentWithLicense getLicenseContent_() throws IOException { * the io exception */ public PagedIterable listCommitStatuses(final String sha1) throws IOException { - return root.createRequest().withUrlPath(String.format("/repos/%s/%s/statuses/%s", getOwnerName(), name, sha1)) + return root.createRequest() + .withUrlPath(String.format("/repos/%s/%s/statuses/%s", getOwnerName(), name, sha1)) .toIterable(GHCommitStatus[].class, item -> item.wrapUp(root)); } @@ -1674,12 +1740,20 @@ public GHCommitStatus getLastCommitStatus(String sha1) throws IOException { * @throws IOException * the io exception */ - public GHCommitStatus createCommitStatus(String sha1, GHCommitState state, String targetUrl, String description, + public GHCommitStatus createCommitStatus(String sha1, + GHCommitState state, + String targetUrl, + String description, String context) throws IOException { - return root.createRequest().method("POST").with("state", state).with("target_url", targetUrl) - .with("description", description).with("context", context) + return root.createRequest() + .method("POST") + .with("state", state) + .with("target_url", targetUrl) + .with("description", description) + .with("context", context) .withUrlPath(String.format("/repos/%s/%s/statuses/%s", getOwnerName(), this.name, sha1)) - .fetch(GHCommitStatus.class).wrapUp(root); + .fetch(GHCommitStatus.class) + .wrapUp(root); } /** @@ -1712,7 +1786,8 @@ public GHCommitStatus createCommitStatus(String sha1, GHCommitState state, Strin * the io exception */ public PagedIterable listEvents() throws IOException { - return root.createRequest().withUrlPath(String.format("/repos/%s/%s/events", getOwnerName(), name)) + return root.createRequest() + .withUrlPath(String.format("/repos/%s/%s/events", getOwnerName(), name)) .toIterable(GHEventInfo[].class, item -> item.wrapUp(root)); } @@ -1726,8 +1801,9 @@ public PagedIterable listEvents() throws IOException { * the io exception */ public PagedIterable listLabels() throws IOException { - return root.createRequest().withUrlPath(getApiTailUrl("labels")).toIterable(GHLabel[].class, - item -> item.wrapUp(this)); + return root.createRequest() + .withUrlPath(getApiTailUrl("labels")) + .toIterable(GHLabel[].class, item -> item.wrapUp(this)); } /** @@ -1772,8 +1848,13 @@ public GHLabel createLabel(String name, String color) throws IOException { * the io exception */ public GHLabel createLabel(String name, String color, String description) throws IOException { - return root.createRequest().method("POST").with("name", name).with("color", color) - .with("description", description).withUrlPath(getApiTailUrl("labels")).fetch(GHLabel.class) + return root.createRequest() + .method("POST") + .with("name", name) + .with("color", color) + .with("description", description) + .withUrlPath(getApiTailUrl("labels")) + .fetch(GHLabel.class) .wrapUp(this); } @@ -1783,7 +1864,8 @@ public GHLabel createLabel(String name, String color, String description) throws * @return the paged iterable */ public PagedIterable listInvitations() { - return root.createRequest().withUrlPath(String.format("/repos/%s/%s/invitations", getOwnerName(), name)) + return root.createRequest() + .withUrlPath(String.format("/repos/%s/%s/invitations", getOwnerName(), name)) .toIterable(GHInvitation[].class, item -> item.wrapUp(root)); } @@ -1815,13 +1897,16 @@ public PagedIterable listStargazers() { * @return the paged iterable */ public PagedIterable listStargazers2() { - return root.createRequest().withPreview("application/vnd.github.v3.star+json") - .withUrlPath(getApiTailUrl("stargazers")).toIterable(GHStargazer[].class, item -> item.wrapUp(this)); + return root.createRequest() + .withPreview("application/vnd.github.v3.star+json") + .withUrlPath(getApiTailUrl("stargazers")) + .toIterable(GHStargazer[].class, item -> item.wrapUp(this)); } private PagedIterable listUsers(final String suffix) { - return root.createRequest().withUrlPath(getApiTailUrl(suffix)).toIterable(GHUser[].class, - item -> item.wrapUp(root)); + return root.createRequest() + .withUrlPath(getApiTailUrl(suffix)) + .toIterable(GHUser[].class, item -> item.wrapUp(root)); } /** @@ -1889,7 +1974,8 @@ public GHHook createWebHook(URL url) throws IOException { * @return the post commit hooks * @deprecated Use {@link #getHooks()} and {@link #createHook(String, Map, Collection, boolean)} */ - @SuppressFBWarnings(value = "DMI_COLLECTION_OF_URLS", justification = "It causes a performance degradation, but we have already exposed it to the API") + @SuppressFBWarnings(value = "DMI_COLLECTION_OF_URLS", + justification = "It causes a performance degradation, but we have already exposed it to the API") public Set getPostCommitHooks() { return postCommitHooks; } @@ -1897,7 +1983,8 @@ public Set getPostCommitHooks() { /** * Live set view of the post-commit hook. */ - @SuppressFBWarnings(value = "DMI_COLLECTION_OF_URLS", justification = "It causes a performance degradation, but we have already exposed it to the API") + @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 postCommitHooks = new AbstractSet() { private List getPostCommitHooks() { @@ -2012,7 +2099,9 @@ public Map getMilestones() throws IOException { * @return the paged iterable */ public PagedIterable listMilestones(final GHIssueState state) { - return root.createRequest().with("state", state).withUrlPath(getApiTailUrl("milestones")) + return root.createRequest() + .with("state", state) + .withUrlPath(getApiTailUrl("milestones")) .toIterable(GHMilestone[].class, item -> item.wrap(this)); } @@ -2217,8 +2306,13 @@ public GHContentUpdateResponse createContent(byte[] contentBytes, String commitM * the io exception */ public GHMilestone createMilestone(String title, String description) throws IOException { - return root.createRequest().method("POST").with("title", title).with("description", description) - .withUrlPath(getApiTailUrl("milestones")).fetch(GHMilestone.class).wrap(this); + return root.createRequest() + .method("POST") + .with("title", title) + .with("description", description) + .withUrlPath(getApiTailUrl("milestones")) + .fetch(GHMilestone.class) + .wrap(this); } /** @@ -2233,8 +2327,13 @@ public GHMilestone createMilestone(String title, String description) throws IOEx * the io exception */ public GHDeployKey addDeployKey(String title, String key) throws IOException { - return root.createRequest().method("POST").with("title", title).with("key", key) - .withUrlPath(getApiTailUrl("keys")).fetch(GHDeployKey.class).wrap(this); + return root.createRequest() + .method("POST") + .with("title", title) + .with("key", key) + .withUrlPath(getApiTailUrl("keys")) + .fetch(GHDeployKey.class) + .wrap(this); } @@ -2300,8 +2399,13 @@ public GHRepository getParent() throws IOException { * the io exception */ public GHSubscription subscribe(boolean subscribed, boolean ignored) throws IOException { - return root.createRequest().method("PUT").with("subscribed", subscribed).with("ignored", ignored) - .withUrlPath(getApiTailUrl("subscription")).fetch(GHSubscription.class).wrapUp(this); + return root.createRequest() + .method("PUT") + .with("subscribed", subscribed) + .with("ignored", ignored) + .withUrlPath(getApiTailUrl("subscription")) + .fetch(GHSubscription.class) + .wrapUp(this); } /** @@ -2313,7 +2417,9 @@ public GHSubscription subscribe(boolean subscribed, boolean ignored) throws IOEx */ public GHSubscription getSubscription() throws IOException { try { - return root.createRequest().withUrlPath(getApiTailUrl("subscription")).fetch(GHSubscription.class) + return root.createRequest() + .withUrlPath(getApiTailUrl("subscription")) + .fetch(GHSubscription.class) .wrapUp(this); } catch (FileNotFoundException e) { return null; @@ -2328,8 +2434,9 @@ public GHSubscription getSubscription() throws IOException { * the io exception */ public PagedIterable listContributors() throws IOException { - return root.createRequest().withUrlPath(getApiTailUrl("contributors")).toIterable(Contributor[].class, - item -> item.wrapUp(root)); + return root.createRequest() + .withUrlPath(getApiTailUrl("contributors")) + .toIterable(Contributor[].class, item -> item.wrapUp(root)); } /** @@ -2383,8 +2490,14 @@ public GHRepositoryStatistics getStatistics() { * the io exception */ public GHProject createProject(String name, String body) throws IOException { - return root.createRequest().method("POST").withPreview(INERTIA).with("name", name).with("body", body) - .withUrlPath(getApiTailUrl("projects")).fetch(GHProject.class).wrap(this); + return root.createRequest() + .method("POST") + .withPreview(INERTIA) + .with("name", name) + .with("body", body) + .withUrlPath(getApiTailUrl("projects")) + .fetch(GHProject.class) + .wrap(this); } /** @@ -2397,7 +2510,10 @@ public GHProject createProject(String name, String body) throws IOException { * the io exception */ public PagedIterable listProjects(final GHProject.ProjectStateFilter status) throws IOException { - return root.createRequest().withPreview(INERTIA).with("state", status).withUrlPath(getApiTailUrl("projects")) + return root.createRequest() + .withPreview(INERTIA) + .with("state", status) + .withUrlPath(getApiTailUrl("projects")) .toIterable(GHProject[].class, item -> item.wrap(this)); } @@ -2427,9 +2543,15 @@ public PagedIterable listProjects() throws IOException { * @see GitHub#renderMarkdown(String) GitHub#renderMarkdown(String) */ public Reader renderMarkdown(String text, MarkdownMode mode) throws IOException { - return new InputStreamReader(root.createRequest().method("POST").with("text", text) - .with("mode", mode == null ? null : mode.toString()).with("context", getFullName()) - .withUrlPath("/markdown").fetchStream(), "UTF-8"); + return new InputStreamReader( + root.createRequest() + .method("POST") + .with("text", text) + .with("mode", mode == null ? null : mode.toString()) + .with("context", getFullName()) + .withUrlPath("/markdown") + .fetchStream(), + "UTF-8"); } /** @@ -2494,8 +2616,9 @@ String getApiTailUrl(String tail) { * the io exception */ public PagedIterable listIssueEvents() throws IOException { - return root.createRequest().withUrlPath(getApiTailUrl("issues/events")).toIterable(GHIssueEvent[].class, - item -> item.wrapUp(root)); + return root.createRequest() + .withUrlPath(getApiTailUrl("issues/events")) + .toIterable(GHIssueEvent[].class, item -> item.wrapUp(root)); } /** @@ -2508,7 +2631,9 @@ public PagedIterable listIssueEvents() throws IOException { * the io exception */ public GHIssueEvent getIssueEvent(long id) throws IOException { - return root.createRequest().withUrlPath(getApiTailUrl("issues/events/" + id)).fetch(GHIssueEvent.class) + return root.createRequest() + .withUrlPath(getApiTailUrl("issues/events/" + id)) + .fetch(GHIssueEvent.class) .wrapUp(root); } @@ -2526,7 +2651,9 @@ private static class Topics { * the io exception */ public List listTopics() throws IOException { - Topics topics = root.createRequest().withPreview(MERCY).withUrlPath(getApiTailUrl("topics")) + Topics topics = root.createRequest() + .withPreview(MERCY) + .withUrlPath(getApiTailUrl("topics")) .fetch(Topics.class); return topics.names; } @@ -2541,7 +2668,11 @@ public List listTopics() throws IOException { * the io exception */ public void setTopics(List topics) throws IOException { - root.createRequest().method("PUT").with("names", topics).withPreview(MERCY).withUrlPath(getApiTailUrl("topics")) + root.createRequest() + .method("PUT") + .with("names", topics) + .withPreview(MERCY) + .withUrlPath(getApiTailUrl("topics")) .send(); } @@ -2561,7 +2692,14 @@ public void setTopics(List topics) throws IOException { * The IO exception. */ public GHTagObject createTag(String tag, String message, String object, String type) throws IOException { - return root.createRequest().method("POST").with("tag", tag).with("message", message).with("object", object) - .with("type", type).withUrlPath(getApiTailUrl("git/tags")).fetch(GHTagObject.class).wrap(this); + return root.createRequest() + .method("POST") + .with("tag", tag) + .with("message", message) + .with("object", object) + .with("type", type) + .withUrlPath(getApiTailUrl("git/tags")) + .fetch(GHTagObject.class) + .wrap(this); } } From 6576beae76186c3f2cdfaa55a83a86c2d58ec8b0 Mon Sep 17 00:00:00 2001 From: James Vaughn Date: Sat, 1 Feb 2020 22:39:14 -0600 Subject: [PATCH 06/11] Added missing methods to keep the API from breaking added tests for addCollaborators() --- .gitignore | 1 + .../java/org/kohsuke/github/GHRepository.java | 24 ++ .../org/kohsuke/github/GHRepositoryTest.java | 17 + ...-355d5cda-5423-49ef-b604-6276fbaba24e.json | 25 ++ ...-e5504dd6-42ca-4d7f-9d95-f224e5f36a90.json | 328 ++++++++++++++++++ ...-4533e6b8-1725-4450-97b1-895a776d49b7.json | 45 +++ .../orgs_github-api-test-org-2-355d5c.json | 45 +++ ...thub-api-test-org_github-api-3-e5504d.json | 45 +++ ..._collaborators_jimmysombrero-4-1bfe02.json | 48 +++ .../mappings/user-1-4533e6.json | 45 +++ ...-0f326a28-7b63-4439-b05b-645236cafd19.json | 45 +++ .../mappings/user-3-0f326a.json | 45 +++ 12 files changed, 713 insertions(+) create mode 100644 src/test/resources/org/kohsuke/github/GHRepositoryTest/wiremock/addCollaborators/__files/orgs_github-api-test-org-355d5cda-5423-49ef-b604-6276fbaba24e.json create mode 100644 src/test/resources/org/kohsuke/github/GHRepositoryTest/wiremock/addCollaborators/__files/repos_github-api-test-org_github-api-e5504dd6-42ca-4d7f-9d95-f224e5f36a90.json create mode 100644 src/test/resources/org/kohsuke/github/GHRepositoryTest/wiremock/addCollaborators/__files/user-4533e6b8-1725-4450-97b1-895a776d49b7.json create mode 100644 src/test/resources/org/kohsuke/github/GHRepositoryTest/wiremock/addCollaborators/mappings/orgs_github-api-test-org-2-355d5c.json create mode 100644 src/test/resources/org/kohsuke/github/GHRepositoryTest/wiremock/addCollaborators/mappings/repos_github-api-test-org_github-api-3-e5504d.json create mode 100644 src/test/resources/org/kohsuke/github/GHRepositoryTest/wiremock/addCollaborators/mappings/repos_github-api-test-org_github-api_collaborators_jimmysombrero-4-1bfe02.json create mode 100644 src/test/resources/org/kohsuke/github/GHRepositoryTest/wiremock/addCollaborators/mappings/user-1-4533e6.json create mode 100644 src/test/resources/org/kohsuke/github/GHRepositoryTest/wiremock/checkWatchersCount/__files/user-0f326a28-7b63-4439-b05b-645236cafd19.json create mode 100644 src/test/resources/org/kohsuke/github/GHRepositoryTest/wiremock/checkWatchersCount/mappings/user-3-0f326a.json diff --git a/.gitignore b/.gitignore index 5d7a7d20df..9fad19dc07 100644 --- a/.gitignore +++ b/.gitignore @@ -9,3 +9,4 @@ target .DS_Store dependency-reduced-pom.xml +.factorypath diff --git a/src/main/java/org/kohsuke/github/GHRepository.java b/src/main/java/org/kohsuke/github/GHRepository.java index 454843b78b..5ac4bcb679 100644 --- a/src/main/java/org/kohsuke/github/GHRepository.java +++ b/src/main/java/org/kohsuke/github/GHRepository.java @@ -852,6 +852,30 @@ public void addCollaborators(GHOrganization.Permission perm, GHUser... users) th addCollaborators(perm, asList(users)); } + /** + * Add collaborators. + * + * @param users + * the users + * @throws IOException + * the io exception + */ + public void addCollaborators(GHUser... users) throws IOException { + addCollaborators(asList(users)); + } + + /** + * Add collaborators. + * + * @param users + * the users + * @throws IOException + * the io exception + */ + public void addCollaborators(List users) throws IOException { + modifyCollaborators(users, "PUT"); + } + /** * Add collaborators. * diff --git a/src/test/java/org/kohsuke/github/GHRepositoryTest.java b/src/test/java/org/kohsuke/github/GHRepositoryTest.java index 9508978eb1..71c811b672 100644 --- a/src/test/java/org/kohsuke/github/GHRepositoryTest.java +++ b/src/test/java/org/kohsuke/github/GHRepositoryTest.java @@ -158,6 +158,23 @@ public void LatestRepositoryExist() { } } + @Test + public void addCollaborators() throws Exception { + GHRepository repo = getRepository(); + GHUser user = getUser(); + List users = new ArrayList(); + + users.add(user); + repo.addCollaborators(GHOrganization.Permission.PUSH, users); + + GHPersonSet collabs = repo.getCollaborators(); + + GHUser colabUser = collabs.byLogin(user.getLogin()); + + assertEquals(colabUser.getName(), user.getName()); + assertEquals(GHOrganization.Permission.PUSH, repo.getPermission(user.getName())); + } + @Test public void LatestRepositoryNotExist() { try { diff --git a/src/test/resources/org/kohsuke/github/GHRepositoryTest/wiremock/addCollaborators/__files/orgs_github-api-test-org-355d5cda-5423-49ef-b604-6276fbaba24e.json b/src/test/resources/org/kohsuke/github/GHRepositoryTest/wiremock/addCollaborators/__files/orgs_github-api-test-org-355d5cda-5423-49ef-b604-6276fbaba24e.json new file mode 100644 index 0000000000..e57a3a127b --- /dev/null +++ b/src/test/resources/org/kohsuke/github/GHRepositoryTest/wiremock/addCollaborators/__files/orgs_github-api-test-org-355d5cda-5423-49ef-b604-6276fbaba24e.json @@ -0,0 +1,25 @@ +{ + "login": "github-api-test-org", + "id": 7544739, + "node_id": "MDEyOk9yZ2FuaXphdGlvbjc1NDQ3Mzk=", + "url": "https://api.github.com/orgs/github-api-test-org", + "repos_url": "https://api.github.com/orgs/github-api-test-org/repos", + "events_url": "https://api.github.com/orgs/github-api-test-org/events", + "hooks_url": "https://api.github.com/orgs/github-api-test-org/hooks", + "issues_url": "https://api.github.com/orgs/github-api-test-org/issues", + "members_url": "https://api.github.com/orgs/github-api-test-org/members{/member}", + "public_members_url": "https://api.github.com/orgs/github-api-test-org/public_members{/member}", + "avatar_url": "https://avatars3.githubusercontent.com/u/7544739?v=4", + "description": null, + "is_verified": false, + "has_organization_projects": true, + "has_repository_projects": true, + "public_repos": 10, + "public_gists": 0, + "followers": 0, + "following": 0, + "html_url": "https://github.com/github-api-test-org", + "created_at": "2014-05-10T19:39:11Z", + "updated_at": "2015-04-20T00:42:30Z", + "type": "Organization" +} \ No newline at end of file diff --git a/src/test/resources/org/kohsuke/github/GHRepositoryTest/wiremock/addCollaborators/__files/repos_github-api-test-org_github-api-e5504dd6-42ca-4d7f-9d95-f224e5f36a90.json b/src/test/resources/org/kohsuke/github/GHRepositoryTest/wiremock/addCollaborators/__files/repos_github-api-test-org_github-api-e5504dd6-42ca-4d7f-9d95-f224e5f36a90.json new file mode 100644 index 0000000000..877714e846 --- /dev/null +++ b/src/test/resources/org/kohsuke/github/GHRepositoryTest/wiremock/addCollaborators/__files/repos_github-api-test-org_github-api-e5504dd6-42ca-4d7f-9d95-f224e5f36a90.json @@ -0,0 +1,328 @@ +{ + "id": 206888201, + "node_id": "MDEwOlJlcG9zaXRvcnkyMDY4ODgyMDE=", + "name": "github-api", + "full_name": "github-api-test-org/github-api", + "private": false, + "owner": { + "login": "github-api-test-org", + "id": 7544739, + "node_id": "MDEyOk9yZ2FuaXphdGlvbjc1NDQ3Mzk=", + "avatar_url": "https://avatars3.githubusercontent.com/u/7544739?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/github-api-test-org", + "html_url": "https://github.com/github-api-test-org", + "followers_url": "https://api.github.com/users/github-api-test-org/followers", + "following_url": "https://api.github.com/users/github-api-test-org/following{/other_user}", + "gists_url": "https://api.github.com/users/github-api-test-org/gists{/gist_id}", + "starred_url": "https://api.github.com/users/github-api-test-org/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/github-api-test-org/subscriptions", + "organizations_url": "https://api.github.com/users/github-api-test-org/orgs", + "repos_url": "https://api.github.com/users/github-api-test-org/repos", + "events_url": "https://api.github.com/users/github-api-test-org/events{/privacy}", + "received_events_url": "https://api.github.com/users/github-api-test-org/received_events", + "type": "Organization", + "site_admin": false + }, + "html_url": "https://github.com/github-api-test-org/github-api", + "description": "Tricky", + "fork": true, + "url": "https://api.github.com/repos/github-api-test-org/github-api", + "forks_url": "https://api.github.com/repos/github-api-test-org/github-api/forks", + "keys_url": "https://api.github.com/repos/github-api-test-org/github-api/keys{/key_id}", + "collaborators_url": "https://api.github.com/repos/github-api-test-org/github-api/collaborators{/collaborator}", + "teams_url": "https://api.github.com/repos/github-api-test-org/github-api/teams", + "hooks_url": "https://api.github.com/repos/github-api-test-org/github-api/hooks", + "issue_events_url": "https://api.github.com/repos/github-api-test-org/github-api/issues/events{/number}", + "events_url": "https://api.github.com/repos/github-api-test-org/github-api/events", + "assignees_url": "https://api.github.com/repos/github-api-test-org/github-api/assignees{/user}", + "branches_url": "https://api.github.com/repos/github-api-test-org/github-api/branches{/branch}", + "tags_url": "https://api.github.com/repos/github-api-test-org/github-api/tags", + "blobs_url": "https://api.github.com/repos/github-api-test-org/github-api/git/blobs{/sha}", + "git_tags_url": "https://api.github.com/repos/github-api-test-org/github-api/git/tags{/sha}", + "git_refs_url": "https://api.github.com/repos/github-api-test-org/github-api/git/refs{/sha}", + "trees_url": "https://api.github.com/repos/github-api-test-org/github-api/git/trees{/sha}", + "statuses_url": "https://api.github.com/repos/github-api-test-org/github-api/statuses/{sha}", + "languages_url": "https://api.github.com/repos/github-api-test-org/github-api/languages", + "stargazers_url": "https://api.github.com/repos/github-api-test-org/github-api/stargazers", + "contributors_url": "https://api.github.com/repos/github-api-test-org/github-api/contributors", + "subscribers_url": "https://api.github.com/repos/github-api-test-org/github-api/subscribers", + "subscription_url": "https://api.github.com/repos/github-api-test-org/github-api/subscription", + "commits_url": "https://api.github.com/repos/github-api-test-org/github-api/commits{/sha}", + "git_commits_url": "https://api.github.com/repos/github-api-test-org/github-api/git/commits{/sha}", + "comments_url": "https://api.github.com/repos/github-api-test-org/github-api/comments{/number}", + "issue_comment_url": "https://api.github.com/repos/github-api-test-org/github-api/issues/comments{/number}", + "contents_url": "https://api.github.com/repos/github-api-test-org/github-api/contents/{+path}", + "compare_url": "https://api.github.com/repos/github-api-test-org/github-api/compare/{base}...{head}", + "merges_url": "https://api.github.com/repos/github-api-test-org/github-api/merges", + "archive_url": "https://api.github.com/repos/github-api-test-org/github-api/{archive_format}{/ref}", + "downloads_url": "https://api.github.com/repos/github-api-test-org/github-api/downloads", + "issues_url": "https://api.github.com/repos/github-api-test-org/github-api/issues{/number}", + "pulls_url": "https://api.github.com/repos/github-api-test-org/github-api/pulls{/number}", + "milestones_url": "https://api.github.com/repos/github-api-test-org/github-api/milestones{/number}", + "notifications_url": "https://api.github.com/repos/github-api-test-org/github-api/notifications{?since,all,participating}", + "labels_url": "https://api.github.com/repos/github-api-test-org/github-api/labels{/name}", + "releases_url": "https://api.github.com/repos/github-api-test-org/github-api/releases{/id}", + "deployments_url": "https://api.github.com/repos/github-api-test-org/github-api/deployments", + "created_at": "2019-09-06T23:26:04Z", + "updated_at": "2020-01-16T21:22:56Z", + "pushed_at": "2020-01-18T00:47:43Z", + "git_url": "git://github.com/github-api-test-org/github-api.git", + "ssh_url": "git@github.com:github-api-test-org/github-api.git", + "clone_url": "https://github.com/github-api-test-org/github-api.git", + "svn_url": "https://github.com/github-api-test-org/github-api", + "homepage": "http://github-api.kohsuke.org/", + "size": 11414, + "stargazers_count": 0, + "watchers_count": 0, + "language": "Java", + "has_issues": true, + "has_projects": true, + "has_downloads": true, + "has_wiki": true, + "has_pages": false, + "forks_count": 0, + "mirror_url": null, + "archived": false, + "disabled": false, + "open_issues_count": 0, + "license": { + "key": "mit", + "name": "MIT License", + "spdx_id": "MIT", + "url": "https://api.github.com/licenses/mit", + "node_id": "MDc6TGljZW5zZTEz" + }, + "forks": 0, + "open_issues": 0, + "watchers": 0, + "default_branch": "master", + "permissions": { + "admin": false, + "push": false, + "pull": true + }, + "temp_clone_token": "", + "organization": { + "login": "github-api-test-org", + "id": 7544739, + "node_id": "MDEyOk9yZ2FuaXphdGlvbjc1NDQ3Mzk=", + "avatar_url": "https://avatars3.githubusercontent.com/u/7544739?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/github-api-test-org", + "html_url": "https://github.com/github-api-test-org", + "followers_url": "https://api.github.com/users/github-api-test-org/followers", + "following_url": "https://api.github.com/users/github-api-test-org/following{/other_user}", + "gists_url": "https://api.github.com/users/github-api-test-org/gists{/gist_id}", + "starred_url": "https://api.github.com/users/github-api-test-org/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/github-api-test-org/subscriptions", + "organizations_url": "https://api.github.com/users/github-api-test-org/orgs", + "repos_url": "https://api.github.com/users/github-api-test-org/repos", + "events_url": "https://api.github.com/users/github-api-test-org/events{/privacy}", + "received_events_url": "https://api.github.com/users/github-api-test-org/received_events", + "type": "Organization", + "site_admin": false + }, + "parent": { + "id": 617210, + "node_id": "MDEwOlJlcG9zaXRvcnk2MTcyMTA=", + "name": "github-api", + "full_name": "github-api/github-api", + "private": false, + "owner": { + "login": "github-api", + "id": 54909825, + "node_id": "MDEyOk9yZ2FuaXphdGlvbjU0OTA5ODI1", + "avatar_url": "https://avatars3.githubusercontent.com/u/54909825?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/github-api", + "html_url": "https://github.com/github-api", + "followers_url": "https://api.github.com/users/github-api/followers", + "following_url": "https://api.github.com/users/github-api/following{/other_user}", + "gists_url": "https://api.github.com/users/github-api/gists{/gist_id}", + "starred_url": "https://api.github.com/users/github-api/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/github-api/subscriptions", + "organizations_url": "https://api.github.com/users/github-api/orgs", + "repos_url": "https://api.github.com/users/github-api/repos", + "events_url": "https://api.github.com/users/github-api/events{/privacy}", + "received_events_url": "https://api.github.com/users/github-api/received_events", + "type": "Organization", + "site_admin": false + }, + "html_url": "https://github.com/github-api/github-api", + "description": "Java API for GitHub", + "fork": false, + "url": "https://api.github.com/repos/github-api/github-api", + "forks_url": "https://api.github.com/repos/github-api/github-api/forks", + "keys_url": "https://api.github.com/repos/github-api/github-api/keys{/key_id}", + "collaborators_url": "https://api.github.com/repos/github-api/github-api/collaborators{/collaborator}", + "teams_url": "https://api.github.com/repos/github-api/github-api/teams", + "hooks_url": "https://api.github.com/repos/github-api/github-api/hooks", + "issue_events_url": "https://api.github.com/repos/github-api/github-api/issues/events{/number}", + "events_url": "https://api.github.com/repos/github-api/github-api/events", + "assignees_url": "https://api.github.com/repos/github-api/github-api/assignees{/user}", + "branches_url": "https://api.github.com/repos/github-api/github-api/branches{/branch}", + "tags_url": "https://api.github.com/repos/github-api/github-api/tags", + "blobs_url": "https://api.github.com/repos/github-api/github-api/git/blobs{/sha}", + "git_tags_url": "https://api.github.com/repos/github-api/github-api/git/tags{/sha}", + "git_refs_url": "https://api.github.com/repos/github-api/github-api/git/refs{/sha}", + "trees_url": "https://api.github.com/repos/github-api/github-api/git/trees{/sha}", + "statuses_url": "https://api.github.com/repos/github-api/github-api/statuses/{sha}", + "languages_url": "https://api.github.com/repos/github-api/github-api/languages", + "stargazers_url": "https://api.github.com/repos/github-api/github-api/stargazers", + "contributors_url": "https://api.github.com/repos/github-api/github-api/contributors", + "subscribers_url": "https://api.github.com/repos/github-api/github-api/subscribers", + "subscription_url": "https://api.github.com/repos/github-api/github-api/subscription", + "commits_url": "https://api.github.com/repos/github-api/github-api/commits{/sha}", + "git_commits_url": "https://api.github.com/repos/github-api/github-api/git/commits{/sha}", + "comments_url": "https://api.github.com/repos/github-api/github-api/comments{/number}", + "issue_comment_url": "https://api.github.com/repos/github-api/github-api/issues/comments{/number}", + "contents_url": "https://api.github.com/repos/github-api/github-api/contents/{+path}", + "compare_url": "https://api.github.com/repos/github-api/github-api/compare/{base}...{head}", + "merges_url": "https://api.github.com/repos/github-api/github-api/merges", + "archive_url": "https://api.github.com/repos/github-api/github-api/{archive_format}{/ref}", + "downloads_url": "https://api.github.com/repos/github-api/github-api/downloads", + "issues_url": "https://api.github.com/repos/github-api/github-api/issues{/number}", + "pulls_url": "https://api.github.com/repos/github-api/github-api/pulls{/number}", + "milestones_url": "https://api.github.com/repos/github-api/github-api/milestones{/number}", + "notifications_url": "https://api.github.com/repos/github-api/github-api/notifications{?since,all,participating}", + "labels_url": "https://api.github.com/repos/github-api/github-api/labels{/name}", + "releases_url": "https://api.github.com/repos/github-api/github-api/releases{/id}", + "deployments_url": "https://api.github.com/repos/github-api/github-api/deployments", + "created_at": "2010-04-19T04:13:03Z", + "updated_at": "2020-02-01T02:00:03Z", + "pushed_at": "2020-01-31T21:18:18Z", + "git_url": "git://github.com/github-api/github-api.git", + "ssh_url": "git@github.com:github-api/github-api.git", + "clone_url": "https://github.com/github-api/github-api.git", + "svn_url": "https://github.com/github-api/github-api", + "homepage": "https://github-api.kohsuke.org/", + "size": 19341, + "stargazers_count": 607, + "watchers_count": 607, + "language": "Java", + "has_issues": true, + "has_projects": true, + "has_downloads": true, + "has_wiki": true, + "has_pages": true, + "forks_count": 450, + "mirror_url": null, + "archived": false, + "disabled": false, + "open_issues_count": 54, + "license": { + "key": "mit", + "name": "MIT License", + "spdx_id": "MIT", + "url": "https://api.github.com/licenses/mit", + "node_id": "MDc6TGljZW5zZTEz" + }, + "forks": 450, + "open_issues": 54, + "watchers": 607, + "default_branch": "master" + }, + "source": { + "id": 617210, + "node_id": "MDEwOlJlcG9zaXRvcnk2MTcyMTA=", + "name": "github-api", + "full_name": "github-api/github-api", + "private": false, + "owner": { + "login": "github-api", + "id": 54909825, + "node_id": "MDEyOk9yZ2FuaXphdGlvbjU0OTA5ODI1", + "avatar_url": "https://avatars3.githubusercontent.com/u/54909825?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/github-api", + "html_url": "https://github.com/github-api", + "followers_url": "https://api.github.com/users/github-api/followers", + "following_url": "https://api.github.com/users/github-api/following{/other_user}", + "gists_url": "https://api.github.com/users/github-api/gists{/gist_id}", + "starred_url": "https://api.github.com/users/github-api/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/github-api/subscriptions", + "organizations_url": "https://api.github.com/users/github-api/orgs", + "repos_url": "https://api.github.com/users/github-api/repos", + "events_url": "https://api.github.com/users/github-api/events{/privacy}", + "received_events_url": "https://api.github.com/users/github-api/received_events", + "type": "Organization", + "site_admin": false + }, + "html_url": "https://github.com/github-api/github-api", + "description": "Java API for GitHub", + "fork": false, + "url": "https://api.github.com/repos/github-api/github-api", + "forks_url": "https://api.github.com/repos/github-api/github-api/forks", + "keys_url": "https://api.github.com/repos/github-api/github-api/keys{/key_id}", + "collaborators_url": "https://api.github.com/repos/github-api/github-api/collaborators{/collaborator}", + "teams_url": "https://api.github.com/repos/github-api/github-api/teams", + "hooks_url": "https://api.github.com/repos/github-api/github-api/hooks", + "issue_events_url": "https://api.github.com/repos/github-api/github-api/issues/events{/number}", + "events_url": "https://api.github.com/repos/github-api/github-api/events", + "assignees_url": "https://api.github.com/repos/github-api/github-api/assignees{/user}", + "branches_url": "https://api.github.com/repos/github-api/github-api/branches{/branch}", + "tags_url": "https://api.github.com/repos/github-api/github-api/tags", + "blobs_url": "https://api.github.com/repos/github-api/github-api/git/blobs{/sha}", + "git_tags_url": "https://api.github.com/repos/github-api/github-api/git/tags{/sha}", + "git_refs_url": "https://api.github.com/repos/github-api/github-api/git/refs{/sha}", + "trees_url": "https://api.github.com/repos/github-api/github-api/git/trees{/sha}", + "statuses_url": "https://api.github.com/repos/github-api/github-api/statuses/{sha}", + "languages_url": "https://api.github.com/repos/github-api/github-api/languages", + "stargazers_url": "https://api.github.com/repos/github-api/github-api/stargazers", + "contributors_url": "https://api.github.com/repos/github-api/github-api/contributors", + "subscribers_url": "https://api.github.com/repos/github-api/github-api/subscribers", + "subscription_url": "https://api.github.com/repos/github-api/github-api/subscription", + "commits_url": "https://api.github.com/repos/github-api/github-api/commits{/sha}", + "git_commits_url": "https://api.github.com/repos/github-api/github-api/git/commits{/sha}", + "comments_url": "https://api.github.com/repos/github-api/github-api/comments{/number}", + "issue_comment_url": "https://api.github.com/repos/github-api/github-api/issues/comments{/number}", + "contents_url": "https://api.github.com/repos/github-api/github-api/contents/{+path}", + "compare_url": "https://api.github.com/repos/github-api/github-api/compare/{base}...{head}", + "merges_url": "https://api.github.com/repos/github-api/github-api/merges", + "archive_url": "https://api.github.com/repos/github-api/github-api/{archive_format}{/ref}", + "downloads_url": "https://api.github.com/repos/github-api/github-api/downloads", + "issues_url": "https://api.github.com/repos/github-api/github-api/issues{/number}", + "pulls_url": "https://api.github.com/repos/github-api/github-api/pulls{/number}", + "milestones_url": "https://api.github.com/repos/github-api/github-api/milestones{/number}", + "notifications_url": "https://api.github.com/repos/github-api/github-api/notifications{?since,all,participating}", + "labels_url": "https://api.github.com/repos/github-api/github-api/labels{/name}", + "releases_url": "https://api.github.com/repos/github-api/github-api/releases{/id}", + "deployments_url": "https://api.github.com/repos/github-api/github-api/deployments", + "created_at": "2010-04-19T04:13:03Z", + "updated_at": "2020-02-01T02:00:03Z", + "pushed_at": "2020-01-31T21:18:18Z", + "git_url": "git://github.com/github-api/github-api.git", + "ssh_url": "git@github.com:github-api/github-api.git", + "clone_url": "https://github.com/github-api/github-api.git", + "svn_url": "https://github.com/github-api/github-api", + "homepage": "https://github-api.kohsuke.org/", + "size": 19341, + "stargazers_count": 607, + "watchers_count": 607, + "language": "Java", + "has_issues": true, + "has_projects": true, + "has_downloads": true, + "has_wiki": true, + "has_pages": true, + "forks_count": 450, + "mirror_url": null, + "archived": false, + "disabled": false, + "open_issues_count": 54, + "license": { + "key": "mit", + "name": "MIT License", + "spdx_id": "MIT", + "url": "https://api.github.com/licenses/mit", + "node_id": "MDc6TGljZW5zZTEz" + }, + "forks": 450, + "open_issues": 54, + "watchers": 607, + "default_branch": "master" + }, + "network_count": 450, + "subscribers_count": 0 +} \ No newline at end of file diff --git a/src/test/resources/org/kohsuke/github/GHRepositoryTest/wiremock/addCollaborators/__files/user-4533e6b8-1725-4450-97b1-895a776d49b7.json b/src/test/resources/org/kohsuke/github/GHRepositoryTest/wiremock/addCollaborators/__files/user-4533e6b8-1725-4450-97b1-895a776d49b7.json new file mode 100644 index 0000000000..c01fae6620 --- /dev/null +++ b/src/test/resources/org/kohsuke/github/GHRepositoryTest/wiremock/addCollaborators/__files/user-4533e6b8-1725-4450-97b1-895a776d49b7.json @@ -0,0 +1,45 @@ +{ + "login": "jimmysombrero", + "id": 12157727, + "node_id": "MDQ6VXNlcjEyMTU3NzI3", + "avatar_url": "https://avatars3.githubusercontent.com/u/12157727?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/jimmysombrero", + "html_url": "https://github.com/jimmysombrero", + "followers_url": "https://api.github.com/users/jimmysombrero/followers", + "following_url": "https://api.github.com/users/jimmysombrero/following{/other_user}", + "gists_url": "https://api.github.com/users/jimmysombrero/gists{/gist_id}", + "starred_url": "https://api.github.com/users/jimmysombrero/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/jimmysombrero/subscriptions", + "organizations_url": "https://api.github.com/users/jimmysombrero/orgs", + "repos_url": "https://api.github.com/users/jimmysombrero/repos", + "events_url": "https://api.github.com/users/jimmysombrero/events{/privacy}", + "received_events_url": "https://api.github.com/users/jimmysombrero/received_events", + "type": "User", + "site_admin": false, + "name": null, + "company": null, + "blog": "", + "location": null, + "email": null, + "hireable": null, + "bio": null, + "public_repos": 4, + "public_gists": 0, + "followers": 1, + "following": 0, + "created_at": "2015-04-28T17:47:19Z", + "updated_at": "2020-02-02T04:15:35Z", + "private_gists": 0, + "total_private_repos": 0, + "owned_private_repos": 0, + "disk_usage": 19, + "collaborators": 0, + "two_factor_authentication": false, + "plan": { + "name": "free", + "space": 976562499, + "collaborators": 0, + "private_repos": 10000 + } +} \ No newline at end of file diff --git a/src/test/resources/org/kohsuke/github/GHRepositoryTest/wiremock/addCollaborators/mappings/orgs_github-api-test-org-2-355d5c.json b/src/test/resources/org/kohsuke/github/GHRepositoryTest/wiremock/addCollaborators/mappings/orgs_github-api-test-org-2-355d5c.json new file mode 100644 index 0000000000..f329cbf5b8 --- /dev/null +++ b/src/test/resources/org/kohsuke/github/GHRepositoryTest/wiremock/addCollaborators/mappings/orgs_github-api-test-org-2-355d5c.json @@ -0,0 +1,45 @@ +{ + "id": "355d5cda-5423-49ef-b604-6276fbaba24e", + "name": "orgs_github-api-test-org", + "request": { + "url": "/orgs/github-api-test-org", + "method": "GET", + "headers": { + "Accept": { + "equalTo": "text/html, image/gif, image/jpeg, *; q=.2, */*; q=.2" + } + } + }, + "response": { + "status": 200, + "bodyFileName": "orgs_github-api-test-org-355d5cda-5423-49ef-b604-6276fbaba24e.json", + "headers": { + "Server": "GitHub.com", + "Date": "Sun, 02 Feb 2020 04:29:45 GMT", + "Content-Type": "application/json; charset=utf-8", + "Status": "200 OK", + "X-RateLimit-Limit": "5000", + "X-RateLimit-Remaining": "4951", + "X-RateLimit-Reset": "1580620984", + "Cache-Control": "private, max-age=60, s-maxage=60", + "Vary": "Accept, Authorization, Cookie, X-GitHub-OTP", + "ETag": "W/\"7883ff712872fc993ac511231d8f8c6d\"", + "Last-Modified": "Mon, 20 Apr 2015 00:42:30 GMT", + "X-OAuth-Scopes": "admin:enterprise, admin:gpg_key, admin:org, admin:org_hook, admin:public_key, admin:repo_hook, delete:packages, delete_repo, gist, notifications, read:packages, repo, user, workflow, write:discussion, write:packages", + "X-Accepted-OAuth-Scopes": "admin:org, read:org, repo, user, write:org", + "X-GitHub-Media-Type": "unknown, github.v3", + "Access-Control-Expose-Headers": "ETag, Link, Location, Retry-After, X-GitHub-OTP, X-RateLimit-Limit, X-RateLimit-Remaining, X-RateLimit-Reset, X-OAuth-Scopes, X-Accepted-OAuth-Scopes, X-Poll-Interval, X-GitHub-Media-Type", + "Access-Control-Allow-Origin": "*", + "Strict-Transport-Security": "max-age=31536000; includeSubdomains; preload", + "X-Frame-Options": "deny", + "X-Content-Type-Options": "nosniff", + "X-XSS-Protection": "1; mode=block", + "Referrer-Policy": "origin-when-cross-origin, strict-origin-when-cross-origin", + "Content-Security-Policy": "default-src 'none'", + "X-GitHub-Request-Id": "C7DB:0D8E:63D359:C9F18B:5E365038" + } + }, + "uuid": "355d5cda-5423-49ef-b604-6276fbaba24e", + "persistent": true, + "insertionIndex": 2 +} \ No newline at end of file diff --git a/src/test/resources/org/kohsuke/github/GHRepositoryTest/wiremock/addCollaborators/mappings/repos_github-api-test-org_github-api-3-e5504d.json b/src/test/resources/org/kohsuke/github/GHRepositoryTest/wiremock/addCollaborators/mappings/repos_github-api-test-org_github-api-3-e5504d.json new file mode 100644 index 0000000000..97061665aa --- /dev/null +++ b/src/test/resources/org/kohsuke/github/GHRepositoryTest/wiremock/addCollaborators/mappings/repos_github-api-test-org_github-api-3-e5504d.json @@ -0,0 +1,45 @@ +{ + "id": "e5504dd6-42ca-4d7f-9d95-f224e5f36a90", + "name": "repos_github-api-test-org_github-api", + "request": { + "url": "/repos/github-api-test-org/github-api", + "method": "GET", + "headers": { + "Accept": { + "equalTo": "text/html, image/gif, image/jpeg, *; q=.2, */*; q=.2" + } + } + }, + "response": { + "status": 200, + "bodyFileName": "repos_github-api-test-org_github-api-e5504dd6-42ca-4d7f-9d95-f224e5f36a90.json", + "headers": { + "Server": "GitHub.com", + "Date": "Sun, 02 Feb 2020 04:29:45 GMT", + "Content-Type": "application/json; charset=utf-8", + "Status": "200 OK", + "X-RateLimit-Limit": "5000", + "X-RateLimit-Remaining": "4950", + "X-RateLimit-Reset": "1580620984", + "Cache-Control": "private, max-age=60, s-maxage=60", + "Vary": "Accept, Authorization, Cookie, X-GitHub-OTP", + "ETag": "W/\"c310cb7abd9a90e105810461c34dd8c6\"", + "Last-Modified": "Thu, 16 Jan 2020 21:22:56 GMT", + "X-OAuth-Scopes": "admin:enterprise, admin:gpg_key, admin:org, admin:org_hook, admin:public_key, admin:repo_hook, delete:packages, delete_repo, gist, notifications, read:packages, repo, user, workflow, write:discussion, write:packages", + "X-Accepted-OAuth-Scopes": "repo", + "X-GitHub-Media-Type": "unknown, github.v3", + "Access-Control-Expose-Headers": "ETag, Link, Location, Retry-After, X-GitHub-OTP, X-RateLimit-Limit, X-RateLimit-Remaining, X-RateLimit-Reset, X-OAuth-Scopes, X-Accepted-OAuth-Scopes, X-Poll-Interval, X-GitHub-Media-Type", + "Access-Control-Allow-Origin": "*", + "Strict-Transport-Security": "max-age=31536000; includeSubdomains; preload", + "X-Frame-Options": "deny", + "X-Content-Type-Options": "nosniff", + "X-XSS-Protection": "1; mode=block", + "Referrer-Policy": "origin-when-cross-origin, strict-origin-when-cross-origin", + "Content-Security-Policy": "default-src 'none'", + "X-GitHub-Request-Id": "C7DB:0D8E:63D35D:C9F1A2:5E365039" + } + }, + "uuid": "e5504dd6-42ca-4d7f-9d95-f224e5f36a90", + "persistent": true, + "insertionIndex": 3 +} \ No newline at end of file diff --git a/src/test/resources/org/kohsuke/github/GHRepositoryTest/wiremock/addCollaborators/mappings/repos_github-api-test-org_github-api_collaborators_jimmysombrero-4-1bfe02.json b/src/test/resources/org/kohsuke/github/GHRepositoryTest/wiremock/addCollaborators/mappings/repos_github-api-test-org_github-api_collaborators_jimmysombrero-4-1bfe02.json new file mode 100644 index 0000000000..7862bede8b --- /dev/null +++ b/src/test/resources/org/kohsuke/github/GHRepositoryTest/wiremock/addCollaborators/mappings/repos_github-api-test-org_github-api_collaborators_jimmysombrero-4-1bfe02.json @@ -0,0 +1,48 @@ +{ + "id": "1bfe0280-5533-459c-8515-57f70bed0d04", + "name": "repos_github-api-test-org_github-api_collaborators_jimmysombrero", + "request": { + "url": "/repos/github-api-test-org/github-api/collaborators/jimmysombrero", + "method": "PUT", + "headers": { + "Accept": { + "equalTo": "text/html, image/gif, image/jpeg, *; q=.2, */*; q=.2" + } + }, + "bodyPatterns": [ + { + "equalToJson": "{\"permission\":\"push\"}", + "ignoreArrayOrder": true, + "ignoreExtraElements": true + } + ] + }, + "response": { + "status": 404, + "body": "{\"message\":\"Not Found\",\"documentation_url\":\"https://developer.github.com/v3/repos/collaborators/#add-user-as-a-collaborator\"}", + "headers": { + "Server": "GitHub.com", + "Date": "Sun, 02 Feb 2020 04:29:45 GMT", + "Content-Type": "application/json; charset=utf-8", + "Status": "404 Not Found", + "X-RateLimit-Limit": "5000", + "X-RateLimit-Remaining": "4949", + "X-RateLimit-Reset": "1580620984", + "X-OAuth-Scopes": "admin:enterprise, admin:gpg_key, admin:org, admin:org_hook, admin:public_key, admin:repo_hook, delete:packages, delete_repo, gist, notifications, read:packages, repo, user, workflow, write:discussion, write:packages", + "X-Accepted-OAuth-Scopes": "", + "X-GitHub-Media-Type": "unknown, github.v3", + "Access-Control-Expose-Headers": "ETag, Link, Location, Retry-After, X-GitHub-OTP, X-RateLimit-Limit, X-RateLimit-Remaining, X-RateLimit-Reset, X-OAuth-Scopes, X-Accepted-OAuth-Scopes, X-Poll-Interval, X-GitHub-Media-Type", + "Access-Control-Allow-Origin": "*", + "Strict-Transport-Security": "max-age=31536000; includeSubdomains; preload", + "X-Frame-Options": "deny", + "X-Content-Type-Options": "nosniff", + "X-XSS-Protection": "1; mode=block", + "Referrer-Policy": "origin-when-cross-origin, strict-origin-when-cross-origin", + "Content-Security-Policy": "default-src 'none'", + "X-GitHub-Request-Id": "C7DB:0D8E:63D367:C9F1B5:5E365039" + } + }, + "uuid": "1bfe0280-5533-459c-8515-57f70bed0d04", + "persistent": true, + "insertionIndex": 4 +} \ No newline at end of file diff --git a/src/test/resources/org/kohsuke/github/GHRepositoryTest/wiremock/addCollaborators/mappings/user-1-4533e6.json b/src/test/resources/org/kohsuke/github/GHRepositoryTest/wiremock/addCollaborators/mappings/user-1-4533e6.json new file mode 100644 index 0000000000..84cb10ec8a --- /dev/null +++ b/src/test/resources/org/kohsuke/github/GHRepositoryTest/wiremock/addCollaborators/mappings/user-1-4533e6.json @@ -0,0 +1,45 @@ +{ + "id": "4533e6b8-1725-4450-97b1-895a776d49b7", + "name": "user", + "request": { + "url": "/user", + "method": "GET", + "headers": { + "Accept": { + "equalTo": "text/html, image/gif, image/jpeg, *; q=.2, */*; q=.2" + } + } + }, + "response": { + "status": 200, + "bodyFileName": "user-4533e6b8-1725-4450-97b1-895a776d49b7.json", + "headers": { + "Server": "GitHub.com", + "Date": "Sun, 02 Feb 2020 04:29:44 GMT", + "Content-Type": "application/json; charset=utf-8", + "Status": "200 OK", + "X-RateLimit-Limit": "5000", + "X-RateLimit-Remaining": "4953", + "X-RateLimit-Reset": "1580620983", + "Cache-Control": "private, max-age=60, s-maxage=60", + "Vary": "Accept, Authorization, Cookie, X-GitHub-OTP", + "ETag": "W/\"275d33915a65ed3fa77d5fed34147440\"", + "Last-Modified": "Sun, 02 Feb 2020 04:15:35 GMT", + "X-OAuth-Scopes": "admin:enterprise, admin:gpg_key, admin:org, admin:org_hook, admin:public_key, admin:repo_hook, delete:packages, delete_repo, gist, notifications, read:packages, repo, user, workflow, write:discussion, write:packages", + "X-Accepted-OAuth-Scopes": "", + "X-GitHub-Media-Type": "unknown, github.v3", + "Access-Control-Expose-Headers": "ETag, Link, Location, Retry-After, X-GitHub-OTP, X-RateLimit-Limit, X-RateLimit-Remaining, X-RateLimit-Reset, X-OAuth-Scopes, X-Accepted-OAuth-Scopes, X-Poll-Interval, X-GitHub-Media-Type", + "Access-Control-Allow-Origin": "*", + "Strict-Transport-Security": "max-age=31536000; includeSubdomains; preload", + "X-Frame-Options": "deny", + "X-Content-Type-Options": "nosniff", + "X-XSS-Protection": "1; mode=block", + "Referrer-Policy": "origin-when-cross-origin, strict-origin-when-cross-origin", + "Content-Security-Policy": "default-src 'none'", + "X-GitHub-Request-Id": "C7DB:0D8E:63D34F:C9F17E:5E365038" + } + }, + "uuid": "4533e6b8-1725-4450-97b1-895a776d49b7", + "persistent": true, + "insertionIndex": 1 +} \ No newline at end of file diff --git a/src/test/resources/org/kohsuke/github/GHRepositoryTest/wiremock/checkWatchersCount/__files/user-0f326a28-7b63-4439-b05b-645236cafd19.json b/src/test/resources/org/kohsuke/github/GHRepositoryTest/wiremock/checkWatchersCount/__files/user-0f326a28-7b63-4439-b05b-645236cafd19.json new file mode 100644 index 0000000000..c01fae6620 --- /dev/null +++ b/src/test/resources/org/kohsuke/github/GHRepositoryTest/wiremock/checkWatchersCount/__files/user-0f326a28-7b63-4439-b05b-645236cafd19.json @@ -0,0 +1,45 @@ +{ + "login": "jimmysombrero", + "id": 12157727, + "node_id": "MDQ6VXNlcjEyMTU3NzI3", + "avatar_url": "https://avatars3.githubusercontent.com/u/12157727?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/jimmysombrero", + "html_url": "https://github.com/jimmysombrero", + "followers_url": "https://api.github.com/users/jimmysombrero/followers", + "following_url": "https://api.github.com/users/jimmysombrero/following{/other_user}", + "gists_url": "https://api.github.com/users/jimmysombrero/gists{/gist_id}", + "starred_url": "https://api.github.com/users/jimmysombrero/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/jimmysombrero/subscriptions", + "organizations_url": "https://api.github.com/users/jimmysombrero/orgs", + "repos_url": "https://api.github.com/users/jimmysombrero/repos", + "events_url": "https://api.github.com/users/jimmysombrero/events{/privacy}", + "received_events_url": "https://api.github.com/users/jimmysombrero/received_events", + "type": "User", + "site_admin": false, + "name": null, + "company": null, + "blog": "", + "location": null, + "email": null, + "hireable": null, + "bio": null, + "public_repos": 4, + "public_gists": 0, + "followers": 1, + "following": 0, + "created_at": "2015-04-28T17:47:19Z", + "updated_at": "2020-02-02T04:15:35Z", + "private_gists": 0, + "total_private_repos": 0, + "owned_private_repos": 0, + "disk_usage": 19, + "collaborators": 0, + "two_factor_authentication": false, + "plan": { + "name": "free", + "space": 976562499, + "collaborators": 0, + "private_repos": 10000 + } +} \ No newline at end of file diff --git a/src/test/resources/org/kohsuke/github/GHRepositoryTest/wiremock/checkWatchersCount/mappings/user-3-0f326a.json b/src/test/resources/org/kohsuke/github/GHRepositoryTest/wiremock/checkWatchersCount/mappings/user-3-0f326a.json new file mode 100644 index 0000000000..93fb07e81f --- /dev/null +++ b/src/test/resources/org/kohsuke/github/GHRepositoryTest/wiremock/checkWatchersCount/mappings/user-3-0f326a.json @@ -0,0 +1,45 @@ +{ + "id": "0f326a28-7b63-4439-b05b-645236cafd19", + "name": "user", + "request": { + "url": "/user", + "method": "GET", + "headers": { + "Accept": { + "equalTo": "text/html, image/gif, image/jpeg, *; q=.2, */*; q=.2" + } + } + }, + "response": { + "status": 200, + "bodyFileName": "user-0f326a28-7b63-4439-b05b-645236cafd19.json", + "headers": { + "Server": "GitHub.com", + "Date": "Sun, 02 Feb 2020 04:29:51 GMT", + "Content-Type": "application/json; charset=utf-8", + "Status": "200 OK", + "X-RateLimit-Limit": "5000", + "X-RateLimit-Remaining": "4922", + "X-RateLimit-Reset": "1580620984", + "Cache-Control": "private, max-age=60, s-maxage=60", + "Vary": "Accept, Authorization, Cookie, X-GitHub-OTP", + "ETag": "W/\"275d33915a65ed3fa77d5fed34147440\"", + "Last-Modified": "Sun, 02 Feb 2020 04:15:35 GMT", + "X-OAuth-Scopes": "admin:enterprise, admin:gpg_key, admin:org, admin:org_hook, admin:public_key, admin:repo_hook, delete:packages, delete_repo, gist, notifications, read:packages, repo, user, workflow, write:discussion, write:packages", + "X-Accepted-OAuth-Scopes": "", + "X-GitHub-Media-Type": "unknown, github.v3", + "Access-Control-Expose-Headers": "ETag, Link, Location, Retry-After, X-GitHub-OTP, X-RateLimit-Limit, X-RateLimit-Remaining, X-RateLimit-Reset, X-OAuth-Scopes, X-Accepted-OAuth-Scopes, X-Poll-Interval, X-GitHub-Media-Type", + "Access-Control-Allow-Origin": "*", + "Strict-Transport-Security": "max-age=31536000; includeSubdomains; preload", + "X-Frame-Options": "deny", + "X-Content-Type-Options": "nosniff", + "X-XSS-Protection": "1; mode=block", + "Referrer-Policy": "origin-when-cross-origin, strict-origin-when-cross-origin", + "Content-Security-Policy": "default-src 'none'", + "X-GitHub-Request-Id": "C819:07AB:4E26A4:A432C4:5E36503F" + } + }, + "uuid": "0f326a28-7b63-4439-b05b-645236cafd19", + "persistent": true, + "insertionIndex": 3 +} \ No newline at end of file From d767575f7646c369b1fe375651bd61ea161f06f0 Mon Sep 17 00:00:00 2001 From: James Vaughn Date: Sun, 2 Feb 2020 22:02:56 -0600 Subject: [PATCH 07/11] Added test for addCollaborators Mark old addCollaborators methods depricated --- .gitignore | 1 + .../java/org/kohsuke/github/GHRepository.java | 2 + .../org/kohsuke/github/GHRepositoryTest.java | 3 +- ...a3d2b552-58b8-4028-b731-d00420496ca8.json} | 0 ...95ce4098-4e40-49f0-8661-0870614d5d78.json} | 4 +- ...github-api_get_collaborators-5-ddaa82.json | 27 +++++++++++ ...f20ea960-c1f4-440c-bdc1-a605956a351a.json} | 2 +- ...-6685376c-451b-486d-88cd-502af9a7c5d1.json | 45 +++++++++++++++++++ ...=> orgs_github-api-test-org-1-a3d2b5.json} | 14 +++--- ...hub-api-test-org_github-api-2-95ce40.json} | 18 ++++---- ...org_github-api_collaborators-5-ddaa82.json | 41 +++++++++++++++++ ...collaborators_jimmysombrero-4-3d80b1.json} | 18 ++++---- ...{user-1-4533e6.json => user-3-f20ea9.json} | 18 ++++---- .../users_jimmysombrero-6-668537.json | 45 +++++++++++++++++++ 14 files changed, 199 insertions(+), 39 deletions(-) rename src/test/resources/org/kohsuke/github/GHRepositoryTest/wiremock/addCollaborators/__files/{orgs_github-api-test-org-355d5cda-5423-49ef-b604-6276fbaba24e.json => orgs_github-api-test-org-a3d2b552-58b8-4028-b731-d00420496ca8.json} (100%) rename src/test/resources/org/kohsuke/github/GHRepositoryTest/wiremock/addCollaborators/__files/{repos_github-api-test-org_github-api-e5504dd6-42ca-4d7f-9d95-f224e5f36a90.json => repos_github-api-test-org_github-api-95ce4098-4e40-49f0-8661-0870614d5d78.json} (99%) create mode 100644 src/test/resources/org/kohsuke/github/GHRepositoryTest/wiremock/addCollaborators/__files/repos_github-apit-test-ort_github-api_get_collaborators-5-ddaa82.json rename src/test/resources/org/kohsuke/github/GHRepositoryTest/wiremock/addCollaborators/__files/{user-4533e6b8-1725-4450-97b1-895a776d49b7.json => user-f20ea960-c1f4-440c-bdc1-a605956a351a.json} (97%) create mode 100644 src/test/resources/org/kohsuke/github/GHRepositoryTest/wiremock/addCollaborators/__files/users_jimmysombrero-6685376c-451b-486d-88cd-502af9a7c5d1.json rename src/test/resources/org/kohsuke/github/GHRepositoryTest/wiremock/addCollaborators/mappings/{orgs_github-api-test-org-2-355d5c.json => orgs_github-api-test-org-1-a3d2b5.json} (82%) rename src/test/resources/org/kohsuke/github/GHRepositoryTest/wiremock/addCollaborators/mappings/{repos_github-api-test-org_github-api-3-e5504d.json => repos_github-api-test-org_github-api-2-95ce40.json} (77%) create mode 100644 src/test/resources/org/kohsuke/github/GHRepositoryTest/wiremock/addCollaborators/mappings/repos_github-api-test-org_github-api_collaborators-5-ddaa82.json rename src/test/resources/org/kohsuke/github/GHRepositoryTest/wiremock/addCollaborators/mappings/{repos_github-api-test-org_github-api_collaborators_jimmysombrero-4-1bfe02.json => repos_github-api-test-org_github-api_collaborators_jimmysombrero-4-3d80b1.json} (77%) rename src/test/resources/org/kohsuke/github/GHRepositoryTest/wiremock/addCollaborators/mappings/{user-1-4533e6.json => user-3-f20ea9.json} (77%) create mode 100644 src/test/resources/org/kohsuke/github/GHRepositoryTest/wiremock/addCollaborators/mappings/users_jimmysombrero-6-668537.json diff --git a/.gitignore b/.gitignore index 9fad19dc07..543ce576cd 100644 --- a/.gitignore +++ b/.gitignore @@ -10,3 +10,4 @@ target dependency-reduced-pom.xml .factorypath +.vscode/settings.json diff --git a/src/main/java/org/kohsuke/github/GHRepository.java b/src/main/java/org/kohsuke/github/GHRepository.java index 5ac4bcb679..5b740b88f0 100644 --- a/src/main/java/org/kohsuke/github/GHRepository.java +++ b/src/main/java/org/kohsuke/github/GHRepository.java @@ -860,6 +860,7 @@ public void addCollaborators(GHOrganization.Permission perm, GHUser... users) th * @throws IOException * the io exception */ + @Deprecated public void addCollaborators(GHUser... users) throws IOException { addCollaborators(asList(users)); } @@ -872,6 +873,7 @@ public void addCollaborators(GHUser... users) throws IOException { * @throws IOException * the io exception */ + @Deprecated public void addCollaborators(List users) throws IOException { modifyCollaborators(users, "PUT"); } diff --git a/src/test/java/org/kohsuke/github/GHRepositoryTest.java b/src/test/java/org/kohsuke/github/GHRepositoryTest.java index 71c811b672..d7fa2e3b95 100644 --- a/src/test/java/org/kohsuke/github/GHRepositoryTest.java +++ b/src/test/java/org/kohsuke/github/GHRepositoryTest.java @@ -169,10 +169,9 @@ public void addCollaborators() throws Exception { GHPersonSet collabs = repo.getCollaborators(); - GHUser colabUser = collabs.byLogin(user.getLogin()); + GHUser colabUser = collabs.byLogin("jimmysombrero"); assertEquals(colabUser.getName(), user.getName()); - assertEquals(GHOrganization.Permission.PUSH, repo.getPermission(user.getName())); } @Test diff --git a/src/test/resources/org/kohsuke/github/GHRepositoryTest/wiremock/addCollaborators/__files/orgs_github-api-test-org-355d5cda-5423-49ef-b604-6276fbaba24e.json b/src/test/resources/org/kohsuke/github/GHRepositoryTest/wiremock/addCollaborators/__files/orgs_github-api-test-org-a3d2b552-58b8-4028-b731-d00420496ca8.json similarity index 100% rename from src/test/resources/org/kohsuke/github/GHRepositoryTest/wiremock/addCollaborators/__files/orgs_github-api-test-org-355d5cda-5423-49ef-b604-6276fbaba24e.json rename to src/test/resources/org/kohsuke/github/GHRepositoryTest/wiremock/addCollaborators/__files/orgs_github-api-test-org-a3d2b552-58b8-4028-b731-d00420496ca8.json diff --git a/src/test/resources/org/kohsuke/github/GHRepositoryTest/wiremock/addCollaborators/__files/repos_github-api-test-org_github-api-e5504dd6-42ca-4d7f-9d95-f224e5f36a90.json b/src/test/resources/org/kohsuke/github/GHRepositoryTest/wiremock/addCollaborators/__files/repos_github-api-test-org_github-api-95ce4098-4e40-49f0-8661-0870614d5d78.json similarity index 99% rename from src/test/resources/org/kohsuke/github/GHRepositoryTest/wiremock/addCollaborators/__files/repos_github-api-test-org_github-api-e5504dd6-42ca-4d7f-9d95-f224e5f36a90.json rename to src/test/resources/org/kohsuke/github/GHRepositoryTest/wiremock/addCollaborators/__files/repos_github-api-test-org_github-api-95ce4098-4e40-49f0-8661-0870614d5d78.json index 877714e846..b945be16e4 100644 --- a/src/test/resources/org/kohsuke/github/GHRepositoryTest/wiremock/addCollaborators/__files/repos_github-api-test-org_github-api-e5504dd6-42ca-4d7f-9d95-f224e5f36a90.json +++ b/src/test/resources/org/kohsuke/github/GHRepositoryTest/wiremock/addCollaborators/__files/repos_github-api-test-org_github-api-95ce4098-4e40-49f0-8661-0870614d5d78.json @@ -191,7 +191,7 @@ "deployments_url": "https://api.github.com/repos/github-api/github-api/deployments", "created_at": "2010-04-19T04:13:03Z", "updated_at": "2020-02-01T02:00:03Z", - "pushed_at": "2020-01-31T21:18:18Z", + "pushed_at": "2020-02-02T04:40:57Z", "git_url": "git://github.com/github-api/github-api.git", "ssh_url": "git@github.com:github-api/github-api.git", "clone_url": "https://github.com/github-api/github-api.git", @@ -291,7 +291,7 @@ "deployments_url": "https://api.github.com/repos/github-api/github-api/deployments", "created_at": "2010-04-19T04:13:03Z", "updated_at": "2020-02-01T02:00:03Z", - "pushed_at": "2020-01-31T21:18:18Z", + "pushed_at": "2020-02-02T04:40:57Z", "git_url": "git://github.com/github-api/github-api.git", "ssh_url": "git@github.com:github-api/github-api.git", "clone_url": "https://github.com/github-api/github-api.git", diff --git a/src/test/resources/org/kohsuke/github/GHRepositoryTest/wiremock/addCollaborators/__files/repos_github-apit-test-ort_github-api_get_collaborators-5-ddaa82.json b/src/test/resources/org/kohsuke/github/GHRepositoryTest/wiremock/addCollaborators/__files/repos_github-apit-test-ort_github-api_get_collaborators-5-ddaa82.json new file mode 100644 index 0000000000..f543e9f7d9 --- /dev/null +++ b/src/test/resources/org/kohsuke/github/GHRepositoryTest/wiremock/addCollaborators/__files/repos_github-apit-test-ort_github-api_get_collaborators-5-ddaa82.json @@ -0,0 +1,27 @@ +[ + { + "login": "jimmysombrero", + "id": 12157727, + "node_id": "MDQ6VXNlcjEyMTU3NzI3", + "avatar_url": "https://avatars3.githubusercontent.com/u/12157727?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/jimmysombrero", + "html_url": "https://github.com/jimmysombrero", + "followers_url": "https://api.github.com/users/jimmysombrero/followers", + "following_url": "https://api.github.com/users/jimmysombrero/following{/other_user}", + "gists_url": "https://api.github.com/users/jimmysombrero/gists{/gist_id}", + "starred_url": "https://api.github.com/users/jimmysombrero/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/jimmysombrero/subscriptions", + "organizations_url": "https://api.github.com/users/jimmysombrero/orgs", + "repos_url": "https://api.github.com/users/jimmysombrero/repos", + "events_url": "https://api.github.com/users/jimmysombrero/events{/privacy}", + "received_events_url": "https://api.github.com/users/jimmysombrero/received_events", + "type": "User", + "site_admin": false, + "permissions": { + "push": true, + "pull": true, + "admin": false + } + } +] \ No newline at end of file diff --git a/src/test/resources/org/kohsuke/github/GHRepositoryTest/wiremock/addCollaborators/__files/user-4533e6b8-1725-4450-97b1-895a776d49b7.json b/src/test/resources/org/kohsuke/github/GHRepositoryTest/wiremock/addCollaborators/__files/user-f20ea960-c1f4-440c-bdc1-a605956a351a.json similarity index 97% rename from src/test/resources/org/kohsuke/github/GHRepositoryTest/wiremock/addCollaborators/__files/user-4533e6b8-1725-4450-97b1-895a776d49b7.json rename to src/test/resources/org/kohsuke/github/GHRepositoryTest/wiremock/addCollaborators/__files/user-f20ea960-c1f4-440c-bdc1-a605956a351a.json index c01fae6620..59111e1a88 100644 --- a/src/test/resources/org/kohsuke/github/GHRepositoryTest/wiremock/addCollaborators/__files/user-4533e6b8-1725-4450-97b1-895a776d49b7.json +++ b/src/test/resources/org/kohsuke/github/GHRepositoryTest/wiremock/addCollaborators/__files/user-f20ea960-c1f4-440c-bdc1-a605956a351a.json @@ -29,7 +29,7 @@ "followers": 1, "following": 0, "created_at": "2015-04-28T17:47:19Z", - "updated_at": "2020-02-02T04:15:35Z", + "updated_at": "2020-02-02T04:43:58Z", "private_gists": 0, "total_private_repos": 0, "owned_private_repos": 0, diff --git a/src/test/resources/org/kohsuke/github/GHRepositoryTest/wiremock/addCollaborators/__files/users_jimmysombrero-6685376c-451b-486d-88cd-502af9a7c5d1.json b/src/test/resources/org/kohsuke/github/GHRepositoryTest/wiremock/addCollaborators/__files/users_jimmysombrero-6685376c-451b-486d-88cd-502af9a7c5d1.json new file mode 100644 index 0000000000..59111e1a88 --- /dev/null +++ b/src/test/resources/org/kohsuke/github/GHRepositoryTest/wiremock/addCollaborators/__files/users_jimmysombrero-6685376c-451b-486d-88cd-502af9a7c5d1.json @@ -0,0 +1,45 @@ +{ + "login": "jimmysombrero", + "id": 12157727, + "node_id": "MDQ6VXNlcjEyMTU3NzI3", + "avatar_url": "https://avatars3.githubusercontent.com/u/12157727?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/jimmysombrero", + "html_url": "https://github.com/jimmysombrero", + "followers_url": "https://api.github.com/users/jimmysombrero/followers", + "following_url": "https://api.github.com/users/jimmysombrero/following{/other_user}", + "gists_url": "https://api.github.com/users/jimmysombrero/gists{/gist_id}", + "starred_url": "https://api.github.com/users/jimmysombrero/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/jimmysombrero/subscriptions", + "organizations_url": "https://api.github.com/users/jimmysombrero/orgs", + "repos_url": "https://api.github.com/users/jimmysombrero/repos", + "events_url": "https://api.github.com/users/jimmysombrero/events{/privacy}", + "received_events_url": "https://api.github.com/users/jimmysombrero/received_events", + "type": "User", + "site_admin": false, + "name": null, + "company": null, + "blog": "", + "location": null, + "email": null, + "hireable": null, + "bio": null, + "public_repos": 4, + "public_gists": 0, + "followers": 1, + "following": 0, + "created_at": "2015-04-28T17:47:19Z", + "updated_at": "2020-02-02T04:43:58Z", + "private_gists": 0, + "total_private_repos": 0, + "owned_private_repos": 0, + "disk_usage": 19, + "collaborators": 0, + "two_factor_authentication": false, + "plan": { + "name": "free", + "space": 976562499, + "collaborators": 0, + "private_repos": 10000 + } +} \ No newline at end of file diff --git a/src/test/resources/org/kohsuke/github/GHRepositoryTest/wiremock/addCollaborators/mappings/orgs_github-api-test-org-2-355d5c.json b/src/test/resources/org/kohsuke/github/GHRepositoryTest/wiremock/addCollaborators/mappings/orgs_github-api-test-org-1-a3d2b5.json similarity index 82% rename from src/test/resources/org/kohsuke/github/GHRepositoryTest/wiremock/addCollaborators/mappings/orgs_github-api-test-org-2-355d5c.json rename to src/test/resources/org/kohsuke/github/GHRepositoryTest/wiremock/addCollaborators/mappings/orgs_github-api-test-org-1-a3d2b5.json index f329cbf5b8..fb36c75a05 100644 --- a/src/test/resources/org/kohsuke/github/GHRepositoryTest/wiremock/addCollaborators/mappings/orgs_github-api-test-org-2-355d5c.json +++ b/src/test/resources/org/kohsuke/github/GHRepositoryTest/wiremock/addCollaborators/mappings/orgs_github-api-test-org-1-a3d2b5.json @@ -1,5 +1,5 @@ { - "id": "355d5cda-5423-49ef-b604-6276fbaba24e", + "id": "a3d2b552-58b8-4028-b731-d00420496ca8", "name": "orgs_github-api-test-org", "request": { "url": "/orgs/github-api-test-org", @@ -12,14 +12,14 @@ }, "response": { "status": 200, - "bodyFileName": "orgs_github-api-test-org-355d5cda-5423-49ef-b604-6276fbaba24e.json", + "bodyFileName": "orgs_github-api-test-org-a3d2b552-58b8-4028-b731-d00420496ca8.json", "headers": { "Server": "GitHub.com", - "Date": "Sun, 02 Feb 2020 04:29:45 GMT", + "Date": "Sun, 02 Feb 2020 04:59:39 GMT", "Content-Type": "application/json; charset=utf-8", "Status": "200 OK", "X-RateLimit-Limit": "5000", - "X-RateLimit-Remaining": "4951", + "X-RateLimit-Remaining": "4895", "X-RateLimit-Reset": "1580620984", "Cache-Control": "private, max-age=60, s-maxage=60", "Vary": "Accept, Authorization, Cookie, X-GitHub-OTP", @@ -36,10 +36,10 @@ "X-XSS-Protection": "1; mode=block", "Referrer-Policy": "origin-when-cross-origin, strict-origin-when-cross-origin", "Content-Security-Policy": "default-src 'none'", - "X-GitHub-Request-Id": "C7DB:0D8E:63D359:C9F18B:5E365038" + "X-GitHub-Request-Id": "C903:768E:16C4938:2BA1171:5E36573B" } }, - "uuid": "355d5cda-5423-49ef-b604-6276fbaba24e", + "uuid": "a3d2b552-58b8-4028-b731-d00420496ca8", "persistent": true, - "insertionIndex": 2 + "insertionIndex": 1 } \ No newline at end of file diff --git a/src/test/resources/org/kohsuke/github/GHRepositoryTest/wiremock/addCollaborators/mappings/repos_github-api-test-org_github-api-3-e5504d.json b/src/test/resources/org/kohsuke/github/GHRepositoryTest/wiremock/addCollaborators/mappings/repos_github-api-test-org_github-api-2-95ce40.json similarity index 77% rename from src/test/resources/org/kohsuke/github/GHRepositoryTest/wiremock/addCollaborators/mappings/repos_github-api-test-org_github-api-3-e5504d.json rename to src/test/resources/org/kohsuke/github/GHRepositoryTest/wiremock/addCollaborators/mappings/repos_github-api-test-org_github-api-2-95ce40.json index 97061665aa..a27046c0af 100644 --- a/src/test/resources/org/kohsuke/github/GHRepositoryTest/wiremock/addCollaborators/mappings/repos_github-api-test-org_github-api-3-e5504d.json +++ b/src/test/resources/org/kohsuke/github/GHRepositoryTest/wiremock/addCollaborators/mappings/repos_github-api-test-org_github-api-2-95ce40.json @@ -1,5 +1,5 @@ { - "id": "e5504dd6-42ca-4d7f-9d95-f224e5f36a90", + "id": "95ce4098-4e40-49f0-8661-0870614d5d78", "name": "repos_github-api-test-org_github-api", "request": { "url": "/repos/github-api-test-org/github-api", @@ -12,18 +12,18 @@ }, "response": { "status": 200, - "bodyFileName": "repos_github-api-test-org_github-api-e5504dd6-42ca-4d7f-9d95-f224e5f36a90.json", + "bodyFileName": "repos_github-api-test-org_github-api-95ce4098-4e40-49f0-8661-0870614d5d78.json", "headers": { "Server": "GitHub.com", - "Date": "Sun, 02 Feb 2020 04:29:45 GMT", + "Date": "Sun, 02 Feb 2020 04:59:39 GMT", "Content-Type": "application/json; charset=utf-8", "Status": "200 OK", "X-RateLimit-Limit": "5000", - "X-RateLimit-Remaining": "4950", - "X-RateLimit-Reset": "1580620984", + "X-RateLimit-Remaining": "4894", + "X-RateLimit-Reset": "1580620983", "Cache-Control": "private, max-age=60, s-maxage=60", "Vary": "Accept, Authorization, Cookie, X-GitHub-OTP", - "ETag": "W/\"c310cb7abd9a90e105810461c34dd8c6\"", + "ETag": "W/\"d61f18a7ccc89231875444b59f56580f\"", "Last-Modified": "Thu, 16 Jan 2020 21:22:56 GMT", "X-OAuth-Scopes": "admin:enterprise, admin:gpg_key, admin:org, admin:org_hook, admin:public_key, admin:repo_hook, delete:packages, delete_repo, gist, notifications, read:packages, repo, user, workflow, write:discussion, write:packages", "X-Accepted-OAuth-Scopes": "repo", @@ -36,10 +36,10 @@ "X-XSS-Protection": "1; mode=block", "Referrer-Policy": "origin-when-cross-origin, strict-origin-when-cross-origin", "Content-Security-Policy": "default-src 'none'", - "X-GitHub-Request-Id": "C7DB:0D8E:63D35D:C9F1A2:5E365039" + "X-GitHub-Request-Id": "C903:768E:16C4945:2BA117B:5E36573B" } }, - "uuid": "e5504dd6-42ca-4d7f-9d95-f224e5f36a90", + "uuid": "95ce4098-4e40-49f0-8661-0870614d5d78", "persistent": true, - "insertionIndex": 3 + "insertionIndex": 2 } \ No newline at end of file diff --git a/src/test/resources/org/kohsuke/github/GHRepositoryTest/wiremock/addCollaborators/mappings/repos_github-api-test-org_github-api_collaborators-5-ddaa82.json b/src/test/resources/org/kohsuke/github/GHRepositoryTest/wiremock/addCollaborators/mappings/repos_github-api-test-org_github-api_collaborators-5-ddaa82.json new file mode 100644 index 0000000000..fe713cd60d --- /dev/null +++ b/src/test/resources/org/kohsuke/github/GHRepositoryTest/wiremock/addCollaborators/mappings/repos_github-api-test-org_github-api_collaborators-5-ddaa82.json @@ -0,0 +1,41 @@ +{ + "id": "ddaa8229-c0ae-4df6-90ed-08425bfe71f2", + "name": "repos_github-api-test-org_github-api_collaborators", + "request": { + "url": "/repos/github-api-test-org/github-api/collaborators", + "method": "GET", + "headers": { + "Accept": { + "equalTo": "text/html, image/gif, image/jpeg, *; q=.2, */*; q=.2" + } + } + }, + "response": { + "status": "200", + "bodyFileName": "repos_github-apit-test-ort_github-api_get_collaborators-5-ddaa82.json", + "headers": { + "Server": "GitHub.com", + "Date": "Mon, 03 Feb 2020 02:32:07 GMT", + "Content-Type": "application/json; charset=utf-8", + "Status": "200 OK", + "X-RateLimit-Limit": "5000", + "X-RateLimit-Remaining": "4979", + "X-RateLimit-Reset": "1580700723", + "X-OAuth-Scopes": "admin:enterprise, admin:gpg_key, admin:org, admin:org_hook, admin:public_key, admin:repo_hook, delete:packages, delete_repo, gist, notifications, read:packages, repo, user, workflow, write:discussion, write:packages", + "X-Accepted-OAuth-Scopes": "", + "X-GitHub-Media-Type": "unknown, github.v3", + "Access-Control-Expose-Headers": "ETag, Link, Location, Retry-After, X-GitHub-OTP, X-RateLimit-Limit, X-RateLimit-Remaining, X-RateLimit-Reset, X-OAuth-Scopes, X-Accepted-OAuth-Scopes, X-Poll-Interval, X-GitHub-Media-Type", + "Access-Control-Allow-Origin": "*", + "Strict-Transport-Security": "max-age=31536000; includeSubdomains; preload", + "X-Frame-Options": "deny", + "X-Content-Type-Options": "nosniff", + "X-XSS-Protection": "1; mode=block", + "Referrer-Policy": "origin-when-cross-origin, strict-origin-when-cross-origin", + "Content-Security-Policy": "default-src 'none'", + "X-GitHub-Request-Id": "CBB1:43C6:FBCD05:26D0ED5:5E378627" + } + }, + "uuid": "ddaa8229-c0ae-4df6-90ed-08425bfe71f2", + "persistent": true, + "insertionIndex": 5 +} \ No newline at end of file diff --git a/src/test/resources/org/kohsuke/github/GHRepositoryTest/wiremock/addCollaborators/mappings/repos_github-api-test-org_github-api_collaborators_jimmysombrero-4-1bfe02.json b/src/test/resources/org/kohsuke/github/GHRepositoryTest/wiremock/addCollaborators/mappings/repos_github-api-test-org_github-api_collaborators_jimmysombrero-4-3d80b1.json similarity index 77% rename from src/test/resources/org/kohsuke/github/GHRepositoryTest/wiremock/addCollaborators/mappings/repos_github-api-test-org_github-api_collaborators_jimmysombrero-4-1bfe02.json rename to src/test/resources/org/kohsuke/github/GHRepositoryTest/wiremock/addCollaborators/mappings/repos_github-api-test-org_github-api_collaborators_jimmysombrero-4-3d80b1.json index 7862bede8b..515c252094 100644 --- a/src/test/resources/org/kohsuke/github/GHRepositoryTest/wiremock/addCollaborators/mappings/repos_github-api-test-org_github-api_collaborators_jimmysombrero-4-1bfe02.json +++ b/src/test/resources/org/kohsuke/github/GHRepositoryTest/wiremock/addCollaborators/mappings/repos_github-api-test-org_github-api_collaborators_jimmysombrero-4-3d80b1.json @@ -1,5 +1,5 @@ { - "id": "1bfe0280-5533-459c-8515-57f70bed0d04", + "id": "3d80b19e-05f4-4ad9-a610-5f573abc4363", "name": "repos_github-api-test-org_github-api_collaborators_jimmysombrero", "request": { "url": "/repos/github-api-test-org/github-api/collaborators/jimmysombrero", @@ -18,16 +18,16 @@ ] }, "response": { - "status": 404, - "body": "{\"message\":\"Not Found\",\"documentation_url\":\"https://developer.github.com/v3/repos/collaborators/#add-user-as-a-collaborator\"}", + "status": 201, + "body": "[]", "headers": { "Server": "GitHub.com", - "Date": "Sun, 02 Feb 2020 04:29:45 GMT", + "Date": "Sun, 02 Feb 2020 04:59:39 GMT", "Content-Type": "application/json; charset=utf-8", - "Status": "404 Not Found", + "Status": "201 Created", "X-RateLimit-Limit": "5000", - "X-RateLimit-Remaining": "4949", - "X-RateLimit-Reset": "1580620984", + "X-RateLimit-Remaining": "4892", + "X-RateLimit-Reset": "1580620983", "X-OAuth-Scopes": "admin:enterprise, admin:gpg_key, admin:org, admin:org_hook, admin:public_key, admin:repo_hook, delete:packages, delete_repo, gist, notifications, read:packages, repo, user, workflow, write:discussion, write:packages", "X-Accepted-OAuth-Scopes": "", "X-GitHub-Media-Type": "unknown, github.v3", @@ -39,10 +39,10 @@ "X-XSS-Protection": "1; mode=block", "Referrer-Policy": "origin-when-cross-origin, strict-origin-when-cross-origin", "Content-Security-Policy": "default-src 'none'", - "X-GitHub-Request-Id": "C7DB:0D8E:63D367:C9F1B5:5E365039" + "X-GitHub-Request-Id": "C903:768E:16C4966:2BA11B0:5E36573B" } }, - "uuid": "1bfe0280-5533-459c-8515-57f70bed0d04", + "uuid": "3d80b19e-05f4-4ad9-a610-5f573abc4363", "persistent": true, "insertionIndex": 4 } \ No newline at end of file diff --git a/src/test/resources/org/kohsuke/github/GHRepositoryTest/wiremock/addCollaborators/mappings/user-1-4533e6.json b/src/test/resources/org/kohsuke/github/GHRepositoryTest/wiremock/addCollaborators/mappings/user-3-f20ea9.json similarity index 77% rename from src/test/resources/org/kohsuke/github/GHRepositoryTest/wiremock/addCollaborators/mappings/user-1-4533e6.json rename to src/test/resources/org/kohsuke/github/GHRepositoryTest/wiremock/addCollaborators/mappings/user-3-f20ea9.json index 84cb10ec8a..bd001a05da 100644 --- a/src/test/resources/org/kohsuke/github/GHRepositoryTest/wiremock/addCollaborators/mappings/user-1-4533e6.json +++ b/src/test/resources/org/kohsuke/github/GHRepositoryTest/wiremock/addCollaborators/mappings/user-3-f20ea9.json @@ -1,5 +1,5 @@ { - "id": "4533e6b8-1725-4450-97b1-895a776d49b7", + "id": "f20ea960-c1f4-440c-bdc1-a605956a351a", "name": "user", "request": { "url": "/user", @@ -12,19 +12,19 @@ }, "response": { "status": 200, - "bodyFileName": "user-4533e6b8-1725-4450-97b1-895a776d49b7.json", + "bodyFileName": "user-f20ea960-c1f4-440c-bdc1-a605956a351a.json", "headers": { "Server": "GitHub.com", - "Date": "Sun, 02 Feb 2020 04:29:44 GMT", + "Date": "Sun, 02 Feb 2020 04:59:39 GMT", "Content-Type": "application/json; charset=utf-8", "Status": "200 OK", "X-RateLimit-Limit": "5000", - "X-RateLimit-Remaining": "4953", + "X-RateLimit-Remaining": "4893", "X-RateLimit-Reset": "1580620983", "Cache-Control": "private, max-age=60, s-maxage=60", "Vary": "Accept, Authorization, Cookie, X-GitHub-OTP", - "ETag": "W/\"275d33915a65ed3fa77d5fed34147440\"", - "Last-Modified": "Sun, 02 Feb 2020 04:15:35 GMT", + "ETag": "W/\"7a0206b47e995649c88218afeb2266a6\"", + "Last-Modified": "Sun, 02 Feb 2020 04:43:58 GMT", "X-OAuth-Scopes": "admin:enterprise, admin:gpg_key, admin:org, admin:org_hook, admin:public_key, admin:repo_hook, delete:packages, delete_repo, gist, notifications, read:packages, repo, user, workflow, write:discussion, write:packages", "X-Accepted-OAuth-Scopes": "", "X-GitHub-Media-Type": "unknown, github.v3", @@ -36,10 +36,10 @@ "X-XSS-Protection": "1; mode=block", "Referrer-Policy": "origin-when-cross-origin, strict-origin-when-cross-origin", "Content-Security-Policy": "default-src 'none'", - "X-GitHub-Request-Id": "C7DB:0D8E:63D34F:C9F17E:5E365038" + "X-GitHub-Request-Id": "C903:768E:16C495A:2BA119D:5E36573B" } }, - "uuid": "4533e6b8-1725-4450-97b1-895a776d49b7", + "uuid": "f20ea960-c1f4-440c-bdc1-a605956a351a", "persistent": true, - "insertionIndex": 1 + "insertionIndex": 3 } \ No newline at end of file diff --git a/src/test/resources/org/kohsuke/github/GHRepositoryTest/wiremock/addCollaborators/mappings/users_jimmysombrero-6-668537.json b/src/test/resources/org/kohsuke/github/GHRepositoryTest/wiremock/addCollaborators/mappings/users_jimmysombrero-6-668537.json new file mode 100644 index 0000000000..fcb4c6b398 --- /dev/null +++ b/src/test/resources/org/kohsuke/github/GHRepositoryTest/wiremock/addCollaborators/mappings/users_jimmysombrero-6-668537.json @@ -0,0 +1,45 @@ +{ + "id": "6685376c-451b-486d-88cd-502af9a7c5d1", + "name": "users_jimmysombrero", + "request": { + "url": "/users/jimmysombrero", + "method": "GET", + "headers": { + "Accept": { + "equalTo": "text/html, image/gif, image/jpeg, *; q=.2, */*; q=.2" + } + } + }, + "response": { + "status": 200, + "bodyFileName": "users_jimmysombrero-6685376c-451b-486d-88cd-502af9a7c5d1.json", + "headers": { + "Server": "GitHub.com", + "Date": "Mon, 03 Feb 2020 03:50:14 GMT", + "Content-Type": "application/json; charset=utf-8", + "Status": "200 OK", + "X-RateLimit-Limit": "5000", + "X-RateLimit-Remaining": "4907", + "X-RateLimit-Reset": "1580704799", + "Cache-Control": "private, max-age=60, s-maxage=60", + "Vary": "Accept, Authorization, Cookie, X-GitHub-OTP", + "ETag": "W/\"7a0206b47e995649c88218afeb2266a6\"", + "Last-Modified": "Sun, 02 Feb 2020 04:43:58 GMT", + "X-OAuth-Scopes": "admin:enterprise, admin:gpg_key, admin:org, admin:org_hook, admin:public_key, admin:repo_hook, delete:packages, delete_repo, gist, notifications, read:packages, repo, user, workflow, write:discussion, write:packages", + "X-Accepted-OAuth-Scopes": "", + "X-GitHub-Media-Type": "unknown, github.v3", + "Access-Control-Expose-Headers": "ETag, Link, Location, Retry-After, X-GitHub-OTP, X-RateLimit-Limit, X-RateLimit-Remaining, X-RateLimit-Reset, X-OAuth-Scopes, X-Accepted-OAuth-Scopes, X-Poll-Interval, X-GitHub-Media-Type", + "Access-Control-Allow-Origin": "*", + "Strict-Transport-Security": "max-age=31536000; includeSubdomains; preload", + "X-Frame-Options": "deny", + "X-Content-Type-Options": "nosniff", + "X-XSS-Protection": "1; mode=block", + "Referrer-Policy": "origin-when-cross-origin, strict-origin-when-cross-origin", + "Content-Security-Policy": "default-src 'none'", + "X-GitHub-Request-Id": "CDFE:768D:1021273:26DC788:5E379876" + } + }, + "uuid": "6685376c-451b-486d-88cd-502af9a7c5d1", + "persistent": true, + "insertionIndex": 6 +} \ No newline at end of file From 5a799400a9e3a2d02b698778192a047ce6ba9c30 Mon Sep 17 00:00:00 2001 From: James Vaughn Date: Tue, 4 Feb 2020 21:10:29 -0600 Subject: [PATCH 08/11] fixed minor formatting issues --- src/main/java/org/kohsuke/github/GHRepository.java | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/src/main/java/org/kohsuke/github/GHRepository.java b/src/main/java/org/kohsuke/github/GHRepository.java index 5b740b88f0..9f4076e2c8 100644 --- a/src/main/java/org/kohsuke/github/GHRepository.java +++ b/src/main/java/org/kohsuke/github/GHRepository.java @@ -535,12 +535,9 @@ public Map listLanguages() throws IOException { * @return the owner name */ public String getOwnerName() { - // consistency of the GitHub API is super... some serialized forms of - // GHRepository populate - // a full GHUser while others populate only the owner and email. This later form - // is super helpful - // in putting the login in owner.name not owner.login... thankfully we can - // easily identify this + // consistency of the GitHub API is super... some serialized forms of GHRepository populate + // a full GHUser while others populate only the owner and email. This later form is super helpful + // in putting the login in owner.name not owner.login... thankfully we can easily identify this // second set because owner.login will be null return owner.login != null ? owner.login : owner.name; } @@ -753,7 +750,7 @@ public PagedIterable listCollaborators() throws IOException { /** * Lists all - * the + * the * available assignees to which issues may be assigned. * * @return the paged iterable From dddcf624e6af59787abc6618576ee95e455b35db Mon Sep 17 00:00:00 2001 From: James Vaughn Date: Wed, 5 Feb 2020 21:30:52 -0600 Subject: [PATCH 09/11] finished suggested formatting changes --- src/main/java/org/kohsuke/github/GHRepository.java | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/main/java/org/kohsuke/github/GHRepository.java b/src/main/java/org/kohsuke/github/GHRepository.java index 9f4076e2c8..2b468792b7 100644 --- a/src/main/java/org/kohsuke/github/GHRepository.java +++ b/src/main/java/org/kohsuke/github/GHRepository.java @@ -813,7 +813,7 @@ public GHPermissionType getPermission(String user) throws IOException { * Obtain permission for a given user in this repository. * * @param u - * the u + * the user * @return the permission * @throws IOException * the io exception @@ -1986,8 +1986,7 @@ public GHHook createWebHook(URL url) throws IOException { // * Retrieves all the pull requests. // */ // public List getPullRequests() throws IOException { - // return - // root.retrieveWithAuth("/pulls/"+owner+'/'+name,JsonPullRequests.class).wrap(root); + // return root.retrieveWithAuth("/pulls/"+owner+'/'+name,JsonPullRequests.class).wrap(root); // } /** From 54a059ff68d811685bc485fb32c4b2569e329575 Mon Sep 17 00:00:00 2001 From: James Vaughn Date: Fri, 7 Feb 2020 21:13:23 -0600 Subject: [PATCH 10/11] updated signatures for addCollaborators methods updated javadoc comments for addCollaborators methods combined both modifyCollaborators methods into one method updated addColloaborators test to match new method signature --- .../java/org/kohsuke/github/GHRepository.java | 38 +++++++++---------- .../org/kohsuke/github/GHRepositoryTest.java | 2 +- 2 files changed, 18 insertions(+), 22 deletions(-) diff --git a/src/main/java/org/kohsuke/github/GHRepository.java b/src/main/java/org/kohsuke/github/GHRepository.java index 2b468792b7..148b7694a6 100644 --- a/src/main/java/org/kohsuke/github/GHRepository.java +++ b/src/main/java/org/kohsuke/github/GHRepository.java @@ -25,6 +25,8 @@ import com.fasterxml.jackson.annotation.JsonProperty; import com.infradna.tool.bridge_method_injector.WithBridgeMethods; +import edu.umd.cs.findbugs.annotations.CheckForNull; +import edu.umd.cs.findbugs.annotations.NonNull; import edu.umd.cs.findbugs.annotations.SuppressFBWarnings; import org.apache.commons.lang3.StringUtils; @@ -845,8 +847,8 @@ public Set getTeams() throws IOException { * @throws IOException * the io exception */ - public void addCollaborators(GHOrganization.Permission perm, GHUser... users) throws IOException { - addCollaborators(perm, asList(users)); + public void addCollaborators(GHOrganization.Permission permission, GHUser... user) throws IOException { + addCollaborators(asList(user), permission); } /** @@ -857,7 +859,6 @@ public void addCollaborators(GHOrganization.Permission perm, GHUser... users) th * @throws IOException * the io exception */ - @Deprecated public void addCollaborators(GHUser... users) throws IOException { addCollaborators(asList(users)); } @@ -870,9 +871,8 @@ public void addCollaborators(GHUser... users) throws IOException { * @throws IOException * the io exception */ - @Deprecated - public void addCollaborators(List users) throws IOException { - modifyCollaborators(users, "PUT"); + public void addCollaborators(Collection users) throws IOException { + modifyCollaborators(users, "PUT", null); } /** @@ -885,8 +885,8 @@ public void addCollaborators(List users) throws IOException { * @throws IOException * the io exception */ - public void addCollaborators(GHOrganization.Permission perm, Collection users) throws IOException { - modifyCollaborators(perm, users, "PUT"); + public void addCollaborators(Collection users, GHOrganization.Permission permission) throws IOException { + modifyCollaborators(users, "PUT", permission); } /** @@ -910,24 +910,20 @@ public void removeCollaborators(GHUser... users) throws IOException { * the io exception */ public void removeCollaborators(Collection users) throws IOException { - modifyCollaborators(users, "DELETE"); + modifyCollaborators(users, "DELETE", null); } - private void modifyCollaborators(Collection users, String method) throws IOException { - for (GHUser user : users) { - root.createRequest().method(method).withUrlPath(getApiTailUrl("collaborators/" + user.getLogin())).send(); + private void modifyCollaborators(@NonNull Collection users, + @NonNull String method, + @CheckForNull GHOrganization.Permission permission) throws IOException { + Requester requester = root.createRequest().method(method); + + if (permission != null) { + requester = requester.with("permission", permission).inBody(); } - } - private void modifyCollaborators(GHOrganization.Permission perm, Collection users, String method) - throws IOException { for (GHUser user : users) { - root.createRequest() - .method(method) - .with("permission", perm) - .inBody() - .withUrlPath(getApiTailUrl("collaborators/" + user.getLogin())) - .send(); + requester.withUrlPath(getApiTailUrl("collaborators/" + user.getLogin())).send(); } } diff --git a/src/test/java/org/kohsuke/github/GHRepositoryTest.java b/src/test/java/org/kohsuke/github/GHRepositoryTest.java index d7fa2e3b95..4d556a189d 100644 --- a/src/test/java/org/kohsuke/github/GHRepositoryTest.java +++ b/src/test/java/org/kohsuke/github/GHRepositoryTest.java @@ -165,7 +165,7 @@ public void addCollaborators() throws Exception { List users = new ArrayList(); users.add(user); - repo.addCollaborators(GHOrganization.Permission.PUSH, users); + repo.addCollaborators(users, GHOrganization.Permission.PUSH); GHPersonSet collabs = repo.getCollaborators(); From edc697dd73b68bb0122d6b3bbe3f9a10b249ac8a Mon Sep 17 00:00:00 2001 From: James Vaughn Date: Fri, 7 Feb 2020 21:27:00 -0600 Subject: [PATCH 11/11] fixed javadoc isues --- src/main/java/org/kohsuke/github/GHRepository.java | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/main/java/org/kohsuke/github/GHRepository.java b/src/main/java/org/kohsuke/github/GHRepository.java index 148b7694a6..1093434915 100644 --- a/src/main/java/org/kohsuke/github/GHRepository.java +++ b/src/main/java/org/kohsuke/github/GHRepository.java @@ -842,13 +842,13 @@ public Set getTeams() throws IOException { * * @param users * the users - * @param perm + * @param permission * the permission level * @throws IOException * the io exception */ - public void addCollaborators(GHOrganization.Permission permission, GHUser... user) throws IOException { - addCollaborators(asList(user), permission); + public void addCollaborators(GHOrganization.Permission permission, GHUser... users) throws IOException { + addCollaborators(asList(users), permission); } /** @@ -880,7 +880,7 @@ public void addCollaborators(Collection users) throws IOException { * * @param users * the users - * @param perm + * @param permission * the permission level * @throws IOException * the io exception