[FEAT]: Custom Properties (#2933)

* add custom properties model and clients

* observable

* observable tests

* add search

* error CS8370: 'target-typed object creation'

* Error CS8370: 'target-typed object creation'

* add patch with body that return status code

* fixes for failed ConventionTests

* working UnitTests

* (de)serialization and model tests

* Update Repository.cs
This commit is contained in:
Colby Williams
2024-06-17 17:01:20 -05:00
committed by GitHub
parent 7d54cb0d85
commit 9a3177e385
53 changed files with 3121 additions and 1 deletions

View File

@@ -0,0 +1,73 @@
using System.Collections.Generic;
using System.Threading.Tasks;
namespace Octokit
{
/// <summary>
/// A client for GitHub's Organization Custom Properties API.
/// </summary>
/// <remarks>
/// See <a href="https://docs.github.com/rest/orgs/custom-properties">Custom Properties API documentation</a> for more information.
/// </remarks>
public interface IOrganizationCustomPropertiesClient
{
/// <summary>
/// Get all custom properties for an organization.
/// </summary>
/// <remarks>
/// See the <a href="https://docs.github.com/rest/orgs/custom-properties#get-all-custom-properties-for-an-organization">API documentation</a> for more information.
/// </remarks>
/// <param name="org">The name of the organization</param>
[ExcludeFromPaginationApiOptionsConventionTest("Pagination not supported by GitHub API (tested 15/06/2024)")]
Task<IReadOnlyList<OrganizationCustomProperty>> GetAll(string org);
/// <summary>
/// Get a single custom property by name.
/// </summary>
/// <remarks>
/// See the <a href="https://docs.github.com/rest/orgs/custom-properties#get-a-custom-property-for-an-organization">API documentation</a> for more information.
/// </remarks>
/// <param name="org">The name of the organization</param>
/// <param name="propertyName">The name of the custom property</param>
Task<OrganizationCustomProperty> Get(string org, string propertyName);
/// <summary>
/// Create new or update existing custom properties for an organization.
/// </summary>
/// <remarks>
/// See the <a href="https://docs.github.com/rest/orgs/custom-properties#create-or-update-custom-properties-for-an-organization">API documentation</a> for more information.
/// </remarks>
/// <param name="org">The name of the organization</param>
/// <param name="properties">The custom properties to create or update</param>
Task<IReadOnlyList<OrganizationCustomProperty>> CreateOrUpdate(string org, UpsertOrganizationCustomProperties properties);
/// <summary>
/// Create new or update existing custom property for an organization.
/// </summary>
/// <remarks>
/// See the <a href="https://docs.github.com/rest/orgs/custom-properties#create-or-update-a-custom-property-for-an-organization">API documentation</a> for more information.
/// </remarks>
/// <param name="org">The name of the organization</param>
/// <param name="propertyName">The name of the custom property</param>
/// <param name="property">The custom property to create or update</param>
Task<OrganizationCustomProperty> CreateOrUpdate(string org, string propertyName, UpsertOrganizationCustomProperty property);
/// <summary>
/// Removes a custom property that is defined for an organization.
/// </summary>
/// <remarks>
/// See the <a href="https://docs.github.com/rest/orgs/custom-properties#remove-a-custom-property-for-an-organization">API documentation</a> for more information.
/// </remarks>
/// <param name="org">The name of the organization</param>
/// <param name="propertyName">The name of the custom property</param>
Task Delete(string org, string propertyName);
/// <summary>
/// A client for GitHub's Organization Custom Property Values API.
/// </summary>
/// <remarks>
/// See the <a href="https://docs.github.com/rest/orgs/custom-properties">Custom Properties API documentation</a> for more information.
/// </remarks>
IOrganizationCustomPropertyValuesClient Values { get; }
}
}

View File

@@ -0,0 +1,56 @@
using System.Collections.Generic;
using System.Threading.Tasks;
namespace Octokit
{
/// <summary>
/// A client for GitHub's Organization Custom Property Values API.
/// </summary>
/// <remarks>
/// See <a href="https://docs.github.com/rest/orgs/custom-properties">Custom Properties API documentation</a> for more information.
/// </remarks>
public interface IOrganizationCustomPropertyValuesClient
{
/// <summary>
/// Get all custom property values for repositories an organization.
/// </summary>
/// <remarks>
/// See the <a href="https://docs.github.com/rest/orgs/custom-properties#list-custom-property-values-for-organization-repositories">API documentation</a> for more information.
/// </remarks>
/// <param name="org">The name of the organization</param>
Task<IReadOnlyList<OrganizationCustomPropertyValues>> GetAll(string org);
/// <summary>
/// Get all custom property values for repositories an organization.
/// </summary>
/// <remarks>
/// See the <a href="https://docs.github.com/rest/orgs/custom-properties#list-custom-property-values-for-organization-repositories">API documentation</a> for more information.
/// </remarks>
/// <param name="org">The name of the organization</param>
/// <param name="options">Options for changing the API response</param>
Task<IReadOnlyList<OrganizationCustomPropertyValues>> GetAll(string org, ApiOptions options);
/// <summary>
/// Get all custom property values for repositories an organization.
/// </summary>
/// <remarks>
/// See the <a href="https://docs.github.com/rest/orgs/custom-properties#list-custom-property-values-for-organization-repositories">API documentation</a> for more information.
/// </remarks>
/// <param name="org">The name of the organization</param>
/// <param name="repositoryQuery">Finds repositories in the organization with a query containing one or more search keywords and qualifiers.</param>
[ExcludeFromPaginationApiOptionsConventionTest("This API call uses the OrganizationCustomPropertyValuesRequest parameter for pagination")]
Task<IReadOnlyList<OrganizationCustomPropertyValues>> GetAll(string org, OrganizationCustomPropertyValuesRequest repositoryQuery);
/// <summary>
/// Create new or update existing custom property values for repositories an organization.
/// Using a value of null for a custom property will remove or 'unset' the property value from the repository.
/// A maximum of 30 repositories can be updated in a single request.
/// </summary>
/// <remarks>
/// See the <a href="https://docs.github.com/rest/orgs/custom-properties#create-or-update-custom-property-values-for-organization-repositories">API documentation</a> for more information.
/// </remarks>
/// <param name="org">The name of the organization</param>
/// <param name="propertyValues">The custom property values to create or update</param>
Task CreateOrUpdate(string org, UpsertOrganizationCustomPropertyValues propertyValues);
}
}

View File

@@ -40,6 +40,11 @@ namespace Octokit
/// </summary>
IOrganizationActionsClient Actions { get; }
/// <summary>
/// Returns a client to manage organization custom properties.
/// </summary>
IOrganizationCustomPropertiesClient CustomProperty { get; }
/// <summary>
/// Returns the specified <see cref="Organization"/>.
/// </summary>

View File

@@ -53,6 +53,14 @@ namespace Octokit
/// </remarks>
IRepositoryCommentsClient Comment { get; }
/// <summary>
/// Client for managing custom property values on a repository.
/// </summary>
/// <remarks>
/// See the <a href="https://docs.github.com/rest/repos/custom-properties">Repository Custom Properties API documentation</a> for more information.
/// </remarks>
IRepositoryCustomPropertiesClient CustomProperty { get; }
/// <summary>
/// Client for managing deploy keys in a repository.
/// </summary>

View File

@@ -0,0 +1,36 @@
using System.Collections.Generic;
using System.Threading.Tasks;
namespace Octokit
{
/// <summary>
/// A client for GitHub's Repository Custom Property Values API.
/// </summary>
/// <remarks>
/// See the <a href="https://docs.github.com/rest/repos/custom-properties">Custom Properties API documentation</a> for more information.
/// </remarks>
public interface IRepositoryCustomPropertiesClient
{
/// <summary>
/// Get all custom property values for a repository.
/// </summary>
/// <remarks>
/// See the <a href="https://docs.github.com/rest/repos/custom-properties#get-all-custom-property-values-for-a-repository">API documentation</a> for more information.
/// </remarks>
/// <param name="owner">The owner of the repository.</param>
/// <param name="repoName">The name of the repository.</param>
[ExcludeFromPaginationApiOptionsConventionTest("Pagination not supported by GitHub API (tested 15/06/2024)")]
Task<IReadOnlyList<CustomPropertyValue>> GetAll(string owner, string repoName);
/// <summary>
/// Create new or update existing custom property values for a repository. Using a value of null for a custom property will remove or 'unset' the property value from the repository.
/// </summary>
/// <remarks>
/// See the <a href="https://docs.github.com/rest/repos/custom-properties#create-or-update-custom-property-values-for-a-repository">API documentation</a> for more information.
/// </remarks>
/// <param name="owner">The owner of the repository</param>
/// <param name="repoName">The name of the repository</param>
/// <param name="propertyValues">The custom property values to create or update</param>
Task CreateOrUpdate(string owner, string repoName, UpsertRepositoryCustomPropertyValues propertyValues);
}
}

View File

@@ -0,0 +1,123 @@
using System.Collections.Generic;
using System.Threading.Tasks;
namespace Octokit
{
public class OrganizationCustomPropertiesClient : ApiClient, IOrganizationCustomPropertiesClient
{
/// <summary>
/// Initializes a new GitHub Organization Custom Properties API client.
/// </summary>
/// <param name="apiConnection">An API connection.</param>
public OrganizationCustomPropertiesClient(IApiConnection apiConnection)
: base(apiConnection)
{
Values = new OrganizationCustomPropertyValuesClient(apiConnection);
}
/// <summary>
/// Get all custom properties for an organization.
/// </summary>
/// <remarks>
/// See the <a href="https://docs.github.com/rest/orgs/custom-properties#get-all-custom-properties-for-an-organization">API documentation</a> for more information.
/// </remarks>
/// <param name="org">The name of the organization</param>
[ManualRoute("GET", "orgs/{org}/properties/schema")]
public Task<IReadOnlyList<OrganizationCustomProperty>> GetAll(string org)
{
Ensure.ArgumentNotNullOrEmptyString(org, nameof(org));
var url = ApiUrls.OrganizationCustomProperties(org);
return ApiConnection.Get<IReadOnlyList<OrganizationCustomProperty>>(url, null);
}
/// <summary>
/// Get a single custom property by name.
/// </summary>
/// <remarks>
/// See the <a href="https://docs.github.com/rest/orgs/custom-properties#get-a-custom-property-for-an-organization">API documentation</a> for more information.
/// </remarks>
/// <param name="org">The name of the organization</param>
/// <param name="propertyName">The name of the custom property</param>
[ManualRoute("GET", "orgs/{org}/properties/schema/{propertyName}")]
public Task<OrganizationCustomProperty> Get(string org, string propertyName)
{
Ensure.ArgumentNotNullOrEmptyString(org, nameof(org));
Ensure.ArgumentNotNullOrEmptyString(propertyName, nameof(propertyName));
var url = ApiUrls.OrganizationCustomProperty(org, propertyName);
return ApiConnection.Get<OrganizationCustomProperty>(url);
}
/// <summary>
/// Create new or update existing custom properties for an organization.
/// </summary>
/// <remarks>
/// See the <a href="https://docs.github.com/rest/orgs/custom-properties#create-or-update-custom-properties-for-an-organization">API documentation</a> for more information.
/// </remarks>
/// <param name="org">The name of the organization</param>
/// <param name="properties">The custom properties to create or update</param>
[ManualRoute("PATCH", "orgs/{org}/properties/schema")]
public Task<IReadOnlyList<OrganizationCustomProperty>> CreateOrUpdate(string org, UpsertOrganizationCustomProperties properties)
{
Ensure.ArgumentNotNullOrEmptyString(org, nameof(org));
Ensure.ArgumentNotNull(properties, nameof(properties));
Ensure.ArgumentNotNullOrEmptyEnumerable(properties.Properties, nameof(properties.Properties));
var url = ApiUrls.OrganizationCustomProperties(org);
return ApiConnection.Patch<IReadOnlyList<OrganizationCustomProperty>>(url, properties);
}
/// <summary>
/// Create new or update existing custom property for an organization.
/// </summary>
/// <remarks>
/// See the <a href="https://docs.github.com/rest/orgs/custom-properties#create-or-update-a-custom-property-for-an-organization">API documentation</a> for more information.
/// </remarks>
/// <param name="org">The name of the organization</param>
/// <param name="propertyName">The name of the custom property</param>
/// <param name="property">The custom property to create or update</param>
[ManualRoute("PUT", "orgs/{org}/properties/schema/{propertyName}")]
public Task<OrganizationCustomProperty> CreateOrUpdate(string org, string propertyName, UpsertOrganizationCustomProperty property)
{
Ensure.ArgumentNotNullOrEmptyString(org, nameof(org));
Ensure.ArgumentNotNullOrEmptyString(propertyName, nameof(propertyName));
Ensure.ArgumentNotNull(property, nameof(property));
Ensure.ArgumentNotNullOrDefault(property.ValueType, nameof(property.ValueType));
var url = ApiUrls.OrganizationCustomProperty(org, propertyName);
return ApiConnection.Put<OrganizationCustomProperty>(url, property);
}
/// <summary>
/// Removes a custom property that is defined for an organization.
/// </summary>
/// <remarks>
/// See the <a href="https://docs.github.com/rest/orgs/custom-properties#remove-a-custom-property-for-an-organization">API documentation</a> for more information.
/// </remarks>
/// <param name="org">The name of the organization</param>
/// <param name="propertyName">The name of the custom property</param>
[ManualRoute("DELETE", "orgs/{org}/properties/schema/{propertyName}")]
public Task Delete(string org, string propertyName)
{
Ensure.ArgumentNotNullOrEmptyString(org, nameof(org));
Ensure.ArgumentNotNullOrEmptyString(propertyName, nameof(propertyName));
var url = ApiUrls.OrganizationCustomProperty(org, propertyName);
return ApiConnection.Delete(url);
}
/// <summary>
/// A client for GitHub's Organization Custom Property Values API.
/// </summary>
/// <remarks>
/// See the <a href="https://docs.github.com/rest/orgs/custom-properties">Custom Properties API documentation</a> for more information.
/// </remarks>
public IOrganizationCustomPropertyValuesClient Values { get; private set; }
}
}

View File

@@ -0,0 +1,96 @@
using System.Collections.Generic;
using System.Threading.Tasks;
namespace Octokit
{
public class OrganizationCustomPropertyValuesClient : ApiClient, IOrganizationCustomPropertyValuesClient
{
/// <summary>
/// Initializes a new GitHub Organization Custom Property Values API client.
/// </summary>
/// <param name="apiConnection">An API connection.</param>
public OrganizationCustomPropertyValuesClient(IApiConnection apiConnection)
: base(apiConnection)
{
}
/// <summary>
/// Get all custom property values for repositories an organization.
/// </summary>
/// <remarks>
/// See the <a href="https://docs.github.com/rest/orgs/custom-properties#list-custom-property-values-for-organization-repositories">API documentation</a> for more information.
/// </remarks>
/// <param name="org">The name of the organization</param>
/// <exception cref="ApiException">Thrown when a general API error occurs.</exception>
[ManualRoute("GET", "orgs/{org}/properties/values")]
public Task<IReadOnlyList<OrganizationCustomPropertyValues>> GetAll(string org)
{
Ensure.ArgumentNotNullOrEmptyString(org, nameof(org));
return GetAll(org, new OrganizationCustomPropertyValuesRequest());
}
/// <summary>
/// Get all custom property values for repositories an organization.
/// </summary>
/// <remarks>
/// See the <a href="https://docs.github.com/rest/orgs/custom-properties#list-custom-property-values-for-organization-repositories">API documentation</a> for more information.
/// </remarks>
/// <param name="org">The name of the organization</param>
/// <param name="options">Options for changing the API response</param>
/// <exception cref="ApiException">Thrown when a general API error occurs.</exception>
[ManualRoute("GET", "orgs/{org}/properties/values")]
public Task<IReadOnlyList<OrganizationCustomPropertyValues>> GetAll(string org, ApiOptions options)
{
Ensure.ArgumentNotNullOrEmptyString(org, nameof(org));
Ensure.ArgumentNotNull(options, nameof(options));
var url = ApiUrls.OrganizationCustomPropertyValues(org);
return ApiConnection.GetAll<OrganizationCustomPropertyValues>(url, options);
}
/// <summary>
/// Get all custom property values for repositories an organization.
/// </summary>
/// <remarks>
/// See the <a href="https://docs.github.com/rest/orgs/custom-properties#list-custom-property-values-for-organization-repositories">API documentation</a> for more information.
/// </remarks>
/// <param name="org">The name of the organization</param>
/// <param name="repositoryQuery">Finds repositories in the organization with a query containing one or more search keywords and qualifiers.</param>
/// <exception cref="ApiException">Thrown when a general API error occurs.</exception>
[ManualRoute("GET", "orgs/{org}/properties/values")]
public Task<IReadOnlyList<OrganizationCustomPropertyValues>> GetAll(string org, OrganizationCustomPropertyValuesRequest repositoryQuery)
{
Ensure.ArgumentNotNullOrEmptyString(org, nameof(org));
Ensure.ArgumentNotNull(repositoryQuery, nameof(repositoryQuery));
var url = ApiUrls.OrganizationCustomPropertyValues(org);
return ApiConnection.GetAll<OrganizationCustomPropertyValues>(url, repositoryQuery.Parameters);
}
/// <summary>
/// Create new or update existing custom property values for repositories an organization.
/// Using a value of null for a custom property will remove or 'unset' the property value from the repository.
/// A maximum of 30 repositories can be updated in a single request.
/// </summary>
/// <remarks>
/// See the <a href="https://docs.github.com/rest/orgs/custom-properties#create-or-update-custom-property-values-for-organization-repositories">API documentation</a> for more information.
/// </remarks>
/// <param name="org">The name of the organization</param>
/// <param name="propertyValues">The custom property values to create or update</param>
/// <exception cref="ApiException">Thrown when a general API error occurs.</exception>
[ManualRoute("PATCH", "orgs/{org}/properties/values")]
public Task CreateOrUpdate(string org, UpsertOrganizationCustomPropertyValues propertyValues)
{
Ensure.ArgumentNotNullOrEmptyString(org, nameof(org));
Ensure.ArgumentNotNull(propertyValues, nameof(propertyValues));
Ensure.ArgumentNotNullOrEmptyEnumerable(propertyValues.Properties, nameof(propertyValues.Properties));
var url = ApiUrls.OrganizationCustomPropertyValues(org);
return ApiConnection.Patch(url, propertyValues);
}
}
}

View File

@@ -23,6 +23,7 @@ namespace Octokit
Hook = new OrganizationHooksClient(apiConnection);
OutsideCollaborator = new OrganizationOutsideCollaboratorsClient(apiConnection);
Actions = new OrganizationActionsClient(apiConnection);
CustomProperty = new OrganizationCustomPropertiesClient(apiConnection);
}
/// <summary>
@@ -45,6 +46,11 @@ namespace Octokit
/// </summary>
public IOrganizationOutsideCollaboratorsClient OutsideCollaborator { get; private set; }
/// <summary>
/// Returns a client to manage organization custom properties.
/// </summary>
public IOrganizationCustomPropertiesClient CustomProperty { get; private set; }
/// <summary>
/// Returns the specified <see cref="Organization"/>.
/// </summary>

