From 6105a9deaf5bb10b7053b336b37f9c3b713375f0 Mon Sep 17 00:00:00 2001 From: Ivan Josipovic <9521987+IvanJosipovic@users.noreply.github.com> Date: Sun, 21 Feb 2021 14:38:00 -0800 Subject: [PATCH] preview support for repository visibility (#2217) --- .../Clients/RepositoriesClientTests.cs | 43 +++++++++++++------ .../Models/RepositoryRequestTests.cs | 2 +- Octokit/Clients/RepositoriesClient.cs | 24 ++++++++--- Octokit/Helpers/AcceptHeaders.cs | 2 + Octokit/Models/Request/NewRepository.cs | 34 ++++++++++++++- Octokit/Models/Request/RepositoryRequest.cs | 16 ++++--- Octokit/Models/Request/RepositoryUpdate.cs | 5 +++ Octokit/Models/Response/Repository.cs | 5 ++- 8 files changed, 101 insertions(+), 30 deletions(-) diff --git a/Octokit.Tests/Clients/RepositoriesClientTests.cs b/Octokit.Tests/Clients/RepositoriesClientTests.cs index 56de5a76..1bc89b7b 100644 --- a/Octokit.Tests/Clients/RepositoriesClientTests.cs +++ b/Octokit.Tests/Clients/RepositoriesClientTests.cs @@ -40,7 +40,9 @@ namespace Octokit.Tests.Clients client.Create(new NewRepository("aName")); - connection.Received().Post(Arg.Is(u => u.ToString() == "user/repos"), Arg.Any()); + connection.Received().Post(Arg.Is(u => u.ToString() == "user/repos"), + Arg.Any(), + "application/vnd.github.nebula-preview+json"); } [Fact] @@ -52,7 +54,7 @@ namespace Octokit.Tests.Clients client.Create(newRepository); - connection.Received().Post(Args.Uri, newRepository); + connection.Received().Post(Args.Uri, newRepository, "application/vnd.github.nebula-preview+json"); } [Fact] @@ -68,7 +70,7 @@ namespace Octokit.Tests.Clients var connection = Substitute.For(); connection.Connection.BaseAddress.Returns(GitHubClient.GitHubApiUrl); connection.Connection.Credentials.Returns(credentials); - connection.Post(Args.Uri, newRepository) + connection.Post(Args.Uri, newRepository, "application/vnd.github.nebula-preview+json") .Returns>(_ => { throw new ApiValidationException(response); }); var client = new RepositoriesClient(connection); @@ -95,7 +97,7 @@ namespace Octokit.Tests.Clients var connection = Substitute.For(); connection.Connection.BaseAddress.Returns(GitHubClient.GitHubApiUrl); connection.Connection.Credentials.Returns(credentials); - connection.Post(Args.Uri, newRepository) + connection.Post(Args.Uri, newRepository, "application/vnd.github.nebula-preview+json") .Returns>(_ => { throw new ApiValidationException(response); }); var client = new RepositoriesClient(connection); @@ -127,7 +129,8 @@ namespace Octokit.Tests.Clients connection.Received().Post( Arg.Is(u => u.ToString() == "orgs/theLogin/repos"), - Args.NewRepository); + Args.NewRepository, + "application/vnd.github.nebula-preview+json"); } [Fact] @@ -139,7 +142,7 @@ namespace Octokit.Tests.Clients await client.Create("aLogin", newRepository); - connection.Received().Post(Args.Uri, newRepository); + connection.Received().Post(Args.Uri, newRepository, "application/vnd.github.nebula-preview+json"); } [Fact] @@ -153,7 +156,7 @@ namespace Octokit.Tests.Clients + @"""code"":""custom"",""field"":""name"",""message"":""name already exists on this account""}]}"); var connection = Substitute.For(); connection.Connection.BaseAddress.Returns(GitHubClient.GitHubApiUrl); - connection.Post(Args.Uri, newRepository) + connection.Post(Args.Uri, newRepository, "application/vnd.github.nebula-preview+json") .Returns>(_ => { throw new ApiValidationException(response); }); var client = new RepositoriesClient(connection); @@ -178,7 +181,7 @@ namespace Octokit.Tests.Clients + @"""http://developer.github.com/v3/repos/#create"",""errors"":[]}"); var connection = Substitute.For(); connection.Connection.BaseAddress.Returns(GitHubClient.GitHubApiUrl); - connection.Post(Args.Uri, newRepository) + connection.Post(Args.Uri, newRepository, "application/vnd.github.nebula-preview+json") .Returns>(_ => { throw new ApiValidationException(response); }); var client = new RepositoriesClient(connection); @@ -199,7 +202,7 @@ namespace Octokit.Tests.Clients + @"""code"":""custom"",""field"":""name"",""message"":""name already exists on this account""}]}"); var connection = Substitute.For(); connection.Connection.BaseAddress.Returns(new Uri("https://example.com")); - connection.Post(Args.Uri, newRepository) + connection.Post(Args.Uri, newRepository, "application/vnd.github.nebula-preview+json") .Returns>(_ => { throw new ApiValidationException(response); }); var client = new RepositoriesClient(connection); @@ -402,7 +405,9 @@ namespace Octokit.Tests.Clients await client.Get("owner", "name"); connection.Received() - .Get(Arg.Is(u => u.ToString() == "repos/owner/name")); + .Get(Arg.Is(u => u.ToString() == "repos/owner/name"), + null, + "application/vnd.github.nebula-preview+json"); } [Fact] @@ -483,7 +488,10 @@ namespace Octokit.Tests.Clients await client.GetAllForCurrent(); connection.Received() - .GetAll(Arg.Is(u => u.ToString() == "user/repos"), Args.ApiOptions); + .GetAll(Arg.Is(u => u.ToString() == "user/repos"), + null, + "application/vnd.github.nebula-preview+json", + Args.ApiOptions); } [Fact] @@ -503,6 +511,7 @@ namespace Octokit.Tests.Clients .GetAll( Arg.Is(u => u.ToString() == "user/repos"), Arg.Is>(d => d["type"] == "all"), + "application/vnd.github.nebula-preview+json", Args.ApiOptions); } @@ -524,6 +533,7 @@ namespace Octokit.Tests.Clients .GetAll( Arg.Is(u => u.ToString() == "user/repos"), Arg.Is>(d => d["type"] == "private" && d["sort"] == "full_name"), + "application/vnd.github.nebula-preview+json", Args.ApiOptions); } @@ -546,6 +556,7 @@ namespace Octokit.Tests.Clients .GetAll( Arg.Is(u => u.ToString() == "user/repos"), Arg.Is>(d => d["type"] == "member" && d["sort"] == "updated" && d["direction"] == "asc"), + "application/vnd.github.nebula-preview+json", Args.ApiOptions); } @@ -557,7 +568,7 @@ namespace Octokit.Tests.Clients var request = new RepositoryRequest { - Visibility = RepositoryVisibility.Private + Visibility = RepositoryRequestVisibility.Private }; await client.GetAllForCurrent(request); @@ -566,6 +577,7 @@ namespace Octokit.Tests.Clients .GetAll( Arg.Is(u => u.ToString() == "user/repos"), Arg.Is>(d => d["visibility"] == "private"), + "application/vnd.github.nebula-preview+json", Args.ApiOptions); } @@ -587,6 +599,7 @@ namespace Octokit.Tests.Clients .GetAll( Arg.Is(u => u.ToString() == "user/repos"), Arg.Is>(d => d["affiliation"] == "owner" && d["sort"] == "full_name"), + "application/vnd.github.nebula-preview+json", Args.ApiOptions); } } @@ -631,7 +644,7 @@ namespace Octokit.Tests.Clients await client.GetAllForOrg("orgname"); connection.Received() - .GetAll(Arg.Is(u => u.ToString() == "orgs/orgname/repos"), Args.ApiOptions); + .GetAll(Arg.Is(u => u.ToString() == "orgs/orgname/repos"), null, "application/vnd.github.nebula-preview+json", Args.ApiOptions); } [Fact] @@ -1063,7 +1076,9 @@ namespace Octokit.Tests.Clients client.Edit("owner", "repo", update); connection.Received() - .Patch(Arg.Is(u => u.ToString() == "repos/owner/repo"), Arg.Any()); + .Patch(Arg.Is(u => u.ToString() == "repos/owner/repo"), + Arg.Any(), + "application/vnd.github.nebula-preview+json"); } [Fact] diff --git a/Octokit.Tests/Models/RepositoryRequestTests.cs b/Octokit.Tests/Models/RepositoryRequestTests.cs index e5d89562..74471d7e 100644 --- a/Octokit.Tests/Models/RepositoryRequestTests.cs +++ b/Octokit.Tests/Models/RepositoryRequestTests.cs @@ -26,7 +26,7 @@ namespace Octokit.Tests.Models request = new RepositoryRequest { Affiliation = RepositoryAffiliation.All, - Visibility = RepositoryVisibility.Public + Visibility = RepositoryRequestVisibility.Public }; parameters = request.ToParametersDictionary(); diff --git a/Octokit/Clients/RepositoriesClient.cs b/Octokit/Clients/RepositoriesClient.cs index d067ddcf..44a7ab70 100644 --- a/Octokit/Clients/RepositoriesClient.cs +++ b/Octokit/Clients/RepositoriesClient.cs @@ -50,6 +50,7 @@ namespace Octokit /// A instance describing the new repository to create /// Thrown when a general API error occurs. /// A instance for the created repository. + [Preview("nebula")] [ManualRoute("POST", "/user/repos")] public Task Create(NewRepository newRepository) { @@ -68,6 +69,7 @@ namespace Octokit /// A instance describing the new repository to create /// Thrown when a general API error occurs. /// A instance for the created repository + [Preview("nebula")] [ManualRoute("POST", "/orgs/{org}/repos")] public Task Create(string organizationLogin, NewRepository newRepository) { @@ -83,7 +85,7 @@ namespace Octokit { try { - return await ApiConnection.Post(url, newRepository).ConfigureAwait(false); + return await ApiConnection.Post(url, newRepository, AcceptHeaders.VisibilityPreview).ConfigureAwait(false); } catch (ApiValidationException e) { @@ -211,6 +213,7 @@ namespace Octokit /// The name of the repository /// New values to update the repository with /// The updated + [Preview("nebula")] [ManualRoute("PATCH", "/repos/{owner}/{repo}")] public Task Edit(string owner, string name, RepositoryUpdate update) { @@ -219,7 +222,7 @@ namespace Octokit Ensure.ArgumentNotNull(update, nameof(update)); Ensure.ArgumentNotNull(update.Name, nameof(update.Name)); - return ApiConnection.Patch(ApiUrls.Repository(owner, name), update); + return ApiConnection.Patch(ApiUrls.Repository(owner, name), update, AcceptHeaders.VisibilityPreview); } /// @@ -246,13 +249,14 @@ namespace Octokit /// The name of the repository /// Thrown when a general API error occurs. /// A + [Preview("nebula")] [ManualRoute("GET", "/repos/{owner}/{repo}")] public Task Get(string owner, string name) { Ensure.ArgumentNotNullOrEmptyString(owner, nameof(owner)); Ensure.ArgumentNotNullOrEmptyString(name, nameof(name)); - return ApiConnection.Get(ApiUrls.Repository(owner, name)); + return ApiConnection.Get(ApiUrls.Repository(owner, name), null, AcceptHeaders.VisibilityPreview); } /// @@ -279,7 +283,7 @@ namespace Octokit /// /// Thrown if the client is not authenticated. /// Thrown when a general API error occurs. - /// A of . + /// A of . [ManualRoute("GET", "/repositories")] public Task> GetAllPublic() { @@ -317,6 +321,7 @@ namespace Octokit /// Thrown if the client is not authenticated. /// Thrown when a general API error occurs. /// A of . + [Preview("nebula")] [ManualRoute("GET", "/user/repos")] public Task> GetAllForCurrent() { @@ -333,12 +338,13 @@ namespace Octokit /// Thrown if the client is not authenticated. /// Thrown when a general API error occurs. /// A of . + [Preview("nebula")] [ManualRoute("GET", "/user/repos")] public Task> GetAllForCurrent(ApiOptions options) { Ensure.ArgumentNotNull(options, nameof(options)); - return ApiConnection.GetAll(ApiUrls.Repositories(), options); + return ApiConnection.GetAll(ApiUrls.Repositories(), null, AcceptHeaders.VisibilityPreview, options); } /// @@ -352,6 +358,7 @@ namespace Octokit /// Thrown if the client is not authenticated. /// Thrown when a general API error occurs. /// A of . + [Preview("nebula")] [ManualRoute("GET", "/user/repos")] public Task> GetAllForCurrent(RepositoryRequest request) { @@ -372,13 +379,14 @@ namespace Octokit /// Thrown if the client is not authenticated. /// Thrown when a general API error occurs. /// A of . + [Preview("nebula")] [ManualRoute("GET", "/user/repos")] public Task> GetAllForCurrent(RepositoryRequest request, ApiOptions options) { Ensure.ArgumentNotNull(request, nameof(request)); Ensure.ArgumentNotNull(options, nameof(options)); - return ApiConnection.GetAll(ApiUrls.Repositories(), request.ToParametersDictionary(), options); + return ApiConnection.GetAll(ApiUrls.Repositories(), request.ToParametersDictionary(), AcceptHeaders.VisibilityPreview, options); } /// @@ -427,6 +435,7 @@ namespace Octokit /// /// Thrown when a general API error occurs. /// A of . + [Preview("nebula")] [ManualRoute("GET", "/orgs/{org}/repos")] public Task> GetAllForOrg(string organization) { @@ -445,13 +454,14 @@ namespace Octokit /// Options for changing the API response /// Thrown when a general API error occurs. /// A of . + [Preview("nebula")] [ManualRoute("GET", "/orgs/{org}/repos")] public Task> GetAllForOrg(string organization, ApiOptions options) { Ensure.ArgumentNotNullOrEmptyString(organization, nameof(organization)); Ensure.ArgumentNotNull(options, nameof(options)); - return ApiConnection.GetAll(ApiUrls.OrganizationRepositories(organization), options); + return ApiConnection.GetAll(ApiUrls.OrganizationRepositories(organization), null, AcceptHeaders.VisibilityPreview, options); } /// diff --git a/Octokit/Helpers/AcceptHeaders.cs b/Octokit/Helpers/AcceptHeaders.cs index 9d0848ce..eaca8811 100644 --- a/Octokit/Helpers/AcceptHeaders.cs +++ b/Octokit/Helpers/AcceptHeaders.cs @@ -50,6 +50,8 @@ namespace Octokit public const string OAuthApplicationsPreview = "application/vnd.github.doctor-strange-preview+json"; + public const string VisibilityPreview = "application/vnd.github.nebula-preview+json"; + /// /// Combines multiple preview headers. GitHub API supports Accept header with multiple /// values separated by comma. diff --git a/Octokit/Models/Request/NewRepository.cs b/Octokit/Models/Request/NewRepository.cs index 5c7da588..3942d53e 100644 --- a/Octokit/Models/Request/NewRepository.cs +++ b/Octokit/Models/Request/NewRepository.cs @@ -1,4 +1,5 @@ -using System.Diagnostics; +using Octokit.Internal; +using System.Diagnostics; using System.Diagnostics.CodeAnalysis; using System.Globalization; @@ -81,9 +82,14 @@ namespace Octokit /// Optional. Gets or sets the Id of the team to grant access to this repository. This is only valid when creating a repository for an organization. /// public int? TeamId { get; set; } - + public bool? DeleteBranchOnMerge { get; set; } + /// + /// Optional. Gets or sets whether the new repository is public, private, or internal. A value provided here overrides any value set in the existing private field. + /// + public RepositoryVisibility? Visibility { get; set; } + internal string DebuggerDisplay { get @@ -92,4 +98,28 @@ namespace Octokit } } } + + /// + /// The properties that repositories can be visible by. + /// + public enum RepositoryVisibility + { + /// + /// Sets repository visibility to public + /// + [Parameter(Value = "public")] + Public, + + /// + /// Sets repository visibility to private + /// + [Parameter(Value = "private")] + Private, + + /// + /// Sets repository visibility to internal + /// + [Parameter(Value = "internal")] + Internal, + } } diff --git a/Octokit/Models/Request/RepositoryRequest.cs b/Octokit/Models/Request/RepositoryRequest.cs index fd886815..cd583f48 100644 --- a/Octokit/Models/Request/RepositoryRequest.cs +++ b/Octokit/Models/Request/RepositoryRequest.cs @@ -43,7 +43,7 @@ namespace Octokit /// /// The visibility. /// - public RepositoryVisibility? Visibility { get; set; } + public RepositoryRequestVisibility? Visibility { get; set; } /// /// Gets or sets the affiliation property. @@ -143,17 +143,17 @@ namespace Octokit /// /// The properties that repositories can be visible by. /// - public enum RepositoryVisibility + public enum RepositoryRequestVisibility { /// /// Returns only public repositories - /// + /// [Parameter(Value = "public")] Public, /// /// Returns only private repositories - /// + /// [Parameter(Value = "private")] Private, @@ -161,7 +161,13 @@ namespace Octokit /// Return both public and private repositories /// [Parameter(Value = "all")] - All + All, + + /// + /// Returns only internal repositories + /// + [Parameter(Value = "internal")] + Internal, } /// diff --git a/Octokit/Models/Request/RepositoryUpdate.cs b/Octokit/Models/Request/RepositoryUpdate.cs index 86abfe52..88017879 100644 --- a/Octokit/Models/Request/RepositoryUpdate.cs +++ b/Octokit/Models/Request/RepositoryUpdate.cs @@ -85,6 +85,11 @@ namespace Octokit /// public bool? Archived { get; set; } + /// + /// Optional. Gets or sets whether the new repository is public, private, or internal. A value provided here overrides any value set in the existing private field. + /// + public RepositoryVisibility? Visibility { get; set; } + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] internal string DebuggerDisplay { diff --git a/Octokit/Models/Response/Repository.cs b/Octokit/Models/Response/Repository.cs index f288a6d8..23eab039 100644 --- a/Octokit/Models/Response/Repository.cs +++ b/Octokit/Models/Response/Repository.cs @@ -14,7 +14,7 @@ namespace Octokit Id = id; } - public Repository(string url, string htmlUrl, string cloneUrl, string gitUrl, string sshUrl, string svnUrl, string mirrorUrl, long id, string nodeId, User owner, string name, string fullName, bool isTemplate, 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, LicenseMetadata license, bool hasIssues, bool hasWiki, bool hasDownloads, bool hasPages, int subscribersCount, long size, bool? allowRebaseMerge, bool? allowSquashMerge, bool? allowMergeCommit, bool archived, int watchersCount, bool? deleteBranchOnMerge) + public Repository(string url, string htmlUrl, string cloneUrl, string gitUrl, string sshUrl, string svnUrl, string mirrorUrl, long id, string nodeId, User owner, string name, string fullName, bool isTemplate, 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, LicenseMetadata license, bool hasIssues, bool hasWiki, bool hasDownloads, bool hasPages, int subscribersCount, long size, bool? allowRebaseMerge, bool? allowSquashMerge, bool? allowMergeCommit, bool archived, int watchersCount, bool? deleteBranchOnMerge, RepositoryVisibility visibility) { Url = url; HtmlUrl = htmlUrl; @@ -57,6 +57,7 @@ namespace Octokit Archived = archived; WatchersCount = watchersCount; DeleteBranchOnMerge = deleteBranchOnMerge; + Visibility = visibility; } public string Url { get; protected set; } @@ -145,6 +146,8 @@ namespace Octokit public bool? DeleteBranchOnMerge { get; protected set; } + public RepositoryVisibility? Visibility { get; protected set; } + internal string DebuggerDisplay { get