diff --git a/CODE_OF_CONDUCT.md b/CODE_OF_CONDUCT.md new file mode 100644 index 0000000000..722bb8dfc7 --- /dev/null +++ b/CODE_OF_CONDUCT.md @@ -0,0 +1,74 @@ +# Contributor Covenant Code of Conduct + +## Our Pledge + +In the interest of fostering an open and welcoming environment, we as +contributors and maintainers pledge to making participation in our project and +our community a harassment-free experience for everyone, regardless of age, body +size, disability, ethnicity, gender identity and expression, level of experience, +nationality, personal appearance, race, religion, or sexual identity and +orientation. + +## Our Standards + +Examples of behavior that contributes to creating a positive environment +include: + +* Using welcoming and inclusive language +* Being respectful of differing viewpoints and experiences +* Gracefully accepting constructive criticism +* Focusing on what is best for the community +* Showing empathy towards other community members + +Examples of unacceptable behavior by participants include: + +* The use of sexualized language or imagery and unwelcome sexual attention or +advances +* Trolling, insulting/derogatory comments, and personal or political attacks +* Public or private harassment +* Publishing others' private information, such as a physical or electronic + address, without explicit permission +* Other conduct which could reasonably be considered inappropriate in a + professional setting + +## Our Responsibilities + +Project maintainers are responsible for clarifying the standards of acceptable +behavior and are expected to take appropriate and fair corrective action in +response to any instances of unacceptable behavior. + +Project maintainers have the right and responsibility to remove, edit, or +reject comments, commits, code, wiki edits, issues, and other contributions +that are not aligned to this Code of Conduct, or to ban temporarily or +permanently any contributor for other behaviors that they deem inappropriate, +threatening, offensive, or harmful. + +## Scope + +This Code of Conduct applies both within project spaces and in public spaces +when an individual is representing the project or its community. Examples of +representing a project or community include using an official project e-mail +address, posting via an official social media account, or acting as an appointed +representative at an online or offline event. Representation of a project may be +further defined and clarified by project maintainers. + +## Enforcement + +Instances of abusive, harassing, or otherwise unacceptable behavior may be +reported by contacting the project team at [support@github.com](mailto:support@github.com). All +complaints will be reviewed and investigated and will result in a response that +is deemed necessary and appropriate to the circumstances. The project team is +obligated to maintain confidentiality with regard to the reporter of an incident. +Further details of specific enforcement policies may be posted separately. + +Project maintainers who do not follow or enforce the Code of Conduct in good +faith may face temporary or permanent repercussions as determined by other +members of the project's leadership. + +## Attribution + +This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, +available at [http://contributor-covenant.org/version/1/4][version] + +[homepage]: http://contributor-covenant.org +[version]: http://contributor-covenant.org/version/1/4/ diff --git a/Octokit.Reactive/Clients/IObservableAssigneesClient.cs b/Octokit.Reactive/Clients/IObservableAssigneesClient.cs index 2f2ae79c14..4fd7e71e8f 100644 --- a/Octokit.Reactive/Clients/IObservableAssigneesClient.cs +++ b/Octokit.Reactive/Clients/IObservableAssigneesClient.cs @@ -46,6 +46,26 @@ public interface IObservableAssigneesClient /// Username of the prospective assignee IObservable CheckAssignee(string owner, string name, string assignee); + /// + /// Add assignees to a specified Issue. + /// + /// The owner of the repository + /// The name of the repository + /// The issue number + /// List of names of assignees to add + /// + IObservable AddAssignees(string owner, string name, int number, AssigneesUpdate assignees); + + /// + /// Remove assignees from a specified Issue. + /// + /// The owner of the repository + /// The name of the repository + /// The issue number + /// List of assignees to remove + /// + IObservable RemoveAssignees(string owner, string name, int number, AssigneesUpdate assignees); + /// /// Checks to see if a user is an assignee for a repository. /// diff --git a/Octokit.Reactive/Clients/IObservableCommitCommentReactionsClient.cs b/Octokit.Reactive/Clients/IObservableCommitCommentReactionsClient.cs index 4771f2ef67..a4df576fff 100644 --- a/Octokit.Reactive/Clients/IObservableCommitCommentReactionsClient.cs +++ b/Octokit.Reactive/Clients/IObservableCommitCommentReactionsClient.cs @@ -40,7 +40,7 @@ public interface IObservableCommitCommentReactionsClient /// The comment id /// IObservable GetAll(string owner, string name, int number); - + /// /// List reactions for a specified Commit Comment /// diff --git a/Octokit.Reactive/Clients/IObservableCommitStatusClient.cs b/Octokit.Reactive/Clients/IObservableCommitStatusClient.cs index 356ac10f1c..ed0eb37307 100644 --- a/Octokit.Reactive/Clients/IObservableCommitStatusClient.cs +++ b/Octokit.Reactive/Clients/IObservableCommitStatusClient.cs @@ -19,7 +19,7 @@ public interface IObservableCommitStatusClient /// The name of the repository /// The reference (SHA, branch name, or tag name) to list commits for IObservable GetAll(string owner, string name, string reference); - + /// /// Retrieves commit statuses for the specified reference. A reference can be a commit SHA, a branch name, or /// a tag name. diff --git a/Octokit.Reactive/Clients/IObservableCommitsClient.cs b/Octokit.Reactive/Clients/IObservableCommitsClient.cs index 213b1d7f94..832f8e4dc8 100644 --- a/Octokit.Reactive/Clients/IObservableCommitsClient.cs +++ b/Octokit.Reactive/Clients/IObservableCommitsClient.cs @@ -46,7 +46,7 @@ public interface IObservableCommitsClient /// The name of the repository /// The commit to create IObservable Create(string owner, string name, NewCommit commit); - + /// /// Create a commit for a given repository /// diff --git a/Octokit.Reactive/Clients/IObservableDeploymentsClient.cs b/Octokit.Reactive/Clients/IObservableDeploymentsClient.cs index 361a1346a9..250e0e0948 100644 --- a/Octokit.Reactive/Clients/IObservableDeploymentsClient.cs +++ b/Octokit.Reactive/Clients/IObservableDeploymentsClient.cs @@ -21,7 +21,7 @@ public interface IObservableDeploymentsClient /// The owner of the repository /// The name of the repository IObservable GetAll(string owner, string name); - + /// /// Gets all the deployments for the specified repository. Any user with pull access /// to a repository can view deployments. @@ -43,7 +43,7 @@ public interface IObservableDeploymentsClient /// The name of the repository /// Options for changing the API response IObservable GetAll(string owner, string name, ApiOptions options); - + /// /// Gets all the deployments for the specified repository. Any user with pull access /// to a repository can view deployments. diff --git a/Octokit.Reactive/Clients/IObservableEventsClient.cs b/Octokit.Reactive/Clients/IObservableEventsClient.cs index 558b7f7055..7bf37345a7 100644 --- a/Octokit.Reactive/Clients/IObservableEventsClient.cs +++ b/Octokit.Reactive/Clients/IObservableEventsClient.cs @@ -76,7 +76,7 @@ public interface IObservableEventsClient /// /// The owner of the repository /// The name of the repository - IObservable GetAllIssuesForRepository(string owner, string name); + IObservable GetAllIssuesForRepository(string owner, string name); /// /// Gets all the issue events for a given repository @@ -85,7 +85,7 @@ public interface IObservableEventsClient /// http://developer.github.com/v3/activity/events/#list-issue-events-for-a-repository /// /// The Id of the repository - IObservable GetAllIssuesForRepository(long repositoryId); + IObservable GetAllIssuesForRepository(long repositoryId); /// /// Gets all the issue events for a given repository @@ -96,7 +96,7 @@ public interface IObservableEventsClient /// The owner of the repository /// The name of the repository /// Options for changing the API response - IObservable GetAllIssuesForRepository(string owner, string name, ApiOptions options); + IObservable GetAllIssuesForRepository(string owner, string name, ApiOptions options); /// /// Gets all the issue events for a given repository @@ -106,7 +106,7 @@ public interface IObservableEventsClient /// /// The Id of the repository /// Options for changing the API response - IObservable GetAllIssuesForRepository(long repositoryId, ApiOptions options); + IObservable GetAllIssuesForRepository(long repositoryId, ApiOptions options); /// /// Gets all the events for a given repository network diff --git a/Octokit.Reactive/Clients/IObservableIssueCommentsClient.cs b/Octokit.Reactive/Clients/IObservableIssueCommentsClient.cs index 24c29d48f1..9f0c2783e8 100644 --- a/Octokit.Reactive/Clients/IObservableIssueCommentsClient.cs +++ b/Octokit.Reactive/Clients/IObservableIssueCommentsClient.cs @@ -65,6 +65,42 @@ public interface IObservableIssueCommentsClient /// Options for changing the API response IObservable GetAllForRepository(long repositoryId, ApiOptions options); + /// + /// Gets Issue Comments for a repository. + /// + /// http://developer.github.com/v3/issues/comments/#list-comments-in-a-repository + /// The owner of the repository + /// The name of the repository + /// The sorting parameters + IObservable GetAllForRepository(string owner, string name, IssueCommentRequest request); + + /// + /// Gets Issue Comments for a repository. + /// + /// http://developer.github.com/v3/issues/comments/#list-comments-in-a-repository + /// The Id of the repository + /// The sorting parameters + IObservable GetAllForRepository(long repositoryId, IssueCommentRequest request); + + /// + /// Gets Issue Comments for a repository. + /// + /// http://developer.github.com/v3/issues/comments/#list-comments-in-a-repository + /// The owner of the repository + /// The name of the repository + /// The sorting parameters + /// Options for changing the API response + IObservable GetAllForRepository(string owner, string name, IssueCommentRequest request, ApiOptions options); + + /// + /// Gets Issue Comments for a repository. + /// + /// http://developer.github.com/v3/issues/comments/#list-comments-in-a-repository + /// The Id of the repository + /// The sorting parameters + /// Options for changing the API response + IObservable GetAllForRepository(long repositoryId, IssueCommentRequest request, ApiOptions options); + /// /// Gets Issue Comments for a specified Issue. /// diff --git a/Octokit.Reactive/Clients/IObservableIssueTimelineClient.cs b/Octokit.Reactive/Clients/IObservableIssueTimelineClient.cs index 053c1221f1..f60a824731 100644 --- a/Octokit.Reactive/Clients/IObservableIssueTimelineClient.cs +++ b/Octokit.Reactive/Clients/IObservableIssueTimelineClient.cs @@ -32,7 +32,7 @@ public interface IObservableIssueTimelineClient /// The issue number /// Options for changing the API response IObservable GetAllForIssue(string owner, string repo, int number, ApiOptions options); - + /// /// Gets all the various events that have occurred around an issue or pull request. /// diff --git a/Octokit.Reactive/Clients/IObservableIssuesEventsClient.cs b/Octokit.Reactive/Clients/IObservableIssuesEventsClient.cs index 0307f84629..44c714e3bf 100644 --- a/Octokit.Reactive/Clients/IObservableIssuesEventsClient.cs +++ b/Octokit.Reactive/Clients/IObservableIssuesEventsClient.cs @@ -21,7 +21,7 @@ public interface IObservableIssuesEventsClient /// The name of the repository /// The issue number IObservable GetAllForIssue(string owner, string name, int number); - + /// /// Gets all events for the issue. /// diff --git a/Octokit.Reactive/Clients/IObservableMilestonesClient.cs b/Octokit.Reactive/Clients/IObservableMilestonesClient.cs index 95cd5f82e0..eab33ef0e3 100644 --- a/Octokit.Reactive/Clients/IObservableMilestonesClient.cs +++ b/Octokit.Reactive/Clients/IObservableMilestonesClient.cs @@ -22,7 +22,7 @@ public interface IObservableMilestonesClient [SuppressMessage("Microsoft.Naming", "CA1716:IdentifiersShouldNotMatchKeywords", MessageId = "Get", Justification = "Method makes a network request")] IObservable Get(string owner, string name, int number); - + /// /// Gets a single Milestone by number. /// @@ -44,7 +44,7 @@ public interface IObservableMilestonesClient /// The name of the repository /// IObservable GetAllForRepository(string owner, string name); - + /// /// Gets all open milestones for the repository. /// diff --git a/Octokit.Reactive/Clients/IObservableOrganizationsClient.cs b/Octokit.Reactive/Clients/IObservableOrganizationsClient.cs index fb9efd7f07..85b9955e33 100644 --- a/Octokit.Reactive/Clients/IObservableOrganizationsClient.cs +++ b/Octokit.Reactive/Clients/IObservableOrganizationsClient.cs @@ -46,6 +46,7 @@ public interface IObservableOrganizationsClient /// /// The login for the user /// + [Obsolete("Please use IObservableOrganizationsClient.GetAllForUser() instead. This method will be removed in a future version")] IObservable GetAll(string user); /// @@ -54,8 +55,37 @@ public interface IObservableOrganizationsClient /// The login for the user /// Options for changing the API response /// + [Obsolete("Please use IObservableOrganizationsClient.GetAllForUser() instead. This method will be removed in a future version")] IObservable GetAll(string user, ApiOptions options); + /// + /// Returns all the organizations for the specified user + /// + /// The login for the user + /// + IObservable GetAllForUser(string user); + + /// + /// Returns all the organizations for the specified user + /// + /// The login for the user + /// Options for changing the API response + /// + IObservable GetAllForUser(string user, ApiOptions options); + + /// + /// Returns all the organizations + /// + /// + IObservable GetAll(); + + /// + /// Returns all the organizations + /// + /// Search parameters of the last organization seen + /// + IObservable GetAll(OrganizationRequest request); + /// /// Update the specified organization with data from . /// diff --git a/Octokit.Reactive/Clients/IObservablePullRequestsClient.cs b/Octokit.Reactive/Clients/IObservablePullRequestsClient.cs index 752024be3f..ad5dd7c97a 100644 --- a/Octokit.Reactive/Clients/IObservablePullRequestsClient.cs +++ b/Octokit.Reactive/Clients/IObservablePullRequestsClient.cs @@ -12,10 +12,16 @@ namespace Octokit.Reactive public interface IObservablePullRequestsClient { /// - /// Client for managing comments. + /// Client for managing review comments. /// + [Obsolete("Please use IObservablePullRequestsClient.ReviewComment. This will be removed in a future version")] IObservablePullRequestReviewCommentsClient Comment { get; } + /// + /// Client for managing review comments. + /// + IObservablePullRequestReviewCommentsClient ReviewComment { get; } + /// /// Gets a single Pull Request by number. /// diff --git a/Octokit.Reactive/Clients/IObservableReferencesClient.cs b/Octokit.Reactive/Clients/IObservableReferencesClient.cs index 51d5582d7a..a1ff6dc101 100644 --- a/Octokit.Reactive/Clients/IObservableReferencesClient.cs +++ b/Octokit.Reactive/Clients/IObservableReferencesClient.cs @@ -25,7 +25,7 @@ public interface IObservableReferencesClient [SuppressMessage("Microsoft.Naming", "CA1716:IdentifiersShouldNotMatchKeywords", MessageId = "Get", Justification = "Method makes a network request")] IObservable Get(string owner, string name, string reference); - + /// /// Gets a reference for a given repository by reference name /// diff --git a/Octokit.Reactive/Clients/IObservableReleasesClient.cs b/Octokit.Reactive/Clients/IObservableReleasesClient.cs index be24c954f8..ec56e379e4 100644 --- a/Octokit.Reactive/Clients/IObservableReleasesClient.cs +++ b/Octokit.Reactive/Clients/IObservableReleasesClient.cs @@ -231,7 +231,7 @@ public interface IObservableReleasesClient /// Description of the asset with its data /// Thrown when a general API error occurs. IObservable UploadAsset(Release release, ReleaseAssetUpload data); - + /// /// Gets the specified for the specified release of the specified repository. /// diff --git a/Octokit.Reactive/Clients/IObservableRepositoryContentsClient.cs b/Octokit.Reactive/Clients/IObservableRepositoryContentsClient.cs index bca5a1a237..e08c7128c6 100644 --- a/Octokit.Reactive/Clients/IObservableRepositoryContentsClient.cs +++ b/Octokit.Reactive/Clients/IObservableRepositoryContentsClient.cs @@ -36,7 +36,7 @@ public interface IObservableRepositoryContentsClient /// /// The Id of the repository IObservable GetReadmeHtml(long repositoryId); - + /// /// Get an archive of a given repository's contents /// @@ -167,7 +167,7 @@ public interface IObservableRepositoryContentsClient /// The name of the commit/branch/tag. Default: the repository’s default branch (usually master) /// The content path IObservable GetAllContentsByRef(long repositoryId, string reference, string path); - + /// /// Returns the contents of the home directory in a repository. /// diff --git a/Octokit.Reactive/Clients/IObservableRepositoryHooksClient.cs b/Octokit.Reactive/Clients/IObservableRepositoryHooksClient.cs index 844b970552..e6daa3d909 100644 --- a/Octokit.Reactive/Clients/IObservableRepositoryHooksClient.cs +++ b/Octokit.Reactive/Clients/IObservableRepositoryHooksClient.cs @@ -35,7 +35,7 @@ public interface IObservableRepositoryHooksClient /// Options for changing the API response /// See API documentation for more information. IObservable GetAll(string owner, string name, ApiOptions options); - + /// /// Gets the list of hooks defined for a repository /// diff --git a/Octokit.Reactive/Clients/IObservableStarredClient.cs b/Octokit.Reactive/Clients/IObservableStarredClient.cs index 1b81508569..d583287636 100644 --- a/Octokit.Reactive/Clients/IObservableStarredClient.cs +++ b/Octokit.Reactive/Clients/IObservableStarredClient.cs @@ -33,7 +33,7 @@ public interface IObservableStarredClient /// Options for changing the API response /// Thrown if the client is not authenticated IObservable GetAllStargazers(string owner, string name, ApiOptions options); - + /// /// Retrieves all of the stargazers for the passed repository /// @@ -49,7 +49,7 @@ public interface IObservableStarredClient /// The name of the repository /// Thrown if the client is not authenticated. IObservable GetAllStargazersWithTimestamps(string owner, string name); - + /// /// Retrieves all of the stargazers for the passed repository with star creation timestamps. /// @@ -79,7 +79,7 @@ public interface IObservableStarredClient /// /// Thrown if the client is not authenticated IObservable GetAllForCurrent(); - + /// /// Retrieves all of the starred (ies) for the current user /// @@ -91,7 +91,7 @@ public interface IObservableStarredClient /// /// Thrown if the client is not authenticated. IObservable GetAllForCurrentWithTimestamps(); - + /// /// Retrieves all of the starred (ies) for the current user with star creation timestamps. /// diff --git a/Octokit.Reactive/Clients/ObservableAssigneesClient.cs b/Octokit.Reactive/Clients/ObservableAssigneesClient.cs index 0eb3cff526..eb242d635b 100644 --- a/Octokit.Reactive/Clients/ObservableAssigneesClient.cs +++ b/Octokit.Reactive/Clients/ObservableAssigneesClient.cs @@ -87,6 +87,39 @@ public IObservable CheckAssignee(string owner, string name, string assigne return _client.CheckAssignee(owner, name, assignee).ToObservable(); } + /// + /// Add assignees to a specified Issue. + /// + /// The owner of the repository + /// The name of the repository + /// The issue number + /// List of names of assignees to add + public IObservable AddAssignees(string owner, string name, int number, AssigneesUpdate assignees) + { + Ensure.ArgumentNotNullOrEmptyString(owner, "owner"); + Ensure.ArgumentNotNullOrEmptyString(name, "name"); + Ensure.ArgumentNotNull(assignees, "assignees"); + + return _client.AddAssignees(owner, name, number, assignees).ToObservable(); + } + + /// + /// Remove assignees from a specified Issue. + /// + /// The owner of the repository + /// The name of the repository + /// The issue number + /// List of assignees to remove + /// + public IObservable RemoveAssignees(string owner, string name, int number, AssigneesUpdate assignees) + { + Ensure.ArgumentNotNullOrEmptyString(owner, "owner"); + Ensure.ArgumentNotNullOrEmptyString(name, "name"); + Ensure.ArgumentNotNull(assignees, "assignees"); + + return _client.RemoveAssignees(owner, name, number, assignees).ToObservable(); + } + /// /// Checks to see if a user is an assignee for a repository. /// diff --git a/Octokit.Reactive/Clients/ObservableCommitStatusClient.cs b/Octokit.Reactive/Clients/ObservableCommitStatusClient.cs index 4edc9e1d3b..8cf0fc04d4 100644 --- a/Octokit.Reactive/Clients/ObservableCommitStatusClient.cs +++ b/Octokit.Reactive/Clients/ObservableCommitStatusClient.cs @@ -37,7 +37,7 @@ public IObservable GetAll(string owner, string name, string refere Ensure.ArgumentNotNullOrEmptyString(name, "name"); Ensure.ArgumentNotNullOrEmptyString(reference, "reference"); - return GetAll(owner, name ,reference, ApiOptions.None); + return GetAll(owner, name, reference, ApiOptions.None); } /// @@ -68,7 +68,7 @@ public IObservable GetAll(string owner, string name, string refere Ensure.ArgumentNotNullOrEmptyString(owner, "owner"); Ensure.ArgumentNotNullOrEmptyString(name, "name"); Ensure.ArgumentNotNullOrEmptyString(reference, "reference"); - Ensure.ArgumentNotNull(options, "options"); + Ensure.ArgumentNotNull(options, "options"); return _connection.GetAndFlattenAllPages(ApiUrls.CommitStatuses(owner, name, reference), options); } diff --git a/Octokit.Reactive/Clients/ObservableEventsClient.cs b/Octokit.Reactive/Clients/ObservableEventsClient.cs index b365ea0ac6..666fc8c1d1 100644 --- a/Octokit.Reactive/Clients/ObservableEventsClient.cs +++ b/Octokit.Reactive/Clients/ObservableEventsClient.cs @@ -107,14 +107,14 @@ public IObservable GetAllForRepository(long repositoryId, ApiOptions o } /// - /// Gets all the events for a given repository + /// Gets all the issue events for a given repository /// /// /// http://developer.github.com/v3/activity/events/#list-issue-events-for-a-repository /// /// The owner of the repository /// The name of the repository - public IObservable GetAllIssuesForRepository(string owner, string name) + public IObservable GetAllIssuesForRepository(string owner, string name) { Ensure.ArgumentNotNullOrEmptyString(owner, "owner"); Ensure.ArgumentNotNullOrEmptyString(name, "name"); @@ -129,13 +129,13 @@ public IObservable GetAllIssuesForRepository(string owner, string name /// http://developer.github.com/v3/activity/events/#list-issue-events-for-a-repository /// /// The Id of the repository - public IObservable GetAllIssuesForRepository(long repositoryId) + public IObservable GetAllIssuesForRepository(long repositoryId) { return GetAllIssuesForRepository(repositoryId, ApiOptions.None); } /// - /// Gets all the events for a given repository + /// Gets all the issue events for a given repository /// /// /// http://developer.github.com/v3/activity/events/#list-issue-events-for-a-repository @@ -143,13 +143,13 @@ public IObservable GetAllIssuesForRepository(long repositoryId) /// The owner of the repository /// The name of the repository /// Options for changing the API response - public IObservable GetAllIssuesForRepository(string owner, string name, ApiOptions options) + public IObservable GetAllIssuesForRepository(string owner, string name, ApiOptions options) { Ensure.ArgumentNotNullOrEmptyString(owner, "owner"); Ensure.ArgumentNotNullOrEmptyString(name, "name"); Ensure.ArgumentNotNull(options, "options"); - return _connection.GetAndFlattenAllPages(ApiUrls.IssuesEvents(owner, name), options); + return _connection.GetAndFlattenAllPages(ApiUrls.IssuesEvents(owner, name), options); } /// @@ -160,11 +160,11 @@ public IObservable GetAllIssuesForRepository(string owner, string name /// /// The Id of the repository /// Options for changing the API response - public IObservable GetAllIssuesForRepository(long repositoryId, ApiOptions options) + public IObservable GetAllIssuesForRepository(long repositoryId, ApiOptions options) { Ensure.ArgumentNotNull(options, "options"); - return _connection.GetAndFlattenAllPages(ApiUrls.IssuesEvents(repositoryId), options); + return _connection.GetAndFlattenAllPages(ApiUrls.IssuesEvents(repositoryId), options); } /// @@ -382,7 +382,7 @@ public IObservable GetAllForAnOrganization(string user, string organiz Ensure.ArgumentNotNullOrEmptyString(organization, "organization"); Ensure.ArgumentNotNull(options, "options"); - return _connection.GetAndFlattenAllPages(ApiUrls.OrganizationEvents(user, organization),options); + return _connection.GetAndFlattenAllPages(ApiUrls.OrganizationEvents(user, organization), options); } } } diff --git a/Octokit.Reactive/Clients/ObservableGistCommentsClient.cs b/Octokit.Reactive/Clients/ObservableGistCommentsClient.cs index 57165687ab..240dd6f3a8 100644 --- a/Octokit.Reactive/Clients/ObservableGistCommentsClient.cs +++ b/Octokit.Reactive/Clients/ObservableGistCommentsClient.cs @@ -38,7 +38,7 @@ public IObservable Get(string gistId, int commentId) /// IObservable{GistComment}. public IObservable GetAllForGist(string gistId) { - Ensure.ArgumentNotNullOrEmptyString(gistId, "gistId"); + Ensure.ArgumentNotNullOrEmptyString(gistId, "gistId"); return GetAllForGist(gistId, ApiOptions.None); } diff --git a/Octokit.Reactive/Clients/ObservableGistsClient.cs b/Octokit.Reactive/Clients/ObservableGistsClient.cs index 1dbd817a8e..a76dd58d64 100644 --- a/Octokit.Reactive/Clients/ObservableGistsClient.cs +++ b/Octokit.Reactive/Clients/ObservableGistsClient.cs @@ -111,7 +111,7 @@ public IObservable GetAll(ApiOptions options) /// /// Only gists updated at or after this time are returned public IObservable GetAll(DateTimeOffset since) - { + { return GetAll(since, ApiOptions.None); } @@ -179,7 +179,7 @@ public IObservable GetAllPublic(DateTimeOffset since) /// Options for changing the API response public IObservable GetAllPublic(DateTimeOffset since, ApiOptions options) { - Ensure.ArgumentNotNull(options, "options"); + Ensure.ArgumentNotNull(options, "options"); var request = new GistRequest(since); return _connection.GetAndFlattenAllPages(ApiUrls.PublicGists(), request.ToParametersDictionary(), options); diff --git a/Octokit.Reactive/Clients/ObservableIssueCommentsClient.cs b/Octokit.Reactive/Clients/ObservableIssueCommentsClient.cs index 54527b7a48..7069091cd1 100644 --- a/Octokit.Reactive/Clients/ObservableIssueCommentsClient.cs +++ b/Octokit.Reactive/Clients/ObservableIssueCommentsClient.cs @@ -87,7 +87,7 @@ public IObservable GetAllForRepository(string owner, string name, Ensure.ArgumentNotNullOrEmptyString(name, "name"); Ensure.ArgumentNotNull(options, "options"); - return _connection.GetAndFlattenAllPages(ApiUrls.IssueComments(owner, name), null, AcceptHeaders.ReactionsPreview, options); + return GetAllForRepository(owner, name, new IssueCommentRequest(), options); } /// @@ -100,7 +100,69 @@ public IObservable GetAllForRepository(long repositoryId, ApiOptio { Ensure.ArgumentNotNull(options, "options"); - return _connection.GetAndFlattenAllPages(ApiUrls.IssueComments(repositoryId), options); + return GetAllForRepository(repositoryId, new IssueCommentRequest(), options); + } + + /// + /// Gets Issue Comments for a repository. + /// + /// http://developer.github.com/v3/issues/comments/#list-comments-in-a-repository + /// The owner of the repository + /// The name of the repository + /// The sorting parameters + public IObservable GetAllForRepository(string owner, string name, IssueCommentRequest request) + { + Ensure.ArgumentNotNullOrEmptyString(owner, "owner"); + Ensure.ArgumentNotNullOrEmptyString(name, "name"); + Ensure.ArgumentNotNull(request, "request"); + + return GetAllForRepository(owner, name, request, ApiOptions.None); + } + + /// + /// Gets Issue Comments for a repository. + /// + /// http://developer.github.com/v3/issues/comments/#list-comments-in-a-repository + /// The Id of the repository + /// The sorting parameters + public IObservable GetAllForRepository(long repositoryId, IssueCommentRequest request) + { + Ensure.ArgumentNotNull(request, "request"); + + return GetAllForRepository(repositoryId, request, ApiOptions.None); + } + + /// + /// Gets Issue Comments for a repository. + /// + /// http://developer.github.com/v3/issues/comments/#list-comments-in-a-repository + /// The owner of the repository + /// The name of the repository + /// The sorting parameters + /// Options for changing the API response + public IObservable GetAllForRepository(string owner, string name, IssueCommentRequest request, ApiOptions options) + { + Ensure.ArgumentNotNullOrEmptyString(owner, "owner"); + Ensure.ArgumentNotNullOrEmptyString(name, "name"); + Ensure.ArgumentNotNull(request, "request"); + Ensure.ArgumentNotNull(options, "options"); + + return _connection.GetAndFlattenAllPages(ApiUrls.IssueComments(owner, name), request.ToParametersDictionary(), AcceptHeaders.ReactionsPreview, options); + } + + /// + /// Gets Issue Comments for a repository. + /// + /// http://developer.github.com/v3/issues/comments/#list-comments-in-a-repository + /// The Id of the repository + /// The sorting parameters + /// Options for changing the API response + public IObservable GetAllForRepository(long repositoryId, IssueCommentRequest request, ApiOptions options) + { + Ensure.ArgumentNotNull(request, "request"); + Ensure.ArgumentNotNull(options, "options"); + + return _connection.GetAndFlattenAllPages(ApiUrls.IssueComments(repositoryId), request.ToParametersDictionary(), AcceptHeaders.ReactionsPreview, options); } /// diff --git a/Octokit.Reactive/Clients/ObservableOrganizationsClient.cs b/Octokit.Reactive/Clients/ObservableOrganizationsClient.cs index ff5b310132..966cd18415 100644 --- a/Octokit.Reactive/Clients/ObservableOrganizationsClient.cs +++ b/Octokit.Reactive/Clients/ObservableOrganizationsClient.cs @@ -64,7 +64,7 @@ public IObservable GetAllForCurrent(ApiOptions options) { Ensure.ArgumentNotNull(options, "options"); - return _connection.GetAndFlattenAllPages(ApiUrls.Organizations()); + return _connection.GetAndFlattenAllPages(ApiUrls.UserOrganizations()); } /// @@ -72,11 +72,12 @@ public IObservable GetAllForCurrent(ApiOptions options) /// /// The login for the user /// + [Obsolete("Please use ObservableOrganizationsClient.GetAllForUser() instead. This method will be removed in a future version")] public IObservable GetAll(string user) { Ensure.ArgumentNotNullOrEmptyString(user, "user"); - return _connection.GetAndFlattenAllPages(ApiUrls.Organizations(user)); + return _connection.GetAndFlattenAllPages(ApiUrls.UserOrganizations(user)); } /// @@ -85,12 +86,62 @@ public IObservable GetAll(string user) /// The login for the user /// Options for changing the API response /// + [Obsolete("Please use ObservableOrganizationsClient.GetAllForUser() instead. This method will be removed in a future version")] public IObservable GetAll(string user, ApiOptions options) { Ensure.ArgumentNotNullOrEmptyString(user, "user"); Ensure.ArgumentNotNull(options, "options"); - return _connection.GetAndFlattenAllPages(ApiUrls.Organizations(user), options); + return _connection.GetAndFlattenAllPages(ApiUrls.UserOrganizations(user), options); + } + + /// + /// Returns all the organizations for the specified user + /// + /// The login for the user + /// + public IObservable GetAllForUser(string user) + { + Ensure.ArgumentNotNullOrEmptyString(user, "user"); + + return _connection.GetAndFlattenAllPages(ApiUrls.UserOrganizations(user)); + } + + /// + /// Returns all the organizations for the specified user + /// + /// The login for the user + /// Options for changing the API response + /// + public IObservable GetAllForUser(string user, ApiOptions options) + { + Ensure.ArgumentNotNullOrEmptyString(user, "user"); + Ensure.ArgumentNotNull(options, "options"); + + return _connection.GetAndFlattenAllPages(ApiUrls.UserOrganizations(user), options); + } + + /// + /// Returns all the organizations + /// + /// + public IObservable GetAll() + { + return _connection.GetAndFlattenAllPages(ApiUrls.AllOrganizations()); + } + + /// + /// Returns all the organizations + /// + /// Search parameters of the last organization seen + /// + public IObservable GetAll(OrganizationRequest request) + { + Ensure.ArgumentNotNull(request, "request"); + + var url = ApiUrls.AllOrganizations(request.Since); + + return _connection.GetAndFlattenAllPages(url); } /// diff --git a/Octokit.Reactive/Clients/ObservablePullRequestReviewCommentsClient.cs b/Octokit.Reactive/Clients/ObservablePullRequestReviewCommentsClient.cs index 89bb8ea0c8..4caefcd4f4 100644 --- a/Octokit.Reactive/Clients/ObservablePullRequestReviewCommentsClient.cs +++ b/Octokit.Reactive/Clients/ObservablePullRequestReviewCommentsClient.cs @@ -20,7 +20,7 @@ public ObservablePullRequestReviewCommentsClient(IGitHubClient client) { Ensure.ArgumentNotNull(client, "client"); - _client = client.PullRequest.Comment; + _client = client.PullRequest.ReviewComment; _connection = client.Connection; } diff --git a/Octokit.Reactive/Clients/ObservablePullRequestsClient.cs b/Octokit.Reactive/Clients/ObservablePullRequestsClient.cs index be36824697..912d0fe293 100644 --- a/Octokit.Reactive/Clients/ObservablePullRequestsClient.cs +++ b/Octokit.Reactive/Clients/ObservablePullRequestsClient.cs @@ -16,9 +16,15 @@ public class ObservablePullRequestsClient : IObservablePullRequestsClient readonly IConnection _connection; /// - /// Client for managing comments. + /// Client for managing review comments. /// - public IObservablePullRequestReviewCommentsClient Comment { get; private set; } + [Obsolete("Please use ObservablePullRequestsClient.ReviewComment. This will be removed in a future version")] + public IObservablePullRequestReviewCommentsClient Comment { get { return this.ReviewComment; } } + + /// + /// Client for managing review comments. + /// + public IObservablePullRequestReviewCommentsClient ReviewComment { get; private set; } public ObservablePullRequestsClient(IGitHubClient client) { @@ -26,7 +32,7 @@ public ObservablePullRequestsClient(IGitHubClient client) _client = client.Repository.PullRequest; _connection = client.Connection; - Comment = new ObservablePullRequestReviewCommentsClient(client); + ReviewComment = new ObservablePullRequestReviewCommentsClient(client); } /// diff --git a/Octokit.Reactive/Clients/ObservableRepositoryCommentsClient.cs b/Octokit.Reactive/Clients/ObservableRepositoryCommentsClient.cs index e0f2e36e16..7749df06e2 100644 --- a/Octokit.Reactive/Clients/ObservableRepositoryCommentsClient.cs +++ b/Octokit.Reactive/Clients/ObservableRepositoryCommentsClient.cs @@ -15,7 +15,7 @@ public class ObservableRepositoryCommentsClient : IObservableRepositoryCommentsC { readonly IRepositoryCommentsClient _client; readonly IConnection _connection; - + public ObservableRepositoryCommentsClient(IGitHubClient client) { Ensure.ArgumentNotNull(client, "client"); diff --git a/Octokit.Reactive/Clients/ObservableRepositoryHooksClient.cs b/Octokit.Reactive/Clients/ObservableRepositoryHooksClient.cs index ea35f3b4f5..5b0268c0db 100644 --- a/Octokit.Reactive/Clients/ObservableRepositoryHooksClient.cs +++ b/Octokit.Reactive/Clients/ObservableRepositoryHooksClient.cs @@ -15,7 +15,7 @@ public class ObservableRepositoryHooksClient : IObservableRepositoryHooksClient { readonly IRepositoryHooksClient _client; readonly IConnection _connection; - + public ObservableRepositoryHooksClient(IGitHubClient client) { Ensure.ArgumentNotNull(client, "client"); diff --git a/Octokit.Tests.Conventions/ClientConstructorTests.cs b/Octokit.Tests.Conventions/ClientConstructorTests.cs index b5d0e7a5fb..eadd60d541 100644 --- a/Octokit.Tests.Conventions/ClientConstructorTests.cs +++ b/Octokit.Tests.Conventions/ClientConstructorTests.cs @@ -15,7 +15,7 @@ public void CheckTestConstructorNames(Type type) const string constructorTestMethodName = "EnsuresNonNullArguments"; var classes = new HashSet(type.GetNestedTypes().Select(t => t.Name)); - + if (!classes.Contains(constructorTestClassName)) { throw new MissingClientConstructorTestClassException(type); diff --git a/Octokit.Tests.Conventions/Exception/ApiOptionsMissingException.cs b/Octokit.Tests.Conventions/Exception/ApiOptionsMissingException.cs index 61d1111f12..51002dae8e 100644 --- a/Octokit.Tests.Conventions/Exception/ApiOptionsMissingException.cs +++ b/Octokit.Tests.Conventions/Exception/ApiOptionsMissingException.cs @@ -8,7 +8,8 @@ namespace Octokit.Tests.Conventions public class ApiOptionsMissingException : Exception { public ApiOptionsMissingException(Type type, IEnumerable methods) - : base(CreateMessage(type, methods)) { } + : base(CreateMessage(type, methods)) + { } static string CreateMessage(Type type, IEnumerable methods) { diff --git a/Octokit.Tests.Integration/Clients/AssigneesClientTests.cs b/Octokit.Tests.Integration/Clients/AssigneesClientTests.cs index 8df64aa123..2ebc10d0e3 100644 --- a/Octokit.Tests.Integration/Clients/AssigneesClientTests.cs +++ b/Octokit.Tests.Integration/Clients/AssigneesClientTests.cs @@ -1,4 +1,5 @@ -using System.Linq; +using System.Collections.Generic; +using System.Linq; using System.Threading.Tasks; using Octokit; using Octokit.Tests.Integration; @@ -9,6 +10,7 @@ public class AssigneesClientTests { readonly IGitHubClient _github; readonly RepositoryContext _context; + readonly IIssuesClient _issuesClient; public AssigneesClientTests() { @@ -53,6 +55,30 @@ public async Task CanListAssignees() } [IntegrationTest] + public async Task CanAddAndRemoveAssignees() + { + var newAssignees = new AssigneesUpdate(new List() { _context.RepositoryOwner }); + var newIssue = new NewIssue("a test issue") { Body = "A new unassigned issue" }; + var issuesClient = _github.Issue; + + var issue = await issuesClient.Create(_context.RepositoryOwner, _context.RepositoryName, newIssue); + + Assert.NotNull(issue); + + var addAssignees = await _github.Issue.Assignee.AddAssignees(_context.RepositoryOwner, _context.RepositoryName, issue.Number, newAssignees); + + Assert.IsType(addAssignees); + + //Check if assignee was added to issue + Assert.True(addAssignees.Assignees.Any(x => x.Login == _context.RepositoryOwner)); + + //Test to remove assignees + var removeAssignees = await _github.Issue.Assignee.RemoveAssignees(_context.RepositoryOwner, _context.RepositoryName, issue.Number, newAssignees); + + //Check if assignee was removed + Assert.False(removeAssignees.Assignees.Any(x => x.Login == _context.RepositoryOwner)); + } + public async Task CanListAssigneesWithRepositoryId() { // Repository owner is always an assignee diff --git a/Octokit.Tests.Integration/Clients/AuthorizationClientTests.cs b/Octokit.Tests.Integration/Clients/AuthorizationClientTests.cs index 72ed1ad5cd..3ef380659a 100644 --- a/Octokit.Tests.Integration/Clients/AuthorizationClientTests.cs +++ b/Octokit.Tests.Integration/Clients/AuthorizationClientTests.cs @@ -30,7 +30,7 @@ public async Task CanCreatePersonalToken() public async Task CanGetAuthorization() { var github = Helper.GetBasicAuthClient(); - + var authorizations = await github.Authorization.GetAll(); Assert.NotEmpty(authorizations); } diff --git a/Octokit.Tests.Integration/Clients/DeploymentStatusClientTests.cs b/Octokit.Tests.Integration/Clients/DeploymentStatusClientTests.cs index 4c6ae33861..bb6ce3aaee 100644 --- a/Octokit.Tests.Integration/Clients/DeploymentStatusClientTests.cs +++ b/Octokit.Tests.Integration/Clients/DeploymentStatusClientTests.cs @@ -162,7 +162,7 @@ public async Task ReturnsCorrectCountOfDeploymentStatusesWithStartWithRepository var newStatus1 = new NewDeploymentStatus(DeploymentState.Success); var newStatus2 = new NewDeploymentStatus(DeploymentState.Success); var newStatus3 = new NewDeploymentStatus(DeploymentState.Success); - await _deploymentsClient.Status.Create(_context.Repository.Id,_deployment.Id, newStatus1); + await _deploymentsClient.Status.Create(_context.Repository.Id, _deployment.Id, newStatus1); await _deploymentsClient.Status.Create(_context.Repository.Id, _deployment.Id, newStatus2); await _deploymentsClient.Status.Create(_context.Repository.Id, _deployment.Id, newStatus3); diff --git a/Octokit.Tests.Integration/Clients/EventsClientTests.cs b/Octokit.Tests.Integration/Clients/EventsClientTests.cs index d8cc1f0c25..e0e8545665 100644 --- a/Octokit.Tests.Integration/Clients/EventsClientTests.cs +++ b/Octokit.Tests.Integration/Clients/EventsClientTests.cs @@ -109,7 +109,7 @@ public async Task ReturnsCorrectCountOfEventsWithStartWithRepositoryId() public async Task ReturnsDistinctEventsBasedOnStartPage() { var github = Helper.GetAuthenticatedClient(); - + var startOptions = new ApiOptions { PageSize = 1, @@ -134,7 +134,7 @@ public async Task ReturnsDistinctEventsBasedOnStartPage() public async Task ReturnsDistinctEventsBasedOnStartPageWithRepositoryId() { var github = Helper.GetAuthenticatedClient(); - + var startOptions = new ApiOptions { PageSize = 1, @@ -158,7 +158,7 @@ public async Task ReturnsDistinctEventsBasedOnStartPageWithRepositoryId() public class TheGetAllIssuesForRepositoryMethod { - [IntegrationTest(Skip = "Fails because of SimpleJsonSerializer, see https://github.com/octokit/octokit.net/issues/1374 for details.")] + [IntegrationTest] public async Task CanListIssues() { var github = Helper.GetAuthenticatedClient(); @@ -167,7 +167,7 @@ public async Task CanListIssues() Assert.NotEmpty(issues); } - [IntegrationTest(Skip = "Fails because of SimpleJsonSerializer, see https://github.com/octokit/octokit.net/issues/1374 for details.")] + [IntegrationTest] public async Task CanListIssuesWithRepositoryId() { var github = Helper.GetAuthenticatedClient(); @@ -176,7 +176,7 @@ public async Task CanListIssuesWithRepositoryId() Assert.NotEmpty(issues); } - [IntegrationTest(Skip = "Fails because of SimpleJsonSerializer, see https://github.com/octokit/octokit.net/issues/1374 for details.")] + [IntegrationTest] public async Task ReturnsCorrectCountOfEventsWithoutStart() { var github = Helper.GetAuthenticatedClient(); @@ -192,7 +192,7 @@ public async Task ReturnsCorrectCountOfEventsWithoutStart() Assert.Equal(3, eventInfos.Count); } - [IntegrationTest(Skip = "Fails because of SimpleJsonSerializer, see https://github.com/octokit/octokit.net/issues/1374 for details.")] + [IntegrationTest] public async Task ReturnsCorrectCountOfEventsWithoutStartWitRepositoryId() { var github = Helper.GetAuthenticatedClient(); @@ -208,7 +208,7 @@ public async Task ReturnsCorrectCountOfEventsWithoutStartWitRepositoryId() Assert.Equal(3, eventInfos.Count); } - [IntegrationTest(Skip = "Fails because of SimpleJsonSerializer, see https://github.com/octokit/octokit.net/issues/1374 for details.")] + [IntegrationTest] public async Task ReturnsCorrectCountOfEventsWithStart() { var github = Helper.GetAuthenticatedClient(); @@ -225,7 +225,7 @@ public async Task ReturnsCorrectCountOfEventsWithStart() Assert.Equal(2, eventInfos.Count); } - [IntegrationTest(Skip = "Fails because of SimpleJsonSerializer, see https://github.com/octokit/octokit.net/issues/1374 for details.")] + [IntegrationTest] public async Task ReturnsCorrectCountOfEventsWithStartWithRepositoryId() { var github = Helper.GetAuthenticatedClient(); @@ -242,7 +242,7 @@ public async Task ReturnsCorrectCountOfEventsWithStartWithRepositoryId() Assert.Equal(2, eventInfos.Count); } - [IntegrationTest(Skip = "Fails because of SimpleJsonSerializer, see https://github.com/octokit/octokit.net/issues/1374 for details.")] + [IntegrationTest] public async Task ReturnsDistinctEventsBasedOnStartPage() { var github = Helper.GetAuthenticatedClient(); @@ -267,7 +267,7 @@ public async Task ReturnsDistinctEventsBasedOnStartPage() Assert.NotEqual(firstPage[0].Id, secondPage[0].Id); } - [IntegrationTest(Skip = "Fails because of SimpleJsonSerializer, see https://github.com/octokit/octokit.net/issues/1374 for details.")] + [IntegrationTest] public async Task ReturnsDistinctEventsBasedOnStartPageWithRepositoryId() { var github = Helper.GetAuthenticatedClient(); diff --git a/Octokit.Tests.Integration/Clients/IssueCommentsClientTests.cs b/Octokit.Tests.Integration/Clients/IssueCommentsClientTests.cs index 9bb74b1232..168b9c087f 100644 --- a/Octokit.Tests.Integration/Clients/IssueCommentsClientTests.cs +++ b/Octokit.Tests.Integration/Clients/IssueCommentsClientTests.cs @@ -13,7 +13,7 @@ public class TheGetMethod { readonly IGitHubClient _github; readonly IIssueCommentsClient _issueCommentsClient; - + const string owner = "octokit"; const string name = "octokit.net"; const int id = 12067722; @@ -220,7 +220,7 @@ public async Task CanGetReactionPayload() using (var context = await _github.CreateRepositoryContext(Helper.MakeNameWithTimestamp("IssueCommentsReactionTests"))) { var commentIds = new List(); - + // Create multiple test issues for (int count = 1; count <= numberToCreate; count++) { diff --git a/Octokit.Tests.Integration/Clients/IssueReactionsClientTests.cs b/Octokit.Tests.Integration/Clients/IssueReactionsClientTests.cs index cb684dbbd2..f4ffbcb31e 100644 --- a/Octokit.Tests.Integration/Clients/IssueReactionsClientTests.cs +++ b/Octokit.Tests.Integration/Clients/IssueReactionsClientTests.cs @@ -71,7 +71,7 @@ public async Task CanCreateReaction() { var newReaction = new NewReaction(reactionType); - var reaction = await _github.Reaction.CommitComment.Create(_context.RepositoryOwner, _context.RepositoryName, issue.Id, newReaction); + var reaction = await _github.Reaction.Issue.Create(_context.RepositoryOwner, _context.RepositoryName, issue.Number, newReaction); Assert.IsType(reaction); Assert.Equal(reactionType, reaction.Content); diff --git a/Octokit.Tests.Integration/Clients/IssueTimelineClientTests.cs b/Octokit.Tests.Integration/Clients/IssueTimelineClientTests.cs index af18d72f67..c19148f03a 100644 --- a/Octokit.Tests.Integration/Clients/IssueTimelineClientTests.cs +++ b/Octokit.Tests.Integration/Clients/IssueTimelineClientTests.cs @@ -5,7 +5,7 @@ namespace Octokit.Tests.Integration.Clients { - public class IssueTimelineClientTests :IDisposable + public class IssueTimelineClientTests : IDisposable { private readonly IIssueTimelineClient _issueTimelineClient; private readonly IIssuesClient _issuesClient; @@ -86,7 +86,7 @@ public async Task CanDeserializeCrossReferenceEvent() var timelineEventInfos = await _issueTimelineClient.GetAllForIssue(_context.RepositoryOwner, _context.RepositoryName, issue.Number); Assert.Equal(1, timelineEventInfos.Count); - Assert.Equal(anotherNewIssue.Id, timelineEventInfos[0].Source.Id); + Assert.Equal(anotherNewIssue.Id, timelineEventInfos[0].Source.Issue.Id); } [IntegrationTest] @@ -133,7 +133,7 @@ public async Task CanDeserializeCrossReferenceEventByRepositoryId() var timelineEventInfos = await _issueTimelineClient.GetAllForIssue(_context.Repository.Id, issue.Number); Assert.Equal(1, timelineEventInfos.Count); - Assert.Equal(anotherNewIssue.Id, timelineEventInfos[0].Source.Id); + Assert.Equal(anotherNewIssue.Id, timelineEventInfos[0].Source.Issue.Id); } public void Dispose() diff --git a/Octokit.Tests.Integration/Clients/IssuesClientTests.cs b/Octokit.Tests.Integration/Clients/IssuesClientTests.cs index 205d99d969..eeafb095cd 100644 --- a/Octokit.Tests.Integration/Clients/IssuesClientTests.cs +++ b/Octokit.Tests.Integration/Clients/IssuesClientTests.cs @@ -98,7 +98,7 @@ public async Task ReturnsPageOfIssuesForARepositoryWithStartPage() var options = new ApiOptions { PageSize = 5, - PageCount = 1, + PageCount = 1, StartPage = 2 }; @@ -186,20 +186,30 @@ public async Task ReturnsPageOfIssuesFromStartForARepositoryWithRepositoryId() public async Task CanCreateRetrieveAndCloseIssue() { var newIssue = new NewIssue("a test issue") { Body = "A new unassigned issue" }; + newIssue.Labels.Add("test"); + newIssue.Assignees.Add(_context.RepositoryOwner); + var issue = await _issuesClient.Create(_context.RepositoryOwner, _context.RepositoryName, newIssue); try { Assert.NotNull(issue); + Assert.True(issue.Assignees.All(x => x.Login == _context.RepositoryOwner)); var retrieved = await _issuesClient.Get(_context.RepositoryOwner, _context.RepositoryName, issue.Number); - var all = await _issuesClient.GetAllForRepository(_context.RepositoryOwner, _context.RepositoryName); Assert.NotNull(retrieved); + Assert.True(retrieved.Assignees.Count == 1); + Assert.True(retrieved.Assignees[0].Login == _context.RepositoryOwner); + var all = await _issuesClient.GetAllForRepository(_context.RepositoryOwner, _context.RepositoryName); Assert.True(all.Any(i => i.Number == retrieved.Number)); + Assert.True(all.Any(i => i.Assignees.Count == 1)); + Assert.True(all.Any(i => i.Assignees[0].Login == _context.RepositoryOwner)); } finally { var closed = _issuesClient.Update(_context.RepositoryOwner, _context.RepositoryName, issue.Number, new IssueUpdate { State = ItemState.Closed }).Result; Assert.NotNull(closed); + Assert.Equal(1, closed.Assignees.Count); + Assert.Equal(_context.RepositoryOwner, closed.Assignees[0].Login); } } @@ -568,6 +578,28 @@ public async Task CanRetrieveAllIssues() Assert.True(retrieved.Any(i => i.Number == issue4.Number)); } + [IntegrationTest] + public async Task CanRetrieveIssueWithMultipleAssignees() + { + var issue = await _issuesClient.Get("octokit", "octokit.net", 1171); + + Assert.Equal(2, issue.Assignees.Count); + } + + [IntegrationTest] + public async Task CanRetrieveIssuesWithMultipleAssignees() + { + var newIssue1 = new NewIssue("A test issue1") { Body = "A new unassigned issue" }; + var issue1 = await _issuesClient.Create(_context.RepositoryOwner, _context.RepositoryName, newIssue1); + + await _issuesClient.Assignee.AddAssignees(_context.RepositoryOwner, _context.RepositoryName, issue1.Number, new AssigneesUpdate(new List() { _context.RepositoryOwner })); + + var request = new RepositoryIssueRequest { State = ItemStateFilter.All }; + var issues = await _issuesClient.GetAllForRepository(_context.RepositoryOwner, _context.RepositoryName, request); + + Assert.True(issues.Any(x => x.Assignees.Count > 0)); + } + [IntegrationTest] public async Task CanRetrieveAllIssuesReturnsDistinctReulstsBasedOnApiOptions() { @@ -634,9 +666,11 @@ public async Task CanRetrieveAllIssuesWithRepositoryId() [IntegrationTest] public async Task CanFilterByAssigned() { - var newIssue1 = new NewIssue("An assigned issue") { Body = "Assigning this to myself", Assignee = _context.RepositoryOwner }; - var newIssue2 = new NewIssue("An unassigned issue") { Body = "A new unassigned issue" }; + var newIssue1 = new NewIssue("An assigned issue") { Body = "Assigning this to myself" }; + newIssue1.Assignees.Add(_context.RepositoryOwner); await _issuesClient.Create(_context.RepositoryOwner, _context.RepositoryName, newIssue1); + + var newIssue2 = new NewIssue("An unassigned issue") { Body = "A new unassigned issue" }; await _issuesClient.Create(_context.RepositoryOwner, _context.RepositoryName, newIssue2); var allIssues = await _issuesClient.GetAllForRepository(_context.RepositoryOwner, _context.RepositoryName, @@ -660,9 +694,11 @@ public async Task CanFilterByAssigned() [IntegrationTest] public async Task CanFilterByAssignedWithRepositoryId() { - var newIssue1 = new NewIssue("An assigned issue") { Body = "Assigning this to myself", Assignee = _context.RepositoryOwner }; - var newIssue2 = new NewIssue("An unassigned issue") { Body = "A new unassigned issue" }; + var newIssue1 = new NewIssue("An assigned issue") { Body = "Assigning this to myself" }; + newIssue1.Assignees.Add(_context.RepositoryOwner); await _issuesClient.Create(_context.Repository.Id, newIssue1); + + var newIssue2 = new NewIssue("An unassigned issue") { Body = "A new unassigned issue" }; await _issuesClient.Create(_context.Repository.Id, newIssue2); var allIssues = await _issuesClient.GetAllForRepository(_context.Repository.Id, @@ -881,6 +917,44 @@ public async Task DoesNotChangeLabelsByDefaultWithRepositoryId() Assert.Equal(1, updatedIssue.Labels.Count); } + [IntegrationTest] + public async Task DoesNotChangeEmptyLabelsByDefault() + { + await _issuesClient.Labels.Create(_context.RepositoryOwner, _context.RepositoryName, new NewLabel("something", "FF0000")); + + var newIssue = new NewIssue("A test issue1") + { + Body = "A new unassigned issue" + }; + + var issue = await _issuesClient.Create(_context.RepositoryOwner, _context.RepositoryName, newIssue); + + var issueUpdate = issue.ToUpdate(); + + var updatedIssue = await _issuesClient.Update(_context.RepositoryOwner, _context.RepositoryName, issue.Number, issueUpdate); + + Assert.Empty(updatedIssue.Labels); + } + + [IntegrationTest] + public async Task DoesNotChangeEmptyLabelsByDefaultWithRepositoryId() + { + await _issuesClient.Labels.Create(_context.RepositoryOwner, _context.RepositoryName, new NewLabel("something", "FF0000")); + + var newIssue = new NewIssue("A test issue1") + { + Body = "A new unassigned issue" + }; + + var issue = await _issuesClient.Create(_context.Repository.Id, newIssue); + + var issueUpdate = issue.ToUpdate(); + + var updatedIssue = await _issuesClient.Update(_context.Repository.Id, issue.Number, issueUpdate); + + Assert.Empty(updatedIssue.Labels); + } + [IntegrationTest] public async Task CanUpdateLabelForAnIssue() { @@ -985,6 +1059,162 @@ public async Task CanClearLabelsForAnIssueWithRepositoryId() Assert.Empty(updatedIssue.Labels); } + [IntegrationTest] + public async Task DoesNotChangeAssigneesByDefault() + { + var newIssue = new NewIssue("A test issue1") + { + Body = "A new unassigned issue" + }; + newIssue.Assignees.Add(_context.RepositoryOwner); + + var issue = await _issuesClient.Create(_context.RepositoryOwner, _context.RepositoryName, newIssue); + + var issueUpdate = issue.ToUpdate(); + + var updatedIssue = await _issuesClient.Update(_context.RepositoryOwner, _context.RepositoryName, issue.Number, issueUpdate); + + Assert.Equal(1, updatedIssue.Assignees.Count); + Assert.Equal(_context.RepositoryOwner, updatedIssue.Assignees[0].Login); + } + + [IntegrationTest] + public async Task DoesNotChangeAssigneesByDefaultWithRepositoryId() + { + var newIssue = new NewIssue("A test issue1") + { + Body = "A new unassigned issue" + }; + newIssue.Assignees.Add(_context.RepositoryOwner); + + var issue = await _issuesClient.Create(_context.Repository.Id, newIssue); + + var issueUpdate = issue.ToUpdate(); + + var updatedIssue = await _issuesClient.Update(_context.Repository.Id, issue.Number, issueUpdate); + + Assert.Equal(1, updatedIssue.Assignees.Count); + Assert.Equal(_context.RepositoryOwner, updatedIssue.Assignees[0].Login); + } + + [IntegrationTest] + public async Task DoesNotChangeEmptyAssigneesByDefault() + { + var newIssue = new NewIssue("A test issue1") + { + Body = "A new unassigned issue" + }; + + var issue = await _issuesClient.Create(_context.RepositoryOwner, _context.RepositoryName, newIssue); + + var issueUpdate = issue.ToUpdate(); + + var updatedIssue = await _issuesClient.Update(_context.RepositoryOwner, _context.RepositoryName, issue.Number, issueUpdate); + + Assert.Empty(updatedIssue.Assignees); + } + + [IntegrationTest] + public async Task DoesNotChangeEmptyAssigneesByDefaultWithRepositoryId() + { + var newIssue = new NewIssue("A test issue1") + { + Body = "A new unassigned issue" + }; + + var issue = await _issuesClient.Create(_context.Repository.Id, newIssue); + + var issueUpdate = issue.ToUpdate(); + + var updatedIssue = await _issuesClient.Update(_context.Repository.Id, issue.Number, issueUpdate); + + Assert.Empty(updatedIssue.Assignees); + } + + [IntegrationTest] + public async Task CanUpdateAssigneeForAnIssue() + { + // setup us the issue + var newIssue = new NewIssue("A test issue1") + { + Body = "A new unassigned issue" + }; + + var issue = await _issuesClient.Create(_context.RepositoryOwner, _context.RepositoryName, newIssue); + + // update the issue + var issueUpdate = issue.ToUpdate(); + issueUpdate.AddAssignee(_context.RepositoryOwner); + + var updatedIssue = await _issuesClient.Update(_context.RepositoryOwner, _context.RepositoryName, issue.Number, issueUpdate); + + Assert.Equal(_context.RepositoryOwner, updatedIssue.Assignees[0].Login); + } + + [IntegrationTest] + public async Task CanUpdateAssigneeForAnIssueWithRepositoryId() + { + // setup us the issue + var newIssue = new NewIssue("A test issue1") + { + Body = "A new unassigned issue" + }; + + var issue = await _issuesClient.Create(_context.Repository.Id, newIssue); + + // update the issue + var issueUpdate = issue.ToUpdate(); + issueUpdate.AddAssignee(_context.RepositoryOwner); + + var updatedIssue = await _issuesClient.Update(_context.Repository.Id, issue.Number, issueUpdate); + + Assert.Equal(_context.RepositoryOwner, updatedIssue.Assignees[0].Login); + } + + [IntegrationTest] + public async Task CanClearAssigneesForAnIssue() + { + // setup us the issue + var newIssue = new NewIssue("A test issue1") + { + Body = "A new unassigned issue" + }; + newIssue.Assignees.Add(_context.RepositoryOwner); + + var issue = await _issuesClient.Create(_context.RepositoryOwner, _context.RepositoryName, newIssue); + Assert.Equal(1, issue.Assignees.Count); + + // update the issue + var issueUpdate = issue.ToUpdate(); + issueUpdate.ClearAssignees(); + + var updatedIssue = await _issuesClient.Update(_context.RepositoryOwner, _context.RepositoryName, issue.Number, issueUpdate); + + Assert.Empty(updatedIssue.Assignees); + } + + [IntegrationTest] + public async Task CanClearAssigneesForAnIssueWithRepositoryId() + { + // setup us the issue + var newIssue = new NewIssue("A test issue1") + { + Body = "A new unassigned issue" + }; + newIssue.Assignees.Add(_context.RepositoryOwner); + + var issue = await _issuesClient.Create(_context.Repository.Id, newIssue); + Assert.Equal(1, issue.Assignees.Count); + + // update the issue + var issueUpdate = issue.ToUpdate(); + issueUpdate.ClearAssignees(); + + var updatedIssue = await _issuesClient.Update(_context.Repository.Id, issue.Number, issueUpdate); + + Assert.Empty(updatedIssue.Assignees); + } + [IntegrationTest] public async Task CanAccessUrls() { diff --git a/Octokit.Tests.Integration/Clients/IssuesLabelsClientTests.cs b/Octokit.Tests.Integration/Clients/IssuesLabelsClientTests.cs index b025fc5544..dd43dc9658 100644 --- a/Octokit.Tests.Integration/Clients/IssuesLabelsClientTests.cs +++ b/Octokit.Tests.Integration/Clients/IssuesLabelsClientTests.cs @@ -139,14 +139,14 @@ public async Task ReturnsCorrectCountOfIssueLabelsWithStartForAnIssue() for (int i = 0; i < 2; i++) { - var label = await _issuesLabelsClient.Create(_context.RepositoryOwner, _context.RepositoryName, new NewLabel("test label " + (i + 1), "FFFFF" + (i+1))); + var label = await _issuesLabelsClient.Create(_context.RepositoryOwner, _context.RepositoryName, new NewLabel("test label " + (i + 1), "FFFFF" + (i + 1))); labels.Add(label); issueUpdate.AddLabel(label.Name); } var issueLabelsInfo = await _issuesLabelsClient.GetAllForIssue(_context.RepositoryOwner, _context.RepositoryName, issue.Number); Assert.Empty(issueLabelsInfo); - + var updated = await _issuesClient.Update(_context.RepositoryOwner, _context.RepositoryName, issue.Number, issueUpdate); Assert.NotNull(updated); @@ -173,14 +173,14 @@ public async Task ReturnsCorrectCountOfIssueLabelsWithStartForAnIssueWithReposit for (int i = 0; i < 2; i++) { - var label = await _issuesLabelsClient.Create(_context.Repository.Id, new NewLabel("test label " + (i + 1), "FFFFF" + (i+1))); + var label = await _issuesLabelsClient.Create(_context.Repository.Id, new NewLabel("test label " + (i + 1), "FFFFF" + (i + 1))); labels.Add(label); issueUpdate.AddLabel(label.Name); } var issueLabelsInfo = await _issuesLabelsClient.GetAllForIssue(_context.Repository.Id, issue.Number); Assert.Empty(issueLabelsInfo); - + var updated = await _issuesClient.Update(_context.RepositoryOwner, _context.RepositoryName, issue.Number, issueUpdate); Assert.NotNull(updated); @@ -202,7 +202,7 @@ public async Task ReturnsDistinctIssueLabelsBasedOnStartPageForAnIssue() { var issue = await _issuesClient.Create(_context.RepositoryOwner, _context.RepositoryName, new NewIssue("A test issue") { Body = "A new unassigned issue" }); var issueUpdate = new IssueUpdate(); - + for (int i = 0; i < 2; i++) { var label = await _issuesLabelsClient.Create(_context.RepositoryOwner, _context.RepositoryName, new NewLabel("test label " + (i + 1), "FFFFF" + (i + 1))); @@ -243,7 +243,7 @@ public async Task ReturnsDistinctIssueLabelsBasedOnStartPageForAnIssueWithReposi { var issue = await _issuesClient.Create(_context.RepositoryOwner, _context.RepositoryName, new NewIssue("A test issue") { Body = "A new unassigned issue" }); var issueUpdate = new IssueUpdate(); - + for (int i = 0; i < 2; i++) { var label = await _issuesLabelsClient.Create(_context.Repository.Id, new NewLabel("test label " + (i + 1), "FFFFF" + (i + 1))); @@ -521,7 +521,7 @@ public async Task CanListLabelsForAnMilestone() var label = await _issuesLabelsClient.Create(_context.RepositoryOwner, _context.RepositoryName, newLabel); var issue = await _issuesClient.Create(_context.RepositoryOwner, _context.RepositoryName, newIssue); var milestone = await _issuesClient.Milestone.Create(_context.RepositoryOwner, _context.RepositoryName, newMilestone); - + var issueLabelsInfo = await _issuesLabelsClient.GetAllForMilestone(_context.RepositoryOwner, _context.RepositoryName, milestone.Number); Assert.Empty(issueLabelsInfo); @@ -547,7 +547,7 @@ public async Task CanListLabelsForAnMilestoneWithRepositoryId() var label = await _issuesLabelsClient.Create(_context.Repository.Id, newLabel); var issue = await _issuesClient.Create(_context.RepositoryOwner, _context.RepositoryName, newIssue); var milestone = await _issuesClient.Milestone.Create(_context.RepositoryOwner, _context.RepositoryName, newMilestone); - + var issueLabelsInfo = await _issuesLabelsClient.GetAllForMilestone(_context.Repository.Id, milestone.Number); Assert.Empty(issueLabelsInfo); @@ -853,7 +853,7 @@ public async Task CanAddToIssue() var issue = await _issuesClient.Create(_context.RepositoryOwner, _context.RepositoryName, newIssue); Assert.NotNull(issue); - await _issuesLabelsClient.AddToIssue(_context.RepositoryOwner, _context.RepositoryName, issue.Number, new []{ label.Name }); + await _issuesLabelsClient.AddToIssue(_context.RepositoryOwner, _context.RepositoryName, issue.Number, new[] { label.Name }); var labels = await _issuesLabelsClient.GetAllForIssue(_context.RepositoryOwner, _context.RepositoryName, issue.Number); @@ -895,7 +895,7 @@ public async Task CanRemoveAllFromIssue() var issue = await _issuesClient.Create(_context.RepositoryOwner, _context.RepositoryName, newIssue); Assert.NotNull(issue); - await _issuesLabelsClient.AddToIssue(_context.RepositoryOwner, _context.RepositoryName, issue.Number, new []{ label.Name }); + await _issuesLabelsClient.AddToIssue(_context.RepositoryOwner, _context.RepositoryName, issue.Number, new[] { label.Name }); await _issuesLabelsClient.RemoveAllFromIssue(_context.RepositoryOwner, _context.RepositoryName, issue.Number); var labels = await _issuesLabelsClient.GetAllForIssue(_context.RepositoryOwner, _context.RepositoryName, issue.Number); @@ -935,7 +935,7 @@ public async Task CanRemoveFromIssue() var issue = await _issuesClient.Create(_context.RepositoryOwner, _context.RepositoryName, newIssue); Assert.NotNull(issue); - await _issuesLabelsClient.AddToIssue(_context.RepositoryOwner, _context.RepositoryName, issue.Number, new []{ label.Name }); + await _issuesLabelsClient.AddToIssue(_context.RepositoryOwner, _context.RepositoryName, issue.Number, new[] { label.Name }); await _issuesLabelsClient.RemoveFromIssue(_context.RepositoryOwner, _context.RepositoryName, issue.Number, label.Name); var labels = await _issuesLabelsClient.GetAllForIssue(_context.RepositoryOwner, _context.RepositoryName, issue.Number); @@ -978,7 +978,7 @@ public async Task CanReplaceAllForIssue() var issue = await _issuesClient.Create(_context.RepositoryOwner, _context.RepositoryName, newIssue1); Assert.NotNull(issue); - await _issuesLabelsClient.AddToIssue(_context.RepositoryOwner, _context.RepositoryName, issue.Number, new []{ label1.Name }); + await _issuesLabelsClient.AddToIssue(_context.RepositoryOwner, _context.RepositoryName, issue.Number, new[] { label1.Name }); await _issuesLabelsClient.ReplaceAllForIssue(_context.RepositoryOwner, _context.RepositoryName, issue.Number, new[] { label2.Name }); var labels = await _issuesLabelsClient.GetAllForIssue(_context.RepositoryOwner, _context.RepositoryName, issue.Number); diff --git a/Octokit.Tests.Integration/Clients/MigrationsClientTests.cs b/Octokit.Tests.Integration/Clients/MigrationsClientTests.cs index 8c43c03dd9..3ed7d8bd09 100644 --- a/Octokit.Tests.Integration/Clients/MigrationsClientTests.cs +++ b/Octokit.Tests.Integration/Clients/MigrationsClientTests.cs @@ -81,11 +81,11 @@ public async Task CanGetArchive() { while (!isExported) { - Thread.Sleep(2000); + Thread.Sleep(2000); } var contents = await _gitHub.Migration.Migrations.GetArchive(_orgName, _migrationContext.Id); - + Assert.NotEmpty(contents); } @@ -127,6 +127,6 @@ async Task ChecksMigrationCompletion() public void Dispose() { - _repos.ForEach( (repo) => repo.Dispose() ); + _repos.ForEach((repo) => repo.Dispose()); } } diff --git a/Octokit.Tests.Integration/Clients/MilestonesClientTests.cs b/Octokit.Tests.Integration/Clients/MilestonesClientTests.cs index 7952c0e49d..9624336dae 100644 --- a/Octokit.Tests.Integration/Clients/MilestonesClientTests.cs +++ b/Octokit.Tests.Integration/Clients/MilestonesClientTests.cs @@ -94,7 +94,7 @@ public async Task CanUpdateOneMilestoneWithRepositoryId() var result1 = await _milestonesClient.Get(_context.Repository.Id, created.Number); Assert.Equal("a milestone", result1.Title); - await _milestonesClient.Update(_context.Repository.Id, created.Number, new MilestoneUpdate {Title = "New title"}); + await _milestonesClient.Update(_context.Repository.Id, created.Number, new MilestoneUpdate { Title = "New title" }); var result2 = await _milestonesClient.Get(_context.Repository.Id, created.Number); Assert.Equal("New title", result2.Title); @@ -315,7 +315,7 @@ public async Task ReturnsDistinctResultsBasedOnStartPage() await _milestonesClient.Create(_context.RepositoryOwner, _context.RepositoryName, milestone1); await _milestonesClient.Create(_context.RepositoryOwner, _context.RepositoryName, milestone2); await _milestonesClient.Create(_context.RepositoryOwner, _context.RepositoryName, milestone3); - + var startOptions = new ApiOptions { PageSize = 1, @@ -345,7 +345,7 @@ public async Task ReturnsDistinctResultsBasedOnStartPageWithRepositoryId() await _milestonesClient.Create(_context.RepositoryOwner, _context.RepositoryName, milestone1); await _milestonesClient.Create(_context.RepositoryOwner, _context.RepositoryName, milestone2); await _milestonesClient.Create(_context.RepositoryOwner, _context.RepositoryName, milestone3); - + var startOptions = new ApiOptions { PageSize = 1, @@ -486,7 +486,7 @@ public async Task ReturnsDistinctResultsBasedOnStartPageParametrized() PageCount = 1, StartPage = 2 }; - + var secondPage = await _milestonesClient.GetAllForRepository(_context.RepositoryOwner, _context.RepositoryName, milestoneRequest, skipStartOptions); Assert.NotEqual(firstPage[0].Number, secondPage[0].Number); @@ -518,7 +518,7 @@ public async Task ReturnsDistinctResultsBasedOnStartPageParametrizedWithReposito PageCount = 1, StartPage = 2 }; - + var secondPage = await _milestonesClient.GetAllForRepository(_context.Repository.Id, milestoneRequest, skipStartOptions); Assert.NotEqual(firstPage[0].Number, secondPage[0].Number); diff --git a/Octokit.Tests.Integration/Clients/OrganizationClientTests.cs b/Octokit.Tests.Integration/Clients/OrganizationClientTests.cs index 5577f15449..1ca0e804c9 100644 --- a/Octokit.Tests.Integration/Clients/OrganizationClientTests.cs +++ b/Octokit.Tests.Integration/Clients/OrganizationClientTests.cs @@ -1,4 +1,5 @@ -using System.Threading.Tasks; +using System.Collections; +using System.Threading.Tasks; using Xunit; namespace Octokit.Tests.Integration.Clients @@ -18,30 +19,88 @@ public TheGetAllMethod() } [GitHubEnterpriseTest] - public async Task CanListOrganizations() + public async Task CanListAllOrganizations() + { + string orgLogin1 = Helper.MakeNameWithTimestamp("MyOrganization1"); + string orgName1 = string.Concat(orgLogin1, " Display Name 1"); + string orgLogin2 = Helper.MakeNameWithTimestamp("MyOrganization2"); + string orgName2 = string.Concat(orgLogin2, " Display Name 2"); + + var newOrganization1 = new NewOrganization(orgLogin1, EnterpriseHelper.UserName, orgName1); + var newOrganization2 = new NewOrganization(orgLogin2, EnterpriseHelper.UserName, orgName2); + await _github.Enterprise.Organization.Create(newOrganization1); + await _github.Enterprise.Organization.Create(newOrganization2); + + var organizations = await _organizationsClient.GetAll(); + + Assert.Contains(organizations, (org => org.Login == orgLogin1)); + Assert.Contains(organizations, (org => org.Login == orgLogin2)); + } + + [GitHubEnterpriseTest] + public async Task ReturnsCorrectOrganizationsWithSince() + { + string orgLogin1 = Helper.MakeNameWithTimestamp("MyOrganization1"); + string orgName1 = string.Concat(orgLogin1, " Display Name 1"); + string orgLogin2 = Helper.MakeNameWithTimestamp("MyOrganization2"); + string orgName2 = string.Concat(orgLogin2, " Display Name 2"); + string orgLogin3 = Helper.MakeNameWithTimestamp("MyOrganization3"); + string orgName3 = string.Concat(orgLogin3, " Display Name 3"); + + var newOrganization1 = new NewOrganization(orgLogin1, EnterpriseHelper.UserName, orgName1); + var newOrganization2 = new NewOrganization(orgLogin2, EnterpriseHelper.UserName, orgName2); + var newOrganization3 = new NewOrganization(orgLogin3, EnterpriseHelper.UserName, orgName3); + + var createdOrganization1 = await _github.Enterprise.Organization.Create(newOrganization1); + var createdOrganization2 = await _github.Enterprise.Organization.Create(newOrganization2); + var createdOrganization3 = await _github.Enterprise.Organization.Create(newOrganization3); + + var requestParameter = new OrganizationRequest(createdOrganization1.Id); + + var organizations = await _organizationsClient.GetAll(requestParameter); + + Assert.DoesNotContain(organizations, (org => org.Login == orgLogin1)); + Assert.Contains(organizations, (org => org.Login == orgLogin2)); + Assert.Contains(organizations, (org => org.Login == orgLogin3)); + } + } + + public class TheGetAllForCurrentMethod + { + readonly IGitHubClient _github; + readonly IOrganizationsClient _organizationsClient; + + public TheGetAllForCurrentMethod() + { + _github = EnterpriseHelper.GetAuthenticatedClient(); + + _organizationsClient = _github.Organization; + } + + [GitHubEnterpriseTest] + public async Task CanListUserOrganizations() { string orgLogin = Helper.MakeNameWithTimestamp("MyOrganization"); string orgName = string.Concat(orgLogin, " Display Name"); var newOrganization = new NewOrganization(orgLogin, EnterpriseHelper.UserName, orgName); - var organization = await - _github.Enterprise.Organization.Create(newOrganization); + var organization = await _github.Enterprise.Organization.Create(newOrganization); Assert.NotNull(organization); - var milestones = await _organizationsClient.GetAllForCurrent(); + var organizations = await _organizationsClient.GetAllForCurrent(); - Assert.NotEmpty(milestones); + Assert.NotEmpty(organizations); } [GitHubEnterpriseTest] - public async Task ReturnsCorrectCountOfOrganizationsWithoutStart() + public async Task ReturnsCorrectCountOfUserOrganizationsWithoutStart() { string orgLogin1 = Helper.MakeNameWithTimestamp("MyOrganization1"); string orgName1 = string.Concat(orgLogin1, " Display Name 1"); string orgLogin2 = Helper.MakeNameWithTimestamp("MyOrganization2"); string orgName2 = string.Concat(orgLogin2, " Display Name 2"); - + var newOrganization1 = new NewOrganization(orgLogin1, EnterpriseHelper.UserName, orgName1); var newOrganization2 = new NewOrganization(orgLogin2, EnterpriseHelper.UserName, orgName2); await _github.Enterprise.Organization.Create(newOrganization1); @@ -59,7 +118,7 @@ public async Task ReturnsCorrectCountOfOrganizationsWithoutStart() } [GitHubEnterpriseTest] - public async Task ReturnsCorrectCountOfOrganizationsWithStart() + public async Task ReturnsCorrectCountOfUserOrganizationsWithStart() { string orgLogin1 = Helper.MakeNameWithTimestamp("MyOrganization1"); string orgName1 = string.Concat(orgLogin1, " Display Name 1"); diff --git a/Octokit.Tests.Integration/Clients/OrganizationMembersClientTests.cs b/Octokit.Tests.Integration/Clients/OrganizationMembersClientTests.cs index 5e3d4c561f..63ea01b0c2 100644 --- a/Octokit.Tests.Integration/Clients/OrganizationMembersClientTests.cs +++ b/Octokit.Tests.Integration/Clients/OrganizationMembersClientTests.cs @@ -20,7 +20,7 @@ public TheGetAllMethod() [IntegrationTest] public async Task ReturnsMembers() { - var members = await + var members = await _gitHub.Organization.Member.GetAll(_organizationFixture); Assert.NotEmpty(members); } @@ -35,7 +35,7 @@ public async Task ReturnsCorrectCountOfMembersWithoutStart() }; var members = await _gitHub.Organization.Member.GetAll(_organizationFixture, options); - + Assert.Equal(1, members.Count); } diff --git a/Octokit.Tests.Integration/Clients/PullRequestReviewCommentReactionsClientTests.cs b/Octokit.Tests.Integration/Clients/PullRequestReviewCommentReactionsClientTests.cs index 92f21dc963..4044adde88 100644 --- a/Octokit.Tests.Integration/Clients/PullRequestReviewCommentReactionsClientTests.cs +++ b/Octokit.Tests.Integration/Clients/PullRequestReviewCommentReactionsClientTests.cs @@ -20,7 +20,7 @@ public PullRequestReviewCommentReactionsClientTests() { _github = Helper.GetAuthenticatedClient(); - _client = _github.PullRequest.Comment; + _client = _github.PullRequest.ReviewComment; // We'll create a pull request that can be used by most tests _context = _github.CreateRepositoryContext("test-repo").Result; diff --git a/Octokit.Tests.Integration/Clients/PullRequestReviewCommentsClientTests.cs b/Octokit.Tests.Integration/Clients/PullRequestReviewCommentsClientTests.cs index 86c9c14ad7..19255e9bb6 100644 --- a/Octokit.Tests.Integration/Clients/PullRequestReviewCommentsClientTests.cs +++ b/Octokit.Tests.Integration/Clients/PullRequestReviewCommentsClientTests.cs @@ -20,7 +20,7 @@ public PullRequestReviewCommentsClientTests() { _github = Helper.GetAuthenticatedClient(); - _client = _github.PullRequest.Comment; + _client = _github.PullRequest.ReviewComment; // We'll create a pull request that can be used by most tests _context = _github.CreateRepositoryContext("test-repo").Result; @@ -406,7 +406,6 @@ public async Task CanGetForRepositoryWithRepositoryId() var pullRequestComments = await _client.GetAllForRepository(_context.Repository.Id); AssertComments(pullRequestComments, commentsToCreate, position); - } [IntegrationTest] @@ -855,7 +854,7 @@ async Task CreatePullRequest(RepositoryContext context, string var repoName = context.RepositoryName; - + // Creating a commit in master var createdCommitInMaster = await CreateCommit(repoName, "Hello World!", "README.md", "heads/master", "A master commit message"); diff --git a/Octokit.Tests.Integration/Clients/PullRequestsClientTests.cs b/Octokit.Tests.Integration/Clients/PullRequestsClientTests.cs index 426c9152b2..80afe81b67 100644 --- a/Octokit.Tests.Integration/Clients/PullRequestsClientTests.cs +++ b/Octokit.Tests.Integration/Clients/PullRequestsClientTests.cs @@ -59,6 +59,7 @@ public async Task CanGetForRepository() Assert.Equal(1, pullRequests.Count); Assert.Equal(result.Title, pullRequests[0].Title); + Assert.True(pullRequests[0].Id > 0); } [IntegrationTest] @@ -75,6 +76,52 @@ public async Task CanGetForRepositoryWithRepositoryId() Assert.Equal(result.Title, pullRequests[0].Title); } + [IntegrationTest] + public async Task CanGetWithAssigneesForRepository() + { + await CreateTheWorld(); + + var newPullRequest = new NewPullRequest("a pull request", branchName, "master"); + var result = await _fixture.Create(Helper.UserName, _context.RepositoryName, newPullRequest); + + // Add an assignee + var issueUpdate = new IssueUpdate(); + issueUpdate.AddAssignee(Helper.UserName); + await _github.Issue.Update(Helper.UserName, _context.RepositoryName, result.Number, issueUpdate); + + // Retrieve the Pull Requests + var pullRequests = await _fixture.GetAllForRepository(Helper.UserName, _context.RepositoryName); + + Assert.Equal(1, pullRequests.Count); + Assert.Equal(result.Title, pullRequests[0].Title); + Assert.Equal(Helper.UserName, pullRequests[0].Assignee.Login); + Assert.Equal(1, pullRequests[0].Assignees.Count); + Assert.True(pullRequests[0].Assignees.Any(x => x.Login == Helper.UserName)); + } + + [IntegrationTest] + public async Task CanGetWithAssigneesForRepositoryWithRepositoryId() + { + await CreateTheWorld(); + + var newPullRequest = new NewPullRequest("a pull request", branchName, "master"); + var result = await _fixture.Create(_context.Repository.Id, newPullRequest); + + // Add an assignee + var issueUpdate = new IssueUpdate(); + issueUpdate.AddAssignee(Helper.UserName); + await _github.Issue.Update(_context.Repository.Id, result.Number, issueUpdate); + + // Retrieve the Pull Requests + var pullRequests = await _fixture.GetAllForRepository(_context.Repository.Id); + + Assert.Equal(1, pullRequests.Count); + Assert.Equal(result.Title, pullRequests[0].Title); + Assert.Equal(Helper.UserName, pullRequests[0].Assignee.Login); + Assert.Equal(1, pullRequests[0].Assignees.Count); + Assert.True(pullRequests[0].Assignees.Any(x => x.Login == Helper.UserName)); + } + [IntegrationTest] public async Task ReturnsCorrectCountOfPullRequestsWithoutStart() { diff --git a/Octokit.Tests.Integration/Clients/ReleasesClientTests.cs b/Octokit.Tests.Integration/Clients/ReleasesClientTests.cs index 28f1fd3889..7104612f37 100644 --- a/Octokit.Tests.Integration/Clients/ReleasesClientTests.cs +++ b/Octokit.Tests.Integration/Clients/ReleasesClientTests.cs @@ -836,7 +836,7 @@ public async Task CanDelete() await _releaseClient.Delete(_context.RepositoryOwner, _context.RepositoryName, createdRelease.Id); - Assert.ThrowsAsync(async ()=> await _releaseClient.Get(_context.RepositoryOwner, _context.RepositoryName, createdRelease.Id)); + Assert.ThrowsAsync(async () => await _releaseClient.Get(_context.RepositoryOwner, _context.RepositoryName, createdRelease.Id)); } [IntegrationTest] diff --git a/Octokit.Tests.Integration/Clients/RepositoriesClientTests.cs b/Octokit.Tests.Integration/Clients/RepositoriesClientTests.cs index 927326b90e..6979d22ad1 100644 --- a/Octokit.Tests.Integration/Clients/RepositoriesClientTests.cs +++ b/Octokit.Tests.Integration/Clients/RepositoriesClientTests.cs @@ -231,7 +231,7 @@ public async Task ThrowsRepositoryExistsExceptionForExistingRepository() } } - [PaidAccountTest(Skip="Paid plans now have unlimited repositories. We shouldn't test this now.")] + [PaidAccountTest(Skip = "Paid plans now have unlimited repositories. We shouldn't test this now.")] public async Task ThrowsPrivateRepositoryQuotaExceededExceptionWhenOverQuota() { var github = Helper.GetAuthenticatedClient(); @@ -782,7 +782,7 @@ public class TheGetAllForOrgMethod public async Task ReturnsRepositoriesForOrganization() { var github = Helper.GetAuthenticatedClient(); - + var options = new ApiOptions { PageSize = 20, @@ -1134,7 +1134,7 @@ public async Task GetsPagesOfContributorsIncludeAnonymous() PageCount = 1 }; - var firstPage = await github.Repository.GetAllContributors("ruby", "ruby", true, firstPageOptions); + var firstPage = await github.Repository.GetAllContributors("ruby", "ruby", true, firstPageOptions); var secondPageOptions = new ApiOptions { @@ -1646,7 +1646,7 @@ public async Task GetsABranchWithRepositoryId() public class TheGetAllTeamsMethod { - [IntegrationTest(Skip="Test requires administration rights to access this endpoint")] + [IntegrationTest(Skip = "Test requires administration rights to access this endpoint")] public async Task GetsAllTeams() { var github = Helper.GetAuthenticatedClient(); @@ -1656,7 +1656,7 @@ public async Task GetsAllTeams() Assert.NotEmpty(branches); } - [IntegrationTest(Skip="Test requires administration rights to access this endpoint")] + [IntegrationTest(Skip = "Test requires administration rights to access this endpoint")] public async Task GetsAllTeamsWithRepositoryId() { var github = Helper.GetAuthenticatedClient(); diff --git a/Octokit.Tests.Integration/Clients/RepositoryBranchesClientTests.cs b/Octokit.Tests.Integration/Clients/RepositoryBranchesClientTests.cs index b59b6e4120..5e300efeba 100644 --- a/Octokit.Tests.Integration/Clients/RepositoryBranchesClientTests.cs +++ b/Octokit.Tests.Integration/Clients/RepositoryBranchesClientTests.cs @@ -683,7 +683,7 @@ public async Task DeletesRequiredStatusChecksWithRepositoryId() public class TheGetRequiredStatusChecksContextsMethod : IDisposable { IRepositoryBranchesClient _client; - RepositoryContext _userRepoContext; + RepositoryContext _userRepoContext; public TheGetRequiredStatusChecksContextsMethod() { @@ -741,7 +741,7 @@ public async Task UpdateRequiredStatusChecksContexts() var repoName = _userRepoContext.RepositoryName; var update = new List() { "build2" }; var requiredStatusChecksContexts = await _client.UpdateRequiredStatusChecksContexts(repoOwner, repoName, "master", update); - + Assert.Equal(1, requiredStatusChecksContexts.Count); } @@ -867,7 +867,7 @@ public async Task GetsRequirProtectedBranchRestrictionsForOrgRepo() var repoOwner = _orgRepoContext.RepositoryContext.RepositoryOwner; var repoName = _orgRepoContext.RepositoryContext.RepositoryName; var restrictions = await _client.GetProtectedBranchRestrictions(repoOwner, repoName, "master"); - + Assert.Equal(1, restrictions.Teams.Count); Assert.Equal(0, restrictions.Users.Count); } @@ -877,7 +877,7 @@ public async Task GetsProtectedBranchRestrictionsForOrgRepoWithRepositoryId() { var repoId = _orgRepoContext.RepositoryContext.RepositoryId; var restrictions = await _client.GetProtectedBranchRestrictions(repoId, "master"); - + Assert.Equal(1, restrictions.Teams.Count); Assert.Equal(0, restrictions.Users.Count); } diff --git a/Octokit.Tests.Integration/Clients/RepositoryCommentsClientTests.cs b/Octokit.Tests.Integration/Clients/RepositoryCommentsClientTests.cs index 47266a4893..aaccd9dfe1 100644 --- a/Octokit.Tests.Integration/Clients/RepositoryCommentsClientTests.cs +++ b/Octokit.Tests.Integration/Clients/RepositoryCommentsClientTests.cs @@ -499,7 +499,7 @@ public async Task CanGetReactionPayload() { var newReaction = new NewReaction(reactionType); - var reaction = await _github.Reaction.Issue.Create(_context.RepositoryOwner, _context.RepositoryName, result.Id, newReaction); + var reaction = await _github.Reaction.CommitComment.Create(_context.RepositoryOwner, _context.RepositoryName, result.Id, newReaction); Assert.IsType(reaction); Assert.Equal(reactionType, reaction.Content); diff --git a/Octokit.Tests.Integration/Clients/RepositoryContentsClientTests.cs b/Octokit.Tests.Integration/Clients/RepositoryContentsClientTests.cs index 2cc8cf7013..e1d70edfa0 100644 --- a/Octokit.Tests.Integration/Clients/RepositoryContentsClientTests.cs +++ b/Octokit.Tests.Integration/Clients/RepositoryContentsClientTests.cs @@ -469,6 +469,182 @@ await Assert.ThrowsAsync( } } + [IntegrationTest] + public async Task CrudTestWithExplicitBase64() + { + var client = Helper.GetAuthenticatedClient(); + var fixture = client.Repository.Content; + var repoName = Helper.MakeNameWithTimestamp("source-repo"); + + using (var context = await client.CreateRepositoryContext(new NewRepository(repoName) { AutoInit = true })) + { + var repository = context.Repository; + + var file = await fixture.CreateFile( + repository.Owner.Login, + repository.Name, + "somefile.txt", + new CreateFileRequest("Test commit", "U29tZSBDb250ZW50", false)); + Assert.Equal("somefile.txt", file.Content.Name); + + var contents = await fixture.GetAllContents(repository.Owner.Login, repository.Name, "somefile.txt"); + string fileSha = contents.First().Sha; + Assert.Equal("Some Content", contents.First().Content); + + var update = await fixture.UpdateFile( + repository.Owner.Login, + repository.Name, + "somefile.txt", + new UpdateFileRequest("Updating file", "TmV3IENvbnRlbnQ=", fileSha, false)); + Assert.Equal("somefile.txt", update.Content.Name); + + contents = await fixture.GetAllContents(repository.Owner.Login, repository.Name, "somefile.txt"); + Assert.Equal("New Content", contents.First().Content); + fileSha = contents.First().Sha; + + await fixture.DeleteFile( + repository.Owner.Login, + repository.Name, + "somefile.txt", + new DeleteFileRequest("Deleted file", fileSha)); + + await Assert.ThrowsAsync( + () => fixture.GetAllContents(repository.Owner.Login, repository.Name, "somefile.txt")); + } + } + + [IntegrationTest] + public async Task CrudTestWithRepositoryIdWithExplicitBase64() + { + var client = Helper.GetAuthenticatedClient(); + var fixture = client.Repository.Content; + var repoName = Helper.MakeNameWithTimestamp("source-repo"); + + using (var context = await client.CreateRepositoryContext(new NewRepository(repoName) { AutoInit = true })) + { + var repository = context.Repository; + + var file = await fixture.CreateFile( + repository.Id, + "somefile.txt", + new CreateFileRequest("Test commit", "U29tZSBDb250ZW50", false)); + Assert.Equal("somefile.txt", file.Content.Name); + + var contents = await fixture.GetAllContents(repository.Owner.Login, repository.Name, "somefile.txt"); + string fileSha = contents.First().Sha; + Assert.Equal("Some Content", contents.First().Content); + + var update = await fixture.UpdateFile( + repository.Id, + "somefile.txt", + new UpdateFileRequest("Updating file", "TmV3IENvbnRlbnQ=", fileSha, false)); + Assert.Equal("somefile.txt", update.Content.Name); + + contents = await fixture.GetAllContents(repository.Owner.Login, repository.Name, "somefile.txt"); + Assert.Equal("New Content", contents.First().Content); + fileSha = contents.First().Sha; + + await fixture.DeleteFile( + repository.Id, + "somefile.txt", + new DeleteFileRequest("Deleted file", fileSha)); + + await Assert.ThrowsAsync( + () => fixture.GetAllContents(repository.Owner.Login, repository.Name, "somefile.txt")); + } + } + + [IntegrationTest] + public async Task CrudTestWithNamedBranchWithExplicitBase64() + { + var client = Helper.GetAuthenticatedClient(); + var fixture = client.Repository.Content; + var repoName = Helper.MakeNameWithTimestamp("source-repo"); + var branchName = "other-branch"; + + using (var context = await client.CreateRepositoryContext(new NewRepository(repoName) { AutoInit = true })) + { + var repository = context.Repository; + + var master = await client.Git.Reference.Get(Helper.UserName, repository.Name, "heads/master"); + await client.Git.Reference.Create(Helper.UserName, repository.Name, new NewReference("refs/heads/" + branchName, master.Object.Sha)); + var file = await fixture.CreateFile( + repository.Owner.Login, + repository.Name, + "somefile.txt", + new CreateFileRequest("Test commit", "U29tZSBDb250ZW50", branchName, false)); + Assert.Equal("somefile.txt", file.Content.Name); + + var contents = await fixture.GetAllContentsByRef(repository.Owner.Login, repository.Name, "somefile.txt", branchName); + string fileSha = contents.First().Sha; + Assert.Equal("Some Content", contents.First().Content); + + var update = await fixture.UpdateFile( + repository.Owner.Login, + repository.Name, + "somefile.txt", + new UpdateFileRequest("Updating file", "TmV3IENvbnRlbnQ=", fileSha, branchName, false)); + Assert.Equal("somefile.txt", update.Content.Name); + + contents = await fixture.GetAllContentsByRef(repository.Owner.Login, repository.Name, "somefile.txt", branchName); + Assert.Equal("New Content", contents.First().Content); + fileSha = contents.First().Sha; + + await fixture.DeleteFile( + repository.Owner.Login, + repository.Name, + "somefile.txt", + new DeleteFileRequest("Deleted file", fileSha, branchName)); + + await Assert.ThrowsAsync( + () => fixture.GetAllContents(repository.Owner.Login, repository.Name, "somefile.txt")); + } + } + + [IntegrationTest] + public async Task CrudTestWithNamedBranchWithRepositoryIdWithExplicitBase64() + { + var client = Helper.GetAuthenticatedClient(); + var fixture = client.Repository.Content; + var repoName = Helper.MakeNameWithTimestamp("source-repo"); + var branchName = "other-branch"; + + using (var context = await client.CreateRepositoryContext(new NewRepository(repoName) { AutoInit = true })) + { + var repository = context.Repository; + + var master = await client.Git.Reference.Get(Helper.UserName, repository.Name, "heads/master"); + await client.Git.Reference.Create(Helper.UserName, repository.Name, new NewReference("refs/heads/" + branchName, master.Object.Sha)); + var file = await fixture.CreateFile( + repository.Id, + "somefile.txt", + new CreateFileRequest("Test commit", "U29tZSBDb250ZW50", branchName, false)); + Assert.Equal("somefile.txt", file.Content.Name); + + var contents = await fixture.GetAllContentsByRef(repository.Owner.Login, repository.Name, "somefile.txt", branchName); + string fileSha = contents.First().Sha; + Assert.Equal("Some Content", contents.First().Content); + + var update = await fixture.UpdateFile( + repository.Id, + "somefile.txt", + new UpdateFileRequest("Updating file", "TmV3IENvbnRlbnQ=", fileSha, branchName, false)); + Assert.Equal("somefile.txt", update.Content.Name); + + contents = await fixture.GetAllContentsByRef(repository.Owner.Login, repository.Name, "somefile.txt", branchName); + Assert.Equal("New Content", contents.First().Content); + fileSha = contents.First().Sha; + + await fixture.DeleteFile( + repository.Id, + "somefile.txt", + new DeleteFileRequest("Deleted file", fileSha, branchName)); + + await Assert.ThrowsAsync( + () => fixture.GetAllContents(repository.Owner.Login, repository.Name, "somefile.txt")); + } + } + public class TheGetArchiveMethod { [IntegrationTest(Skip = "this will probably take too long")] diff --git a/Octokit.Tests.Integration/Clients/RepositoryHooksClientTests.cs b/Octokit.Tests.Integration/Clients/RepositoryHooksClientTests.cs index a4c8404756..719bf7c9ae 100644 --- a/Octokit.Tests.Integration/Clients/RepositoryHooksClientTests.cs +++ b/Octokit.Tests.Integration/Clients/RepositoryHooksClientTests.cs @@ -48,7 +48,7 @@ public async Task ReturnsAllHooksFromRepositoryWithRepositoryId() public async Task ReturnsCorrectCountOfHooksWithoutStart() { var github = Helper.GetAuthenticatedClient(); - + var options = new ApiOptions { PageSize = 5, @@ -64,7 +64,7 @@ public async Task ReturnsCorrectCountOfHooksWithoutStart() public async Task ReturnsCorrectCountOfHooksWithoutStartWithRepositoryId() { var github = Helper.GetAuthenticatedClient(); - + var options = new ApiOptions { PageSize = 5, diff --git a/Octokit.Tests.Integration/Clients/RepositoryPagesClientTests.cs b/Octokit.Tests.Integration/Clients/RepositoryPagesClientTests.cs index 561fea2506..a26d989eeb 100644 --- a/Octokit.Tests.Integration/Clients/RepositoryPagesClientTests.cs +++ b/Octokit.Tests.Integration/Clients/RepositoryPagesClientTests.cs @@ -18,14 +18,14 @@ public TheGetMethod() _repositoryPagesClient = github.Repository.Page; } - [IntegrationTest(Skip= "These tests require repository admin rights - see https://github.com/octokit/octokit.net/issues/1263 for discussion")] + [IntegrationTest(Skip = "These tests require repository admin rights - see https://github.com/octokit/octokit.net/issues/1263 for discussion")] public async Task ReturnsMetadata() { var data = await _repositoryPagesClient.Get(owner, name); Assert.Equal("https://api.github.com/repos/octokit/octokit.net/pages", data.Url); } - [IntegrationTest(Skip= "These tests require repository admin rights - see https://github.com/octokit/octokit.net/issues/1263 for discussion")] + [IntegrationTest(Skip = "These tests require repository admin rights - see https://github.com/octokit/octokit.net/issues/1263 for discussion")] public async Task ReturnsMetadataWithRepositoryId() { var data = await _repositoryPagesClient.Get(repositoryId); diff --git a/Octokit.Tests.Integration/Clients/StarredClientTests.cs b/Octokit.Tests.Integration/Clients/StarredClientTests.cs index 0196a5e73e..9e6802e4d2 100644 --- a/Octokit.Tests.Integration/Clients/StarredClientTests.cs +++ b/Octokit.Tests.Integration/Clients/StarredClientTests.cs @@ -32,7 +32,7 @@ public async Task CanGetAllForCurrent() { var repositories = await _fixture.GetAllForCurrent(); Assert.NotEmpty(repositories); - + var repo = repositories.FirstOrDefault(repository => repository.Owner.Login == _repositoryContext.RepositoryOwner && repository.Name == _repositoryContext.RepositoryName); Assert.NotNull(repo); } diff --git a/Octokit.Tests.Integration/Clients/TagsClientTests.cs b/Octokit.Tests.Integration/Clients/TagsClientTests.cs index f4a5fd5900..a74320cd84 100644 --- a/Octokit.Tests.Integration/Clients/TagsClientTests.cs +++ b/Octokit.Tests.Integration/Clients/TagsClientTests.cs @@ -125,7 +125,6 @@ public async Task DeserializeTagSignatureVerification() Assert.Equal(gitTag.Verification.Reason, VerificationReason.Unsigned); Assert.Null(gitTag.Verification.Signature); Assert.Null(gitTag.Verification.Payload); - } } } diff --git a/Octokit.Tests.Integration/Clients/UserEmailsClientTests.cs b/Octokit.Tests.Integration/Clients/UserEmailsClientTests.cs index 12ac23e496..492132ceda 100644 --- a/Octokit.Tests.Integration/Clients/UserEmailsClientTests.cs +++ b/Octokit.Tests.Integration/Clients/UserEmailsClientTests.cs @@ -41,7 +41,7 @@ public async Task ReturnsCorrectCountOfEmailsWithoutStart() Assert.NotEmpty(emails); } - + const string testEmailAddress = "hahaha-not-a-real-email@foo.com"; [IntegrationTest(Skip = "this isn't passing in CI - i hate past me right now")] diff --git a/Octokit.Tests.Integration/Clients/UserKeysClientTests.cs b/Octokit.Tests.Integration/Clients/UserKeysClientTests.cs index 4df8f13f0e..4bf48d3a18 100644 --- a/Octokit.Tests.Integration/Clients/UserKeysClientTests.cs +++ b/Octokit.Tests.Integration/Clients/UserKeysClientTests.cs @@ -57,19 +57,21 @@ public async Task CanGetKeyById() [IntegrationTest] public async Task CanCreateAndDeleteKey() { - // Create a key - string keyTitle = "title"; - string keyData = "ssh-rsa AAAAB3NzaC1yc2EAAAABJQAAAQEAjo4DqFKg8dOxiz/yjypmN1A4itU5QOStyYrfOFuTinesU/2zm9hqxJ5BctIhgtSHJ5foxkhsiBji0qrUg73Q25BThgNg8YFE8njr4EwjmqSqW13akx/zLV0GFFU0SdJ2F6rBldhi93lMnl0ex9swBqa3eLTY8C+HQGBI6MQUMw+BKp0oFkz87Kv+Pfp6lt/Uo32ejSxML1PT5hTH5n+fyl0ied+sRmPGZWmWoHB5Bc9mox7lB6I6A/ZgjtBqbEEn4HQ2/6vp4ojKfSgA4Mm7XMu0bZzX0itKjH1QWD9Lr5apV1cmZsj49Xf8SHucTtH+bq98hb8OOXEGFzplwsX2MQ=="; var github = Helper.GetAuthenticatedClient(); - var key = await github.User.GitSshKey.Create(new NewPublicKey(keyTitle, keyData)); + // Use context helper to create/destroy a key safely (to avoid test failures when a key exists due to not having been deleted) + string keyTitle = null; + string keyData = null; + using (var context = await github.CreatePublicKeyContext()) + { + var observable = github.User.GitSshKey.Get(context.KeyId); + var key = await observable; - Assert.NotNull(key); - Assert.Equal(key.Title, "title"); - Assert.Equal(key.Key, keyData); + Assert.NotNull(key); - // Delete key - await github.User.GitSshKey.Delete(key.Id); + keyTitle = key.Title; + keyData = key.Key; + } // Verify key no longer exists var keys = await github.User.GitSshKey.GetAllForCurrent(); diff --git a/Octokit.Tests.Integration/Helpers/GithubClientExtensions.cs b/Octokit.Tests.Integration/Helpers/GithubClientExtensions.cs index ac7ef4b7b8..ff869c6241 100644 --- a/Octokit.Tests.Integration/Helpers/GithubClientExtensions.cs +++ b/Octokit.Tests.Integration/Helpers/GithubClientExtensions.cs @@ -44,7 +44,7 @@ internal static async Task CreatePublicKeyContext(this IGitHub { // Create a key string keyTitle = "title"; - string keyData = "ssh-rsa AAAAB3NzaC1yc2EAAAABJQAAAQEAjo4DqFKg8dOxiz/yjypmN1A4itU5QOStyYrfOFuTinesU/2zm9hqxJ5BctIhgtSHJ5foxkhsiBji0qrUg73Q25BThgNg8YFE8njr4EwjmqSqW13akx/zLV0GFFU0SdJ2F6rBldhi93lMnl0ex9swBqa3eLTY8C+HQGBI6MQUMw+BKp0oFkz87Kv+Pfp6lt/Uo32ejSxML1PT5hTH5n+fyl0ied+sRmPGZWmWoHB5Bc9mox7lB6I6A/ZgjtBqbEEn4HQ2/6vp4ojKfSgA4Mm7XMu0bZzX0itKjH1QWD9Lr5apV1cmZsj49Xf8SHucTtH+bq98hb8OOXEGFzplwsX2MQ=="; + string keyData = "ssh-rsa AAAAB3NzaC1yc2EAAAABJQAAAQEAq42HufbSy1BUbZTdKyEy8nX44gdchbh1A/cYuVFkRXETrFr6XYLETi4tauXGS3Wp3E4s3oG272O4JW+fIBX0kuOJXnRgYz52H3BDk6aY9B0ny+PYFJrYrpG43px5EVfojj9o7oxugNq4zLCGqWTqZU1maTf5T4Mopjt0ggA7cyNnM5B645cBxXjD2KNfrTIyLI+meYxptzjRiB6fHLGFRA9fxpVqUnbq7EcGbwsTlILRuEPt58hZ9He88M45m0F8rkVZOewt4JSzsLsC+sQs+h/LXI8dbrg6xWpxJVi0trzYuMuY/MwygloWKtaFQYuPkJ7yqMZ3Aew+J3DupF6uxQ=="; var key = await client.User.GitSshKey.Create(new NewPublicKey(keyTitle, keyData)); diff --git a/Octokit.Tests.Integration/Helpers/ObservableGithubClientExtensions.cs b/Octokit.Tests.Integration/Helpers/ObservableGithubClientExtensions.cs index a3073409bf..90d8e435bc 100644 --- a/Octokit.Tests.Integration/Helpers/ObservableGithubClientExtensions.cs +++ b/Octokit.Tests.Integration/Helpers/ObservableGithubClientExtensions.cs @@ -46,7 +46,7 @@ internal static async Task CreatePublicKeyContext(this IObserv { // Create a key string keyTitle = "title"; - string keyData = "ssh-rsa AAAAB3NzaC1yc2EAAAABJQAAAQEAjo4DqFKg8dOxiz/yjypmN1A4itU5QOStyYrfOFuTinesU/2zm9hqxJ5BctIhgtSHJ5foxkhsiBji0qrUg73Q25BThgNg8YFE8njr4EwjmqSqW13akx/zLV0GFFU0SdJ2F6rBldhi93lMnl0ex9swBqa3eLTY8C+HQGBI6MQUMw+BKp0oFkz87Kv+Pfp6lt/Uo32ejSxML1PT5hTH5n+fyl0ied+sRmPGZWmWoHB5Bc9mox7lB6I6A/ZgjtBqbEEn4HQ2/6vp4ojKfSgA4Mm7XMu0bZzX0itKjH1QWD9Lr5apV1cmZsj49Xf8SHucTtH+bq98hb8OOXEGFzplwsX2MQ=="; + string keyData = "ssh-rsa AAAAB3NzaC1yc2EAAAABJQAAAQEAq42HufbSy1BUbZTdKyEy8nX44gdchbh1A/cYuVFkRXETrFr6XYLETi4tauXGS3Wp3E4s3oG272O4JW+fIBX0kuOJXnRgYz52H3BDk6aY9B0ny+PYFJrYrpG43px5EVfojj9o7oxugNq4zLCGqWTqZU1maTf5T4Mopjt0ggA7cyNnM5B645cBxXjD2KNfrTIyLI+meYxptzjRiB6fHLGFRA9fxpVqUnbq7EcGbwsTlILRuEPt58hZ9He88M45m0F8rkVZOewt4JSzsLsC+sQs+h/LXI8dbrg6xWpxJVi0trzYuMuY/MwygloWKtaFQYuPkJ7yqMZ3Aew+J3DupF6uxQ=="; var key = await client.User.GitSshKey.Create(new NewPublicKey(keyTitle, keyData)); diff --git a/Octokit.Tests.Integration/Reactive/ObservableCommitStatusClientTests.cs b/Octokit.Tests.Integration/Reactive/ObservableCommitStatusClientTests.cs index f903f896ae..569c1e7cb9 100644 --- a/Octokit.Tests.Integration/Reactive/ObservableCommitStatusClientTests.cs +++ b/Octokit.Tests.Integration/Reactive/ObservableCommitStatusClientTests.cs @@ -12,7 +12,7 @@ public class TheGetAllMethod readonly ObservableCommitStatusClient _commitStatusClient; const string owner = "octokit"; const string name = "octokit.net"; - const string reference = "1335f37"; + const string reference = "1335f37"; public TheGetAllMethod() { @@ -37,7 +37,7 @@ public async Task ReturnsCorrectCountOfCommitStatusWithoutStart() PageCount = 1 }; - var commitStatus = await _commitStatusClient.GetAll(owner, name ,reference , options).ToList(); + var commitStatus = await _commitStatusClient.GetAll(owner, name, reference, options).ToList(); Assert.Equal(2, commitStatus.Count); } @@ -75,10 +75,10 @@ public async Task ReturnsDistinctResultsBasedOnStartPage() StartPage = 2 }; - var secondPage = await _commitStatusClient.GetAll(owner, name, reference,skipStartOptions).ToList(); + var secondPage = await _commitStatusClient.GetAll(owner, name, reference, skipStartOptions).ToList(); Assert.NotEqual(firstPage[0].Id, secondPage[0].Id); - Assert.NotEqual(firstPage[1].Id, secondPage[1].Id); + Assert.NotEqual(firstPage[1].Id, secondPage[1].Id); } } } diff --git a/Octokit.Tests.Integration/Reactive/ObservableEventsClientTests.cs b/Octokit.Tests.Integration/Reactive/ObservableEventsClientTests.cs index 60ae9041b0..40aa6aed1c 100644 --- a/Octokit.Tests.Integration/Reactive/ObservableEventsClientTests.cs +++ b/Octokit.Tests.Integration/Reactive/ObservableEventsClientTests.cs @@ -79,12 +79,10 @@ public async Task ReturnsDistinctEventsBasedOnStartPage() Assert.NotEqual(firstEventsPage[3].Id, secondEventsPage[3].Id); Assert.NotEqual(firstEventsPage[4].Id, secondEventsPage[4].Id); } - } public class TheGetAllForRepositoryMethod { - readonly ObservableEventsClient _eventsClient; const string owner = "octokit"; const string name = "octokit.net"; @@ -156,7 +154,6 @@ public async Task ReturnsDistinctRepositoryEventsBasedOnStartPage() Assert.NotEqual(firstRepositoryEventsPage[3].Id, secondRepositoryEventsPage[3].Id); Assert.NotEqual(firstRepositoryEventsPage[4].Id, secondRepositoryEventsPage[4].Id); } - } public class TheGetAllIssuesForRepositoryMethod @@ -170,7 +167,7 @@ public TheGetAllIssuesForRepositoryMethod() _eventsClient = new ObservableEventsClient(Helper.GetAuthenticatedClient()); } - [IntegrationTest(Skip = "These tests just don't work any more")] + [IntegrationTest] public async Task ReturnsRepositoryEvents() { var options = new ApiOptions @@ -185,7 +182,7 @@ public async Task ReturnsRepositoryEvents() Assert.NotEmpty(repositoryEvents); } - [IntegrationTest(Skip = "These tests just don't work any more")] + [IntegrationTest] public async Task ReturnsCorrectCountOfRepositoryEventsWithoutStart() { var options = new ApiOptions @@ -199,7 +196,7 @@ public async Task ReturnsCorrectCountOfRepositoryEventsWithoutStart() Assert.Equal(5, repositoryEvents.Count); } - [IntegrationTest(Skip = "These tests just don't work any more")] + [IntegrationTest] public async Task ReturnsCorrectCountOfRepositoryEventsWithStart() { var options = new ApiOptions @@ -214,7 +211,7 @@ public async Task ReturnsCorrectCountOfRepositoryEventsWithStart() Assert.Equal(5, repositoryEvents.Count); } - [IntegrationTest(Skip = "These tests just don't work any more")] + [IntegrationTest] public async Task ReturnsDistinctRepositoryEventsBasedOnStartPage() { var startOptions = new ApiOptions @@ -240,7 +237,6 @@ public async Task ReturnsDistinctRepositoryEventsBasedOnStartPage() Assert.NotEqual(firstRepositoryEventsPage[3].Id, secondRepositoryEventsPage[3].Id); Assert.NotEqual(firstRepositoryEventsPage[4].Id, secondRepositoryEventsPage[4].Id); } - } public class TheGetAllForRepositoryNetworkMethod @@ -316,14 +312,12 @@ public async Task ReturnsDistinctRepositoryNetworkEventsBasedOnStartPage() Assert.NotEqual(firstRepositoryNetworkEventsPage[3].Id, secondRepositoryNetworkEventsPage[3].Id); Assert.NotEqual(firstRepositoryNetworkEventsPage[4].Id, secondRepositoryNetworkEventsPage[4].Id); } - } public class TheGetAllForOrganizationMethod { - readonly ObservableEventsClient _eventsClient; - const string organization = "octokit"; + const string organization = "octokit"; public TheGetAllForOrganizationMethod() { @@ -360,7 +354,7 @@ public async Task ReturnsCorrectCountOfOrganizationEventsWithStart() PageSize = 5, PageCount = 1, StartPage = 2 - }; + }; var organizationEvents = await _eventsClient.GetAllForOrganization(organization, options).ToList(); @@ -393,7 +387,6 @@ public async Task ReturnsDistinctOrganizationEventsBasedOnStartPage() Assert.NotEqual(firstOrganizationEventsPage[3].Id, secondOrganizationEventsPage[3].Id); Assert.NotEqual(firstOrganizationEventsPage[4].Id, secondOrganizationEventsPage[4].Id); } - } public class TheGetAllUserReceivedMethod @@ -473,7 +466,6 @@ public async Task ReturnsDistinctUserReceivedEventsBasedOnStartPage() public class TheGetAllUserReceivedPublicMethod { - readonly ObservableEventsClient _eventsClient; const string user = "shiftkey"; @@ -545,7 +537,6 @@ public async Task ReturnsDistinctUserReceivedPublicEventsBasedOnStartPage() Assert.NotEqual(firstUserReceivedPublicEventsPage[3].Id, secondUserReceivedPublicEventsPage[3].Id); Assert.NotEqual(firstUserReceivedPublicEventsPage[4].Id, secondUserReceivedPublicEventsPage[4].Id); } - } public class TheGetAllUserPerformedMethod @@ -585,7 +576,7 @@ public async Task ReturnsCorrectCountOfUserPerformedEventsWithStart() { var options = new ApiOptions { - PageSize = 5, + PageSize = 5, PageCount = 1, StartPage = 2 }; @@ -621,7 +612,6 @@ public async Task ReturnsDistinctUserPerformedEventsBasedOnStartPage() Assert.NotEqual(firstUserPerformedEventsPage[3].Id, secondUserPerformedEventsPage[3].Id); Assert.NotEqual(firstUserPerformedEventsPage[4].Id, secondUserPerformedEventsPage[4].Id); } - } public class TheGetAllUserPerformedPublicMethod @@ -697,7 +687,6 @@ public async Task ReturnsDistinctUserPerformedPublicEventsBasedOnStartPage() Assert.NotEqual(firstUserPerformedPublicEventsPage[3].Id, secondUserPerformedPublicEventsPage[3].Id); Assert.NotEqual(firstUserPerformedPublicEventsPage[4].Id, secondUserPerformedPublicEventsPage[4].Id); } - } public class TheGetAllForAnOrganizationMethod @@ -717,7 +706,7 @@ public TheGetAllForAnOrganizationMethod() [IntegrationTest] public async Task ReturnsUserOrganizationEvents() { - var userOrganizationEvents = await _eventsClient.GetAllForAnOrganization(_user,_organization).ToList(); + var userOrganizationEvents = await _eventsClient.GetAllForAnOrganization(_user, _organization).ToList(); Assert.NotEmpty(userOrganizationEvents); } @@ -777,7 +766,6 @@ public async Task ReturnsDistinctUserOrganizationEventsBasedOnStartPage() Assert.NotEqual(firstUserOrganizationEventsPage[3].Id, secondUserOrganizationEventsPage[3].Id); Assert.NotEqual(firstUserOrganizationEventsPage[4].Id, secondUserOrganizationEventsPage[4].Id); } - } } } diff --git a/Octokit.Tests.Integration/Reactive/ObservableFollowersClientTests.cs b/Octokit.Tests.Integration/Reactive/ObservableFollowersClientTests.cs index 6b3e61dc8d..1eb20be4fe 100644 --- a/Octokit.Tests.Integration/Reactive/ObservableFollowersClientTests.cs +++ b/Octokit.Tests.Integration/Reactive/ObservableFollowersClientTests.cs @@ -1,4 +1,5 @@ -using System.Reactive.Linq; +using System; +using System.Reactive.Linq; using System.Threading.Tasks; using Octokit.Reactive; using Xunit; @@ -9,7 +10,7 @@ public class ObservableFollowersClientTests { public class TheGetAllForCurrentMethod { - readonly ObservableFollowersClient _followersClient; + readonly ObservableFollowersClient _followersClient; public TheGetAllForCurrentMethod() { @@ -18,7 +19,7 @@ public TheGetAllForCurrentMethod() _followersClient = new ObservableFollowersClient(github); } - [IntegrationTest] + [IntegrationTest] public async Task ReturnsFollowers() { var followers = await _followersClient.GetAllForCurrent().ToList(); @@ -30,7 +31,7 @@ public async Task ReturnsFollowers() public async Task ReturnsCorrectCountOfFollowersWithoutStart() { var options = new ApiOptions - { + { PageSize = 1, PageCount = 1 }; @@ -75,7 +76,7 @@ public async Task ReturnsDistinctResultsBasedOnStartPage() var secondFollowersPage = await _followersClient.GetAllForCurrent(skipStartOptions).ToList(); - Assert.NotEqual(firstFollowersPage[0].Id, secondFollowersPage[0].Id); + Assert.NotEqual(firstFollowersPage[0].Id, secondFollowersPage[0].Id); } } @@ -153,15 +154,19 @@ public async Task ReturnsDistinctResultsBasedOnStartPage() } } - public class TheGetAllFollowingForCurrentMethod + public class TheGetAllFollowingForCurrentMethod : IDisposable { - readonly ObservableFollowersClient _followersClient; + readonly ObservableFollowersClient _followersClient; public TheGetAllFollowingForCurrentMethod() { var github = Helper.GetAuthenticatedClient(); _followersClient = new ObservableFollowersClient(github); + + // Follow someone to set initial state + _followersClient.Follow("alfhenrik").ToList(); + _followersClient.Follow("ryangribble").ToList(); } [IntegrationTest] @@ -221,7 +226,13 @@ public async Task ReturnsDistinctResultsBasedOnStartPage() var secondFollowingPage = await _followersClient.GetAllFollowingForCurrent(skipStartOptions).ToList(); - Assert.NotEqual(firstFollowingPage[0].Id, secondFollowingPage[0].Id); + Assert.NotEqual(firstFollowingPage[0].Id, secondFollowingPage[0].Id); + } + + public void Dispose() + { + _followersClient.Unfollow("alfhenrik"); + _followersClient.Unfollow("ryangribble"); } } diff --git a/Octokit.Tests.Integration/Reactive/ObservableGistCommentsClientTests.cs b/Octokit.Tests.Integration/Reactive/ObservableGistCommentsClientTests.cs index 1f350dbe8f..edaaafcbf2 100644 --- a/Octokit.Tests.Integration/Reactive/ObservableGistCommentsClientTests.cs +++ b/Octokit.Tests.Integration/Reactive/ObservableGistCommentsClientTests.cs @@ -6,7 +6,7 @@ namespace Octokit.Tests.Integration.Reactive { public class ObservableGistCommentsClientTests - { + { public class TheGetAllForGistMethod { readonly ObservableGistCommentsClient _gistCommentsClient; @@ -79,8 +79,8 @@ public async Task ReturnsDistinctResultsBasedOnStartPage() Assert.NotEqual(firstCommentsPage[0].Id, secondCommentsPage[0].Id); Assert.NotEqual(firstCommentsPage[1].Id, secondCommentsPage[1].Id); Assert.NotEqual(firstCommentsPage[2].Id, secondCommentsPage[2].Id); - Assert.NotEqual(firstCommentsPage[3].Id, secondCommentsPage[3].Id); + Assert.NotEqual(firstCommentsPage[3].Id, secondCommentsPage[3].Id); } } - } + } } diff --git a/Octokit.Tests.Integration/Reactive/ObservableIssueTimelineClientTests.cs b/Octokit.Tests.Integration/Reactive/ObservableIssueTimelineClientTests.cs index 7cfb66a887..2608591b4f 100644 --- a/Octokit.Tests.Integration/Reactive/ObservableIssueTimelineClientTests.cs +++ b/Octokit.Tests.Integration/Reactive/ObservableIssueTimelineClientTests.cs @@ -5,7 +5,7 @@ using Xunit; namespace Octokit.Tests.Integration.Reactive -{ +{ public class ObservableIssueTimelineClientTests { private readonly RepositoryContext _context; @@ -95,7 +95,7 @@ public async Task CanDeserializeCrossReferenceEvent() var observableTimeline = _client.Issue.Timeline.GetAllForIssue(_context.RepositoryOwner, _context.RepositoryName, issue.Number); var timelineEventInfos = await observableTimeline.ToList(); Assert.Equal(1, timelineEventInfos.Count); - Assert.Equal(anotherNewIssue.Id, timelineEventInfos[0].Source.Id); + Assert.Equal(anotherNewIssue.Id, timelineEventInfos[0].Source.Issue.Id); } [IntegrationTest] @@ -152,7 +152,7 @@ public async Task CanDeserializeCrossReferenceEventByRepositoryId() var observableTimeline = _client.Issue.Timeline.GetAllForIssue(_context.Repository.Id, issue.Number); var timelineEventInfos = await observableTimeline.ToList(); Assert.Equal(1, timelineEventInfos.Count); - Assert.Equal(anotherNewIssue.Id, timelineEventInfos[0].Source.Id); + Assert.Equal(anotherNewIssue.Id, timelineEventInfos[0].Source.Issue.Id); } } } diff --git a/Octokit.Tests.Integration/Reactive/ObservableIssuesClientTests.cs b/Octokit.Tests.Integration/Reactive/ObservableIssuesClientTests.cs index dc195ee123..bedb3d3791 100644 --- a/Octokit.Tests.Integration/Reactive/ObservableIssuesClientTests.cs +++ b/Octokit.Tests.Integration/Reactive/ObservableIssuesClientTests.cs @@ -79,7 +79,8 @@ public async Task ReturnsPageOfIssuesFromStartForARepository() [IntegrationTest] public async Task ReturnsAllIssuesForCurrentUser() { - var newIssue = new NewIssue("Integration test issue") { Assignee = _context.RepositoryOwner }; + var newIssue = new NewIssue("Integration test issue"); + newIssue.Assignees.Add(_context.RepositoryOwner); await _client.Create(_context.RepositoryOwner, _context.RepositoryName, newIssue); var issues = await _client.GetAllForCurrent().ToList(); @@ -90,7 +91,8 @@ public async Task ReturnsAllIssuesForCurrentUser() [IntegrationTest] public async Task ReturnsAllIssuesForOwnedAndMemberRepositories() { - var newIssue = new NewIssue("Integration test issue") { Assignee = _context.RepositoryOwner }; + var newIssue = new NewIssue("Integration test issue"); + newIssue.Assignees.Add(_context.RepositoryOwner); await _client.Create(_context.RepositoryOwner, _context.RepositoryName, newIssue); var result = await _client.GetAllForOwnedAndMemberRepositories().ToList(); @@ -108,23 +110,23 @@ public async Task CanCreateAndUpdateIssues() Assert.Equal("Modified integration test issue", updateResult.Title); } - [IntegrationTest] - public async Task CanLockAndUnlockIssues() - { - var newIssue = new NewIssue("Integration Test Issue"); - - var createResult = await _client.Create(_context.RepositoryOwner, _context.RepositoryName, newIssue); - Assert.False(createResult.Locked); - - await _client.Lock(_context.RepositoryOwner, _context.RepositoryName, createResult.Number); - var lockResult = await _client.Get(_context.RepositoryOwner, _context.RepositoryName, createResult.Number); - Assert.True(lockResult.Locked); - - await _client.Unlock(_context.RepositoryOwner, _context.RepositoryName, createResult.Number); - var unlockIssueResult = await _client.Get(_context.RepositoryOwner, _context.RepositoryName, createResult.Number); - Assert.False(unlockIssueResult.Locked); + [IntegrationTest] + public async Task CanLockAndUnlockIssues() + { + var newIssue = new NewIssue("Integration Test Issue"); + + var createResult = await _client.Create(_context.RepositoryOwner, _context.RepositoryName, newIssue); + Assert.False(createResult.Locked); + + await _client.Lock(_context.RepositoryOwner, _context.RepositoryName, createResult.Number); + var lockResult = await _client.Get(_context.RepositoryOwner, _context.RepositoryName, createResult.Number); + Assert.True(lockResult.Locked); + + await _client.Unlock(_context.RepositoryOwner, _context.RepositoryName, createResult.Number); + var unlockIssueResult = await _client.Get(_context.RepositoryOwner, _context.RepositoryName, createResult.Number); + Assert.False(unlockIssueResult.Locked); } - + public void Dispose() { _context.Dispose(); diff --git a/Octokit.Tests.Integration/Reactive/ObservableRepositoryCommitsClientTests.cs b/Octokit.Tests.Integration/Reactive/ObservableRepositoryCommitsClientTests.cs index 48b6a75f17..be340347cb 100644 --- a/Octokit.Tests.Integration/Reactive/ObservableRepositoryCommitsClientTests.cs +++ b/Octokit.Tests.Integration/Reactive/ObservableRepositoryCommitsClientTests.cs @@ -17,7 +17,7 @@ public TheGetAllMethod() var client = Helper.GetAuthenticatedClient(); _repositoryCommitsClient = new ObservableRepositoryCommitsClient(client); } - + [IntegrationTest] public async Task CanGetCorrectCountOfCommitsWithoutStart() { diff --git a/Octokit.Tests.Integration/Reactive/ObservableRepositoryPagesClientTests.cs b/Octokit.Tests.Integration/Reactive/ObservableRepositoryPagesClientTests.cs index 0bb66f59ed..403ee6b802 100644 --- a/Octokit.Tests.Integration/Reactive/ObservableRepositoryPagesClientTests.cs +++ b/Octokit.Tests.Integration/Reactive/ObservableRepositoryPagesClientTests.cs @@ -33,7 +33,7 @@ public async Task ReturnsPageOfRepositoryBuilds() { var options = new ApiOptions { - PageSize= 5, + PageSize = 5, PageCount = 1 }; diff --git a/Octokit.Tests.Integration/Reactive/ObservableUserKeysClientTests.cs b/Octokit.Tests.Integration/Reactive/ObservableUserKeysClientTests.cs index 864d94eaa6..61cbf8628e 100644 --- a/Octokit.Tests.Integration/Reactive/ObservableUserKeysClientTests.cs +++ b/Octokit.Tests.Integration/Reactive/ObservableUserKeysClientTests.cs @@ -65,19 +65,19 @@ public async Task CanGetKeyById() [IntegrationTest] public async Task CanCreateAndDeleteKey() { - // Create a key - string keyTitle = "title"; - string keyData = "ssh-rsa AAAAB3NzaC1yc2EAAAABJQAAAQEAjo4DqFKg8dOxiz/yjypmN1A4itU5QOStyYrfOFuTinesU/2zm9hqxJ5BctIhgtSHJ5foxkhsiBji0qrUg73Q25BThgNg8YFE8njr4EwjmqSqW13akx/zLV0GFFU0SdJ2F6rBldhi93lMnl0ex9swBqa3eLTY8C+HQGBI6MQUMw+BKp0oFkz87Kv+Pfp6lt/Uo32ejSxML1PT5hTH5n+fyl0ied+sRmPGZWmWoHB5Bc9mox7lB6I6A/ZgjtBqbEEn4HQ2/6vp4ojKfSgA4Mm7XMu0bZzX0itKjH1QWD9Lr5apV1cmZsj49Xf8SHucTtH+bq98hb8OOXEGFzplwsX2MQ=="; - - var observable = _github.User.GitSshKey.Create(new NewPublicKey(keyTitle, keyData)); - var key = await observable; + // Use context helper to create/destroy a key safely (to avoid test failures when a key exists due to not having been deleted) + string keyTitle = null; + string keyData = null; + using (var context = await _github.CreatePublicKeyContext()) + { + var observable = _github.User.GitSshKey.Get(context.KeyId); + var key = await observable; - Assert.NotNull(key); - Assert.Equal(key.Title, "title"); - Assert.Equal(key.Key, keyData); + keyTitle = key.Title; + keyData = key.Key; - // Delete key - await _github.User.GitSshKey.Delete(key.Id); + Assert.NotNull(key); + } // Verify key no longer exists var keys = await _github.User.GitSshKey.GetAllForCurrent().ToList(); diff --git a/Octokit.Tests/Clients/AssigneesClientTests.cs b/Octokit.Tests/Clients/AssigneesClientTests.cs index 2044a817ed..84731319e1 100644 --- a/Octokit.Tests/Clients/AssigneesClientTests.cs +++ b/Octokit.Tests/Clients/AssigneesClientTests.cs @@ -196,6 +196,66 @@ public async Task EnsuresNonNullArguments() } } + public class TheAddAssigneesMethod + { + [Fact] + public async Task PostsToCorrectUrl() + { + var newAssignees = new AssigneesUpdate(new List() { "assignee1", "assignee2" }); + + var connection = Substitute.For(); + var client = new AssigneesClient(connection); + + await client.AddAssignees("fake", "repo", 2, newAssignees); + + connection.Received().Post(Arg.Is(u => u.ToString() == "repos/fake/repo/issues/2/assignees"), Arg.Any()); + } + + [Fact] + public async Task EnsuresNonNullArguments() + { + var client = new AssigneesClient(Substitute.For()); + var newAssignees = new AssigneesUpdate(new List() { "assignee1", "assignee2" }); + + await Assert.ThrowsAsync(() => client.AddAssignees("", "name", 2, newAssignees)); + await Assert.ThrowsAsync(() => client.AddAssignees("owner", "", 2, newAssignees)); + await Assert.ThrowsAsync(() => client.AddAssignees("owner", "name", 2, null)); + + await Assert.ThrowsAsync(() => client.AddAssignees(null, "name", 2, newAssignees)); + await Assert.ThrowsAsync(() => client.AddAssignees("owner", null, 2, newAssignees)); + } + } + + public class TheRemoveAssigneesMethod + { + [Fact] + public async Task PostsToCorrectUrl() + { + var removeAssignees = new AssigneesUpdate(new List() { "assignee1", "assignee2" }); + + var connection = Substitute.For(); + var client = new AssigneesClient(connection); + + await client.RemoveAssignees("fake", "repo", 2, removeAssignees); + + connection.Received().Delete(Arg.Is(u => u.ToString() == "repos/fake/repo/issues/2/assignees"), Arg.Any()); + } + + [Fact] + public async Task EnsuresNonNullArguments() + { + var client = new AssigneesClient(Substitute.For()); + var newAssignees = new AssigneesUpdate(new List() { "assignee1", "assignee2" }); + + await Assert.ThrowsAsync(() => client.RemoveAssignees("", "name", 2, newAssignees)); + await Assert.ThrowsAsync(() => client.RemoveAssignees("owner", "", 2, newAssignees)); + await Assert.ThrowsAsync(() => client.RemoveAssignees("owner", "name", 2, null)); + + await Assert.ThrowsAsync(() => client.RemoveAssignees(null, "name", 2, newAssignees)); + await Assert.ThrowsAsync(() => client.RemoveAssignees("owner", null, 2, newAssignees)); + } + } + public class TheCtor { [Fact] diff --git a/Octokit.Tests/Clients/CommitStatusClientTests.cs b/Octokit.Tests/Clients/CommitStatusClientTests.cs index adf5a0ebc9..b574c63057 100644 --- a/Octokit.Tests/Clients/CommitStatusClientTests.cs +++ b/Octokit.Tests/Clients/CommitStatusClientTests.cs @@ -70,12 +70,12 @@ public async Task RequestsCorrectUrlWithApiOptionsWithRepositoryId() connection.Received() .GetAll(Arg.Is(u => u.ToString() == "repositories/1/commits/sha/statuses"), options); } - + [Fact] public async Task EnsuresNonNullArguments() { var client = new CommitStatusClient(Substitute.For()); - + await Assert.ThrowsAsync(() => client.GetAll(null, "name", "sha")); await Assert.ThrowsAsync(() => client.GetAll("owner", null, "sha")); await Assert.ThrowsAsync(() => client.GetAll("owner", "name", null)); @@ -128,7 +128,7 @@ public async Task RequestsCorrectUrlWithRepositoryId() public async Task EnsuresNonNullArguments() { var client = new CommitStatusClient(Substitute.For()); - + await Assert.ThrowsAsync(() => client.GetCombined(null, "name", "sha")); await Assert.ThrowsAsync(() => client.GetCombined("owner", null, "sha")); await Assert.ThrowsAsync(() => client.GetCombined("owner", "name", null)); diff --git a/Octokit.Tests/Clients/CommitsClientTests.cs b/Octokit.Tests/Clients/CommitsClientTests.cs index adb9deb1c2..b24478ea9e 100644 --- a/Octokit.Tests/Clients/CommitsClientTests.cs +++ b/Octokit.Tests/Clients/CommitsClientTests.cs @@ -18,7 +18,7 @@ public async Task RequestsCorrectUrl() await client.Get("owner", "repo", "reference"); - connection.Received().Get(Arg.Is(u => u.ToString() == "repos/owner/repo/git/commits/reference"), null, + connection.Received().Get(Arg.Is(u => u.ToString() == "repos/owner/repo/git/commits/reference"), null, "application/vnd.github.cryptographer-preview+sha"); } diff --git a/Octokit.Tests/Clients/DeploymentsClientTests.cs b/Octokit.Tests/Clients/DeploymentsClientTests.cs index 703ec7d3b1..92f37bba87 100644 --- a/Octokit.Tests/Clients/DeploymentsClientTests.cs +++ b/Octokit.Tests/Clients/DeploymentsClientTests.cs @@ -60,7 +60,7 @@ public async Task RequestsCorrectUrl() connection.Received(1) .GetAll(Arg.Is(u => u.ToString() == expectedUrl), null, - "application/vnd.github.ant-man-preview+json", + "application/vnd.github.ant-man-preview+json", Args.ApiOptions); } @@ -74,7 +74,7 @@ public async Task RequestsCorrectUrlWithRepositoryId() await client.GetAll(repositoryId); connection.Received(1) - .GetAll(Arg.Is(u => u.ToString() == expectedUrl), + .GetAll(Arg.Is(u => u.ToString() == expectedUrl), Args.ApiOptions); } @@ -95,7 +95,7 @@ public async Task RequestsCorrectUrlWithApiOptions() await client.GetAll(owner, name, options); connection.Received(1) - .GetAll(Arg.Is(u => u.ToString() == expectedUrl), + .GetAll(Arg.Is(u => u.ToString() == expectedUrl), null, "application/vnd.github.ant-man-preview+json", options); diff --git a/Octokit.Tests/Clients/EventsClientTests.cs b/Octokit.Tests/Clients/EventsClientTests.cs index 6f543f7dc1..8be648f6f6 100644 --- a/Octokit.Tests/Clients/EventsClientTests.cs +++ b/Octokit.Tests/Clients/EventsClientTests.cs @@ -47,7 +47,7 @@ public async Task RequestsCorrectUrlWithApiOptions() PageCount = 1, StartPage = 1 }; - + await client.GetAll(options); connection.Received().GetAll(Arg.Is(u => u.ToString() == "events"), options); @@ -59,7 +59,7 @@ public async Task EnsuresNonNullArguments() var connection = Substitute.For(); var client = new EventsClient(connection); - await Assert.ThrowsAsync(() => client.GetAll(null)); + await Assert.ThrowsAsync(() => client.GetAll(null)); } } @@ -154,7 +154,7 @@ public async Task RequestsCorrectUrl() await client.GetAllIssuesForRepository("fake", "repo"); - connection.Received().GetAll(Arg.Is(u => u.ToString() == "repos/fake/repo/issues/events"), Args.ApiOptions); + connection.Received().GetAll(Arg.Is(u => u.ToString() == "repos/fake/repo/issues/events"), Args.ApiOptions); } [Fact] @@ -165,7 +165,7 @@ public async Task RequestsCorrectUrlWithRepositoryId() await client.GetAllIssuesForRepository(1); - connection.Received().GetAll(Arg.Is(u => u.ToString() == "repositories/1/issues/events"), Args.ApiOptions); + connection.Received().GetAll(Arg.Is(u => u.ToString() == "repositories/1/issues/events"), Args.ApiOptions); } [Fact] @@ -183,7 +183,7 @@ public async Task RequestsCorrectUrlWithApiOptions() await client.GetAllIssuesForRepository("fake", "repo", options); - connection.Received().GetAll(Arg.Is(u => u.ToString() == "repos/fake/repo/issues/events"), options); + connection.Received().GetAll(Arg.Is(u => u.ToString() == "repos/fake/repo/issues/events"), options); } [Fact] @@ -201,7 +201,7 @@ public async Task RequestsCorrectUrlWithRepositoryIdWithApiOptions() await client.GetAllIssuesForRepository(1, options); - connection.Received().GetAll(Arg.Is(u => u.ToString() == "repositories/1/issues/events"), options); + connection.Received().GetAll(Arg.Is(u => u.ToString() == "repositories/1/issues/events"), options); } [Fact] diff --git a/Octokit.Tests/Clients/FollowersClientTests.cs b/Octokit.Tests/Clients/FollowersClientTests.cs index 29314bbd9a..e279e1e25d 100644 --- a/Octokit.Tests/Clients/FollowersClientTests.cs +++ b/Octokit.Tests/Clients/FollowersClientTests.cs @@ -34,7 +34,7 @@ public void RequestsTheCorrectUrl() client.GetAllForCurrent(); connection.Received().GetAll( - Arg.Is(u => u.ToString() == "user/followers"),Args.ApiOptions); + Arg.Is(u => u.ToString() == "user/followers"), Args.ApiOptions); } [Fact] @@ -53,7 +53,7 @@ public void RequestsTheCorrectUrlWithApiOptions() client.GetAllForCurrent(options); connection.Received().GetAll( - Arg.Is(u => u.ToString() == "user/followers"),options); + Arg.Is(u => u.ToString() == "user/followers"), options); } [Fact] @@ -61,8 +61,8 @@ public async Task EnsureNonNullArguments() { var connection = Substitute.For(); var client = new FollowersClient(connection); - - await Assert.ThrowsAsync(() => client.GetAllForCurrent(null)); + + await Assert.ThrowsAsync(() => client.GetAllForCurrent(null)); } } @@ -93,7 +93,7 @@ public void RequestsTheCorrectUrlWithOptions() StartPage = 1 }; - client.GetAll("alfhenrik",options); + client.GetAll("alfhenrik", options); connection.Received().GetAll( Arg.Is(u => u.ToString() == "users/alfhenrik/followers"), options); @@ -107,8 +107,8 @@ public async Task EnsureNonNullArguments() await Assert.ThrowsAsync(() => client.GetAll(null)); await Assert.ThrowsAsync(() => client.GetAll("")); - await Assert.ThrowsAsync(() => client.GetAll("fake",null)); - await Assert.ThrowsAsync(() => client.GetAll("",ApiOptions.None)); + await Assert.ThrowsAsync(() => client.GetAll("fake", null)); + await Assert.ThrowsAsync(() => client.GetAll("", ApiOptions.None)); } } diff --git a/Octokit.Tests/Clients/GistCommentsClientTests.cs b/Octokit.Tests/Clients/GistCommentsClientTests.cs index 6b9cf86e58..a3bc2972ca 100644 --- a/Octokit.Tests/Clients/GistCommentsClientTests.cs +++ b/Octokit.Tests/Clients/GistCommentsClientTests.cs @@ -71,7 +71,6 @@ public async Task EnsuresNonNullArguments() await Assert.ThrowsAsync(() => client.GetAllForGist("")); await Assert.ThrowsAsync(() => client.GetAllForGist("24", null)); await Assert.ThrowsAsync(() => client.GetAllForGist("", ApiOptions.None)); - } } diff --git a/Octokit.Tests/Clients/GistsClientTests.cs b/Octokit.Tests/Clients/GistsClientTests.cs index 536d7619d7..3dceab8cdb 100644 --- a/Octokit.Tests/Clients/GistsClientTests.cs +++ b/Octokit.Tests/Clients/GistsClientTests.cs @@ -74,7 +74,6 @@ public void RequestsCorrectGetAllUrlWithApiOptions() client.GetAll(options); connection.Received().GetAll(Arg.Is(u => u.ToString() == "gists"), options); - } [Fact] @@ -107,7 +106,6 @@ public void RequestsCorrectGetAllWithSinceUrlAndApiOptions() connection.Received().GetAll(Arg.Is(u => u.ToString() == "gists"), DictionaryWithSince, options); - } [Fact] @@ -149,7 +147,6 @@ public void RequestsCorrectGetAllPublicUrlWithApiOptions() client.GetAllPublic(options); connection.Received().GetAll(Arg.Is(u => u.ToString() == "gists/public"), options); - } [Fact] @@ -192,9 +189,7 @@ public async Task EnsureNonNullArguments() await Assert.ThrowsAsync(() => client.GetAllPublic(null)); await Assert.ThrowsAsync(() => client.GetAllPublic(DateTimeOffset.Now, null)); - } - } public class TheGetAllStarredMethod @@ -225,7 +220,6 @@ public void RequestsCorrectGetAllStarredUrlWithApiOptions() client.GetAllStarred(options); connection.Received().GetAll(Arg.Is(u => u.ToString() == "gists/starred"), options); - } [Fact] @@ -267,7 +261,6 @@ public async Task EnsureNonNullArguments() await Assert.ThrowsAsync(() => client.GetAllStarred(null)); await Assert.ThrowsAsync(() => client.GetAllStarred(DateTimeOffset.Now, null)); - } } @@ -299,7 +292,6 @@ public void RequestsCorrectGetGistsForAUserUrlWithApiOptions() client.GetAllForUser("octokit", options); connection.Received().GetAll(Arg.Is(u => u.ToString() == "users/octokit/gists"), options); - } [Fact] @@ -313,7 +305,6 @@ public void RequestsCorrectGetGistsForAUserWithSinceUrl() connection.Received().GetAll(Arg.Is(u => u.ToString() == "users/octokit/gists"), DictionaryWithSince, Args.ApiOptions); - } [Fact] @@ -348,7 +339,6 @@ public async Task EnsureNonNullArguments() await Assert.ThrowsAsync(() => client.GetAllForUser("", DateTimeOffset.Now, ApiOptions.None)); await Assert.ThrowsAsync(() => client.GetAllForUser("user", DateTimeOffset.Now, null)); } - } public class TheGetAllCommitsMethod @@ -392,7 +382,6 @@ public async Task EnsureNonNullArguments() await Assert.ThrowsAsync(() => client.GetAllCommits("id", null)); await Assert.ThrowsAsync(() => client.GetAllCommits("", ApiOptions.None)); } - } public class TheGetAllForksMethod @@ -553,7 +542,6 @@ public void RequestsCorrectUrl() connection.Received().Post(Arg.Is(u => u.ToString() == "gists/1/forks"), Arg.Any()); - } } diff --git a/Octokit.Tests/Clients/IssueCommentsClientTests.cs b/Octokit.Tests/Clients/IssueCommentsClientTests.cs index 46a803a5fe..ff5a5ef9f3 100644 --- a/Octokit.Tests/Clients/IssueCommentsClientTests.cs +++ b/Octokit.Tests/Clients/IssueCommentsClientTests.cs @@ -21,7 +21,7 @@ public async Task RequestsCorrectUrl() await client.Get("fake", "repo", 42); connection.Received().Get( - Arg.Is(u => u.ToString() == "repos/fake/repo/issues/comments/42"), + Arg.Is(u => u.ToString() == "repos/fake/repo/issues/comments/42"), Arg.Any>(), "application/vnd.github.squirrel-girl-preview"); } @@ -136,9 +136,11 @@ public async Task EnsuresNonNullArguments() await Assert.ThrowsAsync(() => client.GetAllForRepository("owner", null)); await Assert.ThrowsAsync(() => client.GetAllForRepository(null, "name", ApiOptions.None)); await Assert.ThrowsAsync(() => client.GetAllForRepository("owner", null, ApiOptions.None)); - await Assert.ThrowsAsync(() => client.GetAllForRepository("owner", "name", null)); + await Assert.ThrowsAsync(() => client.GetAllForRepository("owner", "name", options: null)); + await Assert.ThrowsAsync(() => client.GetAllForRepository("owner", "name", null, ApiOptions.None)); - await Assert.ThrowsAsync(() => client.GetAllForRepository(1, null)); + await Assert.ThrowsAsync(() => client.GetAllForRepository(1, options: null)); + await Assert.ThrowsAsync(() => client.GetAllForRepository(1, null, ApiOptions.None)); await Assert.ThrowsAsync(() => client.GetAllForRepository("", "name")); await Assert.ThrowsAsync(() => client.GetAllForRepository("owner", "")); @@ -194,7 +196,7 @@ public async Task RequestsCorrectUrlWithApiOptions() await client.GetAllForIssue("fake", "repo", 3, options); connection.Received().GetAll( - Arg.Is(u => u.ToString() == "repos/fake/repo/issues/3/comments"), + Arg.Is(u => u.ToString() == "repos/fake/repo/issues/3/comments"), Arg.Any>(), "application/vnd.github.squirrel-girl-preview", options); diff --git a/Octokit.Tests/Clients/IssueTimelineClientTests.cs b/Octokit.Tests/Clients/IssueTimelineClientTests.cs index 694cedd7f2..89b8b63f20 100644 --- a/Octokit.Tests/Clients/IssueTimelineClientTests.cs +++ b/Octokit.Tests/Clients/IssueTimelineClientTests.cs @@ -29,7 +29,7 @@ public async Task RequestsTheCorrectUrl() await client.GetAllForIssue("fake", "repo", 42); connection.Received().GetAll( - Arg.Is(u => u.ToString() == "repos/fake/repo/issues/42/timeline"), + Arg.Is(u => u.ToString() == "repos/fake/repo/issues/42/timeline"), Arg.Any>(), "application/vnd.github.mockingbird-preview", Arg.Any()); @@ -41,7 +41,7 @@ public async Task RequestsTheCorrectUrlWithApiOptions() var connection = Substitute.For(); var client = new IssueTimelineClient(connection); - await client.GetAllForIssue("fake", "repo", 42, new ApiOptions {PageSize = 30}); + await client.GetAllForIssue("fake", "repo", 42, new ApiOptions { PageSize = 30 }); connection.Received().GetAll( Arg.Is(u => u.ToString() == "repos/fake/repo/issues/42/timeline"), @@ -71,7 +71,7 @@ public async Task RequestsTheCorrectUrlWithRepositoryIdAndApiOptions() var connection = Substitute.For(); var client = new IssueTimelineClient(connection); - await client.GetAllForIssue(1, 42, new ApiOptions {PageSize = 30}); + await client.GetAllForIssue(1, 42, new ApiOptions { PageSize = 30 }); connection.Received().GetAll( Arg.Is(u => u.ToString() == "repositories/1/issues/42/timeline"), @@ -92,7 +92,6 @@ public async Task EnsuresNonNullArguments() await Assert.ThrowsAsync(() => client.GetAllForIssue("", "repo", 42)); await Assert.ThrowsAsync(() => client.GetAllForIssue("owner", "", 42)); - } } } diff --git a/Octokit.Tests/Clients/IssuesClientTests.cs b/Octokit.Tests/Clients/IssuesClientTests.cs index 981f69b6ef..e3d752deaa 100644 --- a/Octokit.Tests/Clients/IssuesClientTests.cs +++ b/Octokit.Tests/Clients/IssuesClientTests.cs @@ -406,8 +406,7 @@ public void PostsToCorrectUrl() client.Create("fake", "repo", newIssue); - connection.Received().Post(Arg.Is(u => u.ToString() == "repos/fake/repo/issues"), - newIssue); + connection.Received().Post(Arg.Is(u => u.ToString() == "repos/fake/repo/issues"), newIssue); } [Fact] @@ -451,8 +450,7 @@ public void PostsToCorrectUrl() client.Update("fake", "repo", 42, issueUpdate); - connection.Received().Patch(Arg.Is(u => u.ToString() == "repos/fake/repo/issues/42"), - issueUpdate); + connection.Received().Patch(Arg.Is(u => u.ToString() == "repos/fake/repo/issues/42"), issueUpdate); } [Fact] diff --git a/Octokit.Tests/Clients/IssuesLabelsClientTests.cs b/Octokit.Tests/Clients/IssuesLabelsClientTests.cs index b84a453ac4..786cf1201d 100644 --- a/Octokit.Tests/Clients/IssuesLabelsClientTests.cs +++ b/Octokit.Tests/Clients/IssuesLabelsClientTests.cs @@ -560,7 +560,7 @@ public void UpdatesCorrectUrl() { var connection = Substitute.For(); var client = new IssuesLabelsClient(connection); - + var labelUpdate = new LabelUpdate("name", "FF0000"); client.Update("fake", "repo", "labelName", labelUpdate); diff --git a/Octokit.Tests/Clients/OrganizationMembersClientTests.cs b/Octokit.Tests/Clients/OrganizationMembersClientTests.cs index bcd2ec4fd8..efe9527399 100644 --- a/Octokit.Tests/Clients/OrganizationMembersClientTests.cs +++ b/Octokit.Tests/Clients/OrganizationMembersClientTests.cs @@ -295,7 +295,7 @@ public async Task EnsureNonNullArguments() await Assert.ThrowsAsync(() => client.GetAllPublic(null)); await Assert.ThrowsAsync(() => client.GetAllPublic(null, ApiOptions.None)); await Assert.ThrowsAsync(() => client.GetAllPublic("org", null)); - + await Assert.ThrowsAsync(() => client.GetAllPublic("")); await Assert.ThrowsAsync(() => client.GetAllPublic("", ApiOptions.None)); } diff --git a/Octokit.Tests/Clients/OrganizationsClientTests.cs b/Octokit.Tests/Clients/OrganizationsClientTests.cs index ec5b158407..c246cd529a 100644 --- a/Octokit.Tests/Clients/OrganizationsClientTests.cs +++ b/Octokit.Tests/Clients/OrganizationsClientTests.cs @@ -81,7 +81,7 @@ public async Task EnsuresNonNullArguments() var connection = Substitute.For(); var client = new OrganizationsClient(connection); - await Assert.ThrowsAsync(() => client.GetAll(null)); + await Assert.ThrowsAsync(() => client.GetAll((string)null)); await Assert.ThrowsAsync(() => client.GetAll(null, ApiOptions.None)); await Assert.ThrowsAsync(() => client.GetAll("username", null)); @@ -90,6 +90,52 @@ public async Task EnsuresNonNullArguments() } } + public class TheGetAllForUserMethod + { + [Fact] + public async Task RequestsTheCorrectUrl() + { + var connection = Substitute.For(); + var client = new OrganizationsClient(connection); + + await client.GetAllForUser("username"); + + connection.Received().GetAll(Arg.Is(u => u.ToString() == "users/username/orgs"), Args.ApiOptions); + } + + [Fact] + public async Task RequestsTheCorrectUrlWithApiOptions() + { + var connection = Substitute.For(); + var client = new OrganizationsClient(connection); + + var options = new ApiOptions + { + StartPage = 1, + PageCount = 1, + PageSize = 1 + }; + + await client.GetAllForUser("username", options); + + connection.Received().GetAll(Arg.Is(u => u.ToString() == "users/username/orgs"), options); + } + + [Fact] + public async Task EnsuresNonNullArguments() + { + var connection = Substitute.For(); + var client = new OrganizationsClient(connection); + + await Assert.ThrowsAsync(() => client.GetAllForUser(null)); + await Assert.ThrowsAsync(() => client.GetAllForUser(null, ApiOptions.None)); + await Assert.ThrowsAsync(() => client.GetAllForUser("username", null)); + + await Assert.ThrowsAsync(() => client.GetAllForUser("")); + await Assert.ThrowsAsync(() => client.GetAllForUser("", ApiOptions.None)); + } + } + public class TheGetAllForCurrentMethod { [Fact] @@ -131,6 +177,42 @@ public async Task EnsuresNonNullArguments() } } + public class TheGetAllOrganizationsMethod + { + [Fact] + public async Task RequestsTheCorrectUrl() + { + var connection = Substitute.For(); + var client = new OrganizationsClient(connection); + + await client.GetAll(); + + connection.Received().GetAll(Arg.Is(u => u.ToString() == "organizations")); + } + + [Fact] + public async Task RequestsTheCorrectUrlWithRequestParameter() + { + var connection = Substitute.For(); + var client = new OrganizationsClient(connection); + + var request = new OrganizationRequest(1); + + await client.GetAll(request); + + connection.Received().GetAll(Arg.Is(u => u.ToString() == "organizations?since=1")); + } + + [Fact] + public async Task EnsuresNonNullArguments() + { + var connection = Substitute.For(); + var client = new OrganizationsClient(connection); + + await Assert.ThrowsAsync(() => client.GetAll((OrganizationRequest)null)); + } + } + public class TheUpdateMethod { [Fact] diff --git a/Octokit.Tests/Clients/PullRequestReviewCommentsClientTests.cs b/Octokit.Tests/Clients/PullRequestReviewCommentsClientTests.cs index 2217f9b59a..a63a1bedb7 100644 --- a/Octokit.Tests/Clients/PullRequestReviewCommentsClientTests.cs +++ b/Octokit.Tests/Clients/PullRequestReviewCommentsClientTests.cs @@ -200,7 +200,7 @@ public async Task RequestsCorrectUrl() && d["direction"] == "desc" && d["since"] == "2013-11-15T11:43:01Z" && d["sort"] == "updated"), - "application/vnd.github.squirrel-girl-preview", + "application/vnd.github.squirrel-girl-preview", Args.ApiOptions); } @@ -254,7 +254,7 @@ public async Task RequestsCorrectUrlWithApiOptions() && d["direction"] == "desc" && d["since"] == "2013-11-15T11:43:01Z" && d["sort"] == "updated"), - "application/vnd.github.squirrel-girl-preview", + "application/vnd.github.squirrel-girl-preview", options); } diff --git a/Octokit.Tests/Clients/ReleasesClientTests.cs b/Octokit.Tests/Clients/ReleasesClientTests.cs index 29e81a30b1..09a2c49ac0 100644 --- a/Octokit.Tests/Clients/ReleasesClientTests.cs +++ b/Octokit.Tests/Clients/ReleasesClientTests.cs @@ -273,7 +273,6 @@ public async Task EnsuresNonNullArguments() await Assert.ThrowsAsync(() => releasesClient.Edit("", "name", 1, releaseUpdate)); await Assert.ThrowsAsync(() => releasesClient.Edit("owner", "", 1, releaseUpdate)); - } } @@ -390,7 +389,7 @@ public async Task RequestsTheCorrectUrlWithRepositoryIdWithApiOptions() public async Task EnsuresNonNullArguments() { var client = new ReleasesClient(Substitute.For()); - + await Assert.ThrowsAsync(() => client.GetAllAssets(null, "name", 1)); await Assert.ThrowsAsync(() => client.GetAllAssets("owner", null, 1)); diff --git a/Octokit.Tests/Clients/RepositoryContentsClientTests.cs b/Octokit.Tests/Clients/RepositoryContentsClientTests.cs index f04ca7da42..58a04b4ec9 100644 --- a/Octokit.Tests/Clients/RepositoryContentsClientTests.cs +++ b/Octokit.Tests/Clients/RepositoryContentsClientTests.cs @@ -349,7 +349,7 @@ public async Task PassesRequestObject() Arg.Any(), Arg.Is(a => a.Message == "message" - && a.Content == "myfilecontents" + && a.Content == "bXlmaWxlY29udGVudHM=" && a.Branch == "mybranch")); } @@ -365,7 +365,63 @@ public async Task PassesRequestObjectWithRepositoryId() Arg.Any(), Arg.Is(a => a.Message == "message" - && a.Content == "myfilecontents" + && a.Content == "bXlmaWxlY29udGVudHM=" + && a.Branch == "mybranch")); + } + + [Fact] + public async Task RequestsCorrectUrlWithExplicitBase64() + { + var connection = Substitute.For(); + var client = new RepositoryContentsClient(connection); + + string expectedUri = "repos/org/repo/contents/path/to/file"; + await client.CreateFile("org", "repo", "path/to/file", new CreateFileRequest("message", "bXlmaWxlY29udGVudHM=", "mybranch", false)); + + connection.Received().Put(Arg.Is(u => u.ToString() == expectedUri), Arg.Any()); + } + + [Fact] + public async Task RequestsCorrectUrlWithRepositoryIdWithExplicitBase64() + { + var connection = Substitute.For(); + var client = new RepositoryContentsClient(connection); + + string expectedUri = "repositories/1/contents/path/to/file"; + await client.CreateFile(1, "path/to/file", new CreateFileRequest("message", "bXlmaWxlY29udGVudHM=", "mybranch", false)); + + connection.Received().Put(Arg.Is(u => u.ToString() == expectedUri), Arg.Any()); + } + + [Fact] + public async Task PassesRequestObjectWithExplicitBase64() + { + var connection = Substitute.For(); + var client = new RepositoryContentsClient(connection); + + await client.CreateFile("org", "repo", "path/to/file", new CreateFileRequest("message", "bXlmaWxlY29udGVudHM=", "mybranch", false)); + + connection.Received().Put( + Arg.Any(), + Arg.Is(a => + a.Message == "message" + && a.Content == "bXlmaWxlY29udGVudHM=" + && a.Branch == "mybranch")); + } + + [Fact] + public async Task PassesRequestObjectWithRepositoryIdWithExplicitBase64() + { + var connection = Substitute.For(); + var client = new RepositoryContentsClient(connection); + + await client.CreateFile(1, "path/to/file", new CreateFileRequest("message", "bXlmaWxlY29udGVudHM=", "mybranch", false)); + + connection.Received().Put( + Arg.Any(), + Arg.Is(a => + a.Message == "message" + && a.Content == "bXlmaWxlY29udGVudHM=" && a.Branch == "mybranch")); } @@ -509,7 +565,7 @@ public async Task PassesRequestObject() Arg.Any(), Arg.Is(a => a.Message == "message" - && a.Content == "myfilecontents" + && a.Content == "bXlmaWxlY29udGVudHM=" && a.Sha == "1234abc" && a.Branch == "mybranch")); } @@ -526,7 +582,65 @@ public async Task PassesRequestObjectWithRepositoriesId() Arg.Any(), Arg.Is(a => a.Message == "message" - && a.Content == "myfilecontents" + && a.Content == "bXlmaWxlY29udGVudHM=" + && a.Sha == "1234abc" + && a.Branch == "mybranch")); + } + + [Fact] + public async Task RequestsCorrectUrlWithExplicitBase64() + { + var connection = Substitute.For(); + var client = new RepositoryContentsClient(connection); + + string expectedUri = "repos/org/repo/contents/path/to/file"; + await client.UpdateFile("org", "repo", "path/to/file", new UpdateFileRequest("message", "bXlmaWxlY29udGVudHM=", "1234abc", "mybranch", false)); + + connection.Received().Put(Arg.Is(u => u.ToString() == expectedUri), Arg.Any()); + } + + [Fact] + public async Task RequestsCorrectUrlWithRepositoryIdWithExplicitBase64() + { + var connection = Substitute.For(); + var client = new RepositoryContentsClient(connection); + + string expectedUri = "repositories/1/contents/path/to/file"; + await client.UpdateFile(1, "path/to/file", new UpdateFileRequest("message", "bXlmaWxlY29udGVudHM=", "1234abc", "mybranch", false)); + + connection.Received().Put(Arg.Is(u => u.ToString() == expectedUri), Arg.Any()); + } + + [Fact] + public async Task PassesRequestObjectWithExplicitBase64() + { + var connection = Substitute.For(); + var client = new RepositoryContentsClient(connection); + + await client.UpdateFile("org", "repo", "path/to/file", new UpdateFileRequest("message", "bXlmaWxlY29udGVudHM=", "1234abc", "mybranch", false)); + + connection.Received().Put( + Arg.Any(), + Arg.Is(a => + a.Message == "message" + && a.Content == "bXlmaWxlY29udGVudHM=" + && a.Sha == "1234abc" + && a.Branch == "mybranch")); + } + + [Fact] + public async Task PassesRequestObjectWithRepositoriesIdWithExplicitBase64() + { + var connection = Substitute.For(); + var client = new RepositoryContentsClient(connection); + + await client.UpdateFile(1, "path/to/file", new UpdateFileRequest("message", "bXlmaWxlY29udGVudHM=", "1234abc", "mybranch", false)); + + connection.Received().Put( + Arg.Any(), + Arg.Is(a => + a.Message == "message" + && a.Content == "bXlmaWxlY29udGVudHM=" && a.Sha == "1234abc" && a.Branch == "mybranch")); } diff --git a/Octokit.Tests/Clients/RepositoryHooksClientTest.cs b/Octokit.Tests/Clients/RepositoryHooksClientTest.cs index 4a3027f927..9a0601291f 100644 --- a/Octokit.Tests/Clients/RepositoryHooksClientTest.cs +++ b/Octokit.Tests/Clients/RepositoryHooksClientTest.cs @@ -28,7 +28,7 @@ public async Task RequestsCorrectUrl() await client.GetAll("fake", "repo"); - connection.Received().GetAll(Arg.Is(u => u.ToString() == "repos/fake/repo/hooks"), + connection.Received().GetAll(Arg.Is(u => u.ToString() == "repos/fake/repo/hooks"), Args.ApiOptions); } @@ -40,7 +40,7 @@ public async Task RequestsCorrectUrlWithRepositoryId() await client.GetAll(1); - connection.Received().GetAll(Arg.Is(u => u.ToString() == "repositories/1/hooks"), + connection.Received().GetAll(Arg.Is(u => u.ToString() == "repositories/1/hooks"), Args.ApiOptions); } diff --git a/Octokit.Tests/Clients/RepositoryInvitationsClientTests.cs b/Octokit.Tests/Clients/RepositoryInvitationsClientTests.cs index 374ce74826..d103e51292 100644 --- a/Octokit.Tests/Clients/RepositoryInvitationsClientTests.cs +++ b/Octokit.Tests/Clients/RepositoryInvitationsClientTests.cs @@ -107,6 +107,5 @@ public async Task EnsureNonNullArguments() await Assert.ThrowsAsync(() => client.Edit(1, 2, null)); } } - } diff --git a/Octokit.Tests/Clients/RespositoryCommitsClientTests.cs b/Octokit.Tests/Clients/RespositoryCommitsClientTests.cs index c989ced28d..245859436b 100644 --- a/Octokit.Tests/Clients/RespositoryCommitsClientTests.cs +++ b/Octokit.Tests/Clients/RespositoryCommitsClientTests.cs @@ -317,7 +317,7 @@ public async Task RequestsCorrectUrl() await client.GetSha1("fake", "repo", "ref"); - connection.Received().Get(Arg.Is(u => u.ToString() == "repos/fake/repo/commits/ref"), + connection.Received().Get(Arg.Is(u => u.ToString() == "repos/fake/repo/commits/ref"), null, "application/vnd.github.chitauri-preview+sha"); } diff --git a/Octokit.Tests/Clients/StatisticsClientTests.cs b/Octokit.Tests/Clients/StatisticsClientTests.cs index b93547c871..fe89dac20f 100644 --- a/Octokit.Tests/Clients/StatisticsClientTests.cs +++ b/Octokit.Tests/Clients/StatisticsClientTests.cs @@ -63,7 +63,7 @@ public async Task RequestsCorrectUrlWithCancellactionToken() var cancellationToken = new CancellationToken(true); var connection = Substitute.For(); - + connection.GetQueuedOperation(expectedEndPoint, cancellationToken) .Returns(Task.FromResult(contributors)); @@ -82,7 +82,7 @@ public async Task RequestsCorrectUrlWithRepositoryIdWithCancellactionToken() var cancellationToken = new CancellationToken(true); var connection = Substitute.For(); - + connection.GetQueuedOperation(expectedEndPoint, cancellationToken) .Returns(Task.FromResult(contributors)); @@ -163,7 +163,7 @@ public async Task RequestsCorrectUrlWithCancellationToken() .Returns(Task.FromResult(response)); var client = new StatisticsClient(connection); - + var result = await client.GetCommitActivity("owner", "name", cancellationToken); Assert.Equal(2, result.Activity[0].Days.Count); @@ -186,7 +186,7 @@ public async Task RequestsCorrectUrlWithRepositoryIdWithCancellationToken() .Returns(Task.FromResult(response)); var client = new StatisticsClient(connection); - + var result = await client.GetCommitActivity(1, cancellationToken); Assert.Equal(2, result.Activity[0].Days.Count); @@ -378,7 +378,7 @@ public void RequestsCorrectUrlWithCancellationToken() var statisticsClient = new StatisticsClient(client); statisticsClient.GetParticipation("owner", "name", cancellationToken); - + client.Received().GetQueuedOperation(expectedEndPoint, cancellationToken); } @@ -392,7 +392,7 @@ public void RequestsCorrectUrlWithRepositoryIdWithCancellationToken() var statisticsClient = new StatisticsClient(client); statisticsClient.GetParticipation(1, cancellationToken); - + client.Received().GetQueuedOperation(expectedEndPoint, cancellationToken); } diff --git a/Octokit.Tests/Clients/UserGpgKeysClientTests.cs b/Octokit.Tests/Clients/UserGpgKeysClientTests.cs index be5e63181b..bc9a989102 100644 --- a/Octokit.Tests/Clients/UserGpgKeysClientTests.cs +++ b/Octokit.Tests/Clients/UserGpgKeysClientTests.cs @@ -10,7 +10,6 @@ namespace Octokit.Tests.Clients { public class UserGpgKeysClientTests { - public class TheCtor { [Fact] diff --git a/Octokit.Tests/Exceptions/AbuseExceptionTests.cs b/Octokit.Tests/Exceptions/AbuseExceptionTests.cs new file mode 100644 index 0000000000..17b2616c14 --- /dev/null +++ b/Octokit.Tests/Exceptions/AbuseExceptionTests.cs @@ -0,0 +1,120 @@ +using System.Collections.Generic; +using System.Net; +using Octokit.Internal; +using Xunit; + +namespace Octokit.Tests.Exceptions +{ + public class AbuseExceptionTests + { + public class TheConstructor + { + public class Message + { + [Fact] + public void ContainsAbuseMessageFromApi() + { + const string responseBody = "{\"message\":\"You have triggered an abuse detection mechanism. Please wait a few minutes before you try again.\"," + + "\"documentation_url\":\"https://developer.github.com/v3/#abuse-rate-limits\"}"; + + var response = new Response( + HttpStatusCode.Forbidden, + responseBody, + new Dictionary(), + "application/json"); + + var abuseException = new AbuseException(response); + + Assert.Equal("You have triggered an abuse detection mechanism. Please wait a few minutes before you try again.", abuseException.ApiError.Message); + } + + [Fact] + public void HasDefaultMessage() + { + var response = new Response(HttpStatusCode.Forbidden, null, new Dictionary(), "application/json"); + var abuseException = new AbuseException(response); + + Assert.Equal("Request Forbidden - Abuse Detection", abuseException.Message); + } + } + + public class RetryAfterSeconds + { + public class HappyPath + { + [Fact] + public void WithRetryAfterHeader_PopulatesRetryAfterSeconds() + { + var headerDictionary = new Dictionary { { "Retry-After", "30" } }; + + var response = new Response(HttpStatusCode.Forbidden, null, headerDictionary, "application/json"); + var abuseException = new AbuseException(response); + + Assert.Equal(30, abuseException.RetryAfterSeconds); + } + + [Fact] + public void WithZeroHeaderValue_RetryAfterSecondsIsZero() + { + var headerDictionary = new Dictionary { { "Retry-After", "0" } }; + + var response = new Response(HttpStatusCode.Forbidden, null, headerDictionary, "application/json"); + var abuseException = new AbuseException(response); + + Assert.Equal(0, abuseException.RetryAfterSeconds); + } + } + + public class UnhappyPaths + { + [Fact] + public void NoRetryAfterHeader_RetryAfterSecondsIsSetToTheDefaultOfNull() + { + var headerDictionary = new Dictionary(); + + var response = new Response(HttpStatusCode.Forbidden, null, headerDictionary, "application/json"); + var abuseException = new AbuseException(response); + + Assert.False(abuseException.RetryAfterSeconds.HasValue); + } + + [Theory] + [InlineData(null)] + [InlineData("")] + [InlineData(" ")] + public void EmptyHeaderValue_RetryAfterSecondsDefaultsToNull(string emptyValueToTry) + { + var headerDictionary = new Dictionary { { "Retry-After", emptyValueToTry } }; + + var response = new Response(HttpStatusCode.Forbidden, null, headerDictionary, "application/json"); + var abuseException = new AbuseException(response); + + Assert.False(abuseException.RetryAfterSeconds.HasValue); + } + + [Fact] + public void NonParseableIntHeaderValue_RetryAfterSecondsDefaultsToNull() + { + var headerDictionary = new Dictionary { { "Retry-After", "ABC" } }; + + var response = new Response(HttpStatusCode.Forbidden, null, headerDictionary, "application/json"); + var abuseException = new AbuseException(response); + + Assert.False(abuseException.RetryAfterSeconds.HasValue); + } + + [Fact] + public void NegativeHeaderValue_RetryAfterSecondsDefaultsToNull() + { + var headerDictionary = new Dictionary { { "Retry-After", "-123" } }; + + var response = new Response(HttpStatusCode.Forbidden, null, headerDictionary, "application/json"); + var abuseException = new AbuseException(response); + + Assert.False(abuseException.RetryAfterSeconds.HasValue); + } + } + } + } + } +} diff --git a/Octokit.Tests/GitHubClientTests.cs b/Octokit.Tests/GitHubClientTests.cs index 82ea342362..9f466e7dfa 100644 --- a/Octokit.Tests/GitHubClientTests.cs +++ b/Octokit.Tests/GitHubClientTests.cs @@ -23,7 +23,7 @@ public void EnsuresNonNullArguments() Assert.Throws(() => new GitHubClient(productInformation, (ICredentialStore)null)); Assert.Throws(() => new GitHubClient(null, credentialStore)); - + Assert.Throws(() => new GitHubClient(productInformation, (Uri)null)); Assert.Throws(() => new GitHubClient(null, baseAddress)); @@ -33,7 +33,7 @@ public void EnsuresNonNullArguments() Assert.Throws(() => new GitHubClient(productInformation, null, null)); Assert.Throws(() => new GitHubClient(null, credentialStore, null)); Assert.Throws(() => new GitHubClient(null, null, baseAddress)); - + Assert.Throws(() => new GitHubClient(null, credentialStore, baseAddress)); Assert.Throws(() => new GitHubClient(productInformation, null, baseAddress)); Assert.Throws(() => new GitHubClient(productInformation, credentialStore, null)); diff --git a/Octokit.Tests/Helpers/Arg.cs b/Octokit.Tests/Helpers/Arg.cs index bee4238b8f..5408f72ded 100644 --- a/Octokit.Tests/Helpers/Arg.cs +++ b/Octokit.Tests/Helpers/Arg.cs @@ -51,7 +51,7 @@ public static NewRepository NewRepository public static Dictionary EmptyDictionary { get { return Arg.Is>(d => d.Count == 0); } - } + } public static OrganizationUpdate OrganizationUpdate { diff --git a/Octokit.Tests/Http/ConnectionTests.cs b/Octokit.Tests/Http/ConnectionTests.cs index 01850ccc35..f6c0618ef2 100644 --- a/Octokit.Tests/Http/ConnectionTests.cs +++ b/Octokit.Tests/Http/ConnectionTests.cs @@ -271,6 +271,108 @@ public async Task ThrowsForbiddenExceptionForUnknownForbiddenResponse() Assert.Equal("YOU SHALL NOT PASS!", exception.Message); } + + [Fact] + public async Task ThrowsAbuseExceptionForResponseWithAbuseDocumentationLink() + { + var messageText = "blahblahblah this does not matter because we are testing the URL"; + + var httpClient = Substitute.For(); + IResponse response = new Response( + HttpStatusCode.Forbidden, + "{\"message\":\"" + messageText + "\"," + + "\"documentation_url\":\"https://developer.github.com/v3/#abuse-rate-limits\"}", + new Dictionary(), + "application/json"); + httpClient.Send(Args.Request, Args.CancellationToken).Returns(Task.FromResult(response)); + var connection = new Connection(new ProductHeaderValue("OctokitTests"), + _exampleUri, + Substitute.For(), + httpClient, + Substitute.For()); + + await Assert.ThrowsAsync( + () => connection.GetResponse(new Uri("endpoint", UriKind.Relative))); + } + + [Fact] + public async Task ThrowsAbuseExceptionForResponseWithAbuseDescription() + { + var messageText = "You have triggered an abuse detection mechanism. Please wait a few minutes before you try again."; + + var httpClient = Substitute.For(); + IResponse response = new Response( + HttpStatusCode.Forbidden, + "{\"message\":\"" + messageText + "\"," + + "\"documentation_url\":\"https://ThisURLDoesNotMatter.com\"}", + new Dictionary(), + "application/json"); + httpClient.Send(Args.Request, Args.CancellationToken).Returns(Task.FromResult(response)); + var connection = new Connection(new ProductHeaderValue("OctokitTests"), + _exampleUri, + Substitute.For(), + httpClient, + Substitute.For()); + + await Assert.ThrowsAsync( + () => connection.GetResponse(new Uri("endpoint", UriKind.Relative))); + } + + + [Fact] + public async Task AbuseExceptionContainsTheRetryAfterHeaderAmount() + { + var messageText = "You have triggered an abuse detection mechanism. Please wait a few minutes before you try again."; + + var httpClient = Substitute.For(); + var headerDictionary = new Dictionary + { + { "Retry-After", "45" } + }; + + IResponse response = new Response( + HttpStatusCode.Forbidden, + "{\"message\":\"" + messageText + "\"," + + "\"documentation_url\":\"https://ThisURLDoesNotMatter.com\"}", + headerDictionary, + "application/json"); + httpClient.Send(Args.Request, Args.CancellationToken).Returns(Task.FromResult(response)); + var connection = new Connection(new ProductHeaderValue("OctokitTests"), + _exampleUri, + Substitute.For(), + httpClient, + Substitute.For()); + + var exception = await Assert.ThrowsAsync( + () => connection.GetResponse(new Uri("endpoint", UriKind.Relative))); + + Assert.Equal(45, exception.RetryAfterSeconds); + } + + [Fact] + public async Task ThrowsAbuseExceptionWithDefaultMessageForUnsafeAbuseResponse() + { + string messageText = string.Empty; + + var httpClient = Substitute.For(); + IResponse response = new Response( + HttpStatusCode.Forbidden, + "{\"message\":\"" + messageText + "\"," + + "\"documentation_url\":\"https://developer.github.com/v3/#abuse-rate-limits\"}", + new Dictionary(), + "application/json"); + httpClient.Send(Args.Request, Args.CancellationToken).Returns(Task.FromResult(response)); + var connection = new Connection(new ProductHeaderValue("OctokitTests"), + _exampleUri, + Substitute.For(), + httpClient, + Substitute.For()); + + var exception = await Assert.ThrowsAsync( + () => connection.GetResponse(new Uri("endpoint", UriKind.Relative))); + + Assert.Equal("Request Forbidden - Abuse Detection", exception.Message); + } } public class TheGetHtmlMethod diff --git a/Octokit.Tests/Http/RedirectHandlerTests.cs b/Octokit.Tests/Http/RedirectHandlerTests.cs index 860f1cb01a..051e62cddb 100644 --- a/Octokit.Tests/Http/RedirectHandlerTests.cs +++ b/Octokit.Tests/Http/RedirectHandlerTests.cs @@ -119,7 +119,7 @@ public async Task Status301ShouldRedirectPOSTWithBody(HttpStatusCode statusCode) httpRequestMessage.Content = new StringContent("Hello World"); var response = await adapter.SendAsync(httpRequestMessage, new CancellationToken()); - + Assert.Equal(response.RequestMessage.Method, httpRequestMessage.Method); Assert.NotSame(response.RequestMessage, httpRequestMessage); } @@ -136,7 +136,7 @@ public async Task Status303ShouldRedirectToGETWithoutBody() var httpRequestMessage = CreateRequest(HttpMethod.Post); httpRequestMessage.Content = new StringContent("Hello World"); - + var response = await adapter.SendAsync(httpRequestMessage, new CancellationToken()); Assert.Equal(HttpMethod.Get, response.RequestMessage.Method); @@ -152,7 +152,7 @@ public async Task Exceed3RedirectsShouldReturn() var redirectResponse2 = new HttpResponseMessage(HttpStatusCode.Found); redirectResponse2.Headers.Location = new Uri("http://example.org/foo"); - + var handler = CreateMockHttpHandler(redirectResponse, redirectResponse2); var adapter = new HttpClientAdapter(handler); diff --git a/Octokit.Tests/Models/IssueTest.cs b/Octokit.Tests/Models/IssueTest.cs index a663c1ba91..b55b4e416d 100644 --- a/Octokit.Tests/Models/IssueTest.cs +++ b/Octokit.Tests/Models/IssueTest.cs @@ -190,6 +190,27 @@ public void CreatesAnIssueUpdateRequestObject() ""type"": ""User"", ""site_admin"": false }, +""assignees"": [ +{ +""login"": ""octocat"", +""id"": 1, +""avatar_url"": ""https://github.com/images/error/octocat_happy.gif"", +""gravatar_id"": """", +""url"": ""https://api.github.com/users/octocat"", +""html_url"": ""https://github.com/octocat"", +""followers_url"": ""https://api.github.com/users/octocat/followers"", +""following_url"": ""https://api.github.com/users/octocat/following{/other_user}"", +""gists_url"": ""https://api.github.com/users/octocat/gists{/gist_id}"", +""starred_url"": ""https://api.github.com/users/octocat/starred{/owner}{/repo}"", +""subscriptions_url"": ""https://api.github.com/users/octocat/subscriptions"", +""organizations_url"": ""https://api.github.com/users/octocat/orgs"", +""repos_url"": ""https://api.github.com/users/octocat/repos"", +""events_url"": ""https://api.github.com/users/octocat/events{/privacy}"", +""received_events_url"": ""https://api.github.com/users/octocat/received_events"", +""type"": ""User"", +""site_admin"": false +} +], ""milestone"": { ""url"": ""https://api.github.com/repos/octocat/Hello-World/milestones/1"", ""number"": 1, @@ -257,9 +278,9 @@ public void CreatesAnIssueUpdateRequestObject() var update = issue.ToUpdate(); - Assert.Null(update.Labels); + Assert.NotNull(update.Labels); Assert.Equal(1, update.Milestone.GetValueOrDefault()); - Assert.Equal("octocat", update.Assignee); + Assert.Equal("octocat", update.Assignees.FirstOrDefault()); } } } diff --git a/Octokit.Tests/Models/MigrationTests.cs b/Octokit.Tests/Models/MigrationTests.cs index fbe81bac66..31b89da75e 100644 --- a/Octokit.Tests/Models/MigrationTests.cs +++ b/Octokit.Tests/Models/MigrationTests.cs @@ -113,7 +113,7 @@ public class MigrationTests private static readonly Migration migration = new Migration( id: 79, guid: "0b989ba4-242f-11e5-81e1-c7b6966d2516", - state: Migration.MigrationState.Exported, + state: Migration.MigrationState.Exported, lockRepositories: true, excludeAttachments: false, url: "https://api.github.com/orgs/octo-org/migrations/79", @@ -168,6 +168,5 @@ public void CanBeDeserialized() Assert.Equal(1, _migrationReuqest.Repositories.Count); Assert.Equal(true, _migrationReuqest.LockRepositories); } - } } diff --git a/Octokit.Tests/Octokit.Tests.csproj b/Octokit.Tests/Octokit.Tests.csproj index 866b7ce405..b0a797e9b4 100644 --- a/Octokit.Tests/Octokit.Tests.csproj +++ b/Octokit.Tests/Octokit.Tests.csproj @@ -145,6 +145,7 @@ + diff --git a/Octokit.Tests/Reactive/ObservableAssigneesClientTests.cs b/Octokit.Tests/Reactive/ObservableAssigneesClientTests.cs index bd06c24ad9..21e11f6681 100644 --- a/Octokit.Tests/Reactive/ObservableAssigneesClientTests.cs +++ b/Octokit.Tests/Reactive/ObservableAssigneesClientTests.cs @@ -64,10 +64,10 @@ public void RequestsCorrectUrlWithApiOption() StartPage = 1, PageCount = 1 }; - + client.GetAllForRepository(owner, name, new ApiOptions { PageSize = 1, StartPage = 1 }); client.GetAllForRepository(owner, name, options); - gitHubClient.Connection.Received(1).Get>(_expectedUri, + gitHubClient.Connection.Received(2).Get>(_expectedUri, Arg.Is>(dictionary => dictionary.Count == 2), null); } @@ -151,6 +151,66 @@ public void EnsuresNonNullArguments() } } + public class TheAddAssigneesMethod + { + [Fact] + public void RequestsCorrectUrl() + { + var newAssignees = new AssigneesUpdate(new List() { "assignee1", "assignee2" }); + var gitHubClient = Substitute.For(); + var client = new ObservableAssigneesClient(gitHubClient); + + client.AddAssignees("fake", "repo", 2, newAssignees); + + gitHubClient.Issue.Assignee.Received().AddAssignees("fake", "repo", 2, newAssignees); + } + + [Fact] + public void EnsuresNonNullArguments() + { + var githubClient = Substitute.For(); + var client = new ObservableAssigneesClient(githubClient); + var newAssignees = new AssigneesUpdate(new List() { "assignee1", "assignee2" }); + + Assert.Throws(() => client.AddAssignees(null, "name", 2, newAssignees)); + Assert.Throws(() => client.AddAssignees("name", null, 2, newAssignees)); + Assert.Throws(() => client.AddAssignees("owner", "name", 2, null)); + + Assert.Throws(() => client.AddAssignees("owner", "", 2, newAssignees)); + Assert.Throws(() => client.AddAssignees("", "name", 2, newAssignees)); + } + } + + public class TheRemoveAssigneesMethod + { + [Fact] + public void RequestsCorrectUrl() + { + var newAssignees = new AssigneesUpdate(new List() { "assignee1", "assignee2" }); + var gitHubClient = Substitute.For(); + var client = new ObservableAssigneesClient(gitHubClient); + + client.RemoveAssignees("fake", "repo", 2, newAssignees); + + gitHubClient.Issue.Assignee.Received().RemoveAssignees("fake", "repo", 2, newAssignees); + } + + [Fact] + public void EnsuresNonNullArguments() + { + var githubClient = Substitute.For(); + var client = new ObservableAssigneesClient(githubClient); + var newAssignees = new AssigneesUpdate(new List() { "assignee1", "assignee2" }); + + Assert.Throws(() => client.RemoveAssignees(null, "name", 2, newAssignees)); + Assert.Throws(() => client.RemoveAssignees("owner", null, 2, newAssignees)); + Assert.Throws(() => client.RemoveAssignees("owner", "name", 2, null)); + + Assert.Throws(() => client.RemoveAssignees("owner", "", 2, newAssignees)); + Assert.Throws(() => client.RemoveAssignees("", "name", 2, newAssignees)); + } + } + public class TheCtor { [Fact] diff --git a/Octokit.Tests/Reactive/ObservableAuthorizationsClientTests.cs b/Octokit.Tests/Reactive/ObservableAuthorizationsClientTests.cs index 7fe3bea0cd..99d1b55d65 100644 --- a/Octokit.Tests/Reactive/ObservableAuthorizationsClientTests.cs +++ b/Octokit.Tests/Reactive/ObservableAuthorizationsClientTests.cs @@ -29,7 +29,7 @@ public void RequestsCorrectUrlWithApiOption() { var client = Substitute.For(); var authEndpoint = new ObservableAuthorizationsClient(client); - + authEndpoint.GetAll(ApiOptions.None); client.Connection.Received(1).Get>(Arg.Is(u => u.ToString() == "authorizations"), diff --git a/Octokit.Tests/Reactive/ObservableCommitStatusClientTests.cs b/Octokit.Tests/Reactive/ObservableCommitStatusClientTests.cs index b11cba6258..9d7e5d1f95 100644 --- a/Octokit.Tests/Reactive/ObservableCommitStatusClientTests.cs +++ b/Octokit.Tests/Reactive/ObservableCommitStatusClientTests.cs @@ -149,7 +149,7 @@ public void PostsToTheCorrectUrl() client.Create("owner", "repo", "sha", newCommitStatus); - gitHubClient.Received(). Repository.Status.Create("owner", "repo", "sha", newCommitStatus); + gitHubClient.Received().Repository.Status.Create("owner", "repo", "sha", newCommitStatus); } [Fact] diff --git a/Octokit.Tests/Reactive/ObservableDeploymentsClientTests.cs b/Octokit.Tests/Reactive/ObservableDeploymentsClientTests.cs index 9e105b5586..58bdc62d78 100644 --- a/Octokit.Tests/Reactive/ObservableDeploymentsClientTests.cs +++ b/Octokit.Tests/Reactive/ObservableDeploymentsClientTests.cs @@ -60,7 +60,7 @@ public void RequestsCorrectUrl() _githubClient.Connection.Received(1) .Get>(Arg.Is(u => u.ToString() == expectedUrl), - Arg.Is>(dictionary => dictionary.Count == 0), + Arg.Is>(dictionary => dictionary.Count == 0), Arg.Any()); } @@ -73,7 +73,7 @@ public void RequestsCorrectUrlWithRepositoryId() _githubClient.Connection.Received(1) .Get>(Arg.Is(u => u.ToString() == expectedUrl), - Arg.Is>(dictionary => dictionary.Count == 0), + Arg.Is>(dictionary => dictionary.Count == 0), Arg.Any()); } diff --git a/Octokit.Tests/Reactive/ObservableEventsClientTests.cs b/Octokit.Tests/Reactive/ObservableEventsClientTests.cs index 8d06a257d6..30e9629664 100644 --- a/Octokit.Tests/Reactive/ObservableEventsClientTests.cs +++ b/Octokit.Tests/Reactive/ObservableEventsClientTests.cs @@ -83,7 +83,7 @@ public void RequestsCorrectUrlWithRepositoryId() client.GetAllForRepository(1); - gitHubClient.Connection.Received(1).Get>(new Uri("repositories/1/events", UriKind.Relative), + gitHubClient.Connection.Received(1).Get>(new Uri("repositories/1/events", UriKind.Relative), Args.EmptyDictionary, null); } @@ -102,7 +102,7 @@ public void RequestsCorrectUrlWithApiOptions() client.GetAllForRepository("fake", "repo", options); - gitHubClient.Connection.Received(1).Get>(new Uri("repos/fake/repo/events", UriKind.Relative), + gitHubClient.Connection.Received(1).Get>(new Uri("repos/fake/repo/events", UriKind.Relative), Arg.Is>(d => d.Count == 2), null); } @@ -121,7 +121,7 @@ public void RequestsCorrectUrlWithRepositoryIdWithApiOptions() client.GetAllForRepository(1, apiOptions); - gitHubClient.Connection.Received(1).Get>(new Uri("repositories/1/events", UriKind.Relative), + gitHubClient.Connection.Received(1).Get>(new Uri("repositories/1/events", UriKind.Relative), Arg.Is>(d => d.Count == 2), null); } @@ -156,7 +156,7 @@ public void RequestsCorrectUrl() client.GetAllIssuesForRepository("fake", "repo"); - gitHubClient.Connection.Received(1).Get>(new Uri("repos/fake/repo/issues/events", UriKind.Relative), + gitHubClient.Connection.Received(1).Get>(new Uri("repos/fake/repo/issues/events", UriKind.Relative), Args.EmptyDictionary, null); } @@ -168,7 +168,7 @@ public void RequestsCorrectUrlWithRepositoryId() client.GetAllIssuesForRepository(1); - gitHubClient.Connection.Received(1).Get>(new Uri("repositories/1/issues/events", UriKind.Relative), + gitHubClient.Connection.Received(1).Get>(new Uri("repositories/1/issues/events", UriKind.Relative), Args.EmptyDictionary, null); } @@ -187,7 +187,7 @@ public void RequestsCorrectUrlWithApiOptions() client.GetAllIssuesForRepository("fake", "repo", options); - gitHubClient.Connection.Received(1).Get>(new Uri("repos/fake/repo/issues/events", UriKind.Relative), + gitHubClient.Connection.Received(1).Get>(new Uri("repos/fake/repo/issues/events", UriKind.Relative), Arg.Is>(d => d.Count == 2), null); } @@ -206,7 +206,7 @@ public void RequestsCorrectUrlWithRepositoryIdWithApiOptions() client.GetAllIssuesForRepository(1, options); - gitHubClient.Connection.Received(1).Get>(new Uri("repositories/1/issues/events", UriKind.Relative), + gitHubClient.Connection.Received(1).Get>(new Uri("repositories/1/issues/events", UriKind.Relative), Arg.Is>(d => d.Count == 2), null); } diff --git a/Octokit.Tests/Reactive/ObservableGistsTests.cs b/Octokit.Tests/Reactive/ObservableGistsTests.cs index 6f7e73481f..d824c91c29 100644 --- a/Octokit.Tests/Reactive/ObservableGistsTests.cs +++ b/Octokit.Tests/Reactive/ObservableGistsTests.cs @@ -59,7 +59,7 @@ public void RequestsTheCorrectUrlWithApiOptions() }; client.GetAll(options); - gitHubClient.Connection.Received(1).Get>(Arg.Is(u => u.ToString() == "gists"), + gitHubClient.Connection.Received(1).Get>(Arg.Is(u => u.ToString() == "gists"), DictionaryWithApiOptions, null); } @@ -99,8 +99,8 @@ public void EnsuresNonNullArguments() { var gitsClient = new ObservableGistsClient(Substitute.For()); - Assert.Throws(() => gitsClient.GetAll(null)); - Assert.Throws(() => gitsClient.GetAll(DateTimeOffset.Now, null)); + Assert.Throws(() => gitsClient.GetAll(null)); + Assert.Throws(() => gitsClient.GetAll(DateTimeOffset.Now, null)); } } @@ -321,8 +321,8 @@ public void EnsuresNonNullArguments() Assert.Throws(() => gitsClient.GetAllForUser("")); Assert.Throws(() => gitsClient.GetAllForUser(null, DateTimeOffset.Now)); Assert.Throws(() => gitsClient.GetAllForUser("", DateTimeOffset.Now)); - Assert.Throws(() => gitsClient.GetAllForUser("samthedev",DateTimeOffset.Now, null)); - Assert.Throws(() => gitsClient.GetAllForUser("",DateTimeOffset.Now, ApiOptions.None)); + Assert.Throws(() => gitsClient.GetAllForUser("samthedev", DateTimeOffset.Now, null)); + Assert.Throws(() => gitsClient.GetAllForUser("", DateTimeOffset.Now, ApiOptions.None)); } } @@ -355,7 +355,7 @@ public void RequestsTheCorrectUrlWithApiOptions() gitHubClient.Connection.Received(1).Get>(Arg.Is(u => u.ToString() == "gists/id/commits"), DictionaryWithApiOptions, null); - } + } [Fact] @@ -365,9 +365,8 @@ public void EnsuresNonNullArguments() Assert.Throws(() => gitsClient.GetAllCommits(null)); Assert.Throws(() => gitsClient.GetAllCommits("")); - Assert.Throws(() => gitsClient.GetAllCommits("id", null)); - Assert.Throws(() => gitsClient.GetAllCommits("", ApiOptions.None)); - + Assert.Throws(() => gitsClient.GetAllCommits("id", null)); + Assert.Throws(() => gitsClient.GetAllCommits("", ApiOptions.None)); } } @@ -412,7 +411,6 @@ public void EnsuresNonNullArguments() Assert.Throws(() => gitsClient.GetAllForks("")); Assert.Throws(() => gitsClient.GetAllForks("id", null)); Assert.Throws(() => gitsClient.GetAllForks("", ApiOptions.None)); - } } } diff --git a/Octokit.Tests/Reactive/ObservableIssueCommentsClientTests.cs b/Octokit.Tests/Reactive/ObservableIssueCommentsClientTests.cs index 422379ec78..821968b9a1 100644 --- a/Octokit.Tests/Reactive/ObservableIssueCommentsClientTests.cs +++ b/Octokit.Tests/Reactive/ObservableIssueCommentsClientTests.cs @@ -57,8 +57,8 @@ public void RequestsCorrectUrl() client.GetAllForRepository("fake", "repo"); gitHubClient.Connection.Received(1).Get>( - new Uri("repos/fake/repo/issues/comments", UriKind.Relative), - Args.EmptyDictionary, + new Uri("repos/fake/repo/issues/comments", UriKind.Relative), + Arg.Any>(), "application/vnd.github.squirrel-girl-preview"); } @@ -71,7 +71,9 @@ public void RequestsCorrectUrlWithRepositoryId() client.GetAllForRepository(1); gitHubClient.Connection.Received(1).Get>( - new Uri("repositories/1/issues/comments", UriKind.Relative), Args.EmptyDictionary, null); + new Uri("repositories/1/issues/comments", UriKind.Relative), + Arg.Any>(), + "application/vnd.github.squirrel-girl-preview"); } [Fact] @@ -80,6 +82,12 @@ public void RequestsCorrectUrlWithApiOptions() var gitHubClient = Substitute.For(); var client = new ObservableIssueCommentsClient(gitHubClient); + var request = new IssueCommentRequest() + { + Direction = SortDirection.Descending, + Since = new DateTimeOffset(2016, 11, 23, 11, 11, 11, 00, new TimeSpan()), + Sort = PullRequestReviewCommentSort.Updated + }; var options = new ApiOptions { StartPage = 1, @@ -87,11 +95,14 @@ public void RequestsCorrectUrlWithApiOptions() PageCount = 1 }; - client.GetAllForRepository("fake", "repo", options); + client.GetAllForRepository("fake", "repo", request, options); gitHubClient.Connection.Received(1).Get>( - new Uri("repos/fake/repo/issues/comments", UriKind.Relative), - Arg.Any>(), + new Uri("repos/fake/repo/issues/comments", UriKind.Relative), + Arg.Is>(d => d.Count == 5 + && d["direction"] == "desc" + && d["since"] == "2016-11-23T11:11:11Z" + && d["sort"] == "updated"), "application/vnd.github.squirrel-girl-preview"); } @@ -101,6 +112,12 @@ public void RequestsCorrectUrlWithRepositoryIdWithApiOptions() var gitHubClient = Substitute.For(); var client = new ObservableIssueCommentsClient(gitHubClient); + var request = new IssueCommentRequest() + { + Direction = SortDirection.Descending, + Since = new DateTimeOffset(2016, 11, 23, 11, 11, 11, 00, new TimeSpan()), + Sort = PullRequestReviewCommentSort.Updated + }; var options = new ApiOptions { StartPage = 1, @@ -108,10 +125,15 @@ public void RequestsCorrectUrlWithRepositoryIdWithApiOptions() PageCount = 1 }; - client.GetAllForRepository(1, options); + client.GetAllForRepository(1, request, options); gitHubClient.Connection.Received(1).Get>( - new Uri("repositories/1/issues/comments", UriKind.Relative), Arg.Is>(d => d.Count == 2), null); + new Uri("repositories/1/issues/comments", UriKind.Relative), + Arg.Is>(d => d.Count == 5 + && d["direction"] == "desc" + && d["since"] == "2016-11-23T11:11:11Z" + && d["sort"] == "updated"), + "application/vnd.github.squirrel-girl-preview"); } [Fact] @@ -124,9 +146,11 @@ public async Task EnsuresNonNullArguments() Assert.Throws(() => client.GetAllForRepository("owner", null)); Assert.Throws(() => client.GetAllForRepository(null, "name", ApiOptions.None)); Assert.Throws(() => client.GetAllForRepository("owner", null, ApiOptions.None)); - Assert.Throws(() => client.GetAllForRepository("owner", "name", null)); + Assert.Throws(() => client.GetAllForRepository("owner", "name", request: null)); + Assert.Throws(() => client.GetAllForRepository("owner", "name", options: null)); - Assert.Throws(() => client.GetAllForRepository(1, null)); + Assert.Throws(() => client.GetAllForRepository(1, request: null)); + Assert.Throws(() => client.GetAllForRepository(1, options: null)); Assert.Throws(() => client.GetAllForRepository("", "name")); Assert.Throws(() => client.GetAllForRepository("owner", "")); @@ -146,7 +170,7 @@ public void RequestsCorrectUrl() client.GetAllForIssue("fake", "repo", 3); gitHubClient.Connection.Received(1).Get>( - new Uri("repos/fake/repo/issues/3/comments", UriKind.Relative), + new Uri("repos/fake/repo/issues/3/comments", UriKind.Relative), Args.EmptyDictionary, "application/vnd.github.squirrel-girl-preview"); } diff --git a/Octokit.Tests/Reactive/ObservableIssueTimelineClientTests.cs b/Octokit.Tests/Reactive/ObservableIssueTimelineClientTests.cs index 776f84352b..dcc02ca275 100644 --- a/Octokit.Tests/Reactive/ObservableIssueTimelineClientTests.cs +++ b/Octokit.Tests/Reactive/ObservableIssueTimelineClientTests.cs @@ -43,8 +43,8 @@ public async Task RequestsCorrectUrl() var timelineEvents = await client.GetAllForIssue("fake", "repo", 42).ToList(); connection.Received().Get>( - Arg.Is(u => u.ToString() == "repos/fake/repo/issues/42/timeline"), - Arg.Any>(), + Arg.Is(u => u.ToString() == "repos/fake/repo/issues/42/timeline"), + Arg.Any>(), "application/vnd.github.mockingbird-preview"); Assert.Equal(1, timelineEvents.Count); } @@ -66,7 +66,7 @@ public async Task RequestsCorrectUrlWithApiOptions() gitHubClient.Connection.Get>(Args.Uri, Arg.Is>(d => d.Count == 1), "application/vnd.github.mockingbird-preview") .Returns(Task.FromResult(response)); - var timelineEvents = await client.GetAllForIssue("fake", "repo", 42, new ApiOptions {PageSize = 30}).ToList(); + var timelineEvents = await client.GetAllForIssue("fake", "repo", 42, new ApiOptions { PageSize = 30 }).ToList(); connection.Received().Get>( Arg.Is(u => u.ToString() == "repos/fake/repo/issues/42/timeline"), @@ -116,7 +116,7 @@ public async Task RequestCorrectUrlWithRepositoryIdAndApiOptions() githubClient.Connection.Get>(Args.Uri, Arg.Is>(d => d.Count == 1), "application/vnd.github.mockingbird-preview") .Returns(Task.FromResult(response)); - var timelineEvents = await client.GetAllForIssue(1, 42, new ApiOptions {PageSize = 30}).ToList(); + var timelineEvents = await client.GetAllForIssue(1, 42, new ApiOptions { PageSize = 30 }).ToList(); connection.Received().Get>( Arg.Is(u => u.ToString() == "repositories/1/issues/42/timeline"), @@ -137,7 +137,6 @@ public async Task EnsuresNonNullArguments() Assert.Throws(() => client.GetAllForIssue("", "repo", 42)); Assert.Throws(() => client.GetAllForIssue("owner", "", 42)); - } } } diff --git a/Octokit.Tests/Reactive/ObservableIssuesClientTests.cs b/Octokit.Tests/Reactive/ObservableIssuesClientTests.cs index 7df08bb0d3..5577d5a869 100644 --- a/Octokit.Tests/Reactive/ObservableIssuesClientTests.cs +++ b/Octokit.Tests/Reactive/ObservableIssuesClientTests.cs @@ -125,9 +125,9 @@ public void RequestsCorrectUrlWithApiOptions() client.GetAllForRepository("fake", "repo", options); - gitHubClient.Connection.Received().Get>(Arg.Is(u => u.ToString() == "repos/fake/repo/issues"), - Arg.Is>(d => d.Count == 6 - && d["filter"] == "assigned" + gitHubClient.Connection.Received().Get>(Arg.Is(u => u.ToString() == "repos/fake/repo/issues"), + Arg.Is>(d => d.Count == 6 + && d["filter"] == "assigned" && d["state"] == "open" && d["sort"] == "created" && d["direction"] == "desc" @@ -636,7 +636,6 @@ public void EnsuresNonNullArguments() Assert.Throws(() => client.Update("", "name", 42, new IssueUpdate())); Assert.Throws(() => client.Update("owner", "", 42, new IssueUpdate())); - } } diff --git a/Octokit.Tests/Reactive/ObservableIssuesEventsClientTests.cs b/Octokit.Tests/Reactive/ObservableIssuesEventsClientTests.cs index 0ff4de9ee4..85d32e7074 100644 --- a/Octokit.Tests/Reactive/ObservableIssuesEventsClientTests.cs +++ b/Octokit.Tests/Reactive/ObservableIssuesEventsClientTests.cs @@ -77,7 +77,7 @@ public async Task RequestsCorrectUrlWithApiOptions() var connection = Substitute.For(); var gitHubClient = new GitHubClient(connection); var client = new ObservableIssuesEventsClient(gitHubClient); - + var options = new ApiOptions { StartPage = 1, @@ -107,7 +107,7 @@ public async Task RequestsCorrectUrlWithRepositoryIdWithApiOptions() var connection = Substitute.For(); var gitHubClient = new GitHubClient(connection); var client = new ObservableIssuesEventsClient(gitHubClient); - + var options = new ApiOptions { StartPage = 1, diff --git a/Octokit.Tests/Reactive/ObservableIssuesLabelsClientTests.cs b/Octokit.Tests/Reactive/ObservableIssuesLabelsClientTests.cs index 7a880e9c51..fe63561c1f 100644 --- a/Octokit.Tests/Reactive/ObservableIssuesLabelsClientTests.cs +++ b/Octokit.Tests/Reactive/ObservableIssuesLabelsClientTests.cs @@ -562,9 +562,9 @@ public async Task EnsuresNonNullArguments() Assert.Throws(() => client.Create(null, "name", newLabel)); Assert.Throws(() => client.Create("owner", null, newLabel)); Assert.Throws(() => client.Create("owner", "name", null)); - + Assert.Throws(() => client.Create(1, null)); - + Assert.Throws(() => client.Create("", "name", newLabel)); Assert.Throws(() => client.Create("owner", "", newLabel)); } diff --git a/Octokit.Tests/Reactive/ObservableMilestonesClientTests.cs b/Octokit.Tests/Reactive/ObservableMilestonesClientTests.cs index 4281418d37..628575bc68 100644 --- a/Octokit.Tests/Reactive/ObservableMilestonesClientTests.cs +++ b/Octokit.Tests/Reactive/ObservableMilestonesClientTests.cs @@ -186,12 +186,12 @@ public void EnsuresNonNullArguments() Assert.Throws(() => client.GetAllForRepository(null, "name", new MilestoneRequest())); Assert.Throws(() => client.GetAllForRepository("owner", null, new MilestoneRequest())); Assert.Throws(() => client.GetAllForRepository("owner", "name", (MilestoneRequest)null)); - + Assert.Throws(() => client.GetAllForRepository(null, "name", new MilestoneRequest(), ApiOptions.None)); Assert.Throws(() => client.GetAllForRepository("owner", null, new MilestoneRequest(), ApiOptions.None)); Assert.Throws(() => client.GetAllForRepository("owner", "name", null, ApiOptions.None)); Assert.Throws(() => client.GetAllForRepository("owner", "name", new MilestoneRequest(), null)); - + Assert.Throws(() => client.GetAllForRepository(1, (ApiOptions)null)); Assert.Throws(() => client.GetAllForRepository(1, (MilestoneRequest)null)); Assert.Throws(() => client.GetAllForRepository(1, null, ApiOptions.None)); diff --git a/Octokit.Tests/Reactive/ObservableOrganizationsClientTests.cs b/Octokit.Tests/Reactive/ObservableOrganizationsClientTests.cs index 4889a4e513..26324833c2 100644 --- a/Octokit.Tests/Reactive/ObservableOrganizationsClientTests.cs +++ b/Octokit.Tests/Reactive/ObservableOrganizationsClientTests.cs @@ -77,7 +77,7 @@ public void EnsuresNonNullArguments() var gitHubClient = Substitute.For(); var client = new ObservableOrganizationsClient(gitHubClient); - Assert.Throws(() => client.GetAll(null)); + Assert.Throws(() => client.GetAll((string)null)); Assert.Throws(() => client.GetAll(null, ApiOptions.None)); Assert.Throws(() => client.GetAll("username", null)); diff --git a/Octokit.Tests/Reactive/ObservablePullRequestReviewCommentsClientTests.cs b/Octokit.Tests/Reactive/ObservablePullRequestReviewCommentsClientTests.cs index 7e637dbdec..4afdee43b4 100644 --- a/Octokit.Tests/Reactive/ObservablePullRequestReviewCommentsClientTests.cs +++ b/Octokit.Tests/Reactive/ObservablePullRequestReviewCommentsClientTests.cs @@ -38,7 +38,7 @@ public void RequestsCorrectUrl() client.GetAll("fake", "repo", 1); - gitHubClient.Received().PullRequest.Comment.GetAll("fake", "repo", 1); + gitHubClient.Received().PullRequest.ReviewComment.GetAll("fake", "repo", 1); } [Fact] @@ -49,7 +49,7 @@ public void RequestsCorrectUrlWithRepositoryId() client.GetAll(1, 1); - gitHubClient.Received().PullRequest.Comment.GetAll(1, 1); + gitHubClient.Received().PullRequest.ReviewComment.GetAll(1, 1); } [Fact] @@ -67,7 +67,7 @@ public void RequestsCorrectUrlWithApiOptions() client.GetAll("fake", "repo", 1, options); - gitHubClient.Received().PullRequest.Comment.GetAll("fake", "repo", 1, options); + gitHubClient.Received().PullRequest.ReviewComment.GetAll("fake", "repo", 1, options); } [Fact] @@ -85,7 +85,7 @@ public void RequestsCorrectUrlWithApiOptionsWithRepositoryId() client.GetAll(1, 1, options); - gitHubClient.Received().PullRequest.Comment.GetAll(1, 1, options); + gitHubClient.Received().PullRequest.ReviewComment.GetAll(1, 1, options); } [Fact] @@ -237,7 +237,7 @@ public void RequestsCorrectUrl() client.GetAllForRepository("fake", "repo", request); - gitHubClient.Received().PullRequest.Comment.GetAllForRepository("fake", "repo", request); + gitHubClient.Received().PullRequest.ReviewComment.GetAllForRepository("fake", "repo", request); } [Fact] @@ -255,7 +255,7 @@ public void RequestsCorrectUrlWithRepositoryId() client.GetAllForRepository(1, request); - gitHubClient.Received().PullRequest.Comment.GetAllForRepository(1, request); + gitHubClient.Received().PullRequest.ReviewComment.GetAllForRepository(1, request); } [Fact] @@ -280,7 +280,7 @@ public void RequestsCorrectUrlWithApiOptions() client.GetAllForRepository("fake", "repo", request, options); - gitHubClient.Received().PullRequest.Comment.GetAllForRepository("fake", "repo", request, options); + gitHubClient.Received().PullRequest.ReviewComment.GetAllForRepository("fake", "repo", request, options); } [Fact] @@ -305,7 +305,7 @@ public void RequestsCorrectUrlWithApiOptionsWithRepositoryId() client.GetAllForRepository(1, request, options); - gitHubClient.Received().PullRequest.Comment.GetAllForRepository(1, request, options); + gitHubClient.Received().PullRequest.ReviewComment.GetAllForRepository(1, request, options); } [Fact] @@ -483,7 +483,7 @@ public void RequestsCorrectUrlWithoutSelectedSortingArguments() client.GetAllForRepository("fake", "repo"); - gitHubClient.Received().PullRequest.Comment.GetAllForRepository("fake", "repo"); + gitHubClient.Received().PullRequest.ReviewComment.GetAllForRepository("fake", "repo"); } [Fact] @@ -494,7 +494,7 @@ public void RequestsCorrectUrlWithoutSelectedSortingArgumentsWithRepositoryId() client.GetAllForRepository(1); - gitHubClient.Received().PullRequest.Comment.GetAllForRepository(1); + gitHubClient.Received().PullRequest.ReviewComment.GetAllForRepository(1); } [Fact] @@ -512,7 +512,7 @@ public void RequestsCorrectUrlWithoutSelectedSortingArgumentsWithApiOptions() client.GetAllForRepository("fake", "repo", options); - gitHubClient.Received().PullRequest.Comment.GetAllForRepository("fake", "repo", options); + gitHubClient.Received().PullRequest.ReviewComment.GetAllForRepository("fake", "repo", options); } [Fact] @@ -530,7 +530,7 @@ public void RequestsCorrectUrlWithoutSelectedSortingArgumentsWithApiOptionsWithR client.GetAllForRepository(1, options); - gitHubClient.Received().PullRequest.Comment.GetAllForRepository(1, options); + gitHubClient.Received().PullRequest.ReviewComment.GetAllForRepository(1, options); } [Fact] @@ -721,7 +721,7 @@ public void GetsFromClientPullRequestComment() client.GetComment("owner", "name", 53); - gitHubClient.PullRequest.Comment.Received().GetComment("owner", "name", 53); + gitHubClient.PullRequest.ReviewComment.Received().GetComment("owner", "name", 53); } [Fact] @@ -732,7 +732,7 @@ public void GetsFromClientPullRequestCommentWithRepositoryId() client.GetComment(1, 53); - gitHubClient.PullRequest.Comment.Received().GetComment(1, 53); + gitHubClient.PullRequest.ReviewComment.Received().GetComment(1, 53); } [Fact] @@ -760,7 +760,7 @@ public void PostsToCorrectUrl() client.Create("owner", "name", 13, comment); - gitHubClient.PullRequest.Comment.Received().Create("owner", "name", 13, comment); + gitHubClient.PullRequest.ReviewComment.Received().Create("owner", "name", 13, comment); } [Fact] @@ -773,7 +773,7 @@ public void PostsToCorrectUrlWithRepositoryId() client.Create(1, 13, comment); - gitHubClient.PullRequest.Comment.Received().Create(1, 13, comment); + gitHubClient.PullRequest.ReviewComment.Received().Create(1, 13, comment); } [Fact] @@ -812,7 +812,7 @@ public void PostsToCorrectUrl() client.CreateReply("owner", "name", 13, comment); - gitHubClient.PullRequest.Comment.Received().CreateReply("owner", "name", 13, comment); + gitHubClient.PullRequest.ReviewComment.Received().CreateReply("owner", "name", 13, comment); } [Fact] @@ -825,7 +825,7 @@ public void PostsToCorrectUrlWithRepositoryId() client.CreateReply(1, 13, comment); - gitHubClient.PullRequest.Comment.Received().CreateReply(1, 13, comment); + gitHubClient.PullRequest.ReviewComment.Received().CreateReply(1, 13, comment); } [Fact] @@ -862,7 +862,7 @@ public void PostsToCorrectUrl() client.Edit("owner", "name", 13, comment); - gitHubClient.PullRequest.Comment.Received().Edit("owner", "name", 13, comment); + gitHubClient.PullRequest.ReviewComment.Received().Edit("owner", "name", 13, comment); } [Fact] @@ -875,7 +875,7 @@ public void PostsToCorrectUrlWithRepositoryId() client.Edit(1, 13, comment); - gitHubClient.PullRequest.Comment.Received().Edit(1, 13, comment); + gitHubClient.PullRequest.ReviewComment.Received().Edit(1, 13, comment); } [Fact] @@ -909,7 +909,7 @@ public void PostsToCorrectUrl() client.Delete("owner", "name", 13); - gitHubClient.PullRequest.Comment.Received().Delete("owner", "name", 13); + gitHubClient.PullRequest.ReviewComment.Received().Delete("owner", "name", 13); } [Fact] @@ -920,7 +920,7 @@ public void PostsToCorrectUrlWithRepositoryId() client.Delete(1, 13); - gitHubClient.PullRequest.Comment.Received().Delete(1, 13); + gitHubClient.PullRequest.ReviewComment.Received().Delete(1, 13); } [Fact] diff --git a/Octokit.Tests/Reactive/ObservableRepositoriesClientTests.cs b/Octokit.Tests/Reactive/ObservableRepositoriesClientTests.cs index 28b5ddc389..25ff187ab2 100644 --- a/Octokit.Tests/Reactive/ObservableRepositoriesClientTests.cs +++ b/Octokit.Tests/Reactive/ObservableRepositoriesClientTests.cs @@ -656,7 +656,7 @@ public void EnsuresNonNullArguments() Assert.Throws(() => client.GetAllLanguages(null, "repo")); Assert.Throws(() => client.GetAllLanguages("owner", null)); - + Assert.Throws(() => client.GetAllLanguages("", "repo")); Assert.Throws(() => client.GetAllLanguages("owner", "")); } diff --git a/Octokit.Tests/Reactive/ObservableRepositoryCommentsClientTests.cs b/Octokit.Tests/Reactive/ObservableRepositoryCommentsClientTests.cs index 4af7888f52..429ebdd5b2 100644 --- a/Octokit.Tests/Reactive/ObservableRepositoryCommentsClientTests.cs +++ b/Octokit.Tests/Reactive/ObservableRepositoryCommentsClientTests.cs @@ -176,7 +176,7 @@ public void RequestsCorrectUrlWithApiOptions() githubClient.Connection.Received().Get>(Arg.Is(new Uri("repos/fake/repo/commits/sha/comments", UriKind.Relative)), Arg.Is>(d => d.Count == 2), "application/vnd.github.squirrel-girl-preview"); } - + [Fact] public void RequestsCorrectUrlWithRepositoryIdWithApiOptions() { @@ -191,7 +191,7 @@ public void RequestsCorrectUrlWithRepositoryIdWithApiOptions() }; client.GetAllForCommit(1, "sha", options); - githubClient.Connection.Received().Get>(Arg.Is(new Uri("repositories/1/commits/sha/comments", UriKind.Relative)), + githubClient.Connection.Received().Get>(Arg.Is(new Uri("repositories/1/commits/sha/comments", UriKind.Relative)), Arg.Is>(d => d.Count == 2), "application/vnd.github.squirrel-girl-preview"); } diff --git a/Octokit.Tests/Reactive/ObservableRepositoryCommitsClientTests.cs b/Octokit.Tests/Reactive/ObservableRepositoryCommitsClientTests.cs index 9891b046ca..4738a34d3d 100644 --- a/Octokit.Tests/Reactive/ObservableRepositoryCommitsClientTests.cs +++ b/Octokit.Tests/Reactive/ObservableRepositoryCommitsClientTests.cs @@ -44,7 +44,6 @@ public void EnsuresNonNullArguments() Assert.ThrowsAsync(() => client.GetAll("owner", null, request, options).ToTask()); Assert.ThrowsAsync(() => client.GetAll("owner", "name", null, options).ToTask()); Assert.ThrowsAsync(() => client.GetAll("owner", "name", request, null).ToTask()); - } [Fact] diff --git a/Octokit.Tests/Reactive/ObservableRepositoryContentsClientTests.cs b/Octokit.Tests/Reactive/ObservableRepositoryContentsClientTests.cs index f374f9b07f..2d52c22d43 100644 --- a/Octokit.Tests/Reactive/ObservableRepositoryContentsClientTests.cs +++ b/Octokit.Tests/Reactive/ObservableRepositoryContentsClientTests.cs @@ -59,7 +59,7 @@ public async Task ReturnsReadme() Assert.Equal("README", htmlReadme); apiConnection.Received().GetHtml(Arg.Is(u => u.ToString() == "https://github.example.com/readme.md"), null); } - + [Fact] public async Task ReturnsReadmeWithRepositoryId() { @@ -437,7 +437,7 @@ public void PassesRequestObject() Arg.Any(), Arg.Is(a => a.Message == "message" - && a.Content == "myfilecontents" + && a.Content == "bXlmaWxlY29udGVudHM=" && a.Branch == "mybranch")); } @@ -454,7 +454,66 @@ public void PassesRequestObjectWithRepositoryId() Arg.Any(), Arg.Is(a => a.Message == "message" - && a.Content == "myfilecontents" + && a.Content == "bXlmaWxlY29udGVudHM=" + && a.Branch == "mybranch")); + } + [Fact] + public void RequestsCorrectUrlWithExplicitBase64() + { + var connection = Substitute.For(); + var gitHubClient = new GitHubClient(connection); + var client = new ObservableRepositoryContentsClient(gitHubClient); + + string expectedUri = "repos/org/repo/contents/path/to/file"; + client.CreateFile("org", "repo", "path/to/file", new CreateFileRequest("message", "bXlmaWxlY29udGVudHM=", "mybranch", false)); + + gitHubClient.Connection.Received().Put(Arg.Is(u => u.ToString() == expectedUri), Arg.Any()); + } + + [Fact] + public void RequestsCorrectUrlWithRepositoryIdWithExplicitBase64() + { + var connection = Substitute.For(); + var gitHubClient = new GitHubClient(connection); + var client = new ObservableRepositoryContentsClient(gitHubClient); + + string expectedUri = "repositories/1/contents/path/to/file"; + client.CreateFile(1, "path/to/file", new CreateFileRequest("message", "bXlmaWxlY29udGVudHM=", "mybranch", false)); + + gitHubClient.Connection.Received().Put(Arg.Is(u => u.ToString() == expectedUri), Arg.Any()); + } + + [Fact] + public void PassesRequestObjectWithExplicitBase64() + { + var connection = Substitute.For(); + var gitHubClient = new GitHubClient(connection); + var client = new ObservableRepositoryContentsClient(gitHubClient); + + client.CreateFile("org", "repo", "path/to/file", new CreateFileRequest("message", "bXlmaWxlY29udGVudHM=", "mybranch", false)); + + gitHubClient.Connection.Received().Put( + Arg.Any(), + Arg.Is(a => + a.Message == "message" + && a.Content == "bXlmaWxlY29udGVudHM=" + && a.Branch == "mybranch")); + } + + [Fact] + public void PassesRequestObjectWithRepositoryIdWithExplicitBase64() + { + var connection = Substitute.For(); + var gitHubClient = new GitHubClient(connection); + var client = new ObservableRepositoryContentsClient(gitHubClient); + + client.CreateFile(1, "path/to/file", new CreateFileRequest("message", "bXlmaWxlY29udGVudHM=", "mybranch", false)); + + gitHubClient.Connection.Received().Put( + Arg.Any(), + Arg.Is(a => + a.Message == "message" + && a.Content == "bXlmaWxlY29udGVudHM=" && a.Branch == "mybranch")); } @@ -606,7 +665,7 @@ public void PassesRequestObject() Arg.Any(), Arg.Is(a => a.Message == "message" - && a.Content == "myfilecontents" + && a.Content == "bXlmaWxlY29udGVudHM=" && a.Sha == "1234abc" && a.Branch == "mybranch")); } @@ -624,7 +683,69 @@ public void PassesRequestObjectWithRepositoriesId() Arg.Any(), Arg.Is(a => a.Message == "message" - && a.Content == "myfilecontents" + && a.Content == "bXlmaWxlY29udGVudHM=" + && a.Sha == "1234abc" + && a.Branch == "mybranch")); + } + + [Fact] + public void RequestsCorrectUrlWithExplicitBase64() + { + var connection = Substitute.For(); + var gitHubClient = new GitHubClient(connection); + var client = new ObservableRepositoryContentsClient(gitHubClient); + + string expectedUri = "repos/org/repo/contents/path/to/file"; + client.UpdateFile("org", "repo", "path/to/file", new UpdateFileRequest("message", "bXlmaWxlY29udGVudHM=", "1234abc", "mybranch", false)); + + gitHubClient.Connection.Received().Put(Arg.Is(u => u.ToString() == expectedUri), Arg.Any()); + } + + [Fact] + public void RequestsCorrectUrlWithRepositoryIdWithExplicitBase64() + { + var connection = Substitute.For(); + var gitHubClient = new GitHubClient(connection); + var client = new ObservableRepositoryContentsClient(gitHubClient); + + string expectedUri = "repositories/1/contents/path/to/file"; + client.UpdateFile(1, "path/to/file", new UpdateFileRequest("message", "bXlmaWxlY29udGVudHM=", "1234abc", "mybranch", false)); + + gitHubClient.Connection.Received().Put(Arg.Is(u => u.ToString() == expectedUri), Arg.Any()); + } + + [Fact] + public void PassesRequestObjectWithExplicitBase64() + { + var connection = Substitute.For(); + var gitHubClient = new GitHubClient(connection); + var client = new ObservableRepositoryContentsClient(gitHubClient); + + client.UpdateFile("org", "repo", "path/to/file", new UpdateFileRequest("message", "bXlmaWxlY29udGVudHM=", "1234abc", "mybranch", false)); + + gitHubClient.Connection.Received().Put( + Arg.Any(), + Arg.Is(a => + a.Message == "message" + && a.Content == "bXlmaWxlY29udGVudHM=" + && a.Sha == "1234abc" + && a.Branch == "mybranch")); + } + + [Fact] + public void PassesRequestObjectWithRepositoriesIdWithExplicitBase64() + { + var connection = Substitute.For(); + var gitHubClient = new GitHubClient(connection); + var client = new ObservableRepositoryContentsClient(gitHubClient); + + client.UpdateFile(1, "path/to/file", new UpdateFileRequest("message", "bXlmaWxlY29udGVudHM=", "1234abc", "mybranch", false)); + + gitHubClient.Connection.Received().Put( + Arg.Any(), + Arg.Is(a => + a.Message == "message" + && a.Content == "bXlmaWxlY29udGVudHM=" && a.Sha == "1234abc" && a.Branch == "mybranch")); } @@ -660,7 +781,7 @@ public void RequestsCorrectUrl1() var client = new ObservableRepositoryContentsClient(gitHubClient); client.GetArchive("org", "repo"); - + gitHubClient.Received().Repository.Content.GetArchive("org", "repo"); } @@ -715,7 +836,7 @@ public void RequestsCorrectUrl3WithRepositoryId() var client = new ObservableRepositoryContentsClient(gitHubClient); client.GetArchive(1, ArchiveFormat.Zipball, "ref"); - + gitHubClient.Received().Repository.Content.GetArchive(1, ArchiveFormat.Zipball, "ref"); } diff --git a/Octokit.Tests/Reactive/ObservableStarredClientTests.cs b/Octokit.Tests/Reactive/ObservableStarredClientTests.cs index e3f0bc567d..c650878f03 100644 --- a/Octokit.Tests/Reactive/ObservableStarredClientTests.cs +++ b/Octokit.Tests/Reactive/ObservableStarredClientTests.cs @@ -265,7 +265,7 @@ public void RequestsCorrectUrlParametrizedWithApiOptions() client.GetAllForCurrent(request, options); - connection.Received().Get>(endpoint, + connection.Received().Get>(endpoint, Arg.Is>(d => d.Count == 4 && d["direction"] == "asc" && d["per_page"] == "1" && d["page"] == "1"), null); } @@ -301,8 +301,8 @@ public void RequestsCorrectUrlWithTimestampsWithApiOptions() client.GetAllForCurrentWithTimestamps(options); - connection.Received().Get>(endpoint, - Arg.Is>(d => d.Count == 2 && d["per_page"] == "1" && d["page"] == "1"), + connection.Received().Get>(endpoint, + Arg.Is>(d => d.Count == 2 && d["per_page"] == "1" && d["page"] == "1"), "application/vnd.github.v3.star+json"); } @@ -343,7 +343,7 @@ public void RequestsCorrectUrlWithTimestampsParametrizedWithApiOptions() client.GetAllForCurrentWithTimestamps(request, options); - connection.Received().Get>(endpoint, + connection.Received().Get>(endpoint, Arg.Is>(d => d.Count == 4 && d["direction"] == "asc" && d["per_page"] == "1" && d["page"] == "1"), "application/vnd.github.v3.star+json"); } @@ -399,7 +399,7 @@ public void RequestsCorrectUrlWithApiOptions() client.GetAllForUser("banana", options); - connection.Received().Get>(endpoint, + connection.Received().Get>(endpoint, Arg.Is>(d => d.Count == 2 && d["per_page"] == "1" && d["page"] == "1"), null); } @@ -439,7 +439,7 @@ public void RequestsCorrectUrlParametrizedWithApiOptions() client.GetAllForUser("banana", starredRequest, options); - connection.Received().Get>(endpoint, + connection.Received().Get>(endpoint, Arg.Is>(d => d.Count == 4 && d["direction"] == "asc" && d["direction"] == "asc" && d["per_page"] == "1" && d["page"] == "1"), null); } @@ -477,7 +477,7 @@ public void RequestsCorrectUrlWithTimestampsWithApiOptions() client.GetAllForUserWithTimestamps("banana", options); - connection.Received().Get>(endpoint, + connection.Received().Get>(endpoint, Arg.Is>(d => d.Count == 2 && d["per_page"] == "1" && d["page"] == "1"), "application/vnd.github.v3.star+json"); } diff --git a/Octokit.Tests/Reactive/ObservableTeamsClientTests.cs b/Octokit.Tests/Reactive/ObservableTeamsClientTests.cs index 5fc8bd39ca..fdec6e11e8 100644 --- a/Octokit.Tests/Reactive/ObservableTeamsClientTests.cs +++ b/Octokit.Tests/Reactive/ObservableTeamsClientTests.cs @@ -41,6 +41,6 @@ public void EnsuresNonNullArguments() { Assert.Throws(() => new ObservableTeamsClient(null)); } - } + } } } \ No newline at end of file diff --git a/Octokit.Tests/Reactive/ObservableTreesClientTests.cs b/Octokit.Tests/Reactive/ObservableTreesClientTests.cs index b94e211ddc..a1a13f8a06 100644 --- a/Octokit.Tests/Reactive/ObservableTreesClientTests.cs +++ b/Octokit.Tests/Reactive/ObservableTreesClientTests.cs @@ -52,7 +52,7 @@ public async Task EnsuresNonNullArguments() Assert.Throws(() => client.Get("owner", "name", null)); Assert.Throws(() => client.Get(1, null)); - + Assert.Throws(() => client.Get("", "name", "123456ABCD")); Assert.Throws(() => client.Get("owner", "", "123456ABCD")); Assert.Throws(() => client.Get("owner", "name", "")); diff --git a/Octokit.Tests/SimpleJsonSerializerTests.cs b/Octokit.Tests/SimpleJsonSerializerTests.cs index 0b3ff29d4c..9b1b312701 100644 --- a/Octokit.Tests/SimpleJsonSerializerTests.cs +++ b/Octokit.Tests/SimpleJsonSerializerTests.cs @@ -306,7 +306,7 @@ public void DeserializesEnum() Assert.Equal(SomeEnum.Unicode, sample.SomeEnum); } - + [Fact] public void RemovesDashFromEnums() { @@ -366,5 +366,4 @@ public enum SomeEnum SomethingElse, Unicode } - } diff --git a/Octokit/Clients/AssigneesClient.cs b/Octokit/Clients/AssigneesClient.cs index c8cea1b4f1..19ce489596 100644 --- a/Octokit/Clients/AssigneesClient.cs +++ b/Octokit/Clients/AssigneesClient.cs @@ -95,6 +95,40 @@ public async Task CheckAssignee(string owner, string name, string assignee } } + /// + /// Add assignees to a specified Issue. + /// + /// The owner of the repository + /// The name of the repository + /// The issue number + /// List of names of assignees to add + /// + public Task AddAssignees(string owner, string name, int number, AssigneesUpdate assignees) + { + Ensure.ArgumentNotNullOrEmptyString(owner, "owner"); + Ensure.ArgumentNotNullOrEmptyString(name, "name"); + Ensure.ArgumentNotNull(assignees, "assignees"); + + return ApiConnection.Post(ApiUrls.IssueAssignees(owner, name, number), assignees); + } + + /// + /// Remove assignees from a specified Issue. + /// + /// The owner of the repository + /// The name of the repository + /// The issue number + /// List of assignees to remove + /// + public Task RemoveAssignees(string owner, string name, int number, AssigneesUpdate assignees) + { + Ensure.ArgumentNotNullOrEmptyString(owner, "owner"); + Ensure.ArgumentNotNullOrEmptyString(name, "name"); + Ensure.ArgumentNotNull(assignees, "assignees"); + + return ApiConnection.Delete(ApiUrls.IssueAssignees(owner, name, number), assignees); + } + /// /// Checks to see if a user is an assignee for a repository. /// diff --git a/Octokit/Clients/DeploymentStatusClient.cs b/Octokit/Clients/DeploymentStatusClient.cs index 7445fc9c37..92c50620fa 100644 --- a/Octokit/Clients/DeploymentStatusClient.cs +++ b/Octokit/Clients/DeploymentStatusClient.cs @@ -66,7 +66,7 @@ public Task> GetAll(string owner, string name, i Ensure.ArgumentNotNullOrEmptyString(name, "name"); Ensure.ArgumentNotNull(options, "options"); - return ApiConnection.GetAll(ApiUrls.DeploymentStatuses(owner, name, deploymentId), + return ApiConnection.GetAll(ApiUrls.DeploymentStatuses(owner, name, deploymentId), null, AcceptHeaders.DeploymentApiPreview, options); diff --git a/Octokit/Clients/Enterprise/EnterpriseProbe.cs b/Octokit/Clients/Enterprise/EnterpriseProbe.cs index 3ea5bd48e8..bd4e0002c8 100644 --- a/Octokit/Clients/Enterprise/EnterpriseProbe.cs +++ b/Octokit/Clients/Enterprise/EnterpriseProbe.cs @@ -44,7 +44,7 @@ public EnterpriseProbe(ProductHeaderValue productInformation, IHttpClient httpCl Ensure.ArgumentNotNull(productInformation, "productHeader"); Ensure.ArgumentNotNull(httpClient, "httpClient"); - this.productHeader = productInformation; + productHeader = productInformation; this.httpClient = httpClient; } @@ -93,7 +93,6 @@ public async Task Probe(Uri enterpriseBaseUrl) : (IsEnterpriseResponse(response) ? EnterpriseProbeResult.Ok : EnterpriseProbeResult.NotFound); - } static bool IsEnterpriseResponse(IResponse response) diff --git a/Octokit/Clients/EventsClient.cs b/Octokit/Clients/EventsClient.cs index 9016ae865a..d9b0c5c7f6 100644 --- a/Octokit/Clients/EventsClient.cs +++ b/Octokit/Clients/EventsClient.cs @@ -43,7 +43,7 @@ public Task> GetAll(ApiOptions options) { Ensure.ArgumentNotNull(options, "options"); - return ApiConnection.GetAll(ApiUrls.Events(),options); + return ApiConnection.GetAll(ApiUrls.Events(), options); } /// @@ -115,7 +115,7 @@ public Task> GetAllForRepository(long repositoryId, ApiO /// /// The owner of the repository /// The name of the repository - public Task> GetAllIssuesForRepository(string owner, string name) + public Task> GetAllIssuesForRepository(string owner, string name) { Ensure.ArgumentNotNullOrEmptyString(owner, "owner"); Ensure.ArgumentNotNullOrEmptyString(name, "name"); @@ -130,7 +130,7 @@ public Task> GetAllIssuesForRepository(string owner, str /// http://developer.github.com/v3/activity/events/#list-issue-events-for-a-repository /// /// The Id of the repository - public Task> GetAllIssuesForRepository(long repositoryId) + public Task> GetAllIssuesForRepository(long repositoryId) { return GetAllIssuesForRepository(repositoryId, ApiOptions.None); } @@ -144,13 +144,13 @@ public Task> GetAllIssuesForRepository(long repositoryId /// The owner of the repository /// The name of the repository /// Options for changing the API response - public Task> GetAllIssuesForRepository(string owner, string name, ApiOptions options) + public Task> GetAllIssuesForRepository(string owner, string name, ApiOptions options) { Ensure.ArgumentNotNullOrEmptyString(owner, "owner"); Ensure.ArgumentNotNullOrEmptyString(name, "name"); Ensure.ArgumentNotNull(options, "options"); - return ApiConnection.GetAll(ApiUrls.IssuesEvents(owner, name), options); + return ApiConnection.GetAll(ApiUrls.IssuesEvents(owner, name), options); } /// @@ -161,11 +161,11 @@ public Task> GetAllIssuesForRepository(string owner, str /// /// The Id of the repository /// Options for changing the API response - public Task> GetAllIssuesForRepository(long repositoryId, ApiOptions options) + public Task> GetAllIssuesForRepository(long repositoryId, ApiOptions options) { Ensure.ArgumentNotNull(options, "options"); - return ApiConnection.GetAll(ApiUrls.IssuesEvents(repositoryId), options); + return ApiConnection.GetAll(ApiUrls.IssuesEvents(repositoryId), options); } /// @@ -289,7 +289,7 @@ public Task> GetAllUserReceivedPublic(string user, ApiOp Ensure.ArgumentNotNullOrEmptyString(user, "user"); Ensure.ArgumentNotNull(options, "options"); - return ApiConnection.GetAll(ApiUrls.ReceivedEvents(user, true),options); + return ApiConnection.GetAll(ApiUrls.ReceivedEvents(user, true), options); } /// @@ -319,7 +319,7 @@ public Task> GetAllUserPerformed(string user, ApiOptions Ensure.ArgumentNotNullOrEmptyString(user, "user"); Ensure.ArgumentNotNull(options, "options"); - return ApiConnection.GetAll(ApiUrls.PerformedEvents(user),options); + return ApiConnection.GetAll(ApiUrls.PerformedEvents(user), options); } /// @@ -383,7 +383,7 @@ public Task> GetAllForAnOrganization(string user, string Ensure.ArgumentNotNullOrEmptyString(organization, "organization"); Ensure.ArgumentNotNull(options, "options"); - return ApiConnection.GetAll(ApiUrls.OrganizationEvents(user, organization),options); + return ApiConnection.GetAll(ApiUrls.OrganizationEvents(user, organization), options); } } } diff --git a/Octokit/Clients/FollowersClient.cs b/Octokit/Clients/FollowersClient.cs index d1295c2b24..8a80868144 100644 --- a/Octokit/Clients/FollowersClient.cs +++ b/Octokit/Clients/FollowersClient.cs @@ -44,7 +44,7 @@ public Task> GetAllForCurrent(ApiOptions options) { Ensure.ArgumentNotNull(options, "options"); - return ApiConnection.GetAll(ApiUrls.Followers(),options); + return ApiConnection.GetAll(ApiUrls.Followers(), options); } /// diff --git a/Octokit/Clients/GistCommentsClient.cs b/Octokit/Clients/GistCommentsClient.cs index 23eccda0f9..c9954b9c4d 100644 --- a/Octokit/Clients/GistCommentsClient.cs +++ b/Octokit/Clients/GistCommentsClient.cs @@ -53,7 +53,7 @@ public Task> GetAllForGist(string gistId) /// Task{IReadOnlyList{GistComment}}. public Task> GetAllForGist(string gistId, ApiOptions options) { - Ensure.ArgumentNotNullOrEmptyString(gistId, "gistId"); + Ensure.ArgumentNotNullOrEmptyString(gistId, "gistId"); Ensure.ArgumentNotNull(options, "options"); return ApiConnection.GetAll(ApiUrls.GistComments(gistId), options); diff --git a/Octokit/Clients/GistsClient.cs b/Octokit/Clients/GistsClient.cs index e3d567ba2c..aedc99cd7a 100644 --- a/Octokit/Clients/GistsClient.cs +++ b/Octokit/Clients/GistsClient.cs @@ -129,7 +129,6 @@ public Task> GetAll(ApiOptions options) /// Only gists updated at or after this time are returned public Task> GetAll(DateTimeOffset since) { - return GetAll(since, ApiOptions.None); } @@ -183,8 +182,7 @@ public Task> GetAllPublic(ApiOptions options) /// /// Only gists updated at or after this time are returned public Task> GetAllPublic(DateTimeOffset since) - { - + { return GetAllPublic(since, ApiOptions.None); } @@ -212,7 +210,6 @@ public Task> GetAllPublic(DateTimeOffset since, ApiOptions o /// public Task> GetAllStarred() { - return GetAllStarred(ApiOptions.None); } @@ -238,8 +235,7 @@ public Task> GetAllStarred(ApiOptions options) /// /// Only gists updated at or after this time are returned public Task> GetAllStarred(DateTimeOffset since) - { - + { return GetAllStarred(since, ApiOptions.None); } @@ -300,7 +296,7 @@ public Task> GetAllForUser(string user, ApiOptions options) public Task> GetAllForUser(string user, DateTimeOffset since) { Ensure.ArgumentNotNullOrEmptyString(user, "user"); - + return GetAllForUser(user, since, ApiOptions.None); } diff --git a/Octokit/Clients/IAssigneesClient.cs b/Octokit/Clients/IAssigneesClient.cs index 64f8b1968d..bd1d55d592 100644 --- a/Octokit/Clients/IAssigneesClient.cs +++ b/Octokit/Clients/IAssigneesClient.cs @@ -47,6 +47,26 @@ public interface IAssigneesClient /// Username of the prospective assignee Task CheckAssignee(string owner, string name, string assignee); + /// + /// Add assignees to a specified Issue. + /// + /// The owner of the repository + /// The name of the repository + /// The issue number + /// List of names of assignees to add + /// + Task AddAssignees(string owner, string name, int number, AssigneesUpdate assignees); + + /// + /// Remove assignees from a specified Issue. + /// + /// The owner of the repository + /// The name of the repository + /// The issue number + /// List of assignees to remove + /// + Task RemoveAssignees(string owner, string name, int number, AssigneesUpdate assignees); + /// /// Checks to see if a user is an assignee for a repository. /// diff --git a/Octokit/Clients/IEventsClient.cs b/Octokit/Clients/IEventsClient.cs index a1a7ed521e..431295f665 100644 --- a/Octokit/Clients/IEventsClient.cs +++ b/Octokit/Clients/IEventsClient.cs @@ -78,7 +78,7 @@ public interface IEventsClient /// /// The owner of the repository /// The name of the repository - Task> GetAllIssuesForRepository(string owner, string name); + Task> GetAllIssuesForRepository(string owner, string name); /// /// Gets all the issue events for a given repository @@ -87,7 +87,7 @@ public interface IEventsClient /// http://developer.github.com/v3/activity/events/#list-issue-events-for-a-repository /// /// The Id of the repository - Task> GetAllIssuesForRepository(long repositoryId); + Task> GetAllIssuesForRepository(long repositoryId); /// /// Gets all the issue events for a given repository @@ -98,7 +98,7 @@ public interface IEventsClient /// The owner of the repository /// The name of the repository /// Options for changing the API response - Task> GetAllIssuesForRepository(string owner, string name, ApiOptions options); + Task> GetAllIssuesForRepository(string owner, string name, ApiOptions options); /// /// Gets all the issue events for a given repository @@ -108,7 +108,7 @@ public interface IEventsClient /// /// The Id of the repository /// Options for changing the API response - Task> GetAllIssuesForRepository(long repositoryId, ApiOptions options); + Task> GetAllIssuesForRepository(long repositoryId, ApiOptions options); /// /// Gets all the events for a given repository network @@ -130,7 +130,7 @@ public interface IEventsClient /// The name of the repository /// Options for changing the API response Task> GetAllForRepositoryNetwork(string owner, string name, ApiOptions options); - + /// /// Gets all the events for a given organization /// diff --git a/Octokit/Clients/IGistsClient.cs b/Octokit/Clients/IGistsClient.cs index 877a3ce1a0..1dffebca4b 100644 --- a/Octokit/Clients/IGistsClient.cs +++ b/Octokit/Clients/IGistsClient.cs @@ -101,7 +101,7 @@ public interface IGistsClient /// Only gists updated at or after this time are returned /// Options for changing the API response Task> GetAllPublic(DateTimeOffset since, ApiOptions options); - + /// diff --git a/Octokit/Clients/IIssueCommentReactionsClient.cs b/Octokit/Clients/IIssueCommentReactionsClient.cs index d0e1544be0..ef34d6e79a 100644 --- a/Octokit/Clients/IIssueCommentReactionsClient.cs +++ b/Octokit/Clients/IIssueCommentReactionsClient.cs @@ -38,7 +38,7 @@ public interface IIssueCommentReactionsClient /// The name of the repository /// The comment id Task> GetAll(string owner, string name, int number); - + /// /// Get all reactions for a specified Issue Comment /// diff --git a/Octokit/Clients/IIssueCommentsClient.cs b/Octokit/Clients/IIssueCommentsClient.cs index 9906bc5c88..0f75296dec 100644 --- a/Octokit/Clients/IIssueCommentsClient.cs +++ b/Octokit/Clients/IIssueCommentsClient.cs @@ -65,6 +65,42 @@ public interface IIssueCommentsClient /// Options for changing the API response Task> GetAllForRepository(long repositoryId, ApiOptions options); + /// + /// Gets Issue Comments for a repository. + /// + /// http://developer.github.com/v3/issues/comments/#list-comments-in-a-repository + /// The owner of the repository + /// The name of the repository + /// The sorting parameters + Task> GetAllForRepository(string owner, string name, IssueCommentRequest request); + + /// + /// Gets Issue Comments for a repository. + /// + /// http://developer.github.com/v3/issues/comments/#list-comments-in-a-repository + /// The Id of the repository + /// The sorting parameters + Task> GetAllForRepository(long repositoryId, IssueCommentRequest request); + + /// + /// Gets Issue Comments for a repository. + /// + /// http://developer.github.com/v3/issues/comments/#list-comments-in-a-repository + /// The owner of the repository + /// The name of the repository + /// The sorting parameters + /// Options for changing the API response + Task> GetAllForRepository(string owner, string name, IssueCommentRequest request, ApiOptions options); + + /// + /// Gets Issue Comments for a repository. + /// + /// http://developer.github.com/v3/issues/comments/#list-comments-in-a-repository + /// The Id of the repository + /// The sorting parameters + /// Options for changing the API response + Task> GetAllForRepository(long repositoryId, IssueCommentRequest request, ApiOptions options); + /// /// Gets Issue Comments for a specified Issue. /// diff --git a/Octokit/Clients/IIssuesLabelsClient.cs b/Octokit/Clients/IIssuesLabelsClient.cs index 4a3e001964..e34d8304ad 100644 --- a/Octokit/Clients/IIssuesLabelsClient.cs +++ b/Octokit/Clients/IIssuesLabelsClient.cs @@ -22,7 +22,7 @@ public interface IIssuesLabelsClient /// The name of the repository /// The number of the issue Task> GetAllForIssue(string owner, string name, int number); - + /// /// Gets all labels for the issue. /// diff --git a/Octokit/Clients/IOrganizationsClient.cs b/Octokit/Clients/IOrganizationsClient.cs index 6b399e85e8..7b474b3f5d 100644 --- a/Octokit/Clients/IOrganizationsClient.cs +++ b/Octokit/Clients/IOrganizationsClient.cs @@ -1,4 +1,5 @@ -#if NET_45 +using System; +#if NET_45 using System.Threading.Tasks; using System.Collections.Generic; #endif @@ -62,6 +63,7 @@ public interface IOrganizationsClient /// /// Thrown when a general API error occurs. /// A list of the specified user's s. + [Obsolete("Please use IOrganizationsClient.GetAllForUser() instead. This method will be removed in a future version")] Task> GetAll(string user); /// @@ -71,8 +73,40 @@ public interface IOrganizationsClient /// Options for changing the API response /// Thrown when a general API error occurs. /// A list of the specified user's s. + [Obsolete("Please use IOrganizationsClient.GetAllForUser() instead. This method will be removed in a future version")] Task> GetAll(string user, ApiOptions options); + /// + /// Returns all s for the specified user. + /// + /// Thrown when a general API error occurs. + /// A list of the specified user's s. + Task> GetAllForUser(string user); + + /// + /// Returns all s for the specified user. + /// + /// The login of the user + /// Options for changing the API response + /// Thrown when a general API error occurs. + /// A list of the specified user's s. + Task> GetAllForUser(string user, ApiOptions options); + + /// + /// Returns all s. + /// + /// Thrown when a general API error occurs. + /// A list of s. + Task> GetAll(); + + /// + /// Returns all s. + /// + /// Search parameters of the last organization seen + /// Thrown when a general API error occurs. + /// A list of s. + Task> GetAll(OrganizationRequest request); + /// /// Update the specified organization with data from . /// diff --git a/Octokit/Clients/IPullRequestReviewCommentReactionsClient.cs b/Octokit/Clients/IPullRequestReviewCommentReactionsClient.cs index b0d9ff6545..773ff3159f 100644 --- a/Octokit/Clients/IPullRequestReviewCommentReactionsClient.cs +++ b/Octokit/Clients/IPullRequestReviewCommentReactionsClient.cs @@ -19,7 +19,7 @@ public interface IPullRequestReviewCommentReactionsClient /// The name of the repository /// The comment id Task> GetAll(string owner, string name, int number); - + /// /// Get all reactions for a specified Pull Request Review Comment. /// diff --git a/Octokit/Clients/IPullRequestsClient.cs b/Octokit/Clients/IPullRequestsClient.cs index 04b5418b1b..ccb1315856 100644 --- a/Octokit/Clients/IPullRequestsClient.cs +++ b/Octokit/Clients/IPullRequestsClient.cs @@ -1,4 +1,5 @@ -using System.Collections.Generic; +using System; +using System.Collections.Generic; using System.Diagnostics.CodeAnalysis; using System.Threading.Tasks; @@ -13,10 +14,16 @@ namespace Octokit public interface IPullRequestsClient { /// - /// Client for managing comments. + /// Client for managing review comments. /// + [Obsolete("Please use IPullRequestsClient.ReviewComment instead. This method will be removed in a future version")] IPullRequestReviewCommentsClient Comment { get; } + /// + /// Client for managing review comments. + /// + IPullRequestReviewCommentsClient ReviewComment { get; } + /// /// Get a pull request by number. /// diff --git a/Octokit/Clients/IRepositoriesClient.cs b/Octokit/Clients/IRepositoriesClient.cs index bfe46ef43c..c6d0a2fa3a 100644 --- a/Octokit/Clients/IRepositoriesClient.cs +++ b/Octokit/Clients/IRepositoriesClient.cs @@ -291,7 +291,7 @@ public interface IRepositoriesClient /// Client for GitHub's Repository Deployments API /// /// - /// See the Collaborators API documentation for more details + /// See the Deployments API documentation for more details /// IDeploymentsClient Deployment { get; } diff --git a/Octokit/Clients/IRepositoryHooksClient.cs b/Octokit/Clients/IRepositoryHooksClient.cs index 99a4e83d62..c7899ff563 100644 --- a/Octokit/Clients/IRepositoryHooksClient.cs +++ b/Octokit/Clients/IRepositoryHooksClient.cs @@ -19,7 +19,7 @@ public interface IRepositoryHooksClient /// The repository's name /// See API documentation for more information. Task> GetAll(string owner, string name); - + /// /// Gets the list of hooks defined for a repository /// diff --git a/Octokit/Clients/IStarredClient.cs b/Octokit/Clients/IStarredClient.cs index 61c1034dc9..d0c226db32 100644 --- a/Octokit/Clients/IStarredClient.cs +++ b/Octokit/Clients/IStarredClient.cs @@ -202,14 +202,14 @@ public interface IStarredClient /// The name of the repository /// Thrown if the client is not authenticated. Task CheckStarred(string owner, string name); - + /// /// Stars a repository for the authenticated user. /// /// The owner of the repository to star /// The name of the repository to star Task StarRepo(string owner, string name); - + /// /// Unstars a repository for the authenticated user. /// diff --git a/Octokit/Clients/IssueCommentsClient.cs b/Octokit/Clients/IssueCommentsClient.cs index a779a5e7cb..776de3154c 100644 --- a/Octokit/Clients/IssueCommentsClient.cs +++ b/Octokit/Clients/IssueCommentsClient.cs @@ -56,7 +56,7 @@ public Task> GetAllForRepository(string owner, strin Ensure.ArgumentNotNullOrEmptyString(owner, "owner"); Ensure.ArgumentNotNullOrEmptyString(name, "name"); - return GetAllForRepository(owner, name, ApiOptions.None); + return GetAllForRepository(owner, name, new IssueCommentRequest(), ApiOptions.None); } /// @@ -66,7 +66,7 @@ public Task> GetAllForRepository(string owner, strin /// The Id of the repository public Task> GetAllForRepository(long repositoryId) { - return GetAllForRepository(repositoryId, ApiOptions.None); + return GetAllForRepository(repositoryId, new IssueCommentRequest(), ApiOptions.None); } /// @@ -82,7 +82,7 @@ public Task> GetAllForRepository(string owner, strin Ensure.ArgumentNotNullOrEmptyString(name, "name"); Ensure.ArgumentNotNull(options, "options"); - return ApiConnection.GetAll(ApiUrls.IssueComments(owner, name), null, AcceptHeaders.ReactionsPreview, options); + return GetAllForRepository(owner, name, new IssueCommentRequest(), options); } /// @@ -95,7 +95,69 @@ public Task> GetAllForRepository(long repositoryId, { Ensure.ArgumentNotNull(options, "options"); - return ApiConnection.GetAll(ApiUrls.IssueComments(repositoryId), null, AcceptHeaders.ReactionsPreview, options); + return GetAllForRepository(repositoryId, new IssueCommentRequest(), options); + } + + /// + /// Gets Issue Comments for a repository. + /// + /// http://developer.github.com/v3/issues/comments/#list-comments-in-a-repository + /// The owner of the repository + /// The name of the repository + /// The sorting parameters + public Task> GetAllForRepository(string owner, string name, IssueCommentRequest request) + { + Ensure.ArgumentNotNullOrEmptyString(owner, "owner"); + Ensure.ArgumentNotNullOrEmptyString(name, "name"); + Ensure.ArgumentNotNull(request, "request"); + + return GetAllForRepository(owner, name, request, ApiOptions.None); + } + + /// + /// Gets Issue Comments for a repository. + /// + /// http://developer.github.com/v3/issues/comments/#list-comments-in-a-repository + /// The Id of the repository + /// The sorting parameters + public Task> GetAllForRepository(long repositoryId, IssueCommentRequest request) + { + Ensure.ArgumentNotNull(request, "request"); + + return GetAllForRepository(repositoryId, request, ApiOptions.None); + } + + /// + /// Gets Issue Comments for a repository. + /// + /// http://developer.github.com/v3/issues/comments/#list-comments-in-a-repository + /// The owner of the repository + /// The name of the repository + /// The sorting parameters + /// Options for changing the API response + public Task> GetAllForRepository(string owner, string name, IssueCommentRequest request, ApiOptions options) + { + Ensure.ArgumentNotNullOrEmptyString(owner, "owner"); + Ensure.ArgumentNotNullOrEmptyString(name, "name"); + Ensure.ArgumentNotNull(request, "request"); + Ensure.ArgumentNotNull(options, "options"); + + return ApiConnection.GetAll(ApiUrls.IssueComments(owner, name), request.ToParametersDictionary(), AcceptHeaders.ReactionsPreview, options); + } + + /// + /// Gets Issue Comments for a repository. + /// + /// http://developer.github.com/v3/issues/comments/#list-comments-in-a-repository + /// The Id of the repository + /// The sorting parameters + /// Options for changing the API response + public Task> GetAllForRepository(long repositoryId, IssueCommentRequest request, ApiOptions options) + { + Ensure.ArgumentNotNull(request, "request"); + Ensure.ArgumentNotNull(options, "options"); + + return ApiConnection.GetAll(ApiUrls.IssueComments(repositoryId), request.ToParametersDictionary(), AcceptHeaders.ReactionsPreview, options); } /// diff --git a/Octokit/Clients/IssueTimelineClient.cs b/Octokit/Clients/IssueTimelineClient.cs index aa93a6b460..2b827383d6 100644 --- a/Octokit/Clients/IssueTimelineClient.cs +++ b/Octokit/Clients/IssueTimelineClient.cs @@ -15,7 +15,7 @@ namespace Octokit /// /// See the Issue Timeline API documentation for more information. /// - public class IssueTimelineClient: ApiClient, IIssueTimelineClient + public class IssueTimelineClient : ApiClient, IIssueTimelineClient { public IssueTimelineClient(IApiConnection apiConnection) : base(apiConnection) { diff --git a/Octokit/Clients/MilestonesClient.cs b/Octokit/Clients/MilestonesClient.cs index 5e658013ff..c0842d0fa7 100644 --- a/Octokit/Clients/MilestonesClient.cs +++ b/Octokit/Clients/MilestonesClient.cs @@ -59,7 +59,7 @@ public Task> GetAllForRepository(string owner, string n { Ensure.ArgumentNotNullOrEmptyString(owner, "owner"); Ensure.ArgumentNotNullOrEmptyString(name, "name"); - + return GetAllForRepository(owner, name, new MilestoneRequest()); } diff --git a/Octokit/Clients/OrganizationsClient.cs b/Octokit/Clients/OrganizationsClient.cs index 04ad19c254..218d9291b4 100644 --- a/Octokit/Clients/OrganizationsClient.cs +++ b/Octokit/Clients/OrganizationsClient.cs @@ -70,7 +70,7 @@ public Task> GetAllForCurrent(ApiOptions options) { Ensure.ArgumentNotNull(options, "options"); - return ApiConnection.GetAll(ApiUrls.Organizations(), options); + return ApiConnection.GetAll(ApiUrls.UserOrganizations(), options); } /// @@ -79,6 +79,7 @@ public Task> GetAllForCurrent(ApiOptions options) /// The login of the user /// Thrown when a general API error occurs. /// A list of the specified user's s. + [Obsolete("Please use OrganizationsClient.GetAllForUser() instead. This method will be removed in a future version")] public Task> GetAll(string user) { Ensure.ArgumentNotNullOrEmptyString(user, "user"); @@ -93,12 +94,67 @@ public Task> GetAll(string user) /// Options for changing the API response /// Thrown when a general API error occurs. /// A list of the specified user's s. + [Obsolete("Please use OrganizationsClient.GetAllForUser() instead. This method will be removed in a future version")] public Task> GetAll(string user, ApiOptions options) { Ensure.ArgumentNotNullOrEmptyString(user, "user"); Ensure.ArgumentNotNull(options, "options"); - return ApiConnection.GetAll(ApiUrls.Organizations(user), options); + return ApiConnection.GetAll(ApiUrls.UserOrganizations(user), options); + } + + /// + /// Returns all s for the specified user. + /// + /// The login of the user + /// Thrown when a general API error occurs. + /// A list of the specified user's s. + public Task> GetAllForUser(string user) + { + Ensure.ArgumentNotNullOrEmptyString(user, "user"); + + return GetAllForUser(user, ApiOptions.None); + } + + /// + /// Returns all s for the specified user. + /// + /// The login of the user + /// Options for changing the API response + /// Thrown when a general API error occurs. + /// A list of the specified user's s. + public Task> GetAllForUser(string user, ApiOptions options) + { + Ensure.ArgumentNotNullOrEmptyString(user, "user"); + Ensure.ArgumentNotNull(options, "options"); + + return ApiConnection.GetAll(ApiUrls.UserOrganizations(user), options); + } + + + /// + /// Returns all s. + /// + /// Thrown when a general API error occurs. + /// A list of s. + public Task> GetAll() + { + return ApiConnection.GetAll(ApiUrls.AllOrganizations()); + } + + /// + /// Returns all s. + /// + /// Search parameters of the last organization seen + /// Thrown when a general API error occurs. + /// A list of s. + public Task> GetAll(OrganizationRequest request) + { + Ensure.ArgumentNotNull(request, "request"); + + var url = ApiUrls.AllOrganizations(request.Since); + + return ApiConnection.GetAll(url); } /// diff --git a/Octokit/Clients/PullRequestsClient.cs b/Octokit/Clients/PullRequestsClient.cs index dad64321b6..81ea33ffed 100644 --- a/Octokit/Clients/PullRequestsClient.cs +++ b/Octokit/Clients/PullRequestsClient.cs @@ -1,4 +1,5 @@ -using System.Collections.Generic; +using System; +using System.Collections.Generic; using System.Net; using System.Threading.Tasks; @@ -14,13 +15,19 @@ public class PullRequestsClient : ApiClient, IPullRequestsClient { public PullRequestsClient(IApiConnection apiConnection) : base(apiConnection) { - Comment = new PullRequestReviewCommentsClient(apiConnection); + ReviewComment = new PullRequestReviewCommentsClient(apiConnection); } /// - /// Client for managing comments. + /// Client for managing review comments. /// - public IPullRequestReviewCommentsClient Comment { get; private set; } + [Obsolete("Please use PullRequestsClient.ReviewComment instead. This method will be removed in a future version")] + public IPullRequestReviewCommentsClient Comment { get { return this.ReviewComment; } } + + /// + /// Client for managing review comments. + /// + public IPullRequestReviewCommentsClient ReviewComment { get; set; } /// /// Get a pull request by number. diff --git a/Octokit/Clients/RepositoriesClient.cs b/Octokit/Clients/RepositoriesClient.cs index a52988a113..940c0e3ba7 100644 --- a/Octokit/Clients/RepositoriesClient.cs +++ b/Octokit/Clients/RepositoriesClient.cs @@ -486,7 +486,7 @@ public Task> GetAllForOrg(string organization, ApiOpti /// Client for GitHub's Repository Deployments API /// /// - /// See the Collaborators API documentation for more details + /// See the Deployments API documentation for more details /// public IDeploymentsClient Deployment { get; private set; } diff --git a/Octokit/Clients/RepositoryCommitsClient.cs b/Octokit/Clients/RepositoryCommitsClient.cs index 88d85b4fa2..6656f43537 100644 --- a/Octokit/Clients/RepositoryCommitsClient.cs +++ b/Octokit/Clients/RepositoryCommitsClient.cs @@ -11,7 +11,7 @@ namespace Octokit /// public class RepositoryCommitsClient : ApiClient, IRepositoryCommitsClient { - public RepositoryCommitsClient(IApiConnection apiConnection) + public RepositoryCommitsClient(IApiConnection apiConnection) : base(apiConnection) { } diff --git a/Octokit/Clients/RepositoryInvitationsClient.cs b/Octokit/Clients/RepositoryInvitationsClient.cs index 6215660aae..92a50cba6c 100644 --- a/Octokit/Clients/RepositoryInvitationsClient.cs +++ b/Octokit/Clients/RepositoryInvitationsClient.cs @@ -29,7 +29,7 @@ public async Task Accept(int invitationId) var httpStatusCode = await Connection.Patch(endpoint, AcceptHeaders.InvitationsApiPreview).ConfigureAwait(false); return httpStatusCode == HttpStatusCode.NoContent; } - catch(NotFoundException) + catch (NotFoundException) { return false; } @@ -52,7 +52,7 @@ public async Task Decline(int invitationId) var httpStatusCode = await Connection.Delete(endpoint, new object(), AcceptHeaders.InvitationsApiPreview).ConfigureAwait(false); return httpStatusCode == HttpStatusCode.NoContent; } - catch(NotFoundException) + catch (NotFoundException) { return false; } @@ -76,7 +76,7 @@ public async Task Delete(long repositoryId, int invitationId) var httpStatusCode = await Connection.Delete(endpoint, new object(), AcceptHeaders.InvitationsApiPreview).ConfigureAwait(false); return httpStatusCode == HttpStatusCode.NoContent; } - catch(NotFoundException) + catch (NotFoundException) { return false; } diff --git a/Octokit/Clients/UserEmailsClient.cs b/Octokit/Clients/UserEmailsClient.cs index 16f84b02d8..d37906adda 100644 --- a/Octokit/Clients/UserEmailsClient.cs +++ b/Octokit/Clients/UserEmailsClient.cs @@ -38,7 +38,7 @@ public Task> GetAll() { return GetAll(ApiOptions.None); } - + /// /// Gets all email addresses for the authenticated user. /// diff --git a/Octokit/Exceptions/AbuseException.cs b/Octokit/Exceptions/AbuseException.cs new file mode 100644 index 0000000000..d4379aee48 --- /dev/null +++ b/Octokit/Exceptions/AbuseException.cs @@ -0,0 +1,87 @@ +using System; +using System.Diagnostics; +using System.Diagnostics.CodeAnalysis; +using System.Net; +using System.Runtime.Serialization; +using System.Security; + +namespace Octokit +{ + /// + /// Represents a subset of the HTTP 403 - Forbidden response returned from the API when the forbidden response is related to an abuse detection mechanism. + /// Containts the amount of seconds after which it's safe to retry the request. + /// +#if !NETFX_CORE + [Serializable] +#endif + [SuppressMessage("Microsoft.Design", "CA1032:ImplementStandardExceptionConstructors", + Justification = "These exceptions are specific to the GitHub API and not general purpose exceptions")] + public class AbuseException : ForbiddenException + { + /// + /// Constructs an instance of AbuseException + /// + /// The HTTP payload from the server + public AbuseException(IResponse response) : this(response, null) + { + } + + /// + /// Constructs an instance of AbuseException + /// + /// The HTTP payload from the server + /// The inner exception + public AbuseException(IResponse response, Exception innerException) + : base(response, innerException) + { + Debug.Assert(response != null && response.StatusCode == HttpStatusCode.Forbidden, + "AbuseException created with wrong status code"); + + RetryAfterSeconds = ParseRetryAfterSeconds(response); + } + + private static int? ParseRetryAfterSeconds(IResponse response) + { + string secondsValue; + if (!response.Headers.TryGetValue("Retry-After", out secondsValue)) { return null; } + + int retrySeconds; + if (!int.TryParse(secondsValue, out retrySeconds)) { return null; } + if (retrySeconds < 0) { return null; } + + return retrySeconds; + } + + public int? RetryAfterSeconds { get; private set; } + + public override string Message + { + get { return ApiErrorMessageSafe ?? "Request Forbidden - Abuse Detection"; } + } + +#if !NETFX_CORE + /// + /// Constructs an instance of AbuseException + /// + /// + /// The that holds the + /// serialized object data about the exception being thrown. + /// + /// + /// The that contains + /// contextual information about the source or destination. + /// + protected AbuseException(SerializationInfo info, StreamingContext context) + : base(info, context) + { + } + + [SecurityCritical] + public override void GetObjectData(SerializationInfo info, StreamingContext context) + { + base.GetObjectData(info, context); + info.AddValue("RetryAfterSeconds", RetryAfterSeconds); + } +#endif + } +} diff --git a/Octokit/Exceptions/ApiException.cs b/Octokit/Exceptions/ApiException.cs index adee41be72..4939c39684 100644 --- a/Octokit/Exceptions/ApiException.cs +++ b/Octokit/Exceptions/ApiException.cs @@ -2,7 +2,14 @@ using System.Diagnostics.CodeAnalysis; using System.Net; using System.Runtime.Serialization; +using System.Security; using Octokit.Internal; +#if NET_45 +using StringExt = System.String; +#endif +#if NET_35 +using StringExt = GitHub.Extensions.StringExtensions; +#endif namespace Octokit { @@ -154,10 +161,11 @@ protected ApiException(SerializationInfo info, StreamingContext context) : base(info, context) { if (info == null) return; - StatusCode = (HttpStatusCode) info.GetInt32("HttpStatusCode"); - ApiError = (ApiError) info.GetValue("ApiError", typeof(ApiError)); + StatusCode = (HttpStatusCode)info.GetInt32("HttpStatusCode"); + ApiError = (ApiError)info.GetValue("ApiError", typeof(ApiError)); } + [SecurityCritical] public override void GetObjectData(SerializationInfo info, StreamingContext context) { base.GetObjectData(info, context); @@ -176,7 +184,12 @@ protected string ApiErrorMessageSafe { get { - return ApiError != null ? ApiError.Message : null; + if (ApiError != null && !StringExt.IsNullOrWhiteSpace(ApiError.Message)) + { + return ApiError.Message; + } + + return null; } } diff --git a/Octokit/Exceptions/RateLimitExceededException.cs b/Octokit/Exceptions/RateLimitExceededException.cs index 435517da06..2f6fc61d68 100644 --- a/Octokit/Exceptions/RateLimitExceededException.cs +++ b/Octokit/Exceptions/RateLimitExceededException.cs @@ -2,6 +2,7 @@ using System.Collections.Generic; using System.Diagnostics.CodeAnalysis; using System.Runtime.Serialization; +using System.Security; namespace Octokit { @@ -94,6 +95,7 @@ protected RateLimitExceededException(SerializationInfo info, StreamingContext co ?? new RateLimit(new Dictionary()); } + [SecurityCritical] public override void GetObjectData(SerializationInfo info, StreamingContext context) { base.GetObjectData(info, context); diff --git a/Octokit/Exceptions/RepositoryExistsException.cs b/Octokit/Exceptions/RepositoryExistsException.cs index c772926a78..82ab94e537 100644 --- a/Octokit/Exceptions/RepositoryExistsException.cs +++ b/Octokit/Exceptions/RepositoryExistsException.cs @@ -2,6 +2,7 @@ using System.Diagnostics.CodeAnalysis; using System.Globalization; using System.Runtime.Serialization; +using System.Security; namespace Octokit { @@ -114,9 +115,10 @@ protected RepositoryExistsException(SerializationInfo info, StreamingContext con RepositoryName = info.GetString("RepositoryName"); Organization = info.GetString("Organization"); OwnerIsOrganization = info.GetBoolean("OwnerIsOrganization"); - ExistingRepositoryWebUrl = (Uri) info.GetValue("ExistingRepositoryWebUrl", typeof(Uri)); + ExistingRepositoryWebUrl = (Uri)info.GetValue("ExistingRepositoryWebUrl", typeof(Uri)); } + [SecurityCritical] public override void GetObjectData(SerializationInfo info, StreamingContext context) { base.GetObjectData(info, context); diff --git a/Octokit/Exceptions/RepositoryFormatException.cs b/Octokit/Exceptions/RepositoryFormatException.cs index b268632a40..6920cab737 100644 --- a/Octokit/Exceptions/RepositoryFormatException.cs +++ b/Octokit/Exceptions/RepositoryFormatException.cs @@ -3,6 +3,7 @@ using System.Diagnostics.CodeAnalysis; using System.Globalization; using System.Runtime.Serialization; +using System.Security; namespace Octokit { @@ -51,6 +52,7 @@ protected RepositoryFormatException(SerializationInfo info, StreamingContext con message = info.GetString("Message"); } + [SecurityCritical] public override void GetObjectData(SerializationInfo info, StreamingContext context) { base.GetObjectData(info, context); diff --git a/Octokit/Exceptions/RepositoryWebHookConfigException.cs b/Octokit/Exceptions/RepositoryWebHookConfigException.cs index 7e0556503c..9460052900 100644 --- a/Octokit/Exceptions/RepositoryWebHookConfigException.cs +++ b/Octokit/Exceptions/RepositoryWebHookConfigException.cs @@ -4,6 +4,7 @@ using System.Globalization; using System.Linq; using System.Runtime.Serialization; +using System.Security; namespace Octokit { @@ -48,6 +49,7 @@ protected RepositoryWebHookConfigException(SerializationInfo info, StreamingCont message = info.GetString("Message"); } + [SecurityCritical] public override void GetObjectData(SerializationInfo info, StreamingContext context) { base.GetObjectData(info, context); diff --git a/Octokit/Exceptions/TwoFactorAuthorizationException.cs b/Octokit/Exceptions/TwoFactorAuthorizationException.cs index db6d1a6f9f..5f47cafa77 100644 --- a/Octokit/Exceptions/TwoFactorAuthorizationException.cs +++ b/Octokit/Exceptions/TwoFactorAuthorizationException.cs @@ -3,6 +3,7 @@ using System.Diagnostics.CodeAnalysis; using System.Net; using System.Runtime.Serialization; +using System.Security; namespace Octokit { @@ -77,9 +78,10 @@ protected TwoFactorAuthorizationException(SerializationInfo info, StreamingConte : base(info, context) { if (info == null) return; - TwoFactorType = (TwoFactorType) info.GetInt32("TwoFactorType"); + TwoFactorType = (TwoFactorType)info.GetInt32("TwoFactorType"); } + [SecurityCritical] public override void GetObjectData(SerializationInfo info, StreamingContext context) { base.GetObjectData(info, context); diff --git a/Octokit/Exceptions/TwoFactorChallengeFailedException.cs b/Octokit/Exceptions/TwoFactorChallengeFailedException.cs index d501fe18ce..1266dc1ce0 100644 --- a/Octokit/Exceptions/TwoFactorChallengeFailedException.cs +++ b/Octokit/Exceptions/TwoFactorChallengeFailedException.cs @@ -1,6 +1,7 @@ using System; using System.Diagnostics.CodeAnalysis; using System.Runtime.Serialization; +using System.Security; namespace Octokit { @@ -64,7 +65,7 @@ protected TwoFactorChallengeFailedException(SerializationInfo info, StreamingCon if (info == null) return; AuthorizationCode = info.GetString("AuthorizationCode"); } - + [SecurityCritical] public override void GetObjectData(SerializationInfo info, StreamingContext context) { base.GetObjectData(info, context); diff --git a/Octokit/GitHubClient.cs b/Octokit/GitHubClient.cs index eecfc415db..a00614c4f5 100644 --- a/Octokit/GitHubClient.cs +++ b/Octokit/GitHubClient.cs @@ -84,7 +84,6 @@ public GitHubClient(IConnection connection) var apiConnection = new ApiConnection(connection); Activity = new ActivitiesClient(apiConnection); Authorization = new AuthorizationsClient(apiConnection); - Deployment = new DeploymentsClient(apiConnection); Enterprise = new EnterpriseClient(apiConnection); Gist = new GistsClient(apiConnection); Git = new GitDatabaseClient(apiConnection); @@ -247,15 +246,6 @@ public Uri BaseAddress /// public ISearchClient Search { get; private set; } - // TODO: this should be under Repositories to align with the API docs - /// - /// Access GitHub's Deployments API. - /// - /// - /// Refer to the API documentation for more information: https://developer.github.com/v3/repos/deployments/ - /// - public IDeploymentsClient Deployment { get; private set; } - /// /// Access GitHub's Enterprise API. /// diff --git a/Octokit/Helpers/ApiUrls.cs b/Octokit/Helpers/ApiUrls.cs index 6ae6b0b799..e9e465688d 100644 --- a/Octokit/Helpers/ApiUrls.cs +++ b/Octokit/Helpers/ApiUrls.cs @@ -75,6 +75,7 @@ public static Uri OrganizationRepositories(string organization) /// Returns the that returns all of the organizations for the currently logged in user. /// /// + [Obsolete("Please use ApiUrls.UserOrganizations() instead. This method will be removed in a future version")] public static Uri Organizations() { return _currentUserOrganizationsUrl; @@ -85,11 +86,50 @@ public static Uri Organizations() /// /// The login for the user /// + [Obsolete("Please use ApiUrls.UserOrganizations() instead. This method will be removed in a future version")] public static Uri Organizations(string login) { return "users/{0}/orgs".FormatUri(login); } + /// + /// Returns the that returns all of the organizations for the currently logged in user. + /// + /// + public static Uri UserOrganizations() + { + return "user/orgs".FormatUri(); + } + + /// + /// Returns the that returns all of the organizations for the specified login. + /// + /// The login for the user + /// + public static Uri UserOrganizations(string login) + { + return "users/{0}/orgs".FormatUri(login); + } + + /// + /// Returns the that returns all of the organizations. + /// + /// + public static Uri AllOrganizations() + { + return "organizations".FormatUri(); + } + + /// + /// Returns the that returns all of the organizations. + /// + /// /// The integer Id of the last Organization that you’ve seen. + /// + public static Uri AllOrganizations(long since) + { + return "organizations?since={0}".FormatUri(since); + } + /// /// Returns the that returns the organization for the specified organization name /// @@ -504,6 +544,18 @@ public static Uri CheckAssignee(string owner, string name, string login) return "repos/{0}/{1}/assignees/{2}".FormatUri(owner, name, login); } + /// + /// Returns the to add and remove assignees for an issue. + /// + /// The owner of the repository + /// The name of the repository + /// The issue number + /// + public static Uri IssueAssignees(string owner, string name, int number) + { + return "repos/{0}/{1}/issues/{2}/assignees".FormatUri(owner, name, number); + } + /// /// Returns the that returns all of the members of the organization /// @@ -2792,8 +2844,6 @@ public static Uri RepoCollaborators(long repositoryId) /// The for comparing two commits. public static Uri RepoCompare(long repositoryId, string @base, string head) { - - Ensure.ArgumentNotNullOrEmptyString(@base, "base"); Ensure.ArgumentNotNullOrEmptyString(head, "head"); var encodedBase = @base.UriEncode(); diff --git a/Octokit/Http/ApiConnection.cs b/Octokit/Http/ApiConnection.cs index 9dee70dab4..5f41d046fb 100644 --- a/Octokit/Http/ApiConnection.cs +++ b/Octokit/Http/ApiConnection.cs @@ -493,6 +493,22 @@ public Task Delete(Uri uri, object data, string accepts) return Connection.Delete(uri, data, accepts); } + /// + /// Performs an asynchronous HTTP DELETE request. + /// + /// The API resource's type. + /// URI endpoint to send request to + /// The object to serialize as the body of the request + public async Task Delete(Uri uri, object data) + { + Ensure.ArgumentNotNull(uri, "uri"); + Ensure.ArgumentNotNull(data, "data"); + + var response = await Connection.Delete(uri, data).ConfigureAwait(false); + + return response.Body; + } + /// /// Performs an asynchronous HTTP DELETE request. /// Attempts to map the response body to an object of type diff --git a/Octokit/Http/Connection.cs b/Octokit/Http/Connection.cs index 1e2c3aa7f2..a522dcab54 100644 --- a/Octokit/Http/Connection.cs +++ b/Octokit/Http/Connection.cs @@ -490,6 +490,20 @@ public async Task Delete(Uri uri, object data, string accepts) return response.HttpResponse.StatusCode; } + /// + /// Performs an asynchronous HTTP DELETE request. + /// + /// The API resource's type. + /// URI endpoint to send request to + /// The object to serialize as the body of the request + public Task> Delete(Uri uri, object data) + { + Ensure.ArgumentNotNull(uri, "uri"); + Ensure.ArgumentNotNull(data, "data"); + + return SendData(uri, HttpMethod.Delete, data, null, null, CancellationToken.None); + } + /// /// Performs an asynchronous HTTP DELETE request. /// Attempts to map the response body to an object of type @@ -611,11 +625,23 @@ static Exception GetExceptionForUnauthorized(IResponse response) static Exception GetExceptionForForbidden(IResponse response) { string body = response.Body as string ?? ""; - return body.Contains("rate limit exceeded") - ? new RateLimitExceededException(response) - : body.Contains("number of login attempts exceeded") - ? new LoginAttemptsExceededException(response) - : new ForbiddenException(response); + + if (body.Contains("rate limit exceeded")) + { + return new RateLimitExceededException(response); + } + + if (body.Contains("number of login attempts exceeded")) + { + return new LoginAttemptsExceededException(response); + } + + if (body.Contains("abuse-rate-limits") || body.Contains("abuse detection mechanism")) + { + return new AbuseException(response); + } + + return new ForbiddenException(response); } internal static TwoFactorType ParseTwoFactorType(IResponse restResponse) diff --git a/Octokit/Http/IApiConnection.cs b/Octokit/Http/IApiConnection.cs index ec7da6ff6f..1b28ae96d3 100644 --- a/Octokit/Http/IApiConnection.cs +++ b/Octokit/Http/IApiConnection.cs @@ -320,6 +320,14 @@ public interface IApiConnection /// The returned Task Delete(Uri uri, object data, string accepts); + /// + /// Performs an asynchronous HTTP DELETE request. + /// + /// The API resource's type. + /// URI endpoint to send request to + /// The object to serialize as the body of the request + Task Delete(Uri uri, object data); + /// /// Performs an asynchronous HTTP DELETE request. /// Attempts to map the response body to an object of type @@ -330,7 +338,7 @@ public interface IApiConnection /// Specifies accept response media type /// The returned Task Delete(Uri uri, object data, string accepts); - + /// /// Executes a GET to the API object at the specified URI. This operation is appropriate for API calls which /// queue long running calculations and return a collection of a resource. diff --git a/Octokit/Http/IConnection.cs b/Octokit/Http/IConnection.cs index 5ac737e9df..5ae1c1e10d 100644 --- a/Octokit/Http/IConnection.cs +++ b/Octokit/Http/IConnection.cs @@ -237,6 +237,14 @@ public interface IConnection : IApiInfoProvider /// The returned Task Delete(Uri uri, object data, string accepts); + /// + /// Performs an asynchronous HTTP DELETE request. + /// + /// The API resource's type. + /// URI endpoint to send request to + /// The object to serialize as the body of the request + Task> Delete(Uri uri, object data); + /// /// Performs an asynchronous HTTP DELETE request. /// Attempts to map the response body to an object of type diff --git a/Octokit/Http/RateLimit.cs b/Octokit/Http/RateLimit.cs index 6da91f79bb..6667ff099a 100644 --- a/Octokit/Http/RateLimit.cs +++ b/Octokit/Http/RateLimit.cs @@ -4,6 +4,7 @@ using System.Diagnostics.CodeAnalysis; using System.Globalization; using System.Runtime.Serialization; +using System.Security; using Octokit.Helpers; using Octokit.Internal; @@ -82,6 +83,7 @@ protected RateLimit(SerializationInfo info, StreamingContext context) ResetAsUtcEpochSeconds = info.GetInt64("ResetAsUtcEpochSeconds"); } + [SecurityCritical] public virtual void GetObjectData(SerializationInfo info, StreamingContext context) { Ensure.ArgumentNotNull(info, "info"); diff --git a/Octokit/Http/SimpleJsonSerializer.cs b/Octokit/Http/SimpleJsonSerializer.cs index 0e172d8bdf..004b54dc0b 100644 --- a/Octokit/Http/SimpleJsonSerializer.cs +++ b/Octokit/Http/SimpleJsonSerializer.cs @@ -109,7 +109,6 @@ public override object DeserializeObject(object value, Type type) { if (attribute.Value.Equals(value)) _cachedEnums[type].Add(attribute.Value, field.GetValue(null)); - } } } diff --git a/Octokit/Models/Request/AssigneesUpdate.cs b/Octokit/Models/Request/AssigneesUpdate.cs new file mode 100644 index 0000000000..a5ebd4c47c --- /dev/null +++ b/Octokit/Models/Request/AssigneesUpdate.cs @@ -0,0 +1,31 @@ +using System.Collections.Generic; +using System.Diagnostics; +using System.Globalization; + +namespace Octokit +{ + /// + /// Used to add assignees to an issue. + /// + /// + /// API: https://developer.github.com/v3/git/commits/#create-a-commit + /// + [DebuggerDisplay("{DebuggerDisplay,nq}")] + public class AssigneesUpdate + { + public AssigneesUpdate(IReadOnlyList assignees) + { + Assignees = assignees; + } + + public IReadOnlyList Assignees { get; private set; } + + internal string DebuggerDisplay + { + get + { + return string.Format(CultureInfo.InvariantCulture, "Assignees: {0}", Assignees); + } + } + } +} diff --git a/Octokit/Models/Request/CreateFileRequest.cs b/Octokit/Models/Request/CreateFileRequest.cs index b54dfee3d2..06d6f5e133 100644 --- a/Octokit/Models/Request/CreateFileRequest.cs +++ b/Octokit/Models/Request/CreateFileRequest.cs @@ -107,10 +107,32 @@ public class CreateFileRequest : ContentRequest /// /// The message. /// The content. - public CreateFileRequest(string message, string content) : base(message) + public CreateFileRequest(string message, string content) : this(message, content, true) + { } + + /// + /// Initializes a new instance of the class. + /// + /// The message. + /// The content. + /// The branch the request is for. + public CreateFileRequest(string message, string content, string branch) : this(message, content, branch, true) + { } + + /// + /// Creates an instance of a . + /// + /// The message. + /// The content. + /// True to convert content to base64. + public CreateFileRequest(string message, string content, bool convertContentToBase64) : base(message) { Ensure.ArgumentNotNull(content, "content"); + if (convertContentToBase64) + { + content = content.ToBase64String(); + } Content = content; } @@ -120,16 +142,21 @@ public CreateFileRequest(string message, string content) : base(message) /// The message. /// The content. /// The branch the request is for. - public CreateFileRequest(string message, string content, string branch) : base(message, branch) + /// True to convert content to base64. + public CreateFileRequest(string message, string content, string branch, bool convertContentToBase64) : base(message, branch) { Ensure.ArgumentNotNullOrEmptyString(content, "content"); + if (convertContentToBase64) + { + content = content.ToBase64String(); + } Content = content; } + /// - /// The contents of the file to create. This is required. + /// The contents of the file to create, Base64 encoded. This is required. /// - [SerializeAsBase64] public string Content { get; private set; } internal virtual string DebuggerDisplay @@ -154,7 +181,29 @@ public class UpdateFileRequest : CreateFileRequest /// The content. /// The sha. public UpdateFileRequest(string message, string content, string sha) - : base(message, content) + : this(message, content, sha, true) + { } + + /// + /// Creates an instance of a . + /// + /// The message. + /// The content. + /// The sha. + /// The branch the request is for. + public UpdateFileRequest(string message, string content, string sha, string branch) + : this(message, content, sha, branch, true) + { } + + /// + /// Creates an instance of a . + /// + /// The message. + /// The content. + /// The sha. + /// True to convert content to base64. + public UpdateFileRequest(string message, string content, string sha, bool convertContentToBase64) + : base(message, content, convertContentToBase64) { Ensure.ArgumentNotNullOrEmptyString(sha, "sha"); @@ -168,8 +217,9 @@ public UpdateFileRequest(string message, string content, string sha) /// The content. /// The sha. /// The branch the request is for. - public UpdateFileRequest(string message, string content, string sha, string branch) - : base(message, content, branch) + /// True to convert content to base64. + public UpdateFileRequest(string message, string content, string sha, string branch, bool convertContentToBase64) + : base(message, content, branch, convertContentToBase64) { Ensure.ArgumentNotNullOrEmptyString(sha, "sha"); diff --git a/Octokit/Models/Request/IssueCommentRequest.cs b/Octokit/Models/Request/IssueCommentRequest.cs new file mode 100644 index 0000000000..21f0b12fa1 --- /dev/null +++ b/Octokit/Models/Request/IssueCommentRequest.cs @@ -0,0 +1,44 @@ +using System; +using System.Diagnostics; +using System.Globalization; + +namespace Octokit +{ + /// + /// Used to filter issue comments. + /// + [DebuggerDisplay("{DebuggerDisplay,nq}")] + public class IssueCommentRequest : RequestParameters + { + /// + /// Initializes a new instance of the class. + /// + public IssueCommentRequest() + { + // Default arguments + Sort = PullRequestReviewCommentSort.Created; + Direction = SortDirection.Ascending; + Since = null; + } + + /// + /// Can be either created or updated. Default: created. + /// + public PullRequestReviewCommentSort Sort { get; set; } + + /// + /// Can be either asc or desc. Default: asc. + /// + public SortDirection Direction { get; set; } + + /// + /// Only comments updated at or after this time are returned. This is a timestamp in ISO 8601 format: YYYY-MM-DDTHH:MM:SSZ. + /// + public DateTimeOffset? Since { get; set; } + + internal string DebuggerDisplay + { + get { return string.Format(CultureInfo.InvariantCulture, "Sort: {0}, Direction: {1}, Since: {2}", Sort, Direction, Since); } + } + } +} diff --git a/Octokit/Models/Request/IssueUpdate.cs b/Octokit/Models/Request/IssueUpdate.cs index be8d50be7a..e3857ae242 100644 --- a/Octokit/Models/Request/IssueUpdate.cs +++ b/Octokit/Models/Request/IssueUpdate.cs @@ -1,4 +1,5 @@ -using System.Collections.Generic; +using System; +using System.Collections.Generic; using System.Diagnostics; using System.Globalization; using Octokit.Internal; @@ -27,9 +28,17 @@ public class IssueUpdate /// /// Only users with push access can set the assignee for new issues. The assignee is silently dropped otherwise. /// - [SerializeNull] + [Obsolete("Please use Assignees property. This property will no longer be supported by the GitHub API and will be removed in a future version")] public string Assignee { get; set; } + /// + /// List of logins for the multiple users that this issue should be assigned to + /// + /// + /// Only users with push access can set the multiple assignees for new issues. The assignees are silently dropped otherwise. + /// + public ICollection Assignees { get; private set; } + /// /// Milestone to associate this issue with. /// @@ -61,6 +70,54 @@ internal string DebuggerDisplay } } + /// + /// Adds the specified assigness to the issue. + /// + /// The login of the assignee. + public void AddAssignee(string name) + { + // lazily create the assignees array + if (Assignees == null) + { + Assignees = new List(); + } + + Assignees.Add(name); + } + + /// + /// Clears all the assignees. + /// + public void ClearAssignees() + { + // lazily create the assignees array + if (Assignees == null) + { + Assignees = new List(); + } + else + { + Assignees.Clear(); + } + } + + /// + /// Removes the specified assignee from the issue + /// + /// The login of the assignee to remove + public void RemoveAssignee(string name) + { + // lazily create the assignees array + if (Assignees == null) + { + Assignees = new List(); + } + else + { + Assignees.Remove(name); + } + } + /// /// Adds the specified label to the issue. /// @@ -91,5 +148,22 @@ public void ClearLabels() Labels.Clear(); } } + + /// + /// Removes the specified label from the issue + /// + /// The name of the label to remove + public void RemoveLabel(string name) + { + // lazily create the label array + if (Labels == null) + { + Labels = new List(); + } + else + { + Labels.Remove(name); + } + } } } \ No newline at end of file diff --git a/Octokit/Models/Request/NewIssue.cs b/Octokit/Models/Request/NewIssue.cs index b34332cd60..527ea313b3 100644 --- a/Octokit/Models/Request/NewIssue.cs +++ b/Octokit/Models/Request/NewIssue.cs @@ -1,4 +1,5 @@ -using System.Collections.ObjectModel; +using System; +using System.Collections.ObjectModel; using System.Diagnostics; using System.Globalization; @@ -17,6 +18,7 @@ public class NewIssue public NewIssue(string title) { Title = title; + Assignees = new Collection(); Labels = new Collection(); } @@ -36,8 +38,17 @@ public NewIssue(string title) /// /// Only users with push access can set the assignee for new issues. The assignee is silently dropped otherwise. /// + [Obsolete("Please use Assignees property. This property will no longer be supported by the GitHub API and will be removed in a future version")] public string Assignee { get; set; } + /// + /// List of logins for the multiple users that this issue should be assigned to + /// + /// + /// Only users with push access can set the multiple assignees for new issues. The assignees are silently dropped otherwise. + /// + public Collection Assignees { get; private set; } + /// /// Milestone to associate this issue with. /// diff --git a/Octokit/Models/Request/OrganizationRequest.cs b/Octokit/Models/Request/OrganizationRequest.cs new file mode 100644 index 0000000000..3743fe1128 --- /dev/null +++ b/Octokit/Models/Request/OrganizationRequest.cs @@ -0,0 +1,36 @@ +using System.Diagnostics; +using System.Globalization; + +namespace Octokit +{ + /// + /// Used as part of the request to retrieve all organizations. + /// + [DebuggerDisplay("{DebuggerDisplay,nq}")] + public class OrganizationRequest : RequestParameters + { + /// + /// Intializes a new instance of the class. + /// + /// The integer Id of the last Organization that you've seen. + public OrganizationRequest(int since) + { + Ensure.ArgumentNotNull(since, "since"); + + Since = since; + } + + /// + /// Gets or sets the integer Id of the last Organization that you've seen. + /// + public long Since { get; set; } + + internal string DebuggerDisplay + { + get + { + return string.Format(CultureInfo.InvariantCulture, "Since: {0} ", Since); + } + } + } +} \ No newline at end of file diff --git a/Octokit/Models/Request/RepositoryUpdate.cs b/Octokit/Models/Request/RepositoryUpdate.cs index dbce3686a9..b6c856b889 100644 --- a/Octokit/Models/Request/RepositoryUpdate.cs +++ b/Octokit/Models/Request/RepositoryUpdate.cs @@ -15,7 +15,6 @@ public class RepositoryUpdate [Obsolete("Please use the ctor RepositoryUpdate(string name) as Name is a required field")] public RepositoryUpdate() { - } /// @@ -33,42 +32,42 @@ public RepositoryUpdate(string name) /// Required. Gets or sets the repository name. /// public string Name { get; set; } - + /// /// Optional. Gets or sets the repository description. The default is null (do not update) /// public string Description { get; set; } - + /// /// Optional. Gets or sets the repository homepage url. The default is null (do not update). /// public string Homepage { get; set; } - + /// /// Gets or sets whether to make the repository private. The default is null (do not update). /// public bool? Private { get; set; } - + /// /// Gets or sets whether to enable issues for the repository. The default is null (do not update). /// public bool? HasIssues { get; set; } - + /// /// Optional. Gets or sets whether to enable the wiki for the repository. The default is null (do not update). /// public bool? HasWiki { get; set; } - + /// /// Optional. Gets or sets whether to enable downloads for the repository. The default is null (do not update). /// public bool? HasDownloads { get; set; } - + /// /// Optional. Gets or sets the default branch. The default is null (do not update). /// public string DefaultBranch { get; set; } - + /// /// Optional. Allows the "Rebase and Merge" method to be used. /// diff --git a/Octokit/Models/Request/UserUpdate.cs b/Octokit/Models/Request/UserUpdate.cs index 15b428694d..69820a4c54 100644 --- a/Octokit/Models/Request/UserUpdate.cs +++ b/Octokit/Models/Request/UserUpdate.cs @@ -5,7 +5,7 @@ namespace Octokit { /// /// Represents updatable fields on a user. Values that are null will not be sent in the request. - /// Use string.empty if you want to clear clear a value. + /// Use string.empty if you want to clear a value. /// [DebuggerDisplay("{DebuggerDisplay,nq}")] public class UserUpdate diff --git a/Octokit/Models/Response/AccountType.cs b/Octokit/Models/Response/AccountType.cs index b4797ba9c0..dddc366dde 100644 --- a/Octokit/Models/Response/AccountType.cs +++ b/Octokit/Models/Response/AccountType.cs @@ -10,6 +10,11 @@ public enum AccountType /// /// Organization account /// - Organization + Organization, + + /// + /// Bot account + /// + Bot } } diff --git a/Octokit/Models/Response/BranchProtection.cs b/Octokit/Models/Response/BranchProtection.cs index e890899616..b217788b21 100644 --- a/Octokit/Models/Response/BranchProtection.cs +++ b/Octokit/Models/Response/BranchProtection.cs @@ -127,7 +127,7 @@ internal string DebuggerDisplay { get { - return string.Format(CultureInfo.InvariantCulture, + return string.Format(CultureInfo.InvariantCulture, "StatusChecks: {0} Restrictions: {1}", RequiredStatusChecks == null ? "disabled" : RequiredStatusChecks.DebuggerDisplay, Restrictions == null ? "disabled" : Restrictions.DebuggerDisplay); @@ -171,8 +171,8 @@ internal string DebuggerDisplay { return string.Format(CultureInfo.InvariantCulture, "IncludeAdmins: {0} Strict: {1} Contexts: {2}", - IncludeAdmins, - Strict, + IncludeAdmins, + Strict, Contexts == null ? "" : Contexts.Join(",")); } } @@ -206,7 +206,7 @@ internal string DebuggerDisplay { get { - return string.Format(CultureInfo.InvariantCulture, + return string.Format(CultureInfo.InvariantCulture, "Teams: {0} Users: {1}", Teams == null ? "" : Teams.Join(","), Users == null ? "" : Users.Join(",")); diff --git a/Octokit/Models/Response/CommitContent.cs b/Octokit/Models/Response/CommitContent.cs index 752301d897..9aa66e615c 100644 --- a/Octokit/Models/Response/CommitContent.cs +++ b/Octokit/Models/Response/CommitContent.cs @@ -37,7 +37,7 @@ public RepositoryContentInfo(string name, string path, string sha, int size, Con public string Path { get; protected set; } /// - /// SHA of the last commit that modified this content. + /// SHA of this content. /// public string Sha { get; protected set; } diff --git a/Octokit/Models/Response/EventInfo.cs b/Octokit/Models/Response/EventInfo.cs index cd4529570e..34239a7c88 100644 --- a/Octokit/Models/Response/EventInfo.cs +++ b/Octokit/Models/Response/EventInfo.cs @@ -178,6 +178,26 @@ public enum EventInfoState /// Committed, + /// + /// The actor requested review from the subject on this pull request. + /// + ReviewRequested, + + /// + /// The actor dismissed a review from the pull request. + /// + ReviewDismissed, + + /// + /// The actor removed the review request for the subject on this pull request. + /// + ReviewRequestRemoved, + + /// + /// Base branch of the pull request was changed. + /// + BaseRefChanged, + /// /// The issue was referenced from another issue. /// The source attribute contains the id, actor, and @@ -186,4 +206,4 @@ public enum EventInfoState [SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "Crossreferenced")] Crossreferenced } -} \ No newline at end of file +} diff --git a/Octokit/Models/Response/Issue.cs b/Octokit/Models/Response/Issue.cs index e86fbe5c11..7bcb8df22d 100644 --- a/Octokit/Models/Response/Issue.cs +++ b/Octokit/Models/Response/Issue.cs @@ -2,6 +2,7 @@ using System.Collections.Generic; using System.Diagnostics; using System.Globalization; +using System.Linq; namespace Octokit { @@ -10,7 +11,7 @@ public class Issue { public Issue() { } - public Issue(Uri url, Uri htmlUrl, Uri commentsUrl, Uri eventsUrl, int number, ItemState state, string title, string body, User closedBy, User user, IReadOnlyList public User Assignee { get; protected set; } + /// + ///The multiple users this issue is assigned to. + /// + public IReadOnlyList Assignees { get; protected set; } + /// /// The milestone, if any, that this issue is assigned to. /// @@ -153,19 +160,38 @@ public IssueUpdate ToUpdate() ? new int?() : Milestone.Number; - var assignee = Assignee == null + var assignees = Assignees == null ? null - : Assignee.Login; + : Assignees.Select(x => x.Login); + + var labels = Labels == null + ? null + : Labels.Select(x => x.Name); var issueUpdate = new IssueUpdate { - Assignee = assignee, Body = Body, Milestone = milestoneId, State = State, Title = Title }; + if (assignees != null) + { + foreach (var assignee in assignees) + { + issueUpdate.AddAssignee(assignee); + } + } + + if (labels != null) + { + foreach (var label in labels) + { + issueUpdate.AddLabel(label); + } + } + return issueUpdate; } } diff --git a/Octokit/Models/Response/IssueComment.cs b/Octokit/Models/Response/IssueComment.cs index 3cceb72671..6928ca38c0 100644 --- a/Octokit/Models/Response/IssueComment.cs +++ b/Octokit/Models/Response/IssueComment.cs @@ -62,4 +62,17 @@ internal string DebuggerDisplay get { return string.Format(CultureInfo.InvariantCulture, "Id: {0} CreatedAt: {1}", Id, CreatedAt); } } } + + public enum IssueCommentSort + { + /// + /// Sort by create date (default) + /// + Created, + + /// + /// Sort by the date of the last update + /// + Updated + } } diff --git a/Octokit/Models/Response/Milestone.cs b/Octokit/Models/Response/Milestone.cs index ec31306a46..09626e956a 100644 --- a/Octokit/Models/Response/Milestone.cs +++ b/Octokit/Models/Response/Milestone.cs @@ -14,9 +14,10 @@ public Milestone(int number) Number = number; } - public Milestone(Uri url, int number, ItemState state, string title, string description, User creator, int openIssues, int closedIssues, DateTimeOffset createdAt, DateTimeOffset? dueOn, DateTimeOffset? closedAt) + public Milestone(Uri url, Uri htmlUrl, int number, ItemState state, string title, string description, User creator, int openIssues, int closedIssues, DateTimeOffset createdAt, DateTimeOffset? dueOn, DateTimeOffset? closedAt) { Url = url; + HtmlUrl = htmlUrl; Number = number; State = state; Title = title; @@ -34,6 +35,11 @@ public Milestone(Uri url, int number, ItemState state, string title, string desc /// public Uri Url { get; protected set; } + /// + /// The Html page for this milestone. + /// + public Uri HtmlUrl { get; protected set; } + /// /// The milestone number. /// diff --git a/Octokit/Models/Response/PullRequest.cs b/Octokit/Models/Response/PullRequest.cs index 8ede7ac64a..5644a0b3eb 100644 --- a/Octokit/Models/Response/PullRequest.cs +++ b/Octokit/Models/Response/PullRequest.cs @@ -1,4 +1,5 @@ using System; +using System.Collections.Generic; using System.Diagnostics; using System.Globalization; @@ -14,8 +15,9 @@ public PullRequest(int number) Number = number; } - public PullRequest(Uri url, Uri htmlUrl, Uri diffUrl, Uri patchUrl, Uri issueUrl, Uri statusesUrl, int number, ItemState state, string title, string body, DateTimeOffset createdAt, DateTimeOffset updatedAt, DateTimeOffset? closedAt, DateTimeOffset? mergedAt, GitReference head, GitReference @base, User user, User assignee, bool? mergeable, User mergedBy, int comments, int commits, int additions, int deletions, int changedFiles, Milestone milestone, bool locked) + public PullRequest(long id, Uri url, Uri htmlUrl, Uri diffUrl, Uri patchUrl, Uri issueUrl, Uri statusesUrl, int number, ItemState state, string title, string body, DateTimeOffset createdAt, DateTimeOffset updatedAt, DateTimeOffset? closedAt, DateTimeOffset? mergedAt, GitReference head, GitReference @base, User user, User assignee, IReadOnlyList assignees, bool? mergeable, User mergedBy, int comments, int commits, int additions, int deletions, int changedFiles, Milestone milestone, bool locked) { + Id = id; Url = url; HtmlUrl = htmlUrl; DiffUrl = diffUrl; @@ -34,6 +36,7 @@ public PullRequest(Uri url, Uri htmlUrl, Uri diffUrl, Uri patchUrl, Uri issueUrl Base = @base; User = user; Assignee = assignee; + Assignees = assignees; Mergeable = mergeable; MergedBy = mergedBy; Comments = comments; @@ -45,6 +48,11 @@ public PullRequest(Uri url, Uri htmlUrl, Uri diffUrl, Uri patchUrl, Uri issueUrl Locked = locked; } + /// + /// The internal Id for this pull request (not the pull request number) + /// + public long Id { get; protected set; } + /// /// The URL for this pull request. /// @@ -135,6 +143,11 @@ public PullRequest(Uri url, Uri htmlUrl, Uri diffUrl, Uri patchUrl, Uri issueUrl /// public User Assignee { get; protected set; } + /// + ///The multiple users this pull request is assigned to. + /// + public IReadOnlyList Assignees { get; protected set; } + /// /// The milestone, if any, that this pull request is assigned to. /// diff --git a/Octokit/Models/Response/ReactionSummary.cs b/Octokit/Models/Response/ReactionSummary.cs index feb634a136..360f5946f2 100644 --- a/Octokit/Models/Response/ReactionSummary.cs +++ b/Octokit/Models/Response/ReactionSummary.cs @@ -24,14 +24,14 @@ internal string DebuggerDisplay get { return string.Format( - CultureInfo.InvariantCulture, - "TotalCount: {0} +1: {1} -1: {2} Laugh: {3} Confused: {4} Heart: {5} Hooray: {6}", - TotalCount, - Plus1, - Minus1, - Laugh, - Confused, - Heart, + CultureInfo.InvariantCulture, + "TotalCount: {0} +1: {1} -1: {2} Laugh: {3} Confused: {4} Heart: {5} Hooray: {6}", + TotalCount, + Plus1, + Minus1, + Laugh, + Confused, + Heart, Hooray); } } diff --git a/Octokit/Models/Response/Repository.cs b/Octokit/Models/Response/Repository.cs index e0651605e4..575d8404f7 100644 --- a/Octokit/Models/Response/Repository.cs +++ b/Octokit/Models/Response/Repository.cs @@ -14,7 +14,7 @@ public Repository(long id) Id = id; } - public Repository(string url, string htmlUrl, string cloneUrl, string gitUrl, string sshUrl, string svnUrl, string mirrorUrl, long id, User owner, string name, string fullName, string description, string homepage, string language, bool @private, bool fork, int forksCount, int stargazersCount, string defaultBranch, int openIssuesCount, DateTimeOffset? pushedAt, DateTimeOffset createdAt, DateTimeOffset updatedAt, RepositoryPermissions permissions, Repository parent, Repository source, bool hasIssues, bool hasWiki, bool hasDownloads, bool? allowRebaseMerge, bool? allowSquashMerge, bool? allowMergeCommit) + public Repository(string url, string htmlUrl, string cloneUrl, string gitUrl, string sshUrl, string svnUrl, string mirrorUrl, long id, User owner, string name, string fullName, string description, string homepage, string language, bool @private, bool fork, int forksCount, int stargazersCount, string defaultBranch, int openIssuesCount, DateTimeOffset? pushedAt, DateTimeOffset createdAt, DateTimeOffset updatedAt, RepositoryPermissions permissions, Repository parent, Repository source, bool hasIssues, bool hasWiki, bool hasDownloads, bool hasPages, int subscribersCount, long size, bool? allowRebaseMerge, bool? allowSquashMerge, bool? allowMergeCommit) { Url = url; HtmlUrl = htmlUrl; @@ -45,6 +45,9 @@ public Repository(string url, string htmlUrl, string cloneUrl, string gitUrl, st HasIssues = hasIssues; HasWiki = hasWiki; HasDownloads = hasDownloads; + HasPages = hasPages; + SubscribersCount = subscribersCount; + Size = size; AllowRebaseMerge = allowRebaseMerge; AllowSquashMerge = allowSquashMerge; AllowMergeCommit = allowMergeCommit; @@ -107,13 +110,19 @@ public Repository(string url, string htmlUrl, string cloneUrl, string gitUrl, st public bool HasWiki { get; protected set; } public bool HasDownloads { get; protected set; } - + public bool? AllowRebaseMerge { get; protected set; } public bool? AllowSquashMerge { get; protected set; } public bool? AllowMergeCommit { get; protected set; } + public bool HasPages { get; protected set; } + + public int SubscribersCount { get; protected set; } + + public long Size { get; protected set; } + internal string DebuggerDisplay { get diff --git a/Octokit/Models/Response/SourceInfo.cs b/Octokit/Models/Response/SourceInfo.cs index ff91bdfec5..7e52de169a 100644 --- a/Octokit/Models/Response/SourceInfo.cs +++ b/Octokit/Models/Response/SourceInfo.cs @@ -8,11 +8,12 @@ public class SourceInfo { public User Actor { get; protected set; } public int Id { get; protected set; } + public Issue Issue { get; protected set; } public string Url { get; protected set; } internal string DebuggerDisplay { - get { return string.Format(CultureInfo.InvariantCulture, "Id: {0} Url: {1}", Id, Url); } + get { return string.Format(CultureInfo.InvariantCulture, "Id: {0} Url: {1}", Id, Url ?? ""); } } } } diff --git a/Octokit/Octokit-35.csproj b/Octokit/Octokit-35.csproj index 65d523d2ee..0178e3dc32 100644 --- a/Octokit/Octokit-35.csproj +++ b/Octokit/Octokit-35.csproj @@ -120,8 +120,6 @@ - - @@ -146,6 +144,7 @@ + @@ -213,8 +212,6 @@ - - @@ -482,6 +479,7 @@ + @@ -523,11 +521,17 @@ - - + + + + + + + + diff --git a/Octokit/Octokit-Mono.csproj b/Octokit/Octokit-Mono.csproj index 571cf92368..20976b43a7 100644 --- a/Octokit/Octokit-Mono.csproj +++ b/Octokit/Octokit-Mono.csproj @@ -9,9 +9,8 @@ Library Octokit Octokit - v3.5 + v4.5 5 - true @@ -19,7 +18,7 @@ false obj\Debug\Mono bin\Debug\Mono - TRACE;DEBUG;CODE_ANALYSIS;SIMPLE_JSON_OBJARRAYINTERNAL;SIMPLE_JSON_INTERNAL;NET_35;SIMPLE_JSON_READONLY_COLLECTIONS + TRACE;DEBUG;CODE_ANALYSIS;SIMPLE_JSON_OBJARRAYINTERNAL;SIMPLE_JSON_INTERNAL;NET_45;SIMPLE_JSON_READONLY_COLLECTIONS prompt 4 false @@ -37,20 +36,8 @@ 1591 - - ..\..\..\src\packages\AsyncBridge.Net35.0.2.0\lib\net35-Client\AsyncBridge.Net35.dll - True - - - ..\..\..\src\packages\ReadOnlyCollectionInterfaces.1.0.0\lib\NET20\ReadOnlyCollectionsInterfaces.dll - True - - - ..\..\..\src\packages\TaskParallelLibrary.1.0.2856.0\lib\Net35\System.Threading.dll - True - - + @@ -116,8 +103,6 @@ - - @@ -142,6 +127,7 @@ + @@ -209,7 +195,6 @@ - @@ -477,6 +462,7 @@ + @@ -518,21 +504,8 @@ - - - - - - - - - {9862694d-e4fa-418b-8692-a0280feddf36} - System.Net.Http-net_3_5 - - - {3be1a792-e5a3-4374-9479-32b808443c03} - GitHub.Extensions35 - + + \ No newline at end of file diff --git a/Octokit/Octokit-MonoAndroid.csproj b/Octokit/Octokit-MonoAndroid.csproj index 843d485fca..34abb1ce36 100644 --- a/Octokit/Octokit-MonoAndroid.csproj +++ b/Octokit/Octokit-MonoAndroid.csproj @@ -97,6 +97,7 @@ + @@ -471,6 +472,7 @@ + @@ -513,6 +515,8 @@ + + \ No newline at end of file diff --git a/Octokit/Octokit-Monotouch.csproj b/Octokit/Octokit-Monotouch.csproj index 03f59ce587..ca2b90c87a 100644 --- a/Octokit/Octokit-Monotouch.csproj +++ b/Octokit/Octokit-Monotouch.csproj @@ -93,6 +93,7 @@ + @@ -467,6 +468,7 @@ + @@ -509,6 +511,8 @@ + + diff --git a/Octokit/Octokit-Portable.csproj b/Octokit/Octokit-Portable.csproj index 2bef9a4367..f7f5029588 100644 --- a/Octokit/Octokit-Portable.csproj +++ b/Octokit/Octokit-Portable.csproj @@ -208,6 +208,7 @@ + @@ -457,6 +458,7 @@ + @@ -499,6 +501,8 @@ + + diff --git a/Octokit/Octokit-netcore45.csproj b/Octokit/Octokit-netcore45.csproj index 5c1b1ed416..0afbd353b1 100644 --- a/Octokit/Octokit-netcore45.csproj +++ b/Octokit/Octokit-netcore45.csproj @@ -215,6 +215,7 @@ + @@ -465,6 +466,7 @@ + @@ -506,6 +508,8 @@ + + diff --git a/Octokit/Octokit.csproj b/Octokit/Octokit.csproj index 9deb1cd6db..be2f927689 100644 --- a/Octokit/Octokit.csproj +++ b/Octokit/Octokit.csproj @@ -116,6 +116,7 @@ + @@ -144,8 +145,10 @@ + + @@ -157,6 +160,7 @@ + diff --git a/README.md b/README.md index dae6927e48..f5844926b1 100644 --- a/README.md +++ b/README.md @@ -66,7 +66,8 @@ cd Octokit ## Contribute Visit the [Contributor Guidelines](https://github.com/octokit/octokit.net/blob/master/CONTRIBUTING.md) -for more details. +for more details. All contributors are expected to follow our +[Code of Conduct](https://github.com/octokit/octokit.net/blob/master/CODE_OF_CONDUCT.md). ## Problems? diff --git a/ReleaseNotes.md b/ReleaseNotes.md index 388d254f9c..26f3ad556b 100644 --- a/ReleaseNotes.md +++ b/ReleaseNotes.md @@ -1,3 +1,45 @@ +### New in 0.24.0 (released 17/1/2017) + +**Features/Enhancements** + + - Add `GetAll` method to `OrganizationsClient` - [#1469](https://github.com/octokit/octokit.net/pull/1469) via [malamour-work](https://github.com/malamour-work) + - Add missing fields to `Repository` class - `HasPages`, `SubscribersCount`, `Size` - [#1473](https://github.com/octokit/octokit.net/pull/1473) via [ryangribble](https://github.com/ryangribble) + - Allow base64 content for create/update file - [#1488](https://github.com/octokit/octokit.net/pull/1488) via [laedit](https://github.com/laedit) + - Add `HtmlUrl` field to `Milestone` class - [#1489](https://github.com/octokit/octokit.net/pull/1489) via [StanleyGoldman](https://github.com/StanleyGoldman) + - Add support for passing sort options to `IssueCommentsClient.GetAllForRepository()` - [#1501](https://github.com/octokit/octokit.net/pull/1501) via [pjc0247](https://github.com/pjc0247) + - Rename `PullRequest.Comment` to `PullRequest.ReviewComment` for better accuracy - [#1520](https://github.com/octokit/octokit.net/pull/1520) via [bmeverett](https://github.com/bmeverett) + - Introduce `AbuseException` - [#1528](https://github.com/octokit/octokit.net/pull/1528) via [SeanKilleen](https://github.com/SeanKilleen) + - Add `Id` field to `PullRequest` class - [#1537](https://github.com/octokit/octokit.net/pull/1537) via [YunLi1988](https://github.com/YunLi1988) + - Unparseable `ApiErrors` should now fall back to better default error messages - [#1540](https://github.com/octokit/octokit.net/pull/1540) via [SeanKilleen](https://github.com/SeanKilleen) + +**Fixes** + + - Fix errors in `ObservableEventsClient` caused by incorrect return types - [#1490](https://github.com/octokit/octokit.net/pull/1490) via [StanleyGoldman](https://github.com/StanleyGoldman) + - Add missing `SecurityCritical` attribute on `GetObjectData()` overrides - [#1493](https://github.com/octokit/octokit.net/pull/1493) via [M-Zuber](https://github.com/M-Zuber) + - Fix exceptions in Events API by adding missing event types to `EventInfo` enumeration - [#1536](https://github.com/octokit/octokit.net/pull/1536) via [lynnfaraday](https://github.com/lynnfaraday) + - Add new AccountType "Bot" to prevent deserialization errors - [#1541](https://github.com/octokit/octokit.net/pull/1541) via [ryangribble](https://github.com/ryangribble) + +**Documentation Updates** + + - Clarify `ApiInfo` rate limiting usage in docs - [#1524](https://github.com/octokit/octokit.net/pull/1524) via [SeanKilleen](https://github.com/SeanKilleen) + - Clarify label coloring usage in docs - [#1530](https://github.com/octokit/octokit.net/pull/1530) via [SeanKilleen](https://github.com/SeanKilleen) + +**Breaking Changes** + + - Creating and Editing Issues (and PullRequests) using `NewIssue` and `IssueUpdate` requests +should now use the `Assignees` collection rather than the now deprecated 'Assignee` field. +Both fields can't be specified on the same request, so any code still using `Assignee` will +need to explicitly set `Assignees` to `null` to avoid Api validation errors. + + - `OrganizationsClient.GetAll(string user)` has been marked obsolete in favour of +`OrganizationsClient.GetAllForUser(string user)` + + - `PullRequest.Comment` has been marked obsolete in favour of `PullRequest.ReviewComment` + +- Several `EventsClient` methods previously returned the incorrect `Activity` response class. +This has been corrected to `IssueEvent` which although is now correct could break calling +code that was written assuming this previous incorrect return type. + ### New in 0.23.0 (released 07/10/2016) **Features** diff --git a/SolutionInfo.cs b/SolutionInfo.cs index 9ab6bb9a39..5e5694f75e 100644 --- a/SolutionInfo.cs +++ b/SolutionInfo.cs @@ -3,12 +3,17 @@ using System.Runtime.InteropServices; [assembly: AssemblyProductAttribute("Octokit")] -[assembly: AssemblyVersionAttribute("0.23.0.1")] -[assembly: AssemblyFileVersionAttribute("0.23.0.1")] +[assembly: AssemblyVersionAttribute(Consts.LibraryVersion)] +[assembly: AssemblyFileVersionAttribute(Consts.LibraryVersion)] [assembly: ComVisibleAttribute(false)] -namespace System { - internal static class AssemblyVersionInformation { - internal const string Version = "0.23.0.1-ghu"; - internal const string InformationalVersion = "0.23.0.1-ghu"; + +static class Consts { internal const string LibraryVersion = "0.24.0.1"; } + +namespace System +{ + internal static class AssemblyVersionInformation + { + internal const string Version = Consts.LibraryVersion; + internal const string InformationalVersion = Consts.LibraryVersion + "-gfu"; } } diff --git a/docs/getting-started.md b/docs/getting-started.md index e8fd5a16a9..ce58fe6ed3 100644 --- a/docs/getting-started.md +++ b/docs/getting-started.md @@ -69,3 +69,27 @@ If you've authenticated as a given user, you can query their details directly: ``` var user = await client.User.Current(); ``` + +### Too Much of a Good Thing: Dealing with API Rate Limits +Like any popular API, Github needs to throttle some requests. The OctoKit.NET client allows you to get some insight into how many requests you have left and when you can start making requests again. It does this via the `ApiInfo` object and the `GetLastApiInfo()` method. + +Example usage: + +```csharp +GithubClient client; +//Create & initialize the client here + +// Prior to first API call, this will be null, because it only deals with the last call. +var apiInfo = client.GetLastApiInfo(); + +// If the ApiInfo isn't null, there will be a property called RateLimit +var rateLimit = apiInfo?.RateLimit; + +var howManyRequestsCanIMakePerHour = rateLimit?.Limit; +var howManyRequestsDoIHaveLeft = rateLimit?.Remaining; +var whenDoesTheLimitReset = rateLimit?.Reset; +``` + +An authenticated client will have a significantly higher limit than an anonymous client. + +For more information on the API and understanding rate limits, you may want to consult [the Github API docs on rate limits](https://developer.github.com/v3/#rate-limiting). \ No newline at end of file diff --git a/docs/labels.md b/docs/labels.md index 63cc8cb185..494a7aa51b 100644 --- a/docs/labels.md +++ b/docs/labels.md @@ -14,3 +14,8 @@ The default labels that come with every repository are: - invalid - question - wontfix + +## A Note on Label Colors +The official API returns colors without the leading `#` that you may expect when working with hex colors -- for example, white would return `FFFFFF`, not `#FFFFFF`. + +If you're displaying the colors, you may need to add the `#` in order to display them properly. \ No newline at end of file