View File

@@ -33,6 +33,7 @@ namespace Octokit
PullRequest = new PullRequestsClient(apiConnection);
Comment = new RepositoryCommentsClient(apiConnection);
Commit = new RepositoryCommitsClient(apiConnection);
CustomProperty = new RepositoryCustomPropertiesClient(apiConnection);
Release = new ReleasesClient(apiConnection);
DeployKeys = new RepositoryDeployKeysClient(apiConnection);
Merging = new MergingClient(apiConnection);
@@ -569,6 +570,14 @@ namespace Octokit
///</remarks>
public IRepositoryCommitsClient Commit { get; private set; }
/// <summary>
/// Client for GitHub's Repository Custom Property Values API.
/// </summary>
/// <remarks>
/// See the <a href="https://docs.github.com/rest/repos/custom-properties">Repository Custom Properties API documentation</a> for more details.
/// </remarks>
public IRepositoryCustomPropertiesClient CustomProperty { get; private set; }
/// <summary>
/// Access GitHub's Releases API.
/// </summary>

View File

@@ -0,0 +1,66 @@
using System.Threading.Tasks;
using System.Collections.Generic;
namespace Octokit
{
/// <summary>
/// A client for GitHub's Repository Custom Property Values API.
/// </summary>
/// <remarks>
/// See the <a href="https://docs.github.com/rest/repos/custom-properties">Custom Properties API documentation</a> for more information.
/// </remarks>
public class RepositoryCustomPropertiesClient : ApiClient, IRepositoryCustomPropertiesClient
{
/// <summary>
/// Initializes a new GitHub repository custom property values API client.
/// </summary>
/// <param name="apiConnection">An API connection.</param>
public RepositoryCustomPropertiesClient(IApiConnection apiConnection)
: base(apiConnection)
{
}
/// <summary>
/// Get all custom property values for a repository.
/// </summary>
/// <remarks>
/// See the <a href="https://docs.github.com/rest/repos/custom-properties#get-all-custom-property-values-for-a-repository">API documentation</a> for more information.
/// </remarks>
/// <param name="owner">The owner of the repository.</param>
/// <param name="repoName">The name of the repository.</param>
/// <exception cref="ApiException">Thrown when a general API error occurs.</exception>
[ManualRoute("GET", "/repos/{owner}/{repo}/properties/values")]
public Task<IReadOnlyList<CustomPropertyValue>> GetAll(string owner, string repoName)
{
Ensure.ArgumentNotNullOrEmptyString(owner, nameof(owner));
Ensure.ArgumentNotNullOrEmptyString(repoName, nameof(repoName));
var url = ApiUrls.RepositoryCustomPropertyValues(owner, repoName);
return ApiConnection.Get<IReadOnlyList<CustomPropertyValue>>(url, null);
}
/// <summary>
/// Create new or update existing custom property values for a repository. Using a value of null for a custom property will remove or 'unset' the property value from the repository.
/// </summary>
/// <remarks>
/// See the <a href="https://docs.github.com/rest/repos/custom-properties#create-or-update-custom-property-values-for-a-repository">API documentation</a> for more information.
/// </remarks>
/// <param name="owner">The owner of the repository</param>
/// <param name="repoName">The name of the repository</param>
/// <param name="propertyValues">The custom property values to create or update</param>
/// <exception cref="ApiException">Thrown when a general API error occurs.</exception>
[ManualRoute("PATCH", "/repos/{owner}/{repo}/properties/values")]
public Task CreateOrUpdate(string owner, string repoName, UpsertRepositoryCustomPropertyValues propertyValues)
{
Ensure.ArgumentNotNullOrEmptyString(owner, nameof(owner));
Ensure.ArgumentNotNullOrEmptyString(repoName, nameof(repoName));
Ensure.ArgumentNotNull(propertyValues, nameof(propertyValues));
Ensure.ArgumentNotNullOrEmptyEnumerable(propertyValues.Properties, nameof(propertyValues.Properties));
var url = ApiUrls.RepositoryCustomPropertyValues(owner, repoName);
return ApiConnection.Patch(url, propertyValues);
}
}
}

View File

@@ -78,6 +78,41 @@ namespace Octokit
return "orgs/{0}/repos".FormatUri(organization);
}
/// <summary>
/// Returns the <see cref="Uri"/> that returns all of the custom properties for the specified organization in
/// response to a GET request. A PATCH to this URL updates the custom properties for the organization.
/// </summary>
/// <param name="organization">The name of the organization</param>
/// <returns></returns>
public static Uri OrganizationCustomProperties(string organization)
{
return "orgs/{0}/properties/schema".FormatUri(organization);
}
/// <summary>
/// Returns the <see cref="Uri"/> that returns a custom property for the specified organization in
/// response to a GET request. A PUT to this URL updates the custom property for the organization.
/// </summary>
/// <param name="organization">The name of the organization</param>
/// <param name="property">The name of the property</param>
/// <returns></returns>
public static Uri OrganizationCustomProperty(string organization, string property)
{
return "orgs/{0}/properties/schema/{1}".FormatUri(organization, property);
}
/// <summary>
/// Returns the <see cref="Uri"/> that returns a custom property values for repositories in the
/// specified organization in response to a GET request. A PATCH to this URL updates the custom property
/// values for specified repositories in the organization.
/// </summary>
/// <param name="organization">The name of the organization</param>
/// <returns></returns>
public static Uri OrganizationCustomPropertyValues(string organization)
{
return "orgs/{0}/properties/values".FormatUri(organization);
}
/// <summary>
/// Returns the <see cref="Uri"/> that returns all of the secrets for the specified organization in
/// response to a GET request.
@@ -4618,6 +4653,17 @@ namespace Octokit
return "repos/{0}/{1}/check-suites/preferences".FormatUri(owner, repo);
}
/// <summary>
/// Returns the <see cref="Uri"/> that handles the repository custom property values for the repository
/// </summary>
/// <param name="owner">The owner of the repo</param>
/// <param name="repo">The name of the repo</param>
/// <returns>The <see cref="Uri"/> that handles the repository secrets for the repository</returns>
public static Uri RepositoryCustomPropertyValues(string owner, string repo)
{
return "repos/{0}/{1}/properties/values".FormatUri(owner, repo);
}
/// <summary>
/// Returns the <see cref="Uri"/> that handles the repository secrets for the repository
/// </summary>

View File

@@ -460,6 +460,20 @@ namespace Octokit
return Connection.Patch(uri);
}
/// <summary>
/// Updates the API resource at the specified URI.
/// </summary>
/// <param name="uri">URI of the API resource to patch</param>
/// <param name="data">Object that describes the API resource; this will be serialized and used as the request's body</param>
/// <returns>A <see cref="Task"/> for the request's execution.</returns>
public Task Patch(Uri uri, object data)
{
Ensure.ArgumentNotNull(uri, nameof(uri));
Ensure.ArgumentNotNull(data, nameof(data));
return Connection.Patch(uri, data);
}
/// <summary>
/// Updates the API resource at the specified URI.
/// </summary>
@@ -474,6 +488,22 @@ namespace Octokit
return Connection.Patch(uri, accepts);
}
/// <summary>
/// Updates the API resource at the specified URI.
/// </summary>
/// <param name="uri">URI of the API resource to patch</param>
/// <param name="data">Object that describes the API resource; this will be serialized and used as the request's body</param>
/// <param name="accepts">Accept header to use for the API request</param>
/// <returns>A <see cref="Task"/> for the request's execution.</returns>
public Task Patch(Uri uri, object data, string accepts)
{
Ensure.ArgumentNotNull(uri, nameof(uri));
Ensure.ArgumentNotNull(data, nameof(data));
Ensure.ArgumentNotNull(accepts, nameof(accepts));
return Connection.Patch(uri, data, accepts);
}
/// <summary>
/// Updates the API resource at the specified URI.
/// </summary>

View File

@@ -498,6 +498,21 @@ namespace Octokit
return response.HttpResponse.StatusCode;
}
/// <summary>
/// Performs an asynchronous HTTP PATCH request.
/// </summary>
/// <param name="uri">URI endpoint to send request to</param>
/// <param name="body">The object to serialize as the body of the request</param>
/// <returns><seealso cref="IResponse"/> representing the received HTTP response</returns>
public async Task<HttpStatusCode> Patch(Uri uri, object body)
{
Ensure.ArgumentNotNull(uri, nameof(uri));
Ensure.ArgumentNotNull(body, nameof(body));
var response = await SendData<object>(uri, new HttpMethod("PATCH"), body, null, null, CancellationToken.None).ConfigureAwait(false);
return response.HttpResponse.StatusCode;
}
/// <summary>
/// Performs an asynchronous HTTP PATCH request.
/// </summary>
@@ -513,6 +528,23 @@ namespace Octokit
return response.HttpResponse.StatusCode;
}
/// <summary>
/// Performs an asynchronous HTTP PATCH request.
/// </summary>
/// <param name="uri">URI endpoint to send request to</param>
/// <param name="body">The object to serialize as the body of the request</param>
/// <param name="accepts">Specifies accept response media type</param>
/// <returns><seealso cref="IResponse"/> representing the received HTTP response</returns>
public async Task<HttpStatusCode> Patch(Uri uri, object body, string accepts)
{
Ensure.ArgumentNotNull(uri, nameof(uri));
Ensure.ArgumentNotNull(body, nameof(body));
Ensure.ArgumentNotNull(accepts, nameof(accepts));
var response = await SendData<object>(uri, new HttpMethod("PATCH"), body, accepts, null, CancellationToken.None).ConfigureAwait(false);
return response.HttpResponse.StatusCode;
}
/// <summary>
/// Performs an asynchronous HTTP PUT request that expects an empty response.
/// </summary>

View File

@@ -306,6 +306,14 @@ namespace Octokit
/// <returns>A <see cref="Task"/> for the request's execution.</returns>
Task Patch(Uri uri);
/// <summary>
/// Updates the API resource at the specified URI.
/// </summary>
/// <param name="uri">URI of the API resource to patch</param>
/// <param name="data">Object that describes the API resource; this will be serialized and used as the request's body</param>
/// <returns>A <see cref="Task"/> for the request's execution.</returns>
Task Patch(Uri uri, object data);
/// <summary>
/// Updates the API resource at the specified URI.
/// </summary>
@@ -314,6 +322,15 @@ namespace Octokit
/// <returns>A <see cref="Task"/> for the request's execution.</returns>
Task Patch(Uri uri, string accepts);
/// <summary>
/// Updates the API resource at the specified URI.
/// </summary>
/// <param name="uri">URI of the API resource to patch</param>
/// <param name="data">Object that describes the API resource; this will be serialized and used as the request's body</param>
/// <param name="accepts">Accept header to use for the API request</param>
/// <returns>A <see cref="Task"/> for the request's execution.</returns>
Task Patch(Uri uri, object data, string accepts);
/// <summary>
/// Updates the API resource at the specified URI.
/// </summary>

View File

@@ -117,6 +117,14 @@ namespace Octokit
/// <returns><seealso cref="IResponse"/> representing the received HTTP response</returns>
Task<HttpStatusCode> Patch(Uri uri);
/// <summary>
/// Performs an asynchronous HTTP PATCH request.
/// </summary>
/// <param name="uri">URI endpoint to send request to</param>
/// <param name="body">The object to serialize as the body of the request</param>
/// <returns><seealso cref="IResponse"/> representing the received HTTP response</returns>
Task<HttpStatusCode> Patch(Uri uri, object body);
/// <summary>
/// Performs an asynchronous HTTP PATCH request.
/// </summary>
@@ -125,6 +133,15 @@ namespace Octokit
/// <returns><seealso cref="IResponse"/> representing the received HTTP response</returns>
Task<HttpStatusCode> Patch(Uri uri, string accepts);
/// <summary>
/// Performs an asynchronous HTTP PATCH request.
/// </summary>
/// <param name="uri">URI endpoint to send request to</param>
/// <param name="body">The object to serialize as the body of the request</param>
/// <param name="accepts">Specifies accept response media type</param>
/// <returns><seealso cref="IResponse"/> representing the received HTTP response</returns>
Task<HttpStatusCode> Patch(Uri uri, object body, string accepts);
/// <summary>
/// Performs an asynchronous HTTP PATCH request.
/// Attempts to map the response body to an object of type <typeparamref name="T"/>

View File

@@ -0,0 +1,42 @@
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using Octokit.Internal;
namespace Octokit
{
/// <summary>
/// Custom property name and associated value
/// </summary>
[DebuggerDisplay("{DebuggerDisplay,nq}")]
public class CustomPropertyValueUpdate
{
public CustomPropertyValueUpdate() { }
public CustomPropertyValueUpdate(string propertyName, string value)
{
PropertyName = propertyName;
Value = value;
}
public CustomPropertyValueUpdate(string propertyName, IReadOnlyList<string> value)
{
PropertyName = propertyName;
Value = value;
}
/// <summary>
/// The name of the property
/// </summary>
public string PropertyName { get; set; }
/// <summary>
/// The value assigned to the property
/// </summary>
[SerializeNull]
[Parameter(Key = "value")]
public object Value { get; private set; }
internal string DebuggerDisplay => string.Format(CultureInfo.InvariantCulture, "PropertyName: {0}", PropertyName);
}
}

View File

@@ -0,0 +1,66 @@
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
namespace Octokit
{
[DebuggerDisplay("{DebuggerDisplay,nq}")]
public class OrganizationCustomPropertyUpdate
{
public OrganizationCustomPropertyUpdate() { }
public OrganizationCustomPropertyUpdate(string propertyName, CustomPropertyValueType valueType, string defaultValue)
{
PropertyName = propertyName;
ValueType = valueType;
Required = true;
DefaultValue = defaultValue;
}
public OrganizationCustomPropertyUpdate(string propertyName, CustomPropertyValueType valueType, IReadOnlyList<string> defaultValue)
{
PropertyName = propertyName;
ValueType = valueType;
Required = true;
DefaultValue = defaultValue;
}
/// <summary>
/// The name of the property
/// </summary>
public string PropertyName { get; set; }
/// <summary>
/// The type of the value for the property
/// </summary>
public StringEnum<CustomPropertyValueType> ValueType { get; set; }
/// <summary>
/// Whether the property is required
/// </summary>
public bool Required { get; set; }
/// <summary>
/// Default value of the property
/// </summary>
public object DefaultValue { get; private set; }
/// <summary>
/// Short description of the property
/// </summary>
public string Description { get; set; }
/// <summary>
/// An ordered list of the allowed values of the property.
/// The property can have up to 200 allowed values.
/// </summary>
public IEnumerable<string> AllowedValues { get; set; }
/// <summary>
/// Who can edit the values of the property
/// </summary>
public StringEnum<CustomPropertyValuesEditableBy>? ValuesEditableBy { get; set; }
internal string DebuggerDisplay => string.Format(CultureInfo.InvariantCulture, "PropertyName: {0}", PropertyName);
}
}

View File

@@ -0,0 +1,51 @@
using System.Collections.Generic;
using System.Diagnostics;
namespace Octokit
{
[DebuggerDisplay("{DebuggerDisplay,nq}")]
public class OrganizationCustomPropertyValuesRequest : SearchRepositoriesRequest
{
/// <summary>
/// Initializes a new instance of the <see cref="OrganizationCustomPropertyValuesRequest"/> class.
/// </summary>
public OrganizationCustomPropertyValuesRequest() : base()
{ }
/// <summary>
/// Initializes a new instance of the <see cref="OrganizationCustomPropertyValuesRequest"/> class.
/// </summary>
public OrganizationCustomPropertyValuesRequest(string term)
: base(term)
{ }
public override string Sort => null;
/// <summary>
/// Get the query parameters that will be appending onto the search
/// </summary>
public new IDictionary<string, string> Parameters
{
get
{
var parameters = base.Parameters;
// Remove the default sort and order parameters as they are not supported by the API
parameters.Remove("order");
parameters.Remove("sort");
// Replace the default query parameter "q" with the custom query parameter
var query = parameters["q"];
if (!string.IsNullOrWhiteSpace(query))
{
parameters.Add("repository_query", query);
}
parameters.Remove("q");
return parameters;
}
}
}
}

View File

@@ -0,0 +1,38 @@
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using Octokit.Internal;
namespace Octokit
{
/// <summary>
/// Used to create or update custom property values for a repository
/// </summary>
[DebuggerDisplay("{DebuggerDisplay,nq}")]
public class UpsertOrganizationCustomProperties
{
public UpsertOrganizationCustomProperties() { }
public UpsertOrganizationCustomProperties(List<OrganizationCustomPropertyUpdate> properties)
{
Properties = properties;
}
/// <summary>
/// List of organization custom properties
/// </summary>
/// <remarks>
/// See the <a href="https://docs.github.com/rest/orgs/custom-properties#create-or-update-custom-properties-for-an-organization">API documentation</a> for more information.
/// </remarks>
[Parameter(Value = "properties")]
public List<OrganizationCustomPropertyUpdate> Properties { get; set; }
internal string DebuggerDisplay
{
get
{
return string.Format(CultureInfo.InvariantCulture, "Count: {0}", Properties?.Count);
}
}
}
}

View File

@@ -0,0 +1,67 @@
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
namespace Octokit
{
/// <summary>
/// Used to create or update a custom property value for a repository
/// </summary>
[DebuggerDisplay("{DebuggerDisplay,nq}")]
public class UpsertOrganizationCustomProperty
{
public UpsertOrganizationCustomProperty() { }
public UpsertOrganizationCustomProperty(CustomPropertyValueType valueType)
{
ValueType = valueType;
}
public UpsertOrganizationCustomProperty(CustomPropertyValueType valueType, string defaultValue)
{
ValueType = valueType;
Required = true;
DefaultValue = defaultValue;
}
public UpsertOrganizationCustomProperty(CustomPropertyValueType valueType, IReadOnlyList<string> defaultValue)
{
ValueType = valueType;
Required = true;
DefaultValue = defaultValue;
}
/// <summary>
/// The type of the value for the property
/// </summary>
public StringEnum<CustomPropertyValueType> ValueType { get; set; }
/// <summary>
/// Whether the property is required
/// </summary>
public bool Required { get; set; }
/// <summary>
/// Default value of the property
/// </summary>
public object DefaultValue { get; private set; }
/// <summary>
/// Short description of the property
/// </summary>
public string Description { get; set; }
/// <summary>
/// An ordered list of the allowed values of the property.
/// The property can have up to 200 allowed values.
/// </summary>
public IEnumerable<string> AllowedValues { get; set; }
/// <summary>
/// Who can edit the values of the property
/// </summary>
public StringEnum<CustomPropertyValuesEditableBy>? ValuesEditableBy { get; set; }
internal string DebuggerDisplay => string.Format(CultureInfo.InvariantCulture, "ValueType: {0}", ValueType.DebuggerDisplay);
}
}

View File

@@ -0,0 +1,48 @@
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using Octokit.Internal;
namespace Octokit
{
/// <summary>
/// Used to create or update custom property values for organization repositories
/// </summary>
[DebuggerDisplay("{DebuggerDisplay,nq}")]
public class UpsertOrganizationCustomPropertyValues
{
public UpsertOrganizationCustomPropertyValues() { }
public UpsertOrganizationCustomPropertyValues(List<string> repositoryNames, List<CustomPropertyValueUpdate> properties)
{
RepositoryNames = repositoryNames;
Properties = properties;
}
/// <summary>
/// List of repository names that should create or update custom property values
/// </summary>
/// <remarks>
/// See the <a href="https://docs.github.com/rest/orgs/custom-properties#create-or-update-custom-property-values-for-organization-repositories">API documentation</a> for more information.
/// </remarks>
[Parameter(Value = "repository_names")]
public List<string> RepositoryNames { get; set; }
/// <summary>
/// List of organization custom properties
/// </summary>
/// <remarks>
/// See the <a href="https://docs.github.com/rest/orgs/custom-properties#create-or-update-custom-properties-for-an-organization">API documentation</a> for more information.
/// </remarks>
[Parameter(Value = "properties")]
public List<CustomPropertyValueUpdate> Properties { get; set; }
internal string DebuggerDisplay
{
get
{
return string.Format(CultureInfo.InvariantCulture, "Count: {0}", Properties?.Count);
}
}
}
}

View File

@@ -0,0 +1,31 @@
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using Octokit.Internal;
namespace Octokit
{
/// <summary>
/// Used to create or update custom property values for a repository
/// </summary>
[DebuggerDisplay("{DebuggerDisplay,nq}")]
public class UpsertRepositoryCustomPropertyValues
{
/// <summary>
/// List of custom property names and associated values
/// </summary>
/// <remarks>
/// See the <a href="https://docs.github.com/rest/repos/custom-properties#create-or-update-custom-property-values-for-a-repository">API documentation</a> for more information.
/// </remarks>
[Parameter(Value = "properties")]
public List<CustomPropertyValueUpdate> Properties { get; set; }
internal string DebuggerDisplay
{
get
{
return string.Format(CultureInfo.InvariantCulture, "Count: {0}", Properties?.Count);
}
}
}
}

View File

@@ -0,0 +1,79 @@
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using Octokit.Internal;
namespace Octokit
{
/// <summary>
/// Custom property name and associated value
/// </summary>
[DebuggerDisplay("{DebuggerDisplay,nq}")]
[ExcludeFromCtorWithAllPropertiesConventionTest(nameof(Values))]
public class CustomPropertyValue
{
public CustomPropertyValue() { }
public CustomPropertyValue(string propertyName, object value)
{
PropertyName = propertyName;
this.value = value;
}
/// <summary>
/// The name of the property
/// </summary>
[Parameter(Key = "property_name")]
public string PropertyName { get; private set; }
[Parameter(Key = "value")]
public object value { get; private set; }
/// <summary>
/// The value assigned to the property
/// </summary>
public string Value {
get {
if (value is null)
{
return null;
}
if (value is string stringValue)
{
return stringValue;
}
else if (value is JsonArray stringValues)
{
return "[" + string.Join(",", stringValues.ConvertAll(x => x.ToString())) + "]";
}
return null;
}
}
/// <summary>
/// The array of values assigned to the property
/// </summary>
public IReadOnlyList<string> Values {
get {
if (value is null)
{
return null;
}
else if (value is string stringValue)
{
return new List<string> { stringValue };
}
else if (value is JsonArray stringValues)
{
return stringValues.ConvertAll(x => x.ToString());
}
return null;
}
}
internal string DebuggerDisplay => string.Format(CultureInfo.InvariantCulture, "PropertyName: {0}", PropertyName);
}
}

View File

@@ -0,0 +1,16 @@
using Octokit.Internal;
namespace Octokit
{
public enum CustomPropertyValueType
{
[Parameter(Value = "string")]
String,
[Parameter(Value = "single_select")]
SingleSelect,
[Parameter(Value = "multi_select")]
MultiSelect,
[Parameter(Value = "true_false")]
TrueFalse,
}
}

View File

@@ -0,0 +1,12 @@
using Octokit.Internal;
namespace Octokit
{
public enum CustomPropertyValuesEditableBy
{
[Parameter(Value = "org_actors")]
OrgActors,
[Parameter(Value = "org_and_repo_actors")]
OrgAndRepoActors,
}
}

View File

@@ -0,0 +1,105 @@
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using Octokit.Internal;
namespace Octokit
{
[DebuggerDisplay("{DebuggerDisplay,nq}")]
[ExcludeFromCtorWithAllPropertiesConventionTest(nameof(DefaultValues))]
public class OrganizationCustomProperty
{
public OrganizationCustomProperty() { }
public OrganizationCustomProperty(string propertyName, CustomPropertyValueType valueType, bool required, object defaultValue, string description, IReadOnlyList<string> allowedValues, CustomPropertyValuesEditableBy? valuesEditableBy)
{
PropertyName = propertyName;
ValueType = valueType;
Required = required;
this.defaultValue = defaultValue;
Description = description;
AllowedValues = allowedValues;
ValuesEditableBy = valuesEditableBy;
}
[Parameter(Key = "default_value")]
public object defaultValue { get; private set; }
/// <summary>
/// The name of the property
/// </summary>
public string PropertyName { get; private set; }
/// <summary>
/// The type of the value for the property
/// </summary>
public StringEnum<CustomPropertyValueType>? ValueType { get; private set; }
/// <summary>
/// Whether the property is required
/// </summary>
public bool Required { get; private set; }
/// <summary>
/// Default value of the property
/// </summary>
public string DefaultValue {
get {
if (defaultValue is null)
{
return null;
}
if (defaultValue is string stringValue)
{
return stringValue;
}
else if (defaultValue is JsonArray stringValues)
{
return "[" + string.Join(",", stringValues.ConvertAll(x => x.ToString())) + "]";
}
return null;
}
}
/// <summary>
/// Default values of the property
/// </summary>
public IReadOnlyList<string> DefaultValues {
get {
if (defaultValue is null)
{
return null;
}
else if (defaultValue is string stringValue)
{
return new List<string> { stringValue };
}
else if (defaultValue is JsonArray stringValues)
{
return stringValues.ConvertAll(x => x.ToString());
}
return null;
}
}
/// <summary>
/// Short description of the property
/// </summary>
public string Description { get; private set; }
/// <summary>
/// An ordered list of the allowed values of the property.
/// The property can have up to 200 allowed values.
/// </summary>
public IReadOnlyList<string> AllowedValues { get; private set; }
/// <summary>
/// Who can edit the values of the property
/// </summary>
public StringEnum<CustomPropertyValuesEditableBy>? ValuesEditableBy { get; private set; }
internal string DebuggerDisplay => string.Format(CultureInfo.InvariantCulture, "PropertyName: {0}", PropertyName);
}
}

View File

@@ -0,0 +1,45 @@
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
namespace Octokit
{
/// <summary>
/// List of custom property values for a repository
/// </summary>
[DebuggerDisplay("{DebuggerDisplay,nq}")]
public class OrganizationCustomPropertyValues
{
public OrganizationCustomPropertyValues() { }
public OrganizationCustomPropertyValues(long repositoryId, string repositoryName, string repositoryFullName, IReadOnlyList<CustomPropertyValue> properties)
{
RepositoryId = repositoryId;
RepositoryName = repositoryName;
RepositoryFullName = repositoryFullName;
Properties = properties;
}
/// <summary>
/// The repository Id
/// </summary>
public long RepositoryId { get; private set; }
/// <summary>
/// The name of the repository
/// </summary>
public string RepositoryName { get; private set; }
/// <summary>
/// The full name of the repository (owner/repo)
/// </summary>
public string RepositoryFullName { get; private set; }
/// <summary>
/// List of custom property names and associated values
/// </summary>
public IReadOnlyList<CustomPropertyValue> Properties { get; private set; }
internal string DebuggerDisplay => string.Format(CultureInfo.InvariantCulture, "RepositoryFullName: {0}", RepositoryFullName);
}
}

View File

@@ -17,7 +17,7 @@ namespace Octokit
Id = id;
}
public Repository(string url, string htmlUrl, string cloneUrl, string gitUrl, string sshUrl, string svnUrl, string mirrorUrl, string archiveUrl, 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 hasDiscussions, 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, IEnumerable<string> topics, bool? allowAutoMerge, bool? allowUpdateBranch, bool? webCommitSignoffRequired)
public Repository(string url, string htmlUrl, string cloneUrl, string gitUrl, string sshUrl, string svnUrl, string mirrorUrl, string archiveUrl, 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 hasDiscussions, 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, IEnumerable<string> topics, bool? allowAutoMerge, bool? allowUpdateBranch, bool? webCommitSignoffRequired, IReadOnlyDictionary<string, object> customProperties)
{
Url = url;
HtmlUrl = htmlUrl;
@@ -69,6 +69,7 @@ namespace Octokit
AllowAutoMerge = allowAutoMerge;
AllowUpdateBranch = allowUpdateBranch;
WebCommitSignoffRequired = webCommitSignoffRequired;
CustomProperties = customProperties;
}
public string Url { get; private set; }
@@ -170,6 +171,8 @@ namespace Octokit
public bool? WebCommitSignoffRequired { get; private set; }
public IReadOnlyDictionary<string, object> CustomProperties { get; private set; }
internal string DebuggerDisplay
{
get