From 67f33dbdc9854839a707187c5d09d356ec2f33de Mon Sep 17 00:00:00 2001 From: Colby Williams Date: Sat, 15 Jun 2024 03:12:35 -0500 Subject: [PATCH 01/11] add custom properties model and clients --- .../IOrganizationCustomPropertiesClient.cs | 72 +++++++++++ ...IOrganizationCustomPropertyValuesClient.cs | 45 +++++++ Octokit/Clients/IOrganizationsClient.cs | 5 + Octokit/Clients/IRepositoriesClient.cs | 8 ++ .../IRepositoryCustomPropertiesClient.cs | 35 +++++ .../OrganizationCustomPropertiesClient.cs | 121 ++++++++++++++++++ .../OrganizationCustomPropertyValuesClient.cs | 78 +++++++++++ Octokit/Clients/OrganizationsClient.cs | 6 + Octokit/Clients/RepositoriesClient.cs | 9 ++ .../RepositoryCustomPropertiesClient.cs | 65 ++++++++++ Octokit/Helpers/ApiUrls.cs | 46 +++++++ .../Request/CustomPropertyValueUpdate.cs | 41 ++++++ .../OrganizationCustomPropertyUpdate.cs | 77 +++++++++++ .../UpsertOrganizationCustomProperties.cs | 38 ++++++ .../UpsertOrganizationCustomPropertyValues.cs | 48 +++++++ .../UpsertRepositoryCustomPropertyValues.cs | 31 +++++ .../Models/Response/CustomPropertyValue.cs | 41 ++++++ .../Response/CustomPropertyValueType.cs | 16 +++ .../CustomPropertyValuesEditableBy.cs | 12 ++ .../Response/OrganizationCustomProperty.cs | 77 +++++++++++ .../OrganizationCustomPropertyValues.cs | 45 +++++++ Octokit/Models/Response/Repository.cs | 5 +- 22 files changed, 920 insertions(+), 1 deletion(-) create mode 100644 Octokit/Clients/IOrganizationCustomPropertiesClient.cs create mode 100644 Octokit/Clients/IOrganizationCustomPropertyValuesClient.cs create mode 100644 Octokit/Clients/IRepositoryCustomPropertiesClient.cs create mode 100644 Octokit/Clients/OrganizationCustomPropertiesClient.cs create mode 100644 Octokit/Clients/OrganizationCustomPropertyValuesClient.cs create mode 100644 Octokit/Clients/RepositoryCustomPropertiesClient.cs create mode 100644 Octokit/Models/Request/CustomPropertyValueUpdate.cs create mode 100644 Octokit/Models/Request/OrganizationCustomPropertyUpdate.cs create mode 100644 Octokit/Models/Request/UpsertOrganizationCustomProperties.cs create mode 100644 Octokit/Models/Request/UpsertOrganizationCustomPropertyValues.cs create mode 100644 Octokit/Models/Request/UpsertRepositoryCustomPropertyValues.cs create mode 100644 Octokit/Models/Response/CustomPropertyValue.cs create mode 100644 Octokit/Models/Response/CustomPropertyValueType.cs create mode 100644 Octokit/Models/Response/CustomPropertyValuesEditableBy.cs create mode 100644 Octokit/Models/Response/OrganizationCustomProperty.cs create mode 100644 Octokit/Models/Response/OrganizationCustomPropertyValues.cs diff --git a/Octokit/Clients/IOrganizationCustomPropertiesClient.cs b/Octokit/Clients/IOrganizationCustomPropertiesClient.cs new file mode 100644 index 0000000000..e091ef9d16 --- /dev/null +++ b/Octokit/Clients/IOrganizationCustomPropertiesClient.cs @@ -0,0 +1,72 @@ +using System.Collections.Generic; +using System.Threading.Tasks; + +namespace Octokit +{ + /// + /// A client for GitHub's Organization Custom Properties API. + /// + /// + /// See Custom Properties API documentation for more information. + /// + public interface IOrganizationCustomPropertiesClient + { + /// + /// Get all custom properties for an organization. + /// + /// + /// See the API documentation for more information. + /// + /// The name of the organization + Task> GetAll(string org); + + /// + /// Get a single custom property by name. + /// + /// + /// See the API documentation for more information. + /// + /// The name of the organization + /// The name of the custom property + Task Get(string org, string propertyName); + + /// + /// Create new or update existing custom properties for an organization. + /// + /// + /// See the API documentation for more information. + /// + /// The name of the organization + /// The custom properties to create or update + Task> CreateOrUpdate(string org, UpsertOrganizationCustomProperties properties); + + /// + /// Create new or update existing custom property for an organization. + /// + /// + /// See the API documentation for more information. + /// + /// The name of the organization + /// The name of the custom property + /// The custom property to create or update + Task CreateOrUpdate(string org, string propertyName, OrganizationCustomProperty property); + + /// + /// Removes a custom property that is defined for an organization. + /// + /// + /// See the API documentation for more information. + /// + /// The name of the organization + /// The name of the custom property + Task Delete(string org, string propertyName); + + /// + /// A client for GitHub's Organization Custom Property Values API. + /// + /// + /// See the Custom Properties API documentation for more information. + /// + IOrganizationCustomPropertyValuesClient Values { get; } + } +} diff --git a/Octokit/Clients/IOrganizationCustomPropertyValuesClient.cs b/Octokit/Clients/IOrganizationCustomPropertyValuesClient.cs new file mode 100644 index 0000000000..43a918995d --- /dev/null +++ b/Octokit/Clients/IOrganizationCustomPropertyValuesClient.cs @@ -0,0 +1,45 @@ +using System.Collections.Generic; +using System.Threading.Tasks; + +namespace Octokit +{ + /// + /// A client for GitHub's Organization Custom Property Values API. + /// + /// + /// See Custom Properties API documentation for more information. + /// + public interface IOrganizationCustomPropertyValuesClient + { + /// + /// Get all custom property values for repositories an organization. + /// + /// + /// See the API documentation for more information. + /// + /// The name of the organization + Task> GetAll(string org); + + /// + /// Get all custom property values for repositories an organization. + /// + /// + /// See the API documentation for more information. + /// + /// The name of the organization + /// Options for changing the API response + Task> GetAll(string org, ApiOptions options); + + /// + /// 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. + /// + /// + /// See the API documentation for more information. + /// + /// The name of the organization + /// The custom property values to create or update + Task CreateOrUpdate(string org, UpsertOrganizationCustomPropertyValues propertyValues); + } +} diff --git a/Octokit/Clients/IOrganizationsClient.cs b/Octokit/Clients/IOrganizationsClient.cs index d87d69387d..d1f86bd756 100644 --- a/Octokit/Clients/IOrganizationsClient.cs +++ b/Octokit/Clients/IOrganizationsClient.cs @@ -40,6 +40,11 @@ public interface IOrganizationsClient /// IOrganizationActionsClient Actions { get; } + /// + /// Returns a client to manage organization custom properties. + /// + IOrganizationCustomPropertiesClient CustomProperty { get; } + /// /// Returns the specified . /// diff --git a/Octokit/Clients/IRepositoriesClient.cs b/Octokit/Clients/IRepositoriesClient.cs index 67f318e12b..98daa6a9be 100644 --- a/Octokit/Clients/IRepositoriesClient.cs +++ b/Octokit/Clients/IRepositoriesClient.cs @@ -53,6 +53,14 @@ public interface IRepositoriesClient /// IRepositoryCommentsClient Comment { get; } + /// + /// Client for managing custom property values on a repository. + /// + /// + /// See the Repository Custom Properties API documentation for more information. + /// + IRepositoryCustomPropertiesClient CustomProperty { get; } + /// /// Client for managing deploy keys in a repository. /// diff --git a/Octokit/Clients/IRepositoryCustomPropertiesClient.cs b/Octokit/Clients/IRepositoryCustomPropertiesClient.cs new file mode 100644 index 0000000000..614531f45f --- /dev/null +++ b/Octokit/Clients/IRepositoryCustomPropertiesClient.cs @@ -0,0 +1,35 @@ +using System.Collections.Generic; +using System.Threading.Tasks; + +namespace Octokit +{ + /// + /// A client for GitHub's Repository Custom Property Values API. + /// + /// + /// See the Custom Properties API documentation for more information. + /// + public interface IRepositoryCustomPropertiesClient + { + /// + /// Get all custom property values for a repository. + /// + /// + /// See the API documentation for more information. + /// + /// The owner of the repository. + /// The name of the repository. + Task> GetAll(string owner, string repoName); + + /// + /// 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. + /// + /// + /// See the API documentation for more information. + /// + /// The owner of the repository + /// The name of the repository + /// The custom property values to create or update + Task> CreateOrUpdate(string owner, string repoName, UpsertRepositoryCustomPropertyValues upsertPropertyValues); + } +} diff --git a/Octokit/Clients/OrganizationCustomPropertiesClient.cs b/Octokit/Clients/OrganizationCustomPropertiesClient.cs new file mode 100644 index 0000000000..addaf3a39e --- /dev/null +++ b/Octokit/Clients/OrganizationCustomPropertiesClient.cs @@ -0,0 +1,121 @@ +using System.Collections.Generic; +using System.Threading.Tasks; + +namespace Octokit +{ + public class OrganizationCustomPropertiesClient : ApiClient, IOrganizationCustomPropertiesClient + { + /// + /// Initializes a new GitHub Organization Custom Properties API client. + /// + /// An API connection. + public OrganizationCustomPropertiesClient(IApiConnection apiConnection) + : base(apiConnection) + { + Values = new OrganizationCustomPropertyValuesClient(apiConnection); + } + + /// + /// Get all custom properties for an organization. + /// + /// + /// See the API documentation for more information. + /// + /// The name of the organization + [ManualRoute("GET", "orgs/{org}/properties/schemas")] + public Task> GetAll(string org) + { + Ensure.ArgumentNotNullOrEmptyString(org, nameof(org)); + + var url = ApiUrls.OrganizationCustomProperties(org); + + return ApiConnection.GetAll(url); + } + + /// + /// Get a single custom property by name. + /// + /// + /// See the API documentation for more information. + /// + /// The name of the organization + /// The name of the custom property + [ManualRoute("GET", "orgs/{org}/properties/schemas/{custom_property_name}")] + public Task Get(string org, string propertyName) + { + Ensure.ArgumentNotNullOrEmptyString(org, nameof(org)); + Ensure.ArgumentNotNullOrEmptyString(propertyName, nameof(propertyName)); + + var url = ApiUrls.OrganizationCustomProperty(org, propertyName); + + return ApiConnection.Get(url); + } + + /// + /// Create new or update existing custom properties for an organization. + /// + /// + /// See the API documentation for more information. + /// + /// The name of the organization + /// The custom properties to create or update + [ManualRoute("PATCH", "orgs/{org}/properties/schemas")] + public Task> CreateOrUpdate(string org, UpsertOrganizationCustomProperties properties) + { + Ensure.ArgumentNotNullOrEmptyString(org, nameof(org)); + Ensure.ArgumentNotNull(properties, nameof(properties)); + + var url = ApiUrls.OrganizationCustomProperties(org); + + return ApiConnection.Patch>(url, properties); + } + + /// + /// Create new or update existing custom property for an organization. + /// + /// + /// See the API documentation for more information. + /// + /// The name of the organization + /// The name of the custom property + /// The custom property to create or update + [ManualRoute("PUT", "orgs/{org}/properties/schemas/{custom_property_name}")] + public Task CreateOrUpdate(string org, string propertyName, OrganizationCustomProperty property) + { + Ensure.ArgumentNotNullOrEmptyString(org, nameof(org)); + Ensure.ArgumentNotNullOrEmptyString(propertyName, nameof(propertyName)); + Ensure.ArgumentNotNull(property, nameof(property)); + + var url = ApiUrls.OrganizationCustomProperty(org, propertyName); + + return ApiConnection.Put(url, property); + } + + /// + /// Removes a custom property that is defined for an organization. + /// + /// + /// See the API documentation for more information. + /// + /// The name of the organization + /// The name of the custom property + [ManualRoute("DELETE", "orgs/{org}/properties/schemas/{custom_property_name}")] + 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); + } + + /// + /// A client for GitHub's Organization Custom Property Values API. + /// + /// + /// See the Custom Properties API documentation for more information. + /// + public IOrganizationCustomPropertyValuesClient Values { get; private set; } + } +} diff --git a/Octokit/Clients/OrganizationCustomPropertyValuesClient.cs b/Octokit/Clients/OrganizationCustomPropertyValuesClient.cs new file mode 100644 index 0000000000..ed5d80f606 --- /dev/null +++ b/Octokit/Clients/OrganizationCustomPropertyValuesClient.cs @@ -0,0 +1,78 @@ +using System.Collections.Generic; +using System.Threading.Tasks; + +namespace Octokit +{ + public class OrganizationCustomPropertyValuesClient : ApiClient, IOrganizationCustomPropertyValuesClient + { + /// + /// Initializes a new GitHub Organization Custom Property Values API client. + /// + /// An API connection. + public OrganizationCustomPropertyValuesClient(IApiConnection apiConnection) + : base(apiConnection) + { + } + + /// + /// Get all custom property values for repositories an organization. + /// + /// + /// See the API documentation for more information. + /// + /// The name of the organization + /// Thrown when a general API error occurs. + [ManualRoute("GET", "orgs/{org}/properties/values")] + public Task> GetAll(string org) + { + Ensure.ArgumentNotNullOrEmptyString(org, nameof(org)); + + var url = ApiUrls.OrganizationCustomPropertyValues(org); + + return ApiConnection.GetAll(url); + } + + /// + /// Get all custom property values for repositories an organization. + /// + /// + /// See the API documentation for more information. + /// + /// The name of the organization + /// Options for changing the API response + /// Thrown when a general API error occurs. + [ManualRoute("GET", "orgs/{org}/properties/values")] + public Task> GetAll(string org, ApiOptions options) + { + Ensure.ArgumentNotNullOrEmptyString(org, nameof(org)); + Ensure.ArgumentNotNull(options, nameof(options)); + + var url = ApiUrls.OrganizationCustomPropertyValues(org); + + return ApiConnection.GetAll(url, options); + } + + /// + /// 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. + /// + /// + /// See the API documentation for more information. + /// + /// The name of the organization + /// The custom property values to create or update + /// Thrown when a general API error occurs. + [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, "application/vnd.github+json"); + } + } +} diff --git a/Octokit/Clients/OrganizationsClient.cs b/Octokit/Clients/OrganizationsClient.cs index 57abb1e716..526a30686b 100644 --- a/Octokit/Clients/OrganizationsClient.cs +++ b/Octokit/Clients/OrganizationsClient.cs @@ -23,6 +23,7 @@ public OrganizationsClient(IApiConnection apiConnection) : base(apiConnection) Hook = new OrganizationHooksClient(apiConnection); OutsideCollaborator = new OrganizationOutsideCollaboratorsClient(apiConnection); Actions = new OrganizationActionsClient(apiConnection); + CustomProperty = new OrganizationCustomPropertiesClient(apiConnection); } /// @@ -45,6 +46,11 @@ public OrganizationsClient(IApiConnection apiConnection) : base(apiConnection) /// public IOrganizationOutsideCollaboratorsClient OutsideCollaborator { get; private set; } + /// + /// Returns a client to manage organization custom properties. + /// + public IOrganizationCustomPropertiesClient CustomProperty { get; private set; } + /// /// Returns the specified . /// diff --git a/Octokit/Clients/RepositoriesClient.cs b/Octokit/Clients/RepositoriesClient.cs index 70ae3b8037..184da6614b 100644 --- a/Octokit/Clients/RepositoriesClient.cs +++ b/Octokit/Clients/RepositoriesClient.cs @@ -33,6 +33,7 @@ public RepositoriesClient(IApiConnection apiConnection) : base(apiConnection) 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 @@ public Task> GetAllForOrg(string organization, ApiOpti /// public IRepositoryCommitsClient Commit { get; private set; } + /// + /// Client for GitHub's Repository Custom Property Values API. + /// + /// + /// See the Repository Custom Properties API documentation for more details. + /// + public IRepositoryCustomPropertiesClient CustomProperty { get; private set; } + /// /// Access GitHub's Releases API. /// diff --git a/Octokit/Clients/RepositoryCustomPropertiesClient.cs b/Octokit/Clients/RepositoryCustomPropertiesClient.cs new file mode 100644 index 0000000000..52ab1b5e39 --- /dev/null +++ b/Octokit/Clients/RepositoryCustomPropertiesClient.cs @@ -0,0 +1,65 @@ +using System.Threading.Tasks; +using System.Collections.Generic; + +namespace Octokit +{ + /// + /// A client for GitHub's Repository Custom Property Values API. + /// + /// + /// See the Custom Properties API documentation for more information. + /// + public class RepositoryCustomPropertiesClient : ApiClient, IRepositoryCustomPropertiesClient + { + /// + /// Initializes a new GitHub repository custom property values API client. + /// + /// An API connection. + public RepositoryCustomPropertiesClient(IApiConnection apiConnection) + : base(apiConnection) + { + } + + /// + /// Get all custom property values for a repository. + /// + /// + /// See the API documentation for more information. + /// + /// The owner of the repository. + /// The name of the repository. + /// Thrown when a general API error occurs. + [ManualRoute("GET", "/repos/{owner}/{repo}/properties/values")] + public Task> GetAll(string owner, string repoName) + { + Ensure.ArgumentNotNullOrEmptyString(owner, nameof(owner)); + Ensure.ArgumentNotNullOrEmptyString(repoName, nameof(repoName)); + + var url = ApiUrls.RepositoryCustomPropertyValues(owner, repoName); + + return ApiConnection.GetAll(url); + } + + /// + /// 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. + /// + /// + /// See the API documentation for more information. + /// + /// The owner of the repository + /// The name of the repository + /// The custom property values to create or update + /// Thrown when a general API error occurs. + [ManualRoute("PATCH", "/repos/{owner}/{repo}/properties/values")] + public Task> CreateOrUpdate(string owner, string repoName, UpsertRepositoryCustomPropertyValues upsertPropertyValues) + { + Ensure.ArgumentNotNullOrEmptyString(owner, nameof(owner)); + Ensure.ArgumentNotNullOrEmptyString(repoName, nameof(repoName)); + Ensure.ArgumentNotNull(upsertPropertyValues, nameof(upsertPropertyValues)); + + var url = ApiUrls.RepositoryCustomPropertyValues(owner, repoName); + + return ApiConnection.Patch>(url, upsertPropertyValues); + } + } +} diff --git a/Octokit/Helpers/ApiUrls.cs b/Octokit/Helpers/ApiUrls.cs index 06849637ec..ac8c48591d 100644 --- a/Octokit/Helpers/ApiUrls.cs +++ b/Octokit/Helpers/ApiUrls.cs @@ -78,6 +78,41 @@ public static Uri OrganizationRepositories(string organization) return "orgs/{0}/repos".FormatUri(organization); } + /// + /// Returns the 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. + /// + /// The name of the organization + /// + public static Uri OrganizationCustomProperties(string organization) + { + return "orgs/{0}/properties/schema".FormatUri(organization); + } + + /// + /// Returns the 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. + /// + /// The name of the organization + /// The name of the property + /// + public static Uri OrganizationCustomProperty(string organization, string property) + { + return "orgs/{0}/properties/schema/{1}".FormatUri(organization, property); + } + + /// + /// Returns the 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. + /// + /// The name of the organization + /// + public static Uri OrganizationCustomPropertyValues(string organization) + { + return "orgs/{0}/properties/values".FormatUri(organization); + } + /// /// Returns the that returns all of the secrets for the specified organization in /// response to a GET request. @@ -4572,6 +4607,17 @@ public static Uri CheckSuitePreferences(string owner, string repo) return "repos/{0}/{1}/check-suites/preferences".FormatUri(owner, repo); } + /// + /// Returns the that handles the repository custom property values for the repository + /// + /// The owner of the repo + /// The name of the repo + /// The that handles the repository secrets for the repository + public static Uri RepositoryCustomPropertyValues(string owner, string repo) + { + return "repos/{0}/{1}/properties/values".FormatUri(owner, repo); + } + /// /// Returns the that handles the repository secrets for the repository /// diff --git a/Octokit/Models/Request/CustomPropertyValueUpdate.cs b/Octokit/Models/Request/CustomPropertyValueUpdate.cs new file mode 100644 index 0000000000..f901c3f678 --- /dev/null +++ b/Octokit/Models/Request/CustomPropertyValueUpdate.cs @@ -0,0 +1,41 @@ +using System.Collections.Generic; +using System.Diagnostics; + +namespace Octokit +{ + /// + /// Custom property name and associated value + /// + [DebuggerDisplay("{DebuggerDisplay,nq}")] + public class CustomPropertyValueUpdate + { + public CustomPropertyValueUpdate() { } + + public CustomPropertyValueUpdate(string propertyName, string value) + { + PropertyName = propertyName; + Value = value; + } + + public CustomPropertyValueUpdate(string propertyName, IReadOnlyList value) + { + PropertyName = propertyName; + Values = value; + } + + /// + /// The name of the property + /// + public string PropertyName { get; set; } + + /// + /// The value assigned to the property + /// + public string Value { get; set; } + + /// + /// The values assigned to the property + /// + public IReadOnlyList Values { get; set; } + } +} diff --git a/Octokit/Models/Request/OrganizationCustomPropertyUpdate.cs b/Octokit/Models/Request/OrganizationCustomPropertyUpdate.cs new file mode 100644 index 0000000000..c1829402bf --- /dev/null +++ b/Octokit/Models/Request/OrganizationCustomPropertyUpdate.cs @@ -0,0 +1,77 @@ +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, bool required, IReadOnlyList defaultValue, string description, IReadOnlyList allowedValues, CustomPropertyValuesEditableBy? valuesEditableBy) + { + PropertyName = propertyName; + ValueType = valueType; + Required = required; + DefaultValues = defaultValue; + Description = description; + AllowedValues = allowedValues; + ValuesEditableBy = valuesEditableBy; + } + + public OrganizationCustomPropertyUpdate(string propertyName, CustomPropertyValueType valueType, bool required, string defaultValue, string description, IReadOnlyList allowedValues, CustomPropertyValuesEditableBy? valuesEditableBy) + { + PropertyName = propertyName; + ValueType = valueType; + Required = required; + DefaultValue = defaultValue; + Description = description; + AllowedValues = allowedValues; + ValuesEditableBy = valuesEditableBy; + } + + /// + /// The name of the property + /// + public string PropertyName { get; set; } + + /// + /// The type of the value for the property + /// + public StringEnum? ValueType { get; set; } + + /// + /// Whether the property is required + /// + public bool Required { get; set; } + + /// + /// Default value of the property + /// + public string DefaultValue { get; set; } + + /// + /// Default values of the property + /// + public IReadOnlyList DefaultValues { get; set; } + + /// + /// Short description of the property + /// + public string Description { get; set; } + + /// + /// An ordered list of the allowed values of the property. + /// The property can have up to 200 allowed values. + /// + public IEnumerable AllowedValues { get; set; } + + /// + /// Who can edit the values of the property + /// + public StringEnum? ValuesEditableBy { get; set; } + + internal string DebuggerDisplay => string.Format(CultureInfo.InvariantCulture, "PropertyName: {0}", PropertyName); + } +} diff --git a/Octokit/Models/Request/UpsertOrganizationCustomProperties.cs b/Octokit/Models/Request/UpsertOrganizationCustomProperties.cs new file mode 100644 index 0000000000..35c449f31b --- /dev/null +++ b/Octokit/Models/Request/UpsertOrganizationCustomProperties.cs @@ -0,0 +1,38 @@ +using System.Collections.Generic; +using System.Diagnostics; +using System.Globalization; +using Octokit.Internal; + +namespace Octokit +{ + /// + /// Used to create or update custom property values for a repository + /// + [DebuggerDisplay("{DebuggerDisplay,nq}")] + public class UpsertOrganizationCustomProperties + { + public UpsertOrganizationCustomProperties() { } + + public UpsertOrganizationCustomProperties(IReadOnlyList properties) + { + Properties = properties; + } + + /// + /// List of organization custom properties + /// + /// + /// See the API documentation for more information. + /// + [Parameter(Value = "properties")] + public IReadOnlyList Properties { get; set; } + + internal string DebuggerDisplay + { + get + { + return string.Format(CultureInfo.InvariantCulture, "Count: {0}", Properties?.Count); + } + } + } +} diff --git a/Octokit/Models/Request/UpsertOrganizationCustomPropertyValues.cs b/Octokit/Models/Request/UpsertOrganizationCustomPropertyValues.cs new file mode 100644 index 0000000000..2eb54dd87d --- /dev/null +++ b/Octokit/Models/Request/UpsertOrganizationCustomPropertyValues.cs @@ -0,0 +1,48 @@ +using System.Collections.Generic; +using System.Diagnostics; +using System.Globalization; +using Octokit.Internal; + +namespace Octokit +{ + /// + /// Used to create or update custom property values for organization repositories + /// + [DebuggerDisplay("{DebuggerDisplay,nq}")] + public class UpsertOrganizationCustomPropertyValues + { + public UpsertOrganizationCustomPropertyValues() { } + + public UpsertOrganizationCustomPropertyValues(IReadOnlyList repositoryNames, IReadOnlyList properties) + { + RepositoryNames = repositoryNames; + Properties = properties; + } + + /// + /// List of repository names that should create or update custom property values + /// + /// + /// See the API documentation for more information. + /// + [Parameter(Value = "repository_names")] + public IReadOnlyList RepositoryNames { get; set; } + + /// + /// List of organization custom properties + /// + /// + /// See the API documentation for more information. + /// + [Parameter(Value = "properties")] + public IReadOnlyList Properties { get; set; } + + internal string DebuggerDisplay + { + get + { + return string.Format(CultureInfo.InvariantCulture, "Count: {0}", Properties?.Count); + } + } + } +} diff --git a/Octokit/Models/Request/UpsertRepositoryCustomPropertyValues.cs b/Octokit/Models/Request/UpsertRepositoryCustomPropertyValues.cs new file mode 100644 index 0000000000..a3697fb436 --- /dev/null +++ b/Octokit/Models/Request/UpsertRepositoryCustomPropertyValues.cs @@ -0,0 +1,31 @@ +using System.Collections.Generic; +using System.Diagnostics; +using System.Globalization; +using Octokit.Internal; + +namespace Octokit +{ + /// + /// Used to create or update custom property values for a repository + /// + [DebuggerDisplay("{DebuggerDisplay,nq}")] + public class UpsertRepositoryCustomPropertyValues + { + /// + /// List of custom property names and associated values + /// + /// + /// See the API documentation for more information. + /// + [Parameter(Value = "properties")] + public IReadOnlyList Properties { get; set; } + + internal string DebuggerDisplay + { + get + { + return string.Format(CultureInfo.InvariantCulture, "Count: {0}", Properties?.Count); + } + } + } +} diff --git a/Octokit/Models/Response/CustomPropertyValue.cs b/Octokit/Models/Response/CustomPropertyValue.cs new file mode 100644 index 0000000000..1364dd1bc7 --- /dev/null +++ b/Octokit/Models/Response/CustomPropertyValue.cs @@ -0,0 +1,41 @@ +using System.Collections.Generic; +using System.Diagnostics; + +namespace Octokit +{ + /// + /// Custom property name and associated value + /// + [DebuggerDisplay("{DebuggerDisplay,nq}")] + public class CustomPropertyValue + { + public CustomPropertyValue() { } + + public CustomPropertyValue(string propertyName, string value) + { + PropertyName = propertyName; + Value = value; + } + + public CustomPropertyValue(string propertyName, IReadOnlyList value) + { + PropertyName = propertyName; + Values = value; + } + + /// + /// The name of the property + /// + public string PropertyName { get; private set; } + + /// + /// The value assigned to the property + /// + public string Value { get; private set; } + + /// + /// The values assigned to the property + /// + public IReadOnlyList Values { get; private set; } + } +} diff --git a/Octokit/Models/Response/CustomPropertyValueType.cs b/Octokit/Models/Response/CustomPropertyValueType.cs new file mode 100644 index 0000000000..6447b75a30 --- /dev/null +++ b/Octokit/Models/Response/CustomPropertyValueType.cs @@ -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, + } +} diff --git a/Octokit/Models/Response/CustomPropertyValuesEditableBy.cs b/Octokit/Models/Response/CustomPropertyValuesEditableBy.cs new file mode 100644 index 0000000000..5dc074a7b9 --- /dev/null +++ b/Octokit/Models/Response/CustomPropertyValuesEditableBy.cs @@ -0,0 +1,12 @@ +using Octokit.Internal; + +namespace Octokit +{ + public enum CustomPropertyValuesEditableBy + { + [Parameter(Value = "org_actors")] + OrgActors, + [Parameter(Value = "org_and_repo_actors")] + OrgAndRepoActors, + } +} diff --git a/Octokit/Models/Response/OrganizationCustomProperty.cs b/Octokit/Models/Response/OrganizationCustomProperty.cs new file mode 100644 index 0000000000..b36d96f444 --- /dev/null +++ b/Octokit/Models/Response/OrganizationCustomProperty.cs @@ -0,0 +1,77 @@ +using System.Collections.Generic; +using System.Diagnostics; +using System.Globalization; + +namespace Octokit +{ + [DebuggerDisplay("{DebuggerDisplay,nq}")] + public class OrganizationCustomProperty + { + public OrganizationCustomProperty() { } + + public OrganizationCustomProperty(string propertyName, CustomPropertyValueType valueType, bool required, IReadOnlyList defaultValue, string description, IReadOnlyList allowedValues, CustomPropertyValuesEditableBy? valuesEditableBy) + { + PropertyName = propertyName; + ValueType = valueType; + Required = required; + DefaultValues = defaultValue; + Description = description; + AllowedValues = allowedValues; + ValuesEditableBy = valuesEditableBy; + } + + public OrganizationCustomProperty(string propertyName, CustomPropertyValueType valueType, bool required, string defaultValue, string description, IReadOnlyList allowedValues, CustomPropertyValuesEditableBy? valuesEditableBy) + { + PropertyName = propertyName; + ValueType = valueType; + Required = required; + DefaultValue = defaultValue; + Description = description; + AllowedValues = allowedValues; + ValuesEditableBy = valuesEditableBy; + } + + /// + /// The name of the property + /// + public string PropertyName { get; private set; } + + /// + /// The type of the value for the property + /// + public StringEnum? ValueType { get; private set; } + + /// + /// Whether the property is required + /// + public bool Required { get; private set; } + + /// + /// Default value of the property + /// + public string DefaultValue { get; private set; } + + /// + /// Default values of the property + /// + public IReadOnlyList DefaultValues { get; private set; } + + /// + /// Short description of the property + /// + public string Description { get; private set; } + + /// + /// An ordered list of the allowed values of the property. + /// The property can have up to 200 allowed values. + /// + public IEnumerable AllowedValues { get; private set; } + + /// + /// Who can edit the values of the property + /// + public StringEnum? ValuesEditableBy { get; private set; } + + internal string DebuggerDisplay => string.Format(CultureInfo.InvariantCulture, "PropertyName: {0}", PropertyName); + } +} diff --git a/Octokit/Models/Response/OrganizationCustomPropertyValues.cs b/Octokit/Models/Response/OrganizationCustomPropertyValues.cs new file mode 100644 index 0000000000..30b0fb6e4d --- /dev/null +++ b/Octokit/Models/Response/OrganizationCustomPropertyValues.cs @@ -0,0 +1,45 @@ +using System.Collections.Generic; +using System.Diagnostics; +using System.Globalization; + +namespace Octokit +{ + /// + /// List of custom property values for a repository + /// + [DebuggerDisplay("{DebuggerDisplay,nq}")] + public class OrganizationCustomPropertyValues + { + public OrganizationCustomPropertyValues() { } + + public OrganizationCustomPropertyValues(long repositoryId, string repositoryName, string repositoryFullName, IReadOnlyList properties) + { + RepositoryId = repositoryId; + RepositoryName = repositoryName; + RepositoryFullName = repositoryFullName; + Properties = properties; + } + + /// + /// The repository Id + /// + public long RepositoryId { get; private set; } + + /// + /// The name of the repository + /// + public string RepositoryName { get; private set; } + + /// + /// The full name of the repository (owner/repo) + /// + public string RepositoryFullName { get; private set; } + + /// + /// List of custom property names and associated values + /// + public IReadOnlyList Properties { get; private set; } + + internal string DebuggerDisplay => string.Format(CultureInfo.InvariantCulture, "RepositoryFullName: {0}", RepositoryFullName); + } +} diff --git a/Octokit/Models/Response/Repository.cs b/Octokit/Models/Response/Repository.cs index 91ee81c041..6533643e07 100644 --- a/Octokit/Models/Response/Repository.cs +++ b/Octokit/Models/Response/Repository.cs @@ -17,7 +17,7 @@ public Repository(long id) 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 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 topics, bool? allowAutoMerge, bool? allowUpdateBranch, bool? webCommitSignoffRequired, IReadOnlyDictionary customProperties) { Url = url; HtmlUrl = htmlUrl; @@ -69,6 +69,7 @@ public Repository(string url, string htmlUrl, string cloneUrl, string gitUrl, st AllowAutoMerge = allowAutoMerge; AllowUpdateBranch = allowUpdateBranch; WebCommitSignoffRequired = webCommitSignoffRequired; + CustomProperties = customProperties; } public string Url { get; private set; } @@ -170,6 +171,8 @@ public Repository(string url, string htmlUrl, string cloneUrl, string gitUrl, st public bool? WebCommitSignoffRequired { get; private set; } + public IReadOnlyDictionary CustomProperties { get; private set; } + internal string DebuggerDisplay { get From 245d2650c9e3912a393ef5ccdb45986b44bf2925 Mon Sep 17 00:00:00 2001 From: Colby Williams Date: Sat, 15 Jun 2024 03:34:10 -0500 Subject: [PATCH 02/11] observable --- ...vableOrganizationCustomPropertiesClient.cs | 73 ++++++++++++ ...eOrganizationCustomPropertyValuesClient.cs | 46 ++++++++ .../Clients/IObservableOrganizationsClient.cs | 5 + .../Clients/IObservableRepositoriesClient.cs | 8 ++ ...ervableRepositoryCustomPropertiesClient.cs | 35 ++++++ ...vableOrganizationCustomPropertiesClient.cs | 111 ++++++++++++++++++ ...eOrganizationCustomPropertyValuesClient.cs | 73 ++++++++++++ .../Clients/ObservableOrganizationsClient.cs | 6 + .../Clients/ObservableRepositoriesClient.cs | 9 ++ ...ervableRepositoryCustomPropertiesClient.cs | 62 ++++++++++ 10 files changed, 428 insertions(+) create mode 100644 Octokit.Reactive/Clients/IObservableOrganizationCustomPropertiesClient.cs create mode 100644 Octokit.Reactive/Clients/IObservableOrganizationCustomPropertyValuesClient.cs create mode 100644 Octokit.Reactive/Clients/IObservableRepositoryCustomPropertiesClient.cs create mode 100644 Octokit.Reactive/Clients/ObservableOrganizationCustomPropertiesClient.cs create mode 100644 Octokit.Reactive/Clients/ObservableOrganizationCustomPropertyValuesClient.cs create mode 100644 Octokit.Reactive/Clients/ObservableRepositoryCustomPropertiesClient.cs diff --git a/Octokit.Reactive/Clients/IObservableOrganizationCustomPropertiesClient.cs b/Octokit.Reactive/Clients/IObservableOrganizationCustomPropertiesClient.cs new file mode 100644 index 0000000000..622652c0f1 --- /dev/null +++ b/Octokit.Reactive/Clients/IObservableOrganizationCustomPropertiesClient.cs @@ -0,0 +1,73 @@ +using System; +using System.Collections.Generic; +using System.Reactive; + +namespace Octokit +{ + /// + /// A client for GitHub's Organization Custom Properties API. + /// + /// + /// See Custom Properties API documentation for more information. + /// + public interface IObservableOrganizationCustomPropertiesClient + { + /// + /// Get all custom properties for an organization. + /// + /// + /// See the API documentation for more information. + /// + /// The name of the organization + IObservable> GetAll(string org); + + /// + /// Get a single custom property by name. + /// + /// + /// See the API documentation for more information. + /// + /// The name of the organization + /// The name of the custom property + IObservable Get(string org, string propertyName); + + /// + /// Create new or update existing custom properties for an organization. + /// + /// + /// See the API documentation for more information. + /// + /// The name of the organization + /// The custom properties to create or update + IObservable> CreateOrUpdate(string org, UpsertOrganizationCustomProperties properties); + + /// + /// Create new or update existing custom property for an organization. + /// + /// + /// See the API documentation for more information. + /// + /// The name of the organization + /// The name of the custom property + /// The custom property to create or update + IObservable CreateOrUpdate(string org, string propertyName, OrganizationCustomProperty property); + + /// + /// Removes a custom property that is defined for an organization. + /// + /// + /// See the API documentation for more information. + /// + /// The name of the organization + /// The name of the custom property + IObservable Delete(string org, string propertyName); + + /// + /// A client for GitHub's Organization Custom Property Values API. + /// + /// + /// See the Custom Properties API documentation for more information. + /// + IObservableOrganizationCustomPropertyValuesClient Values { get; } + } +} diff --git a/Octokit.Reactive/Clients/IObservableOrganizationCustomPropertyValuesClient.cs b/Octokit.Reactive/Clients/IObservableOrganizationCustomPropertyValuesClient.cs new file mode 100644 index 0000000000..f29f787b40 --- /dev/null +++ b/Octokit.Reactive/Clients/IObservableOrganizationCustomPropertyValuesClient.cs @@ -0,0 +1,46 @@ +using System; +using System.Collections.Generic; +using System.Reactive; + +namespace Octokit +{ + /// + /// A client for GitHub's Organization Custom Property Values API. + /// + /// + /// See Custom Properties API documentation for more information. + /// + public interface IObservableOrganizationCustomPropertyValuesClient + { + /// + /// Get all custom property values for repositories an organization. + /// + /// + /// See the API documentation for more information. + /// + /// The name of the organization + IObservable> GetAll(string org); + + /// + /// Get all custom property values for repositories an organization. + /// + /// + /// See the API documentation for more information. + /// + /// The name of the organization + /// Options for changing the API response + IObservable> GetAll(string org, ApiOptions options); + + /// + /// 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. + /// + /// + /// See the API documentation for more information. + /// + /// The name of the organization + /// The custom property values to create or update + IObservable CreateOrUpdate(string org, UpsertOrganizationCustomPropertyValues propertyValues); + } +} diff --git a/Octokit.Reactive/Clients/IObservableOrganizationsClient.cs b/Octokit.Reactive/Clients/IObservableOrganizationsClient.cs index d44a187990..673b132dfb 100644 --- a/Octokit.Reactive/Clients/IObservableOrganizationsClient.cs +++ b/Octokit.Reactive/Clients/IObservableOrganizationsClient.cs @@ -31,6 +31,11 @@ public interface IObservableOrganizationsClient /// IObservableOrganizationActionsClient Actions { get; } + /// + /// Returns a client to manage organization custom properties. + /// + IObservableOrganizationCustomPropertiesClient CustomProperty { get; } + /// /// Returns the specified organization. /// diff --git a/Octokit.Reactive/Clients/IObservableRepositoriesClient.cs b/Octokit.Reactive/Clients/IObservableRepositoriesClient.cs index 763c56056f..18d14e306b 100644 --- a/Octokit.Reactive/Clients/IObservableRepositoriesClient.cs +++ b/Octokit.Reactive/Clients/IObservableRepositoriesClient.cs @@ -255,6 +255,14 @@ public interface IObservableRepositoriesClient /// IObservableRepositoryCommentsClient Comment { get; } + /// + /// Client for GitHub's Repository Custom Property Values API. + /// + /// + /// See the Repository Custom Property API documentation for more information. + /// + IObservableRepositoryCustomPropertiesClient CustomProperty { get; } + /// /// A client for GitHub's Repository Hooks API. /// diff --git a/Octokit.Reactive/Clients/IObservableRepositoryCustomPropertiesClient.cs b/Octokit.Reactive/Clients/IObservableRepositoryCustomPropertiesClient.cs new file mode 100644 index 0000000000..d45cbc44b1 --- /dev/null +++ b/Octokit.Reactive/Clients/IObservableRepositoryCustomPropertiesClient.cs @@ -0,0 +1,35 @@ +using System; +using System.Collections.Generic; + +namespace Octokit +{ + /// + /// A client for GitHub's Repository Custom Property Values API. + /// + /// + /// See the Custom Properties API documentation for more information. + /// + public interface IObservableRepositoryCustomPropertiesClient + { + /// + /// Get all custom property values for a repository. + /// + /// + /// See the API documentation for more information. + /// + /// The owner of the repository. + /// The name of the repository. + IObservable> GetAll(string owner, string repoName); + + /// + /// 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. + /// + /// + /// See the API documentation for more information. + /// + /// The owner of the repository + /// The name of the repository + /// The custom property values to create or update + IObservable> CreateOrUpdate(string owner, string repoName, UpsertRepositoryCustomPropertyValues upsertPropertyValues); + } +} diff --git a/Octokit.Reactive/Clients/ObservableOrganizationCustomPropertiesClient.cs b/Octokit.Reactive/Clients/ObservableOrganizationCustomPropertiesClient.cs new file mode 100644 index 0000000000..a2649598aa --- /dev/null +++ b/Octokit.Reactive/Clients/ObservableOrganizationCustomPropertiesClient.cs @@ -0,0 +1,111 @@ +using System; +using System.Collections.Generic; +using System.Reactive; +using System.Reactive.Threading.Tasks; + +namespace Octokit +{ + public class ObservableOrganizationCustomPropertiesClient : IObservableOrganizationCustomPropertiesClient + { + readonly IOrganizationCustomPropertiesClient _client; + readonly IConnection _connection; + + public ObservableOrganizationCustomPropertiesClient(IGitHubClient client) + { + Ensure.ArgumentNotNull(client, nameof(client)); + + _client = client.Organization.CustomProperty; + _connection = client.Connection; + + Values = new ObservableOrganizationCustomPropertyValuesClient(client); + } + + /// + /// Get all custom properties for an organization. + /// + /// + /// See the API documentation for more information. + /// + /// The name of the organization + public IObservable> GetAll(string org) + { + Ensure.ArgumentNotNullOrEmptyString(org, nameof(org)); + + return _client.GetAll(org).ToObservable(); + } + + /// + /// Get a single custom property by name. + /// + /// + /// See the API documentation for more information. + /// + /// The name of the organization + /// The name of the custom property + public IObservable Get(string org, string propertyName) + { + Ensure.ArgumentNotNullOrEmptyString(org, nameof(org)); + Ensure.ArgumentNotNullOrEmptyString(propertyName, nameof(propertyName)); + + return _client.Get(org, propertyName).ToObservable(); + } + + /// + /// Create new or update existing custom properties for an organization. + /// + /// + /// See the API documentation for more information. + /// + /// The name of the organization + /// The custom properties to create or update + public IObservable> CreateOrUpdate(string org, UpsertOrganizationCustomProperties properties) + { + Ensure.ArgumentNotNullOrEmptyString(org, nameof(org)); + Ensure.ArgumentNotNull(properties, nameof(properties)); + + return _client.CreateOrUpdate(org, properties).ToObservable(); + } + + /// + /// Create new or update existing custom property for an organization. + /// + /// + /// See the API documentation for more information. + /// + /// The name of the organization + /// The name of the custom property + /// The custom property to create or update + public IObservable CreateOrUpdate(string org, string propertyName, OrganizationCustomProperty property) + { + Ensure.ArgumentNotNullOrEmptyString(org, nameof(org)); + Ensure.ArgumentNotNullOrEmptyString(propertyName, nameof(propertyName)); + Ensure.ArgumentNotNull(property, nameof(property)); + + return _client.CreateOrUpdate(org, propertyName, property).ToObservable(); + } + + /// + /// Removes a custom property that is defined for an organization. + /// + /// + /// See the API documentation for more information. + /// + /// The name of the organization + /// The name of the custom property + public IObservable Delete(string org, string propertyName) + { + Ensure.ArgumentNotNullOrEmptyString(org, nameof(org)); + Ensure.ArgumentNotNullOrEmptyString(propertyName, nameof(propertyName)); + + return _client.Delete(org, propertyName).ToObservable(); + } + + /// + /// A client for GitHub's Organization Custom Property Values API. + /// + /// + /// See the Custom Properties API documentation for more information. + /// + public IObservableOrganizationCustomPropertyValuesClient Values { get; private set; } + } +} diff --git a/Octokit.Reactive/Clients/ObservableOrganizationCustomPropertyValuesClient.cs b/Octokit.Reactive/Clients/ObservableOrganizationCustomPropertyValuesClient.cs new file mode 100644 index 0000000000..ddda3bf6e8 --- /dev/null +++ b/Octokit.Reactive/Clients/ObservableOrganizationCustomPropertyValuesClient.cs @@ -0,0 +1,73 @@ +using System; +using System.Collections.Generic; +using System.Reactive; +using System.Reactive.Threading.Tasks; + +namespace Octokit +{ + public class ObservableOrganizationCustomPropertyValuesClient : IObservableOrganizationCustomPropertyValuesClient + { + readonly IOrganizationCustomPropertyValuesClient _client; + readonly IConnection _connection; + + public ObservableOrganizationCustomPropertyValuesClient(IGitHubClient client) + { + Ensure.ArgumentNotNull(client, nameof(client)); + + _client = client.Organization.CustomProperty.Values; + _connection = client.Connection; + } + + /// + /// Get all custom property values for repositories an organization. + /// + /// + /// See the API documentation for more information. + /// + /// The name of the organization + /// Thrown when a general API error occurs. + public IObservable> GetAll(string org) + { + Ensure.ArgumentNotNullOrEmptyString(org, nameof(org)); + + return _client.GetAll(org).ToObservable(); + } + + /// + /// Get all custom property values for repositories an organization. + /// + /// + /// See the API documentation for more information. + /// + /// The name of the organization + /// Options for changing the API response + /// Thrown when a general API error occurs. + public IObservable> GetAll(string org, ApiOptions options) + { + Ensure.ArgumentNotNullOrEmptyString(org, nameof(org)); + Ensure.ArgumentNotNull(options, nameof(options)); + + return _client.GetAll(org, options).ToObservable(); + } + + /// + /// 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. + /// + /// + /// See the API documentation for more information. + /// + /// The name of the organization + /// The custom property values to create or update + /// Thrown when a general API error occurs. + public IObservable CreateOrUpdate(string org, UpsertOrganizationCustomPropertyValues propertyValues) + { + Ensure.ArgumentNotNullOrEmptyString(org, nameof(org)); + Ensure.ArgumentNotNull(propertyValues, nameof(propertyValues)); + Ensure.ArgumentNotNullOrEmptyEnumerable(propertyValues.Properties, nameof(propertyValues.Properties)); + + return _client.CreateOrUpdate(org, propertyValues).ToObservable(); + } + } +} diff --git a/Octokit.Reactive/Clients/ObservableOrganizationsClient.cs b/Octokit.Reactive/Clients/ObservableOrganizationsClient.cs index e90bac920f..ba00ebf32d 100644 --- a/Octokit.Reactive/Clients/ObservableOrganizationsClient.cs +++ b/Octokit.Reactive/Clients/ObservableOrganizationsClient.cs @@ -23,6 +23,7 @@ public ObservableOrganizationsClient(IGitHubClient client) Hook = new ObservableOrganizationHooksClient(client); OutsideCollaborator = new ObservableOrganizationOutsideCollaboratorsClient(client); Actions = new ObservableOrganizationActionsClient(client); + CustomProperty = new ObservableOrganizationCustomPropertiesClient(client); _client = client.Organization; _connection = client.Connection; @@ -54,6 +55,11 @@ public ObservableOrganizationsClient(IGitHubClient client) /// public IObservableOrganizationActionsClient Actions { get; private set; } + /// + /// Returns a client to manage organization custom properties. + /// + public IObservableOrganizationCustomPropertiesClient CustomProperty { get; private set; } + /// /// Returns the specified organization. /// diff --git a/Octokit.Reactive/Clients/ObservableRepositoriesClient.cs b/Octokit.Reactive/Clients/ObservableRepositoriesClient.cs index 26f35b1f6a..3cfd202b7c 100644 --- a/Octokit.Reactive/Clients/ObservableRepositoriesClient.cs +++ b/Octokit.Reactive/Clients/ObservableRepositoriesClient.cs @@ -33,6 +33,7 @@ public ObservableRepositoriesClient(IGitHubClient client) Branch = new ObservableRepositoryBranchesClient(client); Comment = new ObservableRepositoryCommentsClient(client); Commit = new ObservableRepositoryCommitsClient(client); + CustomProperty = new ObservableRepositoryCustomPropertiesClient(client); Release = new ObservableReleasesClient(client); DeployKeys = new ObservableRepositoryDeployKeysClient(client); Content = new ObservableRepositoryContentsClient(client); @@ -380,6 +381,14 @@ public IObservable GetAllForOrg(string organization, ApiOptions opti /// public IObservableRepositoryCommentsClient Comment { get; private set; } + /// + /// Client for GitHub's Repository Custom Property Values API. + /// + /// + /// See the Repository Custom Property API documentation for more information. + /// + public IObservableRepositoryCustomPropertiesClient CustomProperty { get; private set; } + /// /// A client for GitHub's Repository Hooks API. /// diff --git a/Octokit.Reactive/Clients/ObservableRepositoryCustomPropertiesClient.cs b/Octokit.Reactive/Clients/ObservableRepositoryCustomPropertiesClient.cs new file mode 100644 index 0000000000..6877e361a3 --- /dev/null +++ b/Octokit.Reactive/Clients/ObservableRepositoryCustomPropertiesClient.cs @@ -0,0 +1,62 @@ +using System.Collections.Generic; +using System.Reactive.Threading.Tasks; +using System; + +namespace Octokit +{ + /// + /// A client for GitHub's Repository Custom Property Values API. + /// + /// + /// See the Custom Properties API documentation for more information. + /// + public class ObservableRepositoryCustomPropertiesClient : IObservableRepositoryCustomPropertiesClient + { + readonly IRepositoryCustomPropertiesClient _client; + readonly IConnection _connection; + + public ObservableRepositoryCustomPropertiesClient(IGitHubClient client) + { + Ensure.ArgumentNotNull(client, nameof(client)); + + _client = client.Repository.CustomProperty; + _connection = client.Connection; + } + + /// + /// Get all custom property values for a repository. + /// + /// + /// See the API documentation for more information. + /// + /// The owner of the repository. + /// The name of the repository. + /// Thrown when a general API error occurs. + public IObservable> GetAll(string owner, string repoName) + { + Ensure.ArgumentNotNullOrEmptyString(owner, nameof(owner)); + Ensure.ArgumentNotNullOrEmptyString(repoName, nameof(repoName)); + + return _client.GetAll(owner, repoName).ToObservable(); + } + + /// + /// 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. + /// + /// + /// See the API documentation for more information. + /// + /// The owner of the repository + /// The name of the repository + /// The custom property values to create or update + /// Thrown when a general API error occurs. + public IObservable> CreateOrUpdate(string owner, string repoName, UpsertRepositoryCustomPropertyValues upsertPropertyValues) + { + Ensure.ArgumentNotNullOrEmptyString(owner, nameof(owner)); + Ensure.ArgumentNotNullOrEmptyString(repoName, nameof(repoName)); + Ensure.ArgumentNotNull(upsertPropertyValues, nameof(upsertPropertyValues)); + + return _client.CreateOrUpdate(owner, repoName, upsertPropertyValues).ToObservable(); + } + } +} From 4b4e66714aa0c3645c593408e9f172957931c6d3 Mon Sep 17 00:00:00 2001 From: Colby Williams Date: Sat, 15 Jun 2024 15:11:13 -0500 Subject: [PATCH 03/11] observable tests --- ...vableOrganizationCustomPropertiesClient.cs | 4 +- ...eOrganizationCustomPropertyValuesClient.cs | 2 +- ...ervableRepositoryCustomPropertiesClient.cs | 6 +- ...vableOrganizationCustomPropertiesClient.cs | 4 +- ...eOrganizationCustomPropertyValuesClient.cs | 2 +- ...ervableRepositoryCustomPropertiesClient.cs | 10 +- ...OrganizationCustomPropertiesClientTests.cs | 172 ++++++++++++++++++ ...nizationCustomPropertyValuesClientTests.cs | 81 +++++++++ .../RepositoryCustomPropertiesClientTests.cs | 84 +++++++++ ...OrganizationCustomPropertiesClientTests.cs | 169 +++++++++++++++++ ...nizationCustomPropertyValuesClientTests.cs | 82 +++++++++ ...leRepositoryCustomPropertiesClientTests.cs | 84 +++++++++ .../IOrganizationCustomPropertiesClient.cs | 2 +- .../IRepositoryCustomPropertiesClient.cs | 4 +- .../OrganizationCustomPropertiesClient.cs | 2 +- .../RepositoryCustomPropertiesClient.cs | 8 +- .../UpsertOrganizationCustomProperties.cs | 4 +- .../UpsertOrganizationCustomPropertyValues.cs | 6 +- .../UpsertRepositoryCustomPropertyValues.cs | 2 +- 19 files changed, 700 insertions(+), 28 deletions(-) create mode 100644 Octokit.Tests/Clients/OrganizationCustomPropertiesClientTests.cs create mode 100644 Octokit.Tests/Clients/OrganizationCustomPropertyValuesClientTests.cs create mode 100644 Octokit.Tests/Clients/RepositoryCustomPropertiesClientTests.cs create mode 100644 Octokit.Tests/Reactive/ObservableOrganizationCustomPropertiesClientTests.cs create mode 100644 Octokit.Tests/Reactive/ObservableOrganizationCustomPropertyValuesClientTests.cs create mode 100644 Octokit.Tests/Reactive/ObservableRepositoryCustomPropertiesClientTests.cs diff --git a/Octokit.Reactive/Clients/IObservableOrganizationCustomPropertiesClient.cs b/Octokit.Reactive/Clients/IObservableOrganizationCustomPropertiesClient.cs index 622652c0f1..6b34d3ed62 100644 --- a/Octokit.Reactive/Clients/IObservableOrganizationCustomPropertiesClient.cs +++ b/Octokit.Reactive/Clients/IObservableOrganizationCustomPropertiesClient.cs @@ -2,7 +2,7 @@ using System.Collections.Generic; using System.Reactive; -namespace Octokit +namespace Octokit.Reactive { /// /// A client for GitHub's Organization Custom Properties API. @@ -50,7 +50,7 @@ public interface IObservableOrganizationCustomPropertiesClient /// The name of the organization /// The name of the custom property /// The custom property to create or update - IObservable CreateOrUpdate(string org, string propertyName, OrganizationCustomProperty property); + IObservable CreateOrUpdate(string org, string propertyName, OrganizationCustomPropertyUpdate property); /// /// Removes a custom property that is defined for an organization. diff --git a/Octokit.Reactive/Clients/IObservableOrganizationCustomPropertyValuesClient.cs b/Octokit.Reactive/Clients/IObservableOrganizationCustomPropertyValuesClient.cs index f29f787b40..0715439bd8 100644 --- a/Octokit.Reactive/Clients/IObservableOrganizationCustomPropertyValuesClient.cs +++ b/Octokit.Reactive/Clients/IObservableOrganizationCustomPropertyValuesClient.cs @@ -2,7 +2,7 @@ using System.Collections.Generic; using System.Reactive; -namespace Octokit +namespace Octokit.Reactive { /// /// A client for GitHub's Organization Custom Property Values API. diff --git a/Octokit.Reactive/Clients/IObservableRepositoryCustomPropertiesClient.cs b/Octokit.Reactive/Clients/IObservableRepositoryCustomPropertiesClient.cs index d45cbc44b1..25c8a3bc24 100644 --- a/Octokit.Reactive/Clients/IObservableRepositoryCustomPropertiesClient.cs +++ b/Octokit.Reactive/Clients/IObservableRepositoryCustomPropertiesClient.cs @@ -1,7 +1,7 @@ using System; using System.Collections.Generic; -namespace Octokit +namespace Octokit.Reactive { /// /// A client for GitHub's Repository Custom Property Values API. @@ -29,7 +29,7 @@ public interface IObservableRepositoryCustomPropertiesClient /// /// The owner of the repository /// The name of the repository - /// The custom property values to create or update - IObservable> CreateOrUpdate(string owner, string repoName, UpsertRepositoryCustomPropertyValues upsertPropertyValues); + /// The custom property values to create or update + IObservable> CreateOrUpdate(string owner, string repoName, UpsertRepositoryCustomPropertyValues propertyValues); } } diff --git a/Octokit.Reactive/Clients/ObservableOrganizationCustomPropertiesClient.cs b/Octokit.Reactive/Clients/ObservableOrganizationCustomPropertiesClient.cs index a2649598aa..a20918b80d 100644 --- a/Octokit.Reactive/Clients/ObservableOrganizationCustomPropertiesClient.cs +++ b/Octokit.Reactive/Clients/ObservableOrganizationCustomPropertiesClient.cs @@ -3,7 +3,7 @@ using System.Reactive; using System.Reactive.Threading.Tasks; -namespace Octokit +namespace Octokit.Reactive { public class ObservableOrganizationCustomPropertiesClient : IObservableOrganizationCustomPropertiesClient { @@ -75,7 +75,7 @@ public IObservable> CreateOrUpdate(str /// The name of the organization /// The name of the custom property /// The custom property to create or update - public IObservable CreateOrUpdate(string org, string propertyName, OrganizationCustomProperty property) + public IObservable CreateOrUpdate(string org, string propertyName, OrganizationCustomPropertyUpdate property) { Ensure.ArgumentNotNullOrEmptyString(org, nameof(org)); Ensure.ArgumentNotNullOrEmptyString(propertyName, nameof(propertyName)); diff --git a/Octokit.Reactive/Clients/ObservableOrganizationCustomPropertyValuesClient.cs b/Octokit.Reactive/Clients/ObservableOrganizationCustomPropertyValuesClient.cs index ddda3bf6e8..6a11493f1b 100644 --- a/Octokit.Reactive/Clients/ObservableOrganizationCustomPropertyValuesClient.cs +++ b/Octokit.Reactive/Clients/ObservableOrganizationCustomPropertyValuesClient.cs @@ -3,7 +3,7 @@ using System.Reactive; using System.Reactive.Threading.Tasks; -namespace Octokit +namespace Octokit.Reactive { public class ObservableOrganizationCustomPropertyValuesClient : IObservableOrganizationCustomPropertyValuesClient { diff --git a/Octokit.Reactive/Clients/ObservableRepositoryCustomPropertiesClient.cs b/Octokit.Reactive/Clients/ObservableRepositoryCustomPropertiesClient.cs index 6877e361a3..10874090ea 100644 --- a/Octokit.Reactive/Clients/ObservableRepositoryCustomPropertiesClient.cs +++ b/Octokit.Reactive/Clients/ObservableRepositoryCustomPropertiesClient.cs @@ -2,7 +2,7 @@ using System.Reactive.Threading.Tasks; using System; -namespace Octokit +namespace Octokit.Reactive { /// /// A client for GitHub's Repository Custom Property Values API. @@ -48,15 +48,15 @@ public IObservable> GetAll(string owner, stri /// /// The owner of the repository /// The name of the repository - /// The custom property values to create or update + /// The custom property values to create or update /// Thrown when a general API error occurs. - public IObservable> CreateOrUpdate(string owner, string repoName, UpsertRepositoryCustomPropertyValues upsertPropertyValues) + public IObservable> CreateOrUpdate(string owner, string repoName, UpsertRepositoryCustomPropertyValues propertyValues) { Ensure.ArgumentNotNullOrEmptyString(owner, nameof(owner)); Ensure.ArgumentNotNullOrEmptyString(repoName, nameof(repoName)); - Ensure.ArgumentNotNull(upsertPropertyValues, nameof(upsertPropertyValues)); + Ensure.ArgumentNotNull(propertyValues, nameof(propertyValues)); - return _client.CreateOrUpdate(owner, repoName, upsertPropertyValues).ToObservable(); + return _client.CreateOrUpdate(owner, repoName, propertyValues).ToObservable(); } } } diff --git a/Octokit.Tests/Clients/OrganizationCustomPropertiesClientTests.cs b/Octokit.Tests/Clients/OrganizationCustomPropertiesClientTests.cs new file mode 100644 index 0000000000..9f13aee059 --- /dev/null +++ b/Octokit.Tests/Clients/OrganizationCustomPropertiesClientTests.cs @@ -0,0 +1,172 @@ +using NSubstitute; +using System; +using System.Collections.Generic; +using System.Threading.Tasks; +using Xunit; + +namespace Octokit.Tests.Clients +{ + public class OrganizationCustomPropertiesClientTests + { + public class TheCtor + { + [Fact] + public void EnsuresNonNullArguments() + { + Assert.Throws(() => new OrganizationCustomPropertiesClient(null)); + } + } + + public class GetAllMethod + { + [Fact] + public async Task RequestsTheCorrectUrl() + { + var connection = Substitute.For(); + var client = new OrganizationCustomPropertiesClient(connection); + + await client.GetAll("org"); + + connection.Received() + .Get>(Arg.Is(u => u.ToString() == "orgs/org/properties/schemas")); + } + + [Fact] + public async Task EnsuresNonNullArguments() + { + var client = new OrganizationCustomPropertiesClient(Substitute.For()); + + await Assert.ThrowsAsync(() => client.GetAll(null)); + await Assert.ThrowsAsync(() => client.GetAll("")); + } + } + + public class GetMethod + { + [Fact] + public async Task RequestsTheCorrectUrl() + { + var connection = Substitute.For(); + var client = new OrganizationCustomPropertiesClient(connection); + + await client.Get("org", "custom_property_name"); + + connection.Received() + .Get(Arg.Is(u => u.ToString() == "orgs/org/properties/schemas/custom_property_name")); + } + + [Fact] + public async Task EnsuresNonNullArguments() + { + var client = new OrganizationCustomPropertiesClient(Substitute.For()); + + await Assert.ThrowsAsync(() => client.Get(null, "custom_property_name")); + await Assert.ThrowsAsync(() => client.Get("org", null)); + + await Assert.ThrowsAsync(() => client.Get("", "custom_property_name")); + await Assert.ThrowsAsync(() => client.Get("org", "")); + } + } + + public class BatchCreateOrUpdateMethod + { + [Fact] + public async Task PatchTheCorrectUrl() + { + var connection = Substitute.For(); + var client = new OrganizationCustomPropertiesClient(connection); + var properties = new UpsertOrganizationCustomProperties + { + Properties = new List + { + new OrganizationCustomPropertyUpdate { PropertyName = "name", DefaultValue = "value", ValueType = CustomPropertyValueType.String } + } + }; + + await client.CreateOrUpdate("org", properties); + + connection.Received() + .Patch>(Arg.Is(u => u.ToString() == "orgs/org/properties/schemas"), properties); + } + + [Fact] + public async Task EnsuresNonNullArguments() + { + var client = new OrganizationCustomPropertiesClient(Substitute.For()); + + var properties = new UpsertOrganizationCustomProperties + { + Properties = new List + { + new OrganizationCustomPropertyUpdate { PropertyName = "name", DefaultValue = "value", ValueType = CustomPropertyValueType.String } + } + }; + + await Assert.ThrowsAsync(() => client.CreateOrUpdate(null, properties)); + await Assert.ThrowsAsync(() => client.CreateOrUpdate("owner", null)); + await Assert.ThrowsAsync(() => client.CreateOrUpdate("owner", new UpsertOrganizationCustomProperties())); + + await Assert.ThrowsAsync(() => client.CreateOrUpdate("", properties)); + } + } + + public class CreateOrUpdateMethod + { + [Fact] + public async Task PostsTheCorrectUrl() + { + var connection = Substitute.For(); + var client = new OrganizationCustomPropertiesClient(connection); + var update = new OrganizationCustomPropertyUpdate { PropertyName = "name", DefaultValue = "value", ValueType = CustomPropertyValueType.String }; + + await client.CreateOrUpdate("org", "custom_property_name", update); + + connection.Received() + .Put(Arg.Is(u => u.ToString() == "orgs/org/properties/schemas/custom_property_name"), update); + } + + [Fact] + public async Task EnsuresNonNullArguments() + { + var client = new OrganizationCustomPropertiesClient(Substitute.For()); + + var update = new OrganizationCustomPropertyUpdate { PropertyName = "name", DefaultValue = "value", ValueType = CustomPropertyValueType.String }; + + await Assert.ThrowsAsync(() => client.CreateOrUpdate(null, "custom_property_name", update)); + await Assert.ThrowsAsync(() => client.CreateOrUpdate("owner", null, update)); + await Assert.ThrowsAsync(() => client.CreateOrUpdate("owner", "custom_property_name", null)); + await Assert.ThrowsAsync(() => client.CreateOrUpdate("owner", "custom_property_name", new OrganizationCustomPropertyUpdate())); + + await Assert.ThrowsAsync(() => client.CreateOrUpdate("", "custom_property_name", update)); + await Assert.ThrowsAsync(() => client.CreateOrUpdate("owner", "", update)); + } + } + + public class DeleteMethod + { + [Fact] + public async Task DeletesTheCorrectUrl() + { + var connection = Substitute.For(); + var client = new OrganizationCustomPropertiesClient(connection); + + await client.Delete("org", "custom_property_name"); + + connection.Received() + .Delete(Arg.Is(u => u.ToString() == "orgs/org/properties/schemas/custom_property_name")); + } + + [Fact] + public async Task EnsuresNonNullArguments() + { + var client = new OrganizationCustomPropertiesClient(Substitute.For()); + + await Assert.ThrowsAsync(() => client.Delete(null, "custom_property_name")); + await Assert.ThrowsAsync(() => client.Delete("owner", null)); + + await Assert.ThrowsAsync(() => client.Delete("", "custom_property_name")); + await Assert.ThrowsAsync(() => client.Delete("owner", "")); + } + } + } +} diff --git a/Octokit.Tests/Clients/OrganizationCustomPropertyValuesClientTests.cs b/Octokit.Tests/Clients/OrganizationCustomPropertyValuesClientTests.cs new file mode 100644 index 0000000000..5058f5a29b --- /dev/null +++ b/Octokit.Tests/Clients/OrganizationCustomPropertyValuesClientTests.cs @@ -0,0 +1,81 @@ +using NSubstitute; +using System; +using System.Collections.Generic; +using System.Threading.Tasks; +using Xunit; + +namespace Octokit.Tests.Clients +{ + public class OrganizationCustomPropertyValuesClientTests + { + public class TheCtor + { + [Fact] + public void EnsuresNonNullArguments() + { + Assert.Throws(() => new OrganizationCustomPropertyValuesClient(null)); + } + } + + public class GetAllMethod + { + [Fact] + public async Task RequestsTheCorrectUrl() + { + var connection = Substitute.For(); + var client = new OrganizationCustomPropertyValuesClient(connection); + + await client.GetAll("org"); + + connection.Received() + .Get>(Arg.Is(u => u.ToString() == "orgs/org/properties/values")); + } + + [Fact] + public async Task EnsuresNonNullArguments() + { + var client = new OrganizationCustomPropertyValuesClient(Substitute.For()); + + await Assert.ThrowsAsync(() => client.GetAll(null)); + await Assert.ThrowsAsync(() => client.GetAll("")); + } + } + + public class CreateOrUpdateMethod + { + [Fact] + public async Task PatchTheCorrectUrl() + { + var connection = Substitute.For(); + var client = new OrganizationCustomPropertyValuesClient(connection); + var propertyValues = new UpsertOrganizationCustomPropertyValues + { + RepositoryNames = new() { "repo" }, + Properties = new() { new() { PropertyName = "name", Value = "value" } } + }; + + await client.CreateOrUpdate("org", propertyValues); + + connection.Received() + .Patch>(Arg.Is(u => u.ToString() == "orgs/org/properties/values"), propertyValues); + } + + [Fact] + public async Task EnsuresNonNullArguments() + { + var client = new OrganizationCustomPropertyValuesClient(Substitute.For()); + var propertyValues = new UpsertOrganizationCustomPropertyValues + { + RepositoryNames = new() { "repo" }, + Properties = new() { new() { PropertyName = "name", Value = "value" } } + }; + + await Assert.ThrowsAsync(() => client.CreateOrUpdate(null, propertyValues)); + await Assert.ThrowsAsync(() => client.CreateOrUpdate("org", null)); + await Assert.ThrowsAsync(() => client.CreateOrUpdate("org", new UpsertOrganizationCustomPropertyValues())); + + await Assert.ThrowsAsync(() => client.CreateOrUpdate("", propertyValues)); + } + } + } +} diff --git a/Octokit.Tests/Clients/RepositoryCustomPropertiesClientTests.cs b/Octokit.Tests/Clients/RepositoryCustomPropertiesClientTests.cs new file mode 100644 index 0000000000..88cd23f0e4 --- /dev/null +++ b/Octokit.Tests/Clients/RepositoryCustomPropertiesClientTests.cs @@ -0,0 +1,84 @@ +using NSubstitute; +using System; +using System.Collections.Generic; +using System.Threading.Tasks; +using Xunit; + +namespace Octokit.Tests.Clients +{ + public class RepositoryCustomPropertiesClientTests + { + public class TheCtor + { + [Fact] + public void EnsuresNonNullArguments() + { + Assert.Throws(() => new RepositoryCustomPropertiesClient(null)); + } + } + + public class GetAllMethod + { + [Fact] + public async Task RequestsTheCorrectUrl() + { + var connection = Substitute.For(); + var client = new RepositoryCustomPropertiesClient(connection); + + await client.GetAll("org", "repo"); + + connection.Received() + .Get(Arg.Is(u => u.ToString() == "repos/org/repo/properties/values")); + } + + [Fact] + public async Task EnsuresNonNullArguments() + { + var client = new RepositoryCustomPropertiesClient(Substitute.For()); + + await Assert.ThrowsAsync(() => client.GetAll(null, "repo")); + await Assert.ThrowsAsync(() => client.GetAll("org", null)); + + await Assert.ThrowsAsync(() => client.GetAll("", "repo")); + await Assert.ThrowsAsync(() => client.GetAll("org", "")); + } + } + + public class CreateOrUpdateMethod + { + [Fact] + public async Task PatchTheCorrectUrl() + { + var connection = Substitute.For(); + var client = new RepositoryCustomPropertiesClient(connection); + var propertyValues = new UpsertRepositoryCustomPropertyValues + { + Properties = new() { new() { PropertyName = "name", Value = "value" } } + }; + + await client.CreateOrUpdate("org", "repo", propertyValues); + + connection.Received() + .Patch>(Arg.Is(u => u.ToString() == "repos/org/repo/properties/values"), propertyValues); + } + + [Fact] + public async Task EnsuresNonNullArguments() + { + var client = new RepositoryCustomPropertiesClient(Substitute.For()); + var propertyValues = new UpsertRepositoryCustomPropertyValues + { + Properties = new() { new() { PropertyName = "name", Value = "value" } } + }; + + await Assert.ThrowsAsync(() => client.CreateOrUpdate(null, "repo", propertyValues)); + await Assert.ThrowsAsync(() => client.CreateOrUpdate("org", null, propertyValues)); + await Assert.ThrowsAsync(() => client.CreateOrUpdate("org", "repo", null)); + await Assert.ThrowsAsync(() => client.CreateOrUpdate("org", "repo", new UpsertRepositoryCustomPropertyValues())); + + await Assert.ThrowsAsync(() => client.CreateOrUpdate("", "repo", propertyValues)); + await Assert.ThrowsAsync(() => client.CreateOrUpdate("org", "", propertyValues)); + } + } + } +} diff --git a/Octokit.Tests/Reactive/ObservableOrganizationCustomPropertiesClientTests.cs b/Octokit.Tests/Reactive/ObservableOrganizationCustomPropertiesClientTests.cs new file mode 100644 index 0000000000..c1471863b3 --- /dev/null +++ b/Octokit.Tests/Reactive/ObservableOrganizationCustomPropertiesClientTests.cs @@ -0,0 +1,169 @@ +using NSubstitute; +using Octokit.Reactive; +using System; +using System.Collections.Generic; +using System.Reactive.Linq; +using System.Reactive.Threading.Tasks; +using System.Threading.Tasks; +using Xunit; + +namespace Octokit.Tests.Reactive +{ + public class ObservableOrganizationCustomPropertiesClientTests + { + public class TheCtor + { + [Fact] + public void EnsuresNonNullArguments() + { + Assert.Throws(() => new ObservableOrganizationCustomPropertiesClient(null)); + } + } + + public class GetAllMethod + { + [Fact] + public async Task RequestsTheCorrectUrl() + { + var gitHubClient = Substitute.For(); + var client = new ObservableOrganizationCustomPropertiesClient(gitHubClient); + + await client.GetAll("org"); + + gitHubClient.Received().Organization.CustomProperty.GetAll("org"); + } + + [Fact] + public async Task EnsuresNonNullArguments() + { + var client = new ObservableOrganizationCustomPropertiesClient(Substitute.For()); + + await Assert.ThrowsAsync(() => client.GetAll(null).ToTask()); + await Assert.ThrowsAsync(() => client.GetAll("").ToTask()); + } + } + + public class GetMethod + { + [Fact] + public async Task RequestsTheCorrectUrl() + { + var gitHubClient = Substitute.For(); + var client = new ObservableOrganizationCustomPropertiesClient(gitHubClient); + + await client.Get("org", "custom_property_name"); + + gitHubClient.Received().Organization.CustomProperty.Get("org", "custom_property_name"); + } + + [Fact] + public async Task EnsuresNonNullArguments() + { + var client = new ObservableOrganizationCustomPropertiesClient(Substitute.For()); + + await Assert.ThrowsAsync(() => client.Get(null, "custom_property_name").ToTask()); + await Assert.ThrowsAsync(() => client.Get("org", null).ToTask()); + + await Assert.ThrowsAsync(() => client.Get("", "custom_property_name").ToTask()); + await Assert.ThrowsAsync(() => client.Get("org", "").ToTask()); + } + } + + public class BatchCreateOrUpdateMethod + { + [Fact] + public async Task PostsTheCorrectUrl() + { + var gitHubClient = Substitute.For(); + var client = new ObservableOrganizationCustomPropertiesClient(gitHubClient); + var properties = new UpsertOrganizationCustomProperties + { + Properties = new List + { + new() { PropertyName = "name", DefaultValue = "value", ValueType = CustomPropertyValueType.String } + } + }; + await client.CreateOrUpdate("org", properties); + + gitHubClient.Received().Organization.CustomProperty.CreateOrUpdate("org", properties); + } + + [Fact] + public async Task EnsuresNonNullArguments() + { + var client = new ObservableOrganizationCustomPropertiesClient(Substitute.For()); + + var properties = new UpsertOrganizationCustomProperties + { + Properties = new List + { + new() { PropertyName = "name", DefaultValue = "value", ValueType = CustomPropertyValueType.String } + } + }; + + await Assert.ThrowsAsync(() => client.CreateOrUpdate(null, properties).ToTask()); + await Assert.ThrowsAsync(() => client.CreateOrUpdate("owner", null).ToTask()); + await Assert.ThrowsAsync(() => client.CreateOrUpdate("owner", new UpsertOrganizationCustomProperties()).ToTask()); + + await Assert.ThrowsAsync(() => client.CreateOrUpdate("", properties).ToTask()); + } + } + + public class CreateOrUpdateMethod + { + [Fact] + public async Task PostsTheCorrectUrl() + { + var gitHubClient = Substitute.For(); + var client = new ObservableOrganizationCustomPropertiesClient(gitHubClient); + var update = new OrganizationCustomPropertyUpdate { PropertyName = "name", DefaultValue = "value", ValueType = CustomPropertyValueType.String }; + + await client.CreateOrUpdate("org", "custom_property_name", update); + + gitHubClient.Received().Organization.CustomProperty.CreateOrUpdate("org", "custom_property_name", update); + } + + [Fact] + public async Task EnsuresNonNullArguments() + { + var client = new ObservableOrganizationCustomPropertiesClient(Substitute.For()); + + var update = new OrganizationCustomPropertyUpdate { PropertyName = "name", DefaultValue = "value", ValueType = CustomPropertyValueType.String }; + + await Assert.ThrowsAsync(() => client.CreateOrUpdate(null, "custom_property_name", update).ToTask()); + await Assert.ThrowsAsync(() => client.CreateOrUpdate("owner", null, update).ToTask()); + await Assert.ThrowsAsync(() => client.CreateOrUpdate("owner", "custom_property_name", null).ToTask()); + await Assert.ThrowsAsync(() => client.CreateOrUpdate("owner", "custom_property_name", new OrganizationCustomPropertyUpdate()).ToTask()); + + await Assert.ThrowsAsync(() => client.CreateOrUpdate("", "custom_property_name", update).ToTask()); + await Assert.ThrowsAsync(() => client.CreateOrUpdate("owner", "", update).ToTask()); + } + } + + public class DeleteMethod + { + [Fact] + public async Task DeletesTheCorrectUrl() + { + var gitHubClient = Substitute.For(); + var client = new ObservableOrganizationCustomPropertiesClient(gitHubClient); + + await client.Delete("org", "custom_property_name"); + + gitHubClient.Received().Organization.CustomProperty.Delete("org", "custom_property_name"); + } + + [Fact] + public async Task EnsuresNonNullArguments() + { + var client = new ObservableOrganizationCustomPropertiesClient(Substitute.For()); + + await Assert.ThrowsAsync(() => client.Delete(null, "custom_property_name").ToTask()); + await Assert.ThrowsAsync(() => client.Delete("owner", null).ToTask()); + + await Assert.ThrowsAsync(() => client.Delete("", "custom_property_name").ToTask()); + await Assert.ThrowsAsync(() => client.Delete("owner", "").ToTask()); + } + } + } +} diff --git a/Octokit.Tests/Reactive/ObservableOrganizationCustomPropertyValuesClientTests.cs b/Octokit.Tests/Reactive/ObservableOrganizationCustomPropertyValuesClientTests.cs new file mode 100644 index 0000000000..9e0e78aef5 --- /dev/null +++ b/Octokit.Tests/Reactive/ObservableOrganizationCustomPropertyValuesClientTests.cs @@ -0,0 +1,82 @@ +using NSubstitute; +using Octokit.Reactive; +using System; +using System.Reactive.Linq; +using System.Reactive.Threading.Tasks; +using System.Threading.Tasks; +using Xunit; + +namespace Octokit.Tests.Reactive +{ + public class ObservableOrganizationCustomPropertyValuesClientTests + { + public class TheCtor + { + [Fact] + public void EnsuresNonNullArguments() + { + Assert.Throws(() => new ObservableOrganizationCustomPropertyValuesClient(null)); + } + } + + public class GetAllMethod + { + [Fact] + public async Task RequestsTheCorrectUrl() + { + var gitHubClient = Substitute.For(); + var client = new ObservableOrganizationCustomPropertyValuesClient(gitHubClient); + + await client.GetAll("org"); + + gitHubClient.Received().Organization.CustomProperty.Values.GetAll("org"); + } + + [Fact] + public async Task EnsuresNonNullArguments() + { + var client = new ObservableOrganizationCustomPropertyValuesClient(Substitute.For()); + + await Assert.ThrowsAsync(() => client.GetAll(null).ToTask()); + + await Assert.ThrowsAsync(() => client.GetAll("").ToTask()); + } + } + + public class CreateOrUpdateMethod + { + [Fact] + public async Task PostsTheCorrectUrl() + { + var gitHubClient = Substitute.For(); + var client = new ObservableOrganizationCustomPropertyValuesClient(gitHubClient); + var propertyValues = new UpsertOrganizationCustomPropertyValues + { + RepositoryNames = new() { "repo" }, + Properties = new() { new() { PropertyName = "name", Value = "value" } } + }; + + await client.CreateOrUpdate("org", propertyValues); + + gitHubClient.Received().Organization.CustomProperty.Values.CreateOrUpdate("org", propertyValues); + } + + [Fact] + public async Task EnsuresNonNullArguments() + { + var client = new ObservableOrganizationCustomPropertyValuesClient(Substitute.For()); + var propertyValues = new UpsertOrganizationCustomPropertyValues + { + RepositoryNames = new() { "repo" }, + Properties = new() { new() { PropertyName = "name", Value = "value" } } + }; + + await Assert.ThrowsAsync(() => client.CreateOrUpdate(null, propertyValues).ToTask()); + await Assert.ThrowsAsync(() => client.CreateOrUpdate("org", null).ToTask()); + await Assert.ThrowsAsync(() => client.CreateOrUpdate("org", new UpsertOrganizationCustomPropertyValues()).ToTask()); + + await Assert.ThrowsAsync(() => client.CreateOrUpdate("", propertyValues).ToTask()); + } + } + } +} diff --git a/Octokit.Tests/Reactive/ObservableRepositoryCustomPropertiesClientTests.cs b/Octokit.Tests/Reactive/ObservableRepositoryCustomPropertiesClientTests.cs new file mode 100644 index 0000000000..8e01e0ce80 --- /dev/null +++ b/Octokit.Tests/Reactive/ObservableRepositoryCustomPropertiesClientTests.cs @@ -0,0 +1,84 @@ +using NSubstitute; +using Octokit.Reactive; +using System; +using System.Reactive.Linq; +using System.Reactive.Threading.Tasks; +using System.Threading.Tasks; +using Xunit; + +namespace Octokit.Tests.Reactive +{ + public class ObservableRepositoryCustomPropertiesClientTests + { + public class TheCtor + { + [Fact] + public void EnsuresNonNullArguments() + { + Assert.Throws(() => new ObservableRepositoryCustomPropertiesClient(null)); + } + } + + public class GetAllMethod + { + [Fact] + public async Task RequestsTheCorrectUrl() + { + var gitHubClient = Substitute.For(); + var client = new ObservableRepositoryCustomPropertiesClient(gitHubClient); + + await client.GetAll("org", "repo"); + + gitHubClient.Received().Repository.CustomProperty.GetAll("org", "repo"); + } + + [Fact] + public async Task EnsuresNonNullArguments() + { + var client = new ObservableRepositoryCustomPropertiesClient(Substitute.For()); + + await Assert.ThrowsAsync(() => client.GetAll(null, "repo").ToTask()); + await Assert.ThrowsAsync(() => client.GetAll("org", null).ToTask()); + + await Assert.ThrowsAsync(() => client.GetAll("", "repo").ToTask()); + await Assert.ThrowsAsync(() => client.GetAll("org", "").ToTask()); + } + } + + public class CreateOrUpdateMethod + { + [Fact] + public async Task PostsTheCorrectUrl() + { + var gitHubClient = Substitute.For(); + var client = new ObservableRepositoryCustomPropertiesClient(gitHubClient); + var propertyValues = new UpsertRepositoryCustomPropertyValues + { + Properties = new() { new() { PropertyName = "name", Value = "value" } } + }; + + await client.CreateOrUpdate("org", "repo", propertyValues); + + gitHubClient.Received().Repository.CustomProperty.CreateOrUpdate("org", "repo", propertyValues); + } + + [Fact] + public async Task EnsuresNonNullArguments() + { + var client = new ObservableRepositoryCustomPropertiesClient(Substitute.For()); + var propertyValues = new UpsertRepositoryCustomPropertyValues + { + Properties = new() { new() { PropertyName = "name", Value = "value" } } + }; + + await Assert.ThrowsAsync(() => client.CreateOrUpdate(null, "repo", propertyValues).ToTask()); + await Assert.ThrowsAsync(() => client.CreateOrUpdate("org", null, propertyValues).ToTask()); + await Assert.ThrowsAsync(() => client.CreateOrUpdate("org", "repo", null).ToTask()); + await Assert.ThrowsAsync(() => client.CreateOrUpdate("org", "repo", new UpsertRepositoryCustomPropertyValues()).ToTask()); + + await Assert.ThrowsAsync(() => client.CreateOrUpdate("", "repo", propertyValues).ToTask()); + await Assert.ThrowsAsync(() => client.CreateOrUpdate("org", "", propertyValues).ToTask()); + } + } + } +} diff --git a/Octokit/Clients/IOrganizationCustomPropertiesClient.cs b/Octokit/Clients/IOrganizationCustomPropertiesClient.cs index e091ef9d16..c4da1d36e2 100644 --- a/Octokit/Clients/IOrganizationCustomPropertiesClient.cs +++ b/Octokit/Clients/IOrganizationCustomPropertiesClient.cs @@ -49,7 +49,7 @@ public interface IOrganizationCustomPropertiesClient /// The name of the organization /// The name of the custom property /// The custom property to create or update - Task CreateOrUpdate(string org, string propertyName, OrganizationCustomProperty property); + Task CreateOrUpdate(string org, string propertyName, OrganizationCustomPropertyUpdate property); /// /// Removes a custom property that is defined for an organization. diff --git a/Octokit/Clients/IRepositoryCustomPropertiesClient.cs b/Octokit/Clients/IRepositoryCustomPropertiesClient.cs index 614531f45f..8c1b4e0038 100644 --- a/Octokit/Clients/IRepositoryCustomPropertiesClient.cs +++ b/Octokit/Clients/IRepositoryCustomPropertiesClient.cs @@ -29,7 +29,7 @@ public interface IRepositoryCustomPropertiesClient /// /// The owner of the repository /// The name of the repository - /// The custom property values to create or update - Task> CreateOrUpdate(string owner, string repoName, UpsertRepositoryCustomPropertyValues upsertPropertyValues); + /// The custom property values to create or update + Task> CreateOrUpdate(string owner, string repoName, UpsertRepositoryCustomPropertyValues propertyValues); } } diff --git a/Octokit/Clients/OrganizationCustomPropertiesClient.cs b/Octokit/Clients/OrganizationCustomPropertiesClient.cs index addaf3a39e..1f8a19b574 100644 --- a/Octokit/Clients/OrganizationCustomPropertiesClient.cs +++ b/Octokit/Clients/OrganizationCustomPropertiesClient.cs @@ -80,7 +80,7 @@ public Task> CreateOrUpdate(string org /// The name of the custom property /// The custom property to create or update [ManualRoute("PUT", "orgs/{org}/properties/schemas/{custom_property_name}")] - public Task CreateOrUpdate(string org, string propertyName, OrganizationCustomProperty property) + public Task CreateOrUpdate(string org, string propertyName, OrganizationCustomPropertyUpdate property) { Ensure.ArgumentNotNullOrEmptyString(org, nameof(org)); Ensure.ArgumentNotNullOrEmptyString(propertyName, nameof(propertyName)); diff --git a/Octokit/Clients/RepositoryCustomPropertiesClient.cs b/Octokit/Clients/RepositoryCustomPropertiesClient.cs index 52ab1b5e39..b110094975 100644 --- a/Octokit/Clients/RepositoryCustomPropertiesClient.cs +++ b/Octokit/Clients/RepositoryCustomPropertiesClient.cs @@ -48,18 +48,18 @@ public Task> GetAll(string owner, string repo /// /// The owner of the repository /// The name of the repository - /// The custom property values to create or update + /// The custom property values to create or update /// Thrown when a general API error occurs. [ManualRoute("PATCH", "/repos/{owner}/{repo}/properties/values")] - public Task> CreateOrUpdate(string owner, string repoName, UpsertRepositoryCustomPropertyValues upsertPropertyValues) + public Task> CreateOrUpdate(string owner, string repoName, UpsertRepositoryCustomPropertyValues propertyValues) { Ensure.ArgumentNotNullOrEmptyString(owner, nameof(owner)); Ensure.ArgumentNotNullOrEmptyString(repoName, nameof(repoName)); - Ensure.ArgumentNotNull(upsertPropertyValues, nameof(upsertPropertyValues)); + Ensure.ArgumentNotNull(propertyValues, nameof(propertyValues)); var url = ApiUrls.RepositoryCustomPropertyValues(owner, repoName); - return ApiConnection.Patch>(url, upsertPropertyValues); + return ApiConnection.Patch>(url, propertyValues); } } } diff --git a/Octokit/Models/Request/UpsertOrganizationCustomProperties.cs b/Octokit/Models/Request/UpsertOrganizationCustomProperties.cs index 35c449f31b..2cd47fbaee 100644 --- a/Octokit/Models/Request/UpsertOrganizationCustomProperties.cs +++ b/Octokit/Models/Request/UpsertOrganizationCustomProperties.cs @@ -13,7 +13,7 @@ public class UpsertOrganizationCustomProperties { public UpsertOrganizationCustomProperties() { } - public UpsertOrganizationCustomProperties(IReadOnlyList properties) + public UpsertOrganizationCustomProperties(List properties) { Properties = properties; } @@ -25,7 +25,7 @@ public UpsertOrganizationCustomProperties(IReadOnlyListAPI documentation for more information. /// [Parameter(Value = "properties")] - public IReadOnlyList Properties { get; set; } + public List Properties { get; set; } internal string DebuggerDisplay { diff --git a/Octokit/Models/Request/UpsertOrganizationCustomPropertyValues.cs b/Octokit/Models/Request/UpsertOrganizationCustomPropertyValues.cs index 2eb54dd87d..d1330367e1 100644 --- a/Octokit/Models/Request/UpsertOrganizationCustomPropertyValues.cs +++ b/Octokit/Models/Request/UpsertOrganizationCustomPropertyValues.cs @@ -13,7 +13,7 @@ public class UpsertOrganizationCustomPropertyValues { public UpsertOrganizationCustomPropertyValues() { } - public UpsertOrganizationCustomPropertyValues(IReadOnlyList repositoryNames, IReadOnlyList properties) + public UpsertOrganizationCustomPropertyValues(List repositoryNames, List properties) { RepositoryNames = repositoryNames; Properties = properties; @@ -26,7 +26,7 @@ public UpsertOrganizationCustomPropertyValues(IReadOnlyList repositoryNa /// See the API documentation for more information. /// [Parameter(Value = "repository_names")] - public IReadOnlyList RepositoryNames { get; set; } + public List RepositoryNames { get; set; } /// /// List of organization custom properties @@ -35,7 +35,7 @@ public UpsertOrganizationCustomPropertyValues(IReadOnlyList repositoryNa /// See the API documentation for more information. /// [Parameter(Value = "properties")] - public IReadOnlyList Properties { get; set; } + public List Properties { get; set; } internal string DebuggerDisplay { diff --git a/Octokit/Models/Request/UpsertRepositoryCustomPropertyValues.cs b/Octokit/Models/Request/UpsertRepositoryCustomPropertyValues.cs index a3697fb436..5b0922a701 100644 --- a/Octokit/Models/Request/UpsertRepositoryCustomPropertyValues.cs +++ b/Octokit/Models/Request/UpsertRepositoryCustomPropertyValues.cs @@ -18,7 +18,7 @@ public class UpsertRepositoryCustomPropertyValues /// See the API documentation for more information. /// [Parameter(Value = "properties")] - public IReadOnlyList Properties { get; set; } + public List Properties { get; set; } internal string DebuggerDisplay { From 520493d7d825991e32062b465b7af252ba033ab6 Mon Sep 17 00:00:00 2001 From: Colby Williams Date: Sat, 15 Jun 2024 15:40:03 -0500 Subject: [PATCH 04/11] add search --- .../IObservableOrganizationCustomPropertyValuesClient.cs | 4 ++-- .../ObservableOrganizationCustomPropertyValuesClient.cs | 8 ++++---- .../Clients/IOrganizationCustomPropertyValuesClient.cs | 4 ++-- Octokit/Clients/OrganizationCustomPropertyValuesClient.cs | 8 ++++---- 4 files changed, 12 insertions(+), 12 deletions(-) diff --git a/Octokit.Reactive/Clients/IObservableOrganizationCustomPropertyValuesClient.cs b/Octokit.Reactive/Clients/IObservableOrganizationCustomPropertyValuesClient.cs index 0715439bd8..ce1d452a98 100644 --- a/Octokit.Reactive/Clients/IObservableOrganizationCustomPropertyValuesClient.cs +++ b/Octokit.Reactive/Clients/IObservableOrganizationCustomPropertyValuesClient.cs @@ -28,8 +28,8 @@ public interface IObservableOrganizationCustomPropertyValuesClient /// See the API documentation for more information. /// /// The name of the organization - /// Options for changing the API response - IObservable> GetAll(string org, ApiOptions options); + /// Finds repositories in the organization with a query containing one or more search keywords and qualifiers. + IObservable> GetAll(string org, SearchRepositoriesRequest repositoryQuery); /// /// Create new or update existing custom property values for repositories an organization. diff --git a/Octokit.Reactive/Clients/ObservableOrganizationCustomPropertyValuesClient.cs b/Octokit.Reactive/Clients/ObservableOrganizationCustomPropertyValuesClient.cs index 6a11493f1b..4c8f9a5229 100644 --- a/Octokit.Reactive/Clients/ObservableOrganizationCustomPropertyValuesClient.cs +++ b/Octokit.Reactive/Clients/ObservableOrganizationCustomPropertyValuesClient.cs @@ -40,14 +40,14 @@ public IObservable> GetAll(strin /// See the API documentation for more information. /// /// The name of the organization - /// Options for changing the API response + /// Finds repositories in the organization with a query containing one or more search keywords and qualifiers. /// Thrown when a general API error occurs. - public IObservable> GetAll(string org, ApiOptions options) + public IObservable> GetAll(string org, SearchRepositoriesRequest repositoryQuery) { Ensure.ArgumentNotNullOrEmptyString(org, nameof(org)); - Ensure.ArgumentNotNull(options, nameof(options)); + Ensure.ArgumentNotNull(repositoryQuery, nameof(repositoryQuery)); - return _client.GetAll(org, options).ToObservable(); + return _client.GetAll(org, repositoryQuery).ToObservable(); } /// diff --git a/Octokit/Clients/IOrganizationCustomPropertyValuesClient.cs b/Octokit/Clients/IOrganizationCustomPropertyValuesClient.cs index 43a918995d..171fbad15c 100644 --- a/Octokit/Clients/IOrganizationCustomPropertyValuesClient.cs +++ b/Octokit/Clients/IOrganizationCustomPropertyValuesClient.cs @@ -27,8 +27,8 @@ public interface IOrganizationCustomPropertyValuesClient /// See the API documentation for more information. /// /// The name of the organization - /// Options for changing the API response - Task> GetAll(string org, ApiOptions options); + /// Finds repositories in the organization with a query containing one or more search keywords and qualifiers. + Task> GetAll(string org, SearchRepositoriesRequest repositoryQuery); /// /// Create new or update existing custom property values for repositories an organization. diff --git a/Octokit/Clients/OrganizationCustomPropertyValuesClient.cs b/Octokit/Clients/OrganizationCustomPropertyValuesClient.cs index ed5d80f606..e436932b19 100644 --- a/Octokit/Clients/OrganizationCustomPropertyValuesClient.cs +++ b/Octokit/Clients/OrganizationCustomPropertyValuesClient.cs @@ -39,17 +39,17 @@ public Task> GetAll(string org) /// See the API documentation for more information. /// /// The name of the organization - /// Options for changing the API response + /// Finds repositories in the organization with a query containing one or more search keywords and qualifiers. /// Thrown when a general API error occurs. [ManualRoute("GET", "orgs/{org}/properties/values")] - public Task> GetAll(string org, ApiOptions options) + public Task> GetAll(string org, SearchRepositoriesRequest repositoryQuery) { Ensure.ArgumentNotNullOrEmptyString(org, nameof(org)); - Ensure.ArgumentNotNull(options, nameof(options)); + Ensure.ArgumentNotNull(repositoryQuery, nameof(repositoryQuery)); var url = ApiUrls.OrganizationCustomPropertyValues(org); - return ApiConnection.GetAll(url, options); + return ApiConnection.GetAll(url, repositoryQuery.Parameters); } /// From 0b6bef495f5082253aa8e974045e31cd0f2c1f4c Mon Sep 17 00:00:00 2001 From: Colby Williams Date: Sat, 15 Jun 2024 16:19:17 -0500 Subject: [PATCH 05/11] error CS8370: 'target-typed object creation' --- ...OrganizationCustomPropertiesClientTests.cs | 109 ++++++++++++++++++ ...nizationCustomPropertyValuesClientTests.cs | 59 ++++++++++ .../RepositoryCustomPropertiesClientTests.cs | 59 ++++++++++ ...nizationCustomPropertyValuesClientTests.cs | 14 ++- .../RepositoryCustomPropertiesClientTests.cs | 10 +- ...nizationCustomPropertyValuesClientTests.cs | 15 ++- ...leRepositoryCustomPropertiesClientTests.cs | 11 +- 7 files changed, 265 insertions(+), 12 deletions(-) create mode 100644 Octokit.Tests.Integration/Clients/OrganizationCustomPropertiesClientTests.cs create mode 100644 Octokit.Tests.Integration/Clients/OrganizationCustomPropertyValuesClientTests.cs create mode 100644 Octokit.Tests.Integration/Clients/RepositoryCustomPropertiesClientTests.cs diff --git a/Octokit.Tests.Integration/Clients/OrganizationCustomPropertiesClientTests.cs b/Octokit.Tests.Integration/Clients/OrganizationCustomPropertiesClientTests.cs new file mode 100644 index 0000000000..9961dd7e49 --- /dev/null +++ b/Octokit.Tests.Integration/Clients/OrganizationCustomPropertiesClientTests.cs @@ -0,0 +1,109 @@ +using System.Threading.Tasks; +using Xunit; + +#if SODIUM_CORE_AVAILABLE +using Sodium; +#endif + +namespace Octokit.Tests.Integration.Clients +{ + public class OrganizationCustomPropertiesClientTests + { + public class GetAllMethod + { + [OrganizationTest] + public async Task GetCustomProperties() + { + var github = Helper.GetAuthenticatedClient(); + + var customProperties = await github.Organization.CustomProperty.GetAll(Helper.Organization); + + Assert.NotEmpty(customProperties); + } + } + + /// + /// Please create a custom property in your organization called TEST + /// + public class GetMethod + { + [OrganizationTest] + public async Task GetCustomProperty() + { + var github = Helper.GetAuthenticatedClient(); + + var customProperty = await github.Organization.CustomProperty.Get(Helper.Organization, "TEST"); + + Assert.NotNull(customProperty); + Assert.Equal("TEST", customProperty.PropertyName); + } + } + + public class CreateOrUpdateMethod + { +#if SODIUM_CORE_AVAILABLE + [OrganizationTest] + public async Task UpsertCustomProperty() + { + var github = Helper.GetAuthenticatedClient(); + var upsertValue = GetCustomPropertyUpdateForCreate("UPSERT_TEST", "value"); + + var customProperty = await github.Organization.CustomProperty.CreateOrUpdate(Helper.Organization, "UPSERT_TEST", upsertValue); + + Assert.NotNull(customProperty); + Assert.Equal("UPSERT_TEST", customProperty.PropertyName); + } +#endif + } + + public class DeleteMethod + { +#if SODIUM_CORE_AVAILABLE + [OrganizationTest] + public async Task DeleteCustomProperty() + { + var github = Helper.GetAuthenticatedClient(); + + var propertyName = "DELETE_TEST"; + + var upsertValue = GetCustomPropertyUpdateForCreate(propertyName, "value"); + + await github.Organization.CustomProperty.CreateOrUpdate(Helper.Organization, propertyName, upsertValue); + await github.Organization.CustomProperty.Delete(Helper.Organization, propertyName); + } +#endif + } + + +#if SODIUM_CORE_AVAILABLE + private static UpsertOrganizationCustomProperties GetCustomPropertiesForCreate(string propertyName, string value) + { + var properties = new UpsertOrganizationCustomProperties + { + Properties = new List { GetCustomPropertyUpdateForCreate(propertyName, value) }; + }; + + return upsertValue; + } + + private static OrganizationCustomPropertyUpdate GetCustomPropertyUpdateForCreate(string propertyName, string value) + { + return new OrganizationCustomPropertyUpdate { PropertyName = propertyName, DefaultValue = value, ValueType = CustomPropertyValueType.String }; + } +#endif + + private static async Task CreateRepoIfNotExists(IGitHubClient github, string name) + { + try + { + var existingRepo = await github.Repository.Get(Helper.Organization, name); + return existingRepo; + } + catch + { + var newRepo = await github.Repository.Create(Helper.Organization, new NewRepository(name)); + return newRepo; + } + } + } +} diff --git a/Octokit.Tests.Integration/Clients/OrganizationCustomPropertyValuesClientTests.cs b/Octokit.Tests.Integration/Clients/OrganizationCustomPropertyValuesClientTests.cs new file mode 100644 index 0000000000..30ba3c4ce7 --- /dev/null +++ b/Octokit.Tests.Integration/Clients/OrganizationCustomPropertyValuesClientTests.cs @@ -0,0 +1,59 @@ +using System.Threading.Tasks; +using Xunit; + +#if SODIUM_CORE_AVAILABLE +using Sodium; +#endif + +namespace Octokit.Tests.Integration.Clients +{ + /// + /// Access to view and update custom property values is required for the following tests + /// + public class OrganizationCustomPropertyValuesClientTests + { + /// + /// Fill these in for tests to work + /// + internal const string OWNER = "octokit"; + internal const string REPO = "octokit.net"; + + public class GetAllMethod + { + [IntegrationTest] + public async Task GetPropertyValues() + { + var github = Helper.GetAuthenticatedClient(); + + var propertyValues = await github.Organization.CustomProperty.Values.GetAll(OWNER); + + Assert.NotEmpty(propertyValues); + } + } + + public class CreateOrUpdateMethod + { +#if SODIUM_CORE_AVAILABLE + [IntegrationTest] + public async Task UpsertPropertyValues() + { + var github = Helper.GetAuthenticatedClient(); + + var upsertValue = new UpsertOrganizationCustomPropertyValues + { + RepositoryNames = new List { "repo" }, + Properties = new List + { + new CustomPropertyValueUpdate { PropertyName = "UPSERT_TEST", Value = "value" } + } + }; + + var updatedValues = await github.Organization.CustomProperty.Values.CreateOrUpdate(OWNER, REPO, upsertValue); + + Assert.NotNull(updatedValues); + Assert.True(updatedValues.Count > 0); + } +#endif + } + } +} diff --git a/Octokit.Tests.Integration/Clients/RepositoryCustomPropertiesClientTests.cs b/Octokit.Tests.Integration/Clients/RepositoryCustomPropertiesClientTests.cs new file mode 100644 index 0000000000..3c66e89148 --- /dev/null +++ b/Octokit.Tests.Integration/Clients/RepositoryCustomPropertiesClientTests.cs @@ -0,0 +1,59 @@ +using System.Threading.Tasks; +using Xunit; + +#if SODIUM_CORE_AVAILABLE +using Sodium; +#endif + +namespace Octokit.Tests.Integration.Clients +{ + /// + /// Access to view and update custom property values is required for the following tests + /// + public class RepositoryCustomPropertiesClientTests + { + /// + /// Fill these in for tests to work + /// + internal const string OWNER = "octokit"; + internal const string REPO = "octokit.net"; + + public class GetAllMethod + { + [IntegrationTest] + public async Task GetPropertyValues() + { + var github = Helper.GetAuthenticatedClient(); + + var propertyValues = await github.Repository.CustomProperty.GetAll(OWNER, REPO); + + Assert.NotEmpty(propertyValues); + } + } + + public class CreateOrUpdateMethod + { +#if SODIUM_CORE_AVAILABLE + [IntegrationTest] + public async Task UpsertPropertyValues() + { + var github = Helper.GetAuthenticatedClient(); + var now = DateTime.Now; + + var upsertValue = new UpsertRepositoryCustomPropertyValues + { + Properties = new List + { + new CustomPropertyValueUpdate { PropertyName = "TEST", Value = "UPSERT_TEST" } + } + }; + + var updatedValues = await github.Repository.CustomProperty.CreateOrUpdate(OWNER, REPO, upsertValue); + + Assert.NotNull(updatedValues); + Assert.True(updatedValues.Count > 0); + } +#endif + } + } +} diff --git a/Octokit.Tests/Clients/OrganizationCustomPropertyValuesClientTests.cs b/Octokit.Tests/Clients/OrganizationCustomPropertyValuesClientTests.cs index 5058f5a29b..9bda59ebe0 100644 --- a/Octokit.Tests/Clients/OrganizationCustomPropertyValuesClientTests.cs +++ b/Octokit.Tests/Clients/OrganizationCustomPropertyValuesClientTests.cs @@ -50,8 +50,11 @@ public async Task PatchTheCorrectUrl() var client = new OrganizationCustomPropertyValuesClient(connection); var propertyValues = new UpsertOrganizationCustomPropertyValues { - RepositoryNames = new() { "repo" }, - Properties = new() { new() { PropertyName = "name", Value = "value" } } + RepositoryNames = new List { "repo" }, + Properties = new List + { + new CustomPropertyValueUpdate { PropertyName = "name", Value = "value" } + } }; await client.CreateOrUpdate("org", propertyValues); @@ -66,8 +69,11 @@ public async Task EnsuresNonNullArguments() var client = new OrganizationCustomPropertyValuesClient(Substitute.For()); var propertyValues = new UpsertOrganizationCustomPropertyValues { - RepositoryNames = new() { "repo" }, - Properties = new() { new() { PropertyName = "name", Value = "value" } } + RepositoryNames = new List { "repo" }, + Properties = new List + { + new CustomPropertyValueUpdate { PropertyName = "name", Value = "value" } + } }; await Assert.ThrowsAsync(() => client.CreateOrUpdate(null, propertyValues)); diff --git a/Octokit.Tests/Clients/RepositoryCustomPropertiesClientTests.cs b/Octokit.Tests/Clients/RepositoryCustomPropertiesClientTests.cs index 88cd23f0e4..23574e6f25 100644 --- a/Octokit.Tests/Clients/RepositoryCustomPropertiesClientTests.cs +++ b/Octokit.Tests/Clients/RepositoryCustomPropertiesClientTests.cs @@ -53,7 +53,10 @@ public async Task PatchTheCorrectUrl() var client = new RepositoryCustomPropertiesClient(connection); var propertyValues = new UpsertRepositoryCustomPropertyValues { - Properties = new() { new() { PropertyName = "name", Value = "value" } } + Properties = new List + { + new CustomPropertyValueUpdate { PropertyName = "name", Value = "value" } + } }; await client.CreateOrUpdate("org", "repo", propertyValues); @@ -68,7 +71,10 @@ public async Task EnsuresNonNullArguments() var client = new RepositoryCustomPropertiesClient(Substitute.For()); var propertyValues = new UpsertRepositoryCustomPropertyValues { - Properties = new() { new() { PropertyName = "name", Value = "value" } } + Properties = new List + { + new CustomPropertyValueUpdate { PropertyName = "name", Value = "value" } + } }; await Assert.ThrowsAsync(() => client.CreateOrUpdate(null, "repo", propertyValues)); diff --git a/Octokit.Tests/Reactive/ObservableOrganizationCustomPropertyValuesClientTests.cs b/Octokit.Tests/Reactive/ObservableOrganizationCustomPropertyValuesClientTests.cs index 9e0e78aef5..6671760f8d 100644 --- a/Octokit.Tests/Reactive/ObservableOrganizationCustomPropertyValuesClientTests.cs +++ b/Octokit.Tests/Reactive/ObservableOrganizationCustomPropertyValuesClientTests.cs @@ -1,6 +1,7 @@ using NSubstitute; using Octokit.Reactive; using System; +using System.Collections.Generic; using System.Reactive.Linq; using System.Reactive.Threading.Tasks; using System.Threading.Tasks; @@ -52,8 +53,11 @@ public async Task PostsTheCorrectUrl() var client = new ObservableOrganizationCustomPropertyValuesClient(gitHubClient); var propertyValues = new UpsertOrganizationCustomPropertyValues { - RepositoryNames = new() { "repo" }, - Properties = new() { new() { PropertyName = "name", Value = "value" } } + RepositoryNames = new List { "repo" }, + Properties = new List + { + new CustomPropertyValueUpdate { PropertyName = "name", Value = "value" } + } }; await client.CreateOrUpdate("org", propertyValues); @@ -67,8 +71,11 @@ public async Task EnsuresNonNullArguments() var client = new ObservableOrganizationCustomPropertyValuesClient(Substitute.For()); var propertyValues = new UpsertOrganizationCustomPropertyValues { - RepositoryNames = new() { "repo" }, - Properties = new() { new() { PropertyName = "name", Value = "value" } } + RepositoryNames = new List { "repo" }, + Properties = new List + { + new CustomPropertyValueUpdate { PropertyName = "name", Value = "value" } + } }; await Assert.ThrowsAsync(() => client.CreateOrUpdate(null, propertyValues).ToTask()); diff --git a/Octokit.Tests/Reactive/ObservableRepositoryCustomPropertiesClientTests.cs b/Octokit.Tests/Reactive/ObservableRepositoryCustomPropertiesClientTests.cs index 8e01e0ce80..44c0a7ab13 100644 --- a/Octokit.Tests/Reactive/ObservableRepositoryCustomPropertiesClientTests.cs +++ b/Octokit.Tests/Reactive/ObservableRepositoryCustomPropertiesClientTests.cs @@ -1,6 +1,7 @@ using NSubstitute; using Octokit.Reactive; using System; +using System.Collections.Generic; using System.Reactive.Linq; using System.Reactive.Threading.Tasks; using System.Threading.Tasks; @@ -54,7 +55,10 @@ public async Task PostsTheCorrectUrl() var client = new ObservableRepositoryCustomPropertiesClient(gitHubClient); var propertyValues = new UpsertRepositoryCustomPropertyValues { - Properties = new() { new() { PropertyName = "name", Value = "value" } } + Properties = new List + { + new CustomPropertyValueUpdate { PropertyName = "name", Value = "value" } + } }; await client.CreateOrUpdate("org", "repo", propertyValues); @@ -68,7 +72,10 @@ public async Task EnsuresNonNullArguments() var client = new ObservableRepositoryCustomPropertiesClient(Substitute.For()); var propertyValues = new UpsertRepositoryCustomPropertyValues { - Properties = new() { new() { PropertyName = "name", Value = "value" } } + Properties = new List + { + new CustomPropertyValueUpdate { PropertyName = "name", Value = "value" } + } }; await Assert.ThrowsAsync(() => client.CreateOrUpdate(null, "repo", propertyValues).ToTask()); From 986ff039b93fb80f84b692442971fd76589ac54b Mon Sep 17 00:00:00 2001 From: Colby Williams Date: Sat, 15 Jun 2024 16:21:24 -0500 Subject: [PATCH 06/11] Error CS8370: 'target-typed object creation' --- .../ObservableOrganizationCustomPropertiesClientTests.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Octokit.Tests/Reactive/ObservableOrganizationCustomPropertiesClientTests.cs b/Octokit.Tests/Reactive/ObservableOrganizationCustomPropertiesClientTests.cs index c1471863b3..089b8d9225 100644 --- a/Octokit.Tests/Reactive/ObservableOrganizationCustomPropertiesClientTests.cs +++ b/Octokit.Tests/Reactive/ObservableOrganizationCustomPropertiesClientTests.cs @@ -80,7 +80,7 @@ public async Task PostsTheCorrectUrl() { Properties = new List { - new() { PropertyName = "name", DefaultValue = "value", ValueType = CustomPropertyValueType.String } + new OrganizationCustomPropertyUpdate { PropertyName = "name", DefaultValue = "value", ValueType = CustomPropertyValueType.String } } }; await client.CreateOrUpdate("org", properties); @@ -97,7 +97,7 @@ public async Task EnsuresNonNullArguments() { Properties = new List { - new() { PropertyName = "name", DefaultValue = "value", ValueType = CustomPropertyValueType.String } + new OrganizationCustomPropertyUpdate { PropertyName = "name", DefaultValue = "value", ValueType = CustomPropertyValueType.String } } }; From 6a3af29a324521adc6d16dd46ed43e215ddb558d Mon Sep 17 00:00:00 2001 From: Colby Williams Date: Sat, 15 Jun 2024 23:55:49 -0500 Subject: [PATCH 07/11] add patch with body that return status code --- Octokit/Http/ApiConnection.cs | 30 ++++++++++++++++++++++++++++++ Octokit/Http/Connection.cs | 32 ++++++++++++++++++++++++++++++++ Octokit/Http/IApiConnection.cs | 17 +++++++++++++++++ Octokit/Http/IConnection.cs | 17 +++++++++++++++++ 4 files changed, 96 insertions(+) diff --git a/Octokit/Http/ApiConnection.cs b/Octokit/Http/ApiConnection.cs index 9d729947e9..929de72a65 100644 --- a/Octokit/Http/ApiConnection.cs +++ b/Octokit/Http/ApiConnection.cs @@ -460,6 +460,20 @@ public Task Patch(Uri uri) return Connection.Patch(uri); } + /// + /// Updates the API resource at the specified URI. + /// + /// URI of the API resource to patch + /// Object that describes the API resource; this will be serialized and used as the request's body + /// A for the request's execution. + public Task Patch(Uri uri, object data) + { + Ensure.ArgumentNotNull(uri, nameof(uri)); + Ensure.ArgumentNotNull(data, nameof(data)); + + return Connection.Patch(uri, data); + } + /// /// Updates the API resource at the specified URI. /// @@ -474,6 +488,22 @@ public Task Patch(Uri uri, string accepts) return Connection.Patch(uri, accepts); } + /// + /// Updates the API resource at the specified URI. + /// + /// URI of the API resource to patch + /// Object that describes the API resource; this will be serialized and used as the request's body + /// Accept header to use for the API request + /// A for the request's execution. + 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); + } + /// /// Updates the API resource at the specified URI. /// diff --git a/Octokit/Http/Connection.cs b/Octokit/Http/Connection.cs index 11a67d4502..091af09ca9 100644 --- a/Octokit/Http/Connection.cs +++ b/Octokit/Http/Connection.cs @@ -498,6 +498,21 @@ public async Task Patch(Uri uri) return response.HttpResponse.StatusCode; } + /// + /// Performs an asynchronous HTTP PATCH request. + /// + /// URI endpoint to send request to + /// The object to serialize as the body of the request + /// representing the received HTTP response + public async Task Patch(Uri uri, object body) + { + Ensure.ArgumentNotNull(uri, nameof(uri)); + Ensure.ArgumentNotNull(body, nameof(body)); + + var response = await SendData(uri, new HttpMethod("PATCH"), body, null, null, CancellationToken.None).ConfigureAwait(false); + return response.HttpResponse.StatusCode; + } + /// /// Performs an asynchronous HTTP PATCH request. /// @@ -513,6 +528,23 @@ public async Task Patch(Uri uri, string accepts) return response.HttpResponse.StatusCode; } + /// + /// Performs an asynchronous HTTP PATCH request. + /// + /// URI endpoint to send request to + /// The object to serialize as the body of the request + /// Specifies accept response media type + /// representing the received HTTP response + public async Task 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(uri, new HttpMethod("PATCH"), body, accepts, null, CancellationToken.None).ConfigureAwait(false); + return response.HttpResponse.StatusCode; + } + /// /// Performs an asynchronous HTTP PUT request that expects an empty response. /// diff --git a/Octokit/Http/IApiConnection.cs b/Octokit/Http/IApiConnection.cs index da4a541f1c..3888f5883a 100644 --- a/Octokit/Http/IApiConnection.cs +++ b/Octokit/Http/IApiConnection.cs @@ -306,6 +306,14 @@ public interface IApiConnection /// A for the request's execution. Task Patch(Uri uri); + /// + /// Updates the API resource at the specified URI. + /// + /// URI of the API resource to patch + /// Object that describes the API resource; this will be serialized and used as the request's body + /// A for the request's execution. + Task Patch(Uri uri, object data); + /// /// Updates the API resource at the specified URI. /// @@ -314,6 +322,15 @@ public interface IApiConnection /// A for the request's execution. Task Patch(Uri uri, string accepts); + /// + /// Updates the API resource at the specified URI. + /// + /// URI of the API resource to patch + /// Object that describes the API resource; this will be serialized and used as the request's body + /// Accept header to use for the API request + /// A for the request's execution. + Task Patch(Uri uri, object data, string accepts); + /// /// Updates the API resource at the specified URI. /// diff --git a/Octokit/Http/IConnection.cs b/Octokit/Http/IConnection.cs index c9f8daa848..4e75a10975 100644 --- a/Octokit/Http/IConnection.cs +++ b/Octokit/Http/IConnection.cs @@ -117,6 +117,14 @@ public interface IConnection : IApiInfoProvider /// representing the received HTTP response Task Patch(Uri uri); + /// + /// Performs an asynchronous HTTP PATCH request. + /// + /// URI endpoint to send request to + /// The object to serialize as the body of the request + /// representing the received HTTP response + Task Patch(Uri uri, object body); + /// /// Performs an asynchronous HTTP PATCH request. /// @@ -125,6 +133,15 @@ public interface IConnection : IApiInfoProvider /// representing the received HTTP response Task Patch(Uri uri, string accepts); + /// + /// Performs an asynchronous HTTP PATCH request. + /// + /// URI endpoint to send request to + /// The object to serialize as the body of the request + /// Specifies accept response media type + /// representing the received HTTP response + Task Patch(Uri uri, object body, string accepts); + /// /// Performs an asynchronous HTTP PATCH request. /// Attempts to map the response body to an object of type From f95bea101b80b42b2ef3047e7b16e890cfe33d71 Mon Sep 17 00:00:00 2001 From: Colby Williams Date: Sat, 15 Jun 2024 23:57:21 -0500 Subject: [PATCH 08/11] fixes for failed ConventionTests --- ...vableOrganizationCustomPropertiesClient.cs | 5 ++-- ...eOrganizationCustomPropertyValuesClient.cs | 15 ++++++++-- ...ervableRepositoryCustomPropertiesClient.cs | 6 ++-- ...vableOrganizationCustomPropertiesClient.cs | 10 +++---- ...eOrganizationCustomPropertyValuesClient.cs | 29 +++++++++++++++---- ...ervableRepositoryCustomPropertiesClient.cs | 9 +++--- .../IOrganizationCustomPropertiesClient.cs | 1 + ...IOrganizationCustomPropertyValuesClient.cs | 11 +++++++ .../IRepositoryCustomPropertiesClient.cs | 3 +- .../OrganizationCustomPropertyValuesClient.cs | 22 ++++++++++++-- .../RepositoryCustomPropertiesClient.cs | 4 +-- .../Request/CustomPropertyValueUpdate.cs | 3 ++ .../Models/Response/CustomPropertyValue.cs | 10 +++++++ .../Response/OrganizationCustomProperty.cs | 14 ++++++++- 14 files changed, 113 insertions(+), 29 deletions(-) diff --git a/Octokit.Reactive/Clients/IObservableOrganizationCustomPropertiesClient.cs b/Octokit.Reactive/Clients/IObservableOrganizationCustomPropertiesClient.cs index 6b34d3ed62..8c67026312 100644 --- a/Octokit.Reactive/Clients/IObservableOrganizationCustomPropertiesClient.cs +++ b/Octokit.Reactive/Clients/IObservableOrganizationCustomPropertiesClient.cs @@ -1,5 +1,4 @@ using System; -using System.Collections.Generic; using System.Reactive; namespace Octokit.Reactive @@ -19,7 +18,7 @@ public interface IObservableOrganizationCustomPropertiesClient /// See the API documentation for more information. /// /// The name of the organization - IObservable> GetAll(string org); + IObservable GetAll(string org); /// /// Get a single custom property by name. @@ -39,7 +38,7 @@ public interface IObservableOrganizationCustomPropertiesClient /// /// The name of the organization /// The custom properties to create or update - IObservable> CreateOrUpdate(string org, UpsertOrganizationCustomProperties properties); + IObservable CreateOrUpdate(string org, UpsertOrganizationCustomProperties properties); /// /// Create new or update existing custom property for an organization. diff --git a/Octokit.Reactive/Clients/IObservableOrganizationCustomPropertyValuesClient.cs b/Octokit.Reactive/Clients/IObservableOrganizationCustomPropertyValuesClient.cs index ce1d452a98..530e05dfd8 100644 --- a/Octokit.Reactive/Clients/IObservableOrganizationCustomPropertyValuesClient.cs +++ b/Octokit.Reactive/Clients/IObservableOrganizationCustomPropertyValuesClient.cs @@ -1,5 +1,4 @@ using System; -using System.Collections.Generic; using System.Reactive; namespace Octokit.Reactive @@ -19,7 +18,17 @@ public interface IObservableOrganizationCustomPropertyValuesClient /// See the API documentation for more information. /// /// The name of the organization - IObservable> GetAll(string org); + IObservable GetAll(string org); + + /// + /// Get all custom property values for repositories an organization. + /// + /// + /// See the API documentation for more information. + /// + /// The name of the organization + /// Options for changing the API response + IObservable GetAll(string org, ApiOptions options); /// /// Get all custom property values for repositories an organization. @@ -29,7 +38,7 @@ public interface IObservableOrganizationCustomPropertyValuesClient /// /// The name of the organization /// Finds repositories in the organization with a query containing one or more search keywords and qualifiers. - IObservable> GetAll(string org, SearchRepositoriesRequest repositoryQuery); + IObservable GetAll(string org, SearchRepositoriesRequest repositoryQuery); /// /// Create new or update existing custom property values for repositories an organization. diff --git a/Octokit.Reactive/Clients/IObservableRepositoryCustomPropertiesClient.cs b/Octokit.Reactive/Clients/IObservableRepositoryCustomPropertiesClient.cs index 25c8a3bc24..b624a87077 100644 --- a/Octokit.Reactive/Clients/IObservableRepositoryCustomPropertiesClient.cs +++ b/Octokit.Reactive/Clients/IObservableRepositoryCustomPropertiesClient.cs @@ -1,5 +1,5 @@ using System; -using System.Collections.Generic; +using System.Reactive; namespace Octokit.Reactive { @@ -19,7 +19,7 @@ public interface IObservableRepositoryCustomPropertiesClient /// /// The owner of the repository. /// The name of the repository. - IObservable> GetAll(string owner, string repoName); + IObservable GetAll(string owner, string repoName); /// /// 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. @@ -30,6 +30,6 @@ public interface IObservableRepositoryCustomPropertiesClient /// The owner of the repository /// The name of the repository /// The custom property values to create or update - IObservable> CreateOrUpdate(string owner, string repoName, UpsertRepositoryCustomPropertyValues propertyValues); + IObservable CreateOrUpdate(string owner, string repoName, UpsertRepositoryCustomPropertyValues propertyValues); } } diff --git a/Octokit.Reactive/Clients/ObservableOrganizationCustomPropertiesClient.cs b/Octokit.Reactive/Clients/ObservableOrganizationCustomPropertiesClient.cs index a20918b80d..e5a064cfb5 100644 --- a/Octokit.Reactive/Clients/ObservableOrganizationCustomPropertiesClient.cs +++ b/Octokit.Reactive/Clients/ObservableOrganizationCustomPropertiesClient.cs @@ -1,6 +1,6 @@ using System; -using System.Collections.Generic; using System.Reactive; +using System.Reactive.Linq; using System.Reactive.Threading.Tasks; namespace Octokit.Reactive @@ -27,11 +27,11 @@ public ObservableOrganizationCustomPropertiesClient(IGitHubClient client) /// See the API documentation for more information. /// /// The name of the organization - public IObservable> GetAll(string org) + public IObservable GetAll(string org) { Ensure.ArgumentNotNullOrEmptyString(org, nameof(org)); - return _client.GetAll(org).ToObservable(); + return _client.GetAll(org).ToObservable().SelectMany(p => p); } /// @@ -58,12 +58,12 @@ public IObservable Get(string org, string propertyNa /// /// The name of the organization /// The custom properties to create or update - public IObservable> CreateOrUpdate(string org, UpsertOrganizationCustomProperties properties) + public IObservable CreateOrUpdate(string org, UpsertOrganizationCustomProperties properties) { Ensure.ArgumentNotNullOrEmptyString(org, nameof(org)); Ensure.ArgumentNotNull(properties, nameof(properties)); - return _client.CreateOrUpdate(org, properties).ToObservable(); + return _client.CreateOrUpdate(org, properties).ToObservable().SelectMany(p => p); } /// diff --git a/Octokit.Reactive/Clients/ObservableOrganizationCustomPropertyValuesClient.cs b/Octokit.Reactive/Clients/ObservableOrganizationCustomPropertyValuesClient.cs index 4c8f9a5229..0d17c2bf7f 100644 --- a/Octokit.Reactive/Clients/ObservableOrganizationCustomPropertyValuesClient.cs +++ b/Octokit.Reactive/Clients/ObservableOrganizationCustomPropertyValuesClient.cs @@ -1,7 +1,8 @@ using System; -using System.Collections.Generic; using System.Reactive; +using System.Reactive.Linq; using System.Reactive.Threading.Tasks; +using Octokit.Reactive.Internal; namespace Octokit.Reactive { @@ -26,11 +27,29 @@ public ObservableOrganizationCustomPropertyValuesClient(IGitHubClient client) /// /// The name of the organization /// Thrown when a general API error occurs. - public IObservable> GetAll(string org) + public IObservable GetAll(string org) { Ensure.ArgumentNotNullOrEmptyString(org, nameof(org)); - return _client.GetAll(org).ToObservable(); + return GetAll(org, ApiOptions.None); + } + + /// + /// Get all custom property values for repositories an organization. + /// + /// + /// See the API documentation for more information. + /// + /// The name of the organization + /// Options for changing the API response + public IObservable GetAll(string org, ApiOptions options) + { + Ensure.ArgumentNotNullOrEmptyString(org, nameof(org)); + Ensure.ArgumentNotNull(options, nameof(options)); + + var url = ApiUrls.OrganizationCustomPropertyValues(org); + + return _connection.GetAndFlattenAllPages(url, options); } /// @@ -42,12 +61,12 @@ public IObservable> GetAll(strin /// The name of the organization /// Finds repositories in the organization with a query containing one or more search keywords and qualifiers. /// Thrown when a general API error occurs. - public IObservable> GetAll(string org, SearchRepositoriesRequest repositoryQuery) + public IObservable GetAll(string org, SearchRepositoriesRequest repositoryQuery) { Ensure.ArgumentNotNullOrEmptyString(org, nameof(org)); Ensure.ArgumentNotNull(repositoryQuery, nameof(repositoryQuery)); - return _client.GetAll(org, repositoryQuery).ToObservable(); + return _client.GetAll(org, repositoryQuery).ToObservable().SelectMany(p => p); } /// diff --git a/Octokit.Reactive/Clients/ObservableRepositoryCustomPropertiesClient.cs b/Octokit.Reactive/Clients/ObservableRepositoryCustomPropertiesClient.cs index 10874090ea..0610b9ee43 100644 --- a/Octokit.Reactive/Clients/ObservableRepositoryCustomPropertiesClient.cs +++ b/Octokit.Reactive/Clients/ObservableRepositoryCustomPropertiesClient.cs @@ -1,6 +1,7 @@ -using System.Collections.Generic; using System.Reactive.Threading.Tasks; using System; +using System.Reactive; +using System.Reactive.Linq; namespace Octokit.Reactive { @@ -32,12 +33,12 @@ public ObservableRepositoryCustomPropertiesClient(IGitHubClient client) /// The owner of the repository. /// The name of the repository. /// Thrown when a general API error occurs. - public IObservable> GetAll(string owner, string repoName) + public IObservable GetAll(string owner, string repoName) { Ensure.ArgumentNotNullOrEmptyString(owner, nameof(owner)); Ensure.ArgumentNotNullOrEmptyString(repoName, nameof(repoName)); - return _client.GetAll(owner, repoName).ToObservable(); + return _client.GetAll(owner, repoName).ToObservable().SelectMany(p => p); } /// @@ -50,7 +51,7 @@ public IObservable> GetAll(string owner, stri /// The name of the repository /// The custom property values to create or update /// Thrown when a general API error occurs. - public IObservable> CreateOrUpdate(string owner, string repoName, UpsertRepositoryCustomPropertyValues propertyValues) + public IObservable CreateOrUpdate(string owner, string repoName, UpsertRepositoryCustomPropertyValues propertyValues) { Ensure.ArgumentNotNullOrEmptyString(owner, nameof(owner)); Ensure.ArgumentNotNullOrEmptyString(repoName, nameof(repoName)); diff --git a/Octokit/Clients/IOrganizationCustomPropertiesClient.cs b/Octokit/Clients/IOrganizationCustomPropertiesClient.cs index c4da1d36e2..e203b702d6 100644 --- a/Octokit/Clients/IOrganizationCustomPropertiesClient.cs +++ b/Octokit/Clients/IOrganizationCustomPropertiesClient.cs @@ -18,6 +18,7 @@ public interface IOrganizationCustomPropertiesClient /// See the API documentation for more information. /// /// The name of the organization + [ExcludeFromPaginationApiOptionsConventionTest("Pagination not supported by GitHub API (tested 15/06/2024)")] Task> GetAll(string org); /// diff --git a/Octokit/Clients/IOrganizationCustomPropertyValuesClient.cs b/Octokit/Clients/IOrganizationCustomPropertyValuesClient.cs index 171fbad15c..188ea03fc3 100644 --- a/Octokit/Clients/IOrganizationCustomPropertyValuesClient.cs +++ b/Octokit/Clients/IOrganizationCustomPropertyValuesClient.cs @@ -20,6 +20,16 @@ public interface IOrganizationCustomPropertyValuesClient /// The name of the organization Task> GetAll(string org); + /// + /// Get all custom property values for repositories an organization. + /// + /// + /// See the API documentation for more information. + /// + /// The name of the organization + /// Options for changing the API response + Task> GetAll(string org, ApiOptions options); + /// /// Get all custom property values for repositories an organization. /// @@ -28,6 +38,7 @@ public interface IOrganizationCustomPropertyValuesClient /// /// The name of the organization /// Finds repositories in the organization with a query containing one or more search keywords and qualifiers. + [ExcludeFromPaginationApiOptionsConventionTest("This API call uses the SearchRepositoriesRequest parameter for pagination")] Task> GetAll(string org, SearchRepositoriesRequest repositoryQuery); /// diff --git a/Octokit/Clients/IRepositoryCustomPropertiesClient.cs b/Octokit/Clients/IRepositoryCustomPropertiesClient.cs index 8c1b4e0038..60ff86e071 100644 --- a/Octokit/Clients/IRepositoryCustomPropertiesClient.cs +++ b/Octokit/Clients/IRepositoryCustomPropertiesClient.cs @@ -19,6 +19,7 @@ public interface IRepositoryCustomPropertiesClient /// /// The owner of the repository. /// The name of the repository. + [ExcludeFromPaginationApiOptionsConventionTest("Pagination not supported by GitHub API (tested 15/06/2024)")] Task> GetAll(string owner, string repoName); /// @@ -30,6 +31,6 @@ public interface IRepositoryCustomPropertiesClient /// The owner of the repository /// The name of the repository /// The custom property values to create or update - Task> CreateOrUpdate(string owner, string repoName, UpsertRepositoryCustomPropertyValues propertyValues); + Task CreateOrUpdate(string owner, string repoName, UpsertRepositoryCustomPropertyValues propertyValues); } } diff --git a/Octokit/Clients/OrganizationCustomPropertyValuesClient.cs b/Octokit/Clients/OrganizationCustomPropertyValuesClient.cs index e436932b19..64f9766226 100644 --- a/Octokit/Clients/OrganizationCustomPropertyValuesClient.cs +++ b/Octokit/Clients/OrganizationCustomPropertyValuesClient.cs @@ -27,9 +27,27 @@ public Task> GetAll(string org) { Ensure.ArgumentNotNullOrEmptyString(org, nameof(org)); + return GetAll(org, ApiOptions.None); + } + + /// + /// Get all custom property values for repositories an organization. + /// + /// + /// See the API documentation for more information. + /// + /// The name of the organization + /// Options for changing the API response + /// Thrown when a general API error occurs. + [ManualRoute("GET", "orgs/{org}/properties/values")] + public Task> GetAll(string org, ApiOptions options) + { + Ensure.ArgumentNotNullOrEmptyString(org, nameof(org)); + Ensure.ArgumentNotNull(options, nameof(options)); + var url = ApiUrls.OrganizationCustomPropertyValues(org); - return ApiConnection.GetAll(url); + return ApiConnection.GetAll(url, options); } /// @@ -72,7 +90,7 @@ public Task CreateOrUpdate(string org, UpsertOrganizationCustomPropertyValues pr var url = ApiUrls.OrganizationCustomPropertyValues(org); - return ApiConnection.Patch(url, propertyValues, "application/vnd.github+json"); + return ApiConnection.Patch(url, propertyValues); } } } diff --git a/Octokit/Clients/RepositoryCustomPropertiesClient.cs b/Octokit/Clients/RepositoryCustomPropertiesClient.cs index b110094975..9ee4da5b82 100644 --- a/Octokit/Clients/RepositoryCustomPropertiesClient.cs +++ b/Octokit/Clients/RepositoryCustomPropertiesClient.cs @@ -51,7 +51,7 @@ public Task> GetAll(string owner, string repo /// The custom property values to create or update /// Thrown when a general API error occurs. [ManualRoute("PATCH", "/repos/{owner}/{repo}/properties/values")] - public Task> CreateOrUpdate(string owner, string repoName, UpsertRepositoryCustomPropertyValues propertyValues) + public Task CreateOrUpdate(string owner, string repoName, UpsertRepositoryCustomPropertyValues propertyValues) { Ensure.ArgumentNotNullOrEmptyString(owner, nameof(owner)); Ensure.ArgumentNotNullOrEmptyString(repoName, nameof(repoName)); @@ -59,7 +59,7 @@ public Task> CreateOrUpdate(string owner, str var url = ApiUrls.RepositoryCustomPropertyValues(owner, repoName); - return ApiConnection.Patch>(url, propertyValues); + return ApiConnection.Patch(url, propertyValues); } } } diff --git a/Octokit/Models/Request/CustomPropertyValueUpdate.cs b/Octokit/Models/Request/CustomPropertyValueUpdate.cs index f901c3f678..eb26f879b5 100644 --- a/Octokit/Models/Request/CustomPropertyValueUpdate.cs +++ b/Octokit/Models/Request/CustomPropertyValueUpdate.cs @@ -1,5 +1,6 @@ using System.Collections.Generic; using System.Diagnostics; +using System.Globalization; namespace Octokit { @@ -37,5 +38,7 @@ public CustomPropertyValueUpdate(string propertyName, IReadOnlyList valu /// The values assigned to the property /// public IReadOnlyList Values { get; set; } + + internal string DebuggerDisplay => string.Format(CultureInfo.InvariantCulture, "PropertyName: {0}", PropertyName); } } diff --git a/Octokit/Models/Response/CustomPropertyValue.cs b/Octokit/Models/Response/CustomPropertyValue.cs index 1364dd1bc7..417940803f 100644 --- a/Octokit/Models/Response/CustomPropertyValue.cs +++ b/Octokit/Models/Response/CustomPropertyValue.cs @@ -1,5 +1,6 @@ using System.Collections.Generic; using System.Diagnostics; +using System.Globalization; namespace Octokit { @@ -23,6 +24,13 @@ public CustomPropertyValue(string propertyName, IReadOnlyList value) Values = value; } + public CustomPropertyValue(string propertyName, string value, IReadOnlyList values) + { + PropertyName = propertyName; + Value = value; + Values = values; + } + /// /// The name of the property /// @@ -37,5 +45,7 @@ public CustomPropertyValue(string propertyName, IReadOnlyList value) /// The values assigned to the property /// public IReadOnlyList Values { get; private set; } + + internal string DebuggerDisplay => string.Format(CultureInfo.InvariantCulture, "PropertyName: {0}", PropertyName); } } diff --git a/Octokit/Models/Response/OrganizationCustomProperty.cs b/Octokit/Models/Response/OrganizationCustomProperty.cs index b36d96f444..423af93cb4 100644 --- a/Octokit/Models/Response/OrganizationCustomProperty.cs +++ b/Octokit/Models/Response/OrganizationCustomProperty.cs @@ -31,6 +31,18 @@ public OrganizationCustomProperty(string propertyName, CustomPropertyValueType v ValuesEditableBy = valuesEditableBy; } + public OrganizationCustomProperty(string propertyName, CustomPropertyValueType valueType, bool required, string defaultValue, IReadOnlyList defaultValues, string description, IReadOnlyList allowedValues, CustomPropertyValuesEditableBy? valuesEditableBy) + { + PropertyName = propertyName; + ValueType = valueType; + Required = required; + DefaultValue = defaultValue; + DefaultValues = defaultValues; + Description = description; + AllowedValues = allowedValues; + ValuesEditableBy = valuesEditableBy; + } + /// /// The name of the property /// @@ -65,7 +77,7 @@ public OrganizationCustomProperty(string propertyName, CustomPropertyValueType v /// An ordered list of the allowed values of the property. /// The property can have up to 200 allowed values. /// - public IEnumerable AllowedValues { get; private set; } + public IReadOnlyList AllowedValues { get; private set; } /// /// Who can edit the values of the property From 806dd7774ca993737d8cf831dc35c842e1ce3739 Mon Sep 17 00:00:00 2001 From: Colby Williams Date: Sun, 16 Jun 2024 03:29:36 -0500 Subject: [PATCH 09/11] working UnitTests --- ...vableOrganizationCustomPropertiesClient.cs | 2 +- ...eOrganizationCustomPropertyValuesClient.cs | 2 +- ...vableOrganizationCustomPropertiesClient.cs | 8 ++- ...eOrganizationCustomPropertyValuesClient.cs | 9 ++- ...ervableRepositoryCustomPropertiesClient.cs | 1 + ...OrganizationCustomPropertiesClientTests.cs | 9 ++- ...OrganizationCustomPropertiesClientTests.cs | 36 ++++++------ ...nizationCustomPropertyValuesClientTests.cs | 27 ++++++++- .../RepositoryCustomPropertiesClientTests.cs | 4 +- ...OrganizationCustomPropertiesClientTests.cs | 42 +++++++------- ...nizationCustomPropertyValuesClientTests.cs | 4 +- ...leRepositoryCustomPropertiesClientTests.cs | 4 +- .../IOrganizationCustomPropertiesClient.cs | 2 +- ...IOrganizationCustomPropertyValuesClient.cs | 4 +- .../OrganizationCustomPropertiesClient.cs | 16 ++--- .../OrganizationCustomPropertyValuesClient.cs | 4 +- .../RepositoryCustomPropertiesClient.cs | 3 +- .../OrganizationCustomPropertyUpdate.cs | 2 +- ...OrganizationCustomPropertyValuesRequest.cs | 51 ++++++++++++++++ .../UpsertOrganizationCustomProperty.cs | 58 +++++++++++++++++++ 20 files changed, 217 insertions(+), 71 deletions(-) create mode 100644 Octokit/Models/Request/OrganizationCustomPropertyValuesRequest.cs create mode 100644 Octokit/Models/Request/UpsertOrganizationCustomProperty.cs diff --git a/Octokit.Reactive/Clients/IObservableOrganizationCustomPropertiesClient.cs b/Octokit.Reactive/Clients/IObservableOrganizationCustomPropertiesClient.cs index 8c67026312..eb3a98c965 100644 --- a/Octokit.Reactive/Clients/IObservableOrganizationCustomPropertiesClient.cs +++ b/Octokit.Reactive/Clients/IObservableOrganizationCustomPropertiesClient.cs @@ -49,7 +49,7 @@ public interface IObservableOrganizationCustomPropertiesClient /// The name of the organization /// The name of the custom property /// The custom property to create or update - IObservable CreateOrUpdate(string org, string propertyName, OrganizationCustomPropertyUpdate property); + IObservable CreateOrUpdate(string org, string propertyName, UpsertOrganizationCustomProperty property); /// /// Removes a custom property that is defined for an organization. diff --git a/Octokit.Reactive/Clients/IObservableOrganizationCustomPropertyValuesClient.cs b/Octokit.Reactive/Clients/IObservableOrganizationCustomPropertyValuesClient.cs index 530e05dfd8..cf46c98025 100644 --- a/Octokit.Reactive/Clients/IObservableOrganizationCustomPropertyValuesClient.cs +++ b/Octokit.Reactive/Clients/IObservableOrganizationCustomPropertyValuesClient.cs @@ -38,7 +38,7 @@ public interface IObservableOrganizationCustomPropertyValuesClient /// /// The name of the organization /// Finds repositories in the organization with a query containing one or more search keywords and qualifiers. - IObservable GetAll(string org, SearchRepositoriesRequest repositoryQuery); + IObservable GetAll(string org, OrganizationCustomPropertyValuesRequest repositoryQuery); /// /// Create new or update existing custom property values for repositories an organization. diff --git a/Octokit.Reactive/Clients/ObservableOrganizationCustomPropertiesClient.cs b/Octokit.Reactive/Clients/ObservableOrganizationCustomPropertiesClient.cs index e5a064cfb5..dadd0fa2a8 100644 --- a/Octokit.Reactive/Clients/ObservableOrganizationCustomPropertiesClient.cs +++ b/Octokit.Reactive/Clients/ObservableOrganizationCustomPropertiesClient.cs @@ -14,10 +14,10 @@ public ObservableOrganizationCustomPropertiesClient(IGitHubClient client) { Ensure.ArgumentNotNull(client, nameof(client)); + Values = new ObservableOrganizationCustomPropertyValuesClient(client); + _client = client.Organization.CustomProperty; _connection = client.Connection; - - Values = new ObservableOrganizationCustomPropertyValuesClient(client); } /// @@ -62,6 +62,7 @@ public IObservable CreateOrUpdate(string org, Upsert { Ensure.ArgumentNotNullOrEmptyString(org, nameof(org)); Ensure.ArgumentNotNull(properties, nameof(properties)); + Ensure.ArgumentNotNullOrEmptyEnumerable(properties.Properties, nameof(properties.Properties)); return _client.CreateOrUpdate(org, properties).ToObservable().SelectMany(p => p); } @@ -75,11 +76,12 @@ public IObservable CreateOrUpdate(string org, Upsert /// The name of the organization /// The name of the custom property /// The custom property to create or update - public IObservable CreateOrUpdate(string org, string propertyName, OrganizationCustomPropertyUpdate property) + public IObservable 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)); return _client.CreateOrUpdate(org, propertyName, property).ToObservable(); } diff --git a/Octokit.Reactive/Clients/ObservableOrganizationCustomPropertyValuesClient.cs b/Octokit.Reactive/Clients/ObservableOrganizationCustomPropertyValuesClient.cs index 0d17c2bf7f..bc5c4441a8 100644 --- a/Octokit.Reactive/Clients/ObservableOrganizationCustomPropertyValuesClient.cs +++ b/Octokit.Reactive/Clients/ObservableOrganizationCustomPropertyValuesClient.cs @@ -31,7 +31,7 @@ public IObservable GetAll(string org) { Ensure.ArgumentNotNullOrEmptyString(org, nameof(org)); - return GetAll(org, ApiOptions.None); + return GetAll(org, new OrganizationCustomPropertyValuesRequest()); } /// @@ -61,12 +61,14 @@ public IObservable GetAll(string org, ApiOptio /// The name of the organization /// Finds repositories in the organization with a query containing one or more search keywords and qualifiers. /// Thrown when a general API error occurs. - public IObservable GetAll(string org, SearchRepositoriesRequest repositoryQuery) + public IObservable GetAll(string org, OrganizationCustomPropertyValuesRequest repositoryQuery) { Ensure.ArgumentNotNullOrEmptyString(org, nameof(org)); Ensure.ArgumentNotNull(repositoryQuery, nameof(repositoryQuery)); - return _client.GetAll(org, repositoryQuery).ToObservable().SelectMany(p => p); + var url = ApiUrls.OrganizationCustomPropertyValues(org); + + return _connection.GetAndFlattenAllPages(url, repositoryQuery.Parameters); } /// @@ -85,6 +87,7 @@ public IObservable CreateOrUpdate(string org, UpsertOrganizationCustomProp Ensure.ArgumentNotNullOrEmptyString(org, nameof(org)); Ensure.ArgumentNotNull(propertyValues, nameof(propertyValues)); Ensure.ArgumentNotNullOrEmptyEnumerable(propertyValues.Properties, nameof(propertyValues.Properties)); + Ensure.ArgumentNotNullOrEmptyEnumerable(propertyValues.RepositoryNames, nameof(propertyValues.RepositoryNames)); return _client.CreateOrUpdate(org, propertyValues).ToObservable(); } diff --git a/Octokit.Reactive/Clients/ObservableRepositoryCustomPropertiesClient.cs b/Octokit.Reactive/Clients/ObservableRepositoryCustomPropertiesClient.cs index 0610b9ee43..068012a888 100644 --- a/Octokit.Reactive/Clients/ObservableRepositoryCustomPropertiesClient.cs +++ b/Octokit.Reactive/Clients/ObservableRepositoryCustomPropertiesClient.cs @@ -56,6 +56,7 @@ public IObservable CreateOrUpdate(string owner, string repoName, UpsertRep Ensure.ArgumentNotNullOrEmptyString(owner, nameof(owner)); Ensure.ArgumentNotNullOrEmptyString(repoName, nameof(repoName)); Ensure.ArgumentNotNull(propertyValues, nameof(propertyValues)); + Ensure.ArgumentNotNullOrEmptyEnumerable(propertyValues.Properties, nameof(propertyValues.Properties)); return _client.CreateOrUpdate(owner, repoName, propertyValues).ToObservable(); } diff --git a/Octokit.Tests.Integration/Clients/OrganizationCustomPropertiesClientTests.cs b/Octokit.Tests.Integration/Clients/OrganizationCustomPropertiesClientTests.cs index 9961dd7e49..e5e38df1d9 100644 --- a/Octokit.Tests.Integration/Clients/OrganizationCustomPropertiesClientTests.cs +++ b/Octokit.Tests.Integration/Clients/OrganizationCustomPropertiesClientTests.cs @@ -46,7 +46,7 @@ public class CreateOrUpdateMethod public async Task UpsertCustomProperty() { var github = Helper.GetAuthenticatedClient(); - var upsertValue = GetCustomPropertyUpdateForCreate("UPSERT_TEST", "value"); + var upsertValue = GetCustomPropertyUpdateForCreate("value"); var customProperty = await github.Organization.CustomProperty.CreateOrUpdate(Helper.Organization, "UPSERT_TEST", upsertValue); @@ -66,7 +66,7 @@ public async Task DeleteCustomProperty() var propertyName = "DELETE_TEST"; - var upsertValue = GetCustomPropertyUpdateForCreate(propertyName, "value"); + var upsertValue = GetCustomPropertyUpdateForCreate("value"); await github.Organization.CustomProperty.CreateOrUpdate(Helper.Organization, propertyName, upsertValue); await github.Organization.CustomProperty.Delete(Helper.Organization, propertyName); @@ -90,6 +90,11 @@ private static OrganizationCustomPropertyUpdate GetCustomPropertyUpdateForCreate { return new OrganizationCustomPropertyUpdate { PropertyName = propertyName, DefaultValue = value, ValueType = CustomPropertyValueType.String }; } + + private static UpsertOrganizationCustomProperty GetCustomPropertyUpdateForUpdate(string value) + { + return new UpsertOrganizationCustomProperty { DefaultValue = value, ValueType = CustomPropertyValueType.String }; + } #endif private static async Task CreateRepoIfNotExists(IGitHubClient github, string name) diff --git a/Octokit.Tests/Clients/OrganizationCustomPropertiesClientTests.cs b/Octokit.Tests/Clients/OrganizationCustomPropertiesClientTests.cs index 9f13aee059..c6c59d25b3 100644 --- a/Octokit.Tests/Clients/OrganizationCustomPropertiesClientTests.cs +++ b/Octokit.Tests/Clients/OrganizationCustomPropertiesClientTests.cs @@ -28,7 +28,7 @@ public async Task RequestsTheCorrectUrl() await client.GetAll("org"); connection.Received() - .Get>(Arg.Is(u => u.ToString() == "orgs/org/properties/schemas")); + .Get>(Arg.Is(u => u.ToString() == "orgs/org/properties/schema"), null); } [Fact] @@ -49,10 +49,10 @@ public async Task RequestsTheCorrectUrl() var connection = Substitute.For(); var client = new OrganizationCustomPropertiesClient(connection); - await client.Get("org", "custom_property_name"); + await client.Get("org", "property"); connection.Received() - .Get(Arg.Is(u => u.ToString() == "orgs/org/properties/schemas/custom_property_name")); + .Get(Arg.Is(u => u.ToString() == "orgs/org/properties/schema/property")); } [Fact] @@ -60,10 +60,10 @@ public async Task EnsuresNonNullArguments() { var client = new OrganizationCustomPropertiesClient(Substitute.For()); - await Assert.ThrowsAsync(() => client.Get(null, "custom_property_name")); + await Assert.ThrowsAsync(() => client.Get(null, "property")); await Assert.ThrowsAsync(() => client.Get("org", null)); - await Assert.ThrowsAsync(() => client.Get("", "custom_property_name")); + await Assert.ThrowsAsync(() => client.Get("", "property")); await Assert.ThrowsAsync(() => client.Get("org", "")); } } @@ -86,7 +86,7 @@ public async Task PatchTheCorrectUrl() await client.CreateOrUpdate("org", properties); connection.Received() - .Patch>(Arg.Is(u => u.ToString() == "orgs/org/properties/schemas"), properties); + .Patch>(Arg.Is(u => u.ToString() == "orgs/org/properties/schema"), properties); } [Fact] @@ -117,12 +117,12 @@ public async Task PostsTheCorrectUrl() { var connection = Substitute.For(); var client = new OrganizationCustomPropertiesClient(connection); - var update = new OrganizationCustomPropertyUpdate { PropertyName = "name", DefaultValue = "value", ValueType = CustomPropertyValueType.String }; + var update = new UpsertOrganizationCustomProperty { DefaultValue = "value", ValueType = CustomPropertyValueType.String }; - await client.CreateOrUpdate("org", "custom_property_name", update); + await client.CreateOrUpdate("org", "property", update); connection.Received() - .Put(Arg.Is(u => u.ToString() == "orgs/org/properties/schemas/custom_property_name"), update); + .Put(Arg.Is(u => u.ToString() == "orgs/org/properties/schema/property"), update); } [Fact] @@ -130,14 +130,14 @@ public async Task EnsuresNonNullArguments() { var client = new OrganizationCustomPropertiesClient(Substitute.For()); - var update = new OrganizationCustomPropertyUpdate { PropertyName = "name", DefaultValue = "value", ValueType = CustomPropertyValueType.String }; + var update = new UpsertOrganizationCustomProperty { DefaultValue = "value", ValueType = CustomPropertyValueType.String }; - await Assert.ThrowsAsync(() => client.CreateOrUpdate(null, "custom_property_name", update)); + await Assert.ThrowsAsync(() => client.CreateOrUpdate(null, "property", update)); await Assert.ThrowsAsync(() => client.CreateOrUpdate("owner", null, update)); - await Assert.ThrowsAsync(() => client.CreateOrUpdate("owner", "custom_property_name", null)); - await Assert.ThrowsAsync(() => client.CreateOrUpdate("owner", "custom_property_name", new OrganizationCustomPropertyUpdate())); + await Assert.ThrowsAsync(() => client.CreateOrUpdate("owner", "property", null)); + await Assert.ThrowsAsync(() => client.CreateOrUpdate("owner", "property", new UpsertOrganizationCustomProperty())); - await Assert.ThrowsAsync(() => client.CreateOrUpdate("", "custom_property_name", update)); + await Assert.ThrowsAsync(() => client.CreateOrUpdate("", "property", update)); await Assert.ThrowsAsync(() => client.CreateOrUpdate("owner", "", update)); } } @@ -150,10 +150,10 @@ public async Task DeletesTheCorrectUrl() var connection = Substitute.For(); var client = new OrganizationCustomPropertiesClient(connection); - await client.Delete("org", "custom_property_name"); + await client.Delete("org", "property"); connection.Received() - .Delete(Arg.Is(u => u.ToString() == "orgs/org/properties/schemas/custom_property_name")); + .Delete(Arg.Is(u => u.ToString() == "orgs/org/properties/schema/property")); } [Fact] @@ -161,10 +161,10 @@ public async Task EnsuresNonNullArguments() { var client = new OrganizationCustomPropertiesClient(Substitute.For()); - await Assert.ThrowsAsync(() => client.Delete(null, "custom_property_name")); + await Assert.ThrowsAsync(() => client.Delete(null, "property")); await Assert.ThrowsAsync(() => client.Delete("owner", null)); - await Assert.ThrowsAsync(() => client.Delete("", "custom_property_name")); + await Assert.ThrowsAsync(() => client.Delete("", "property")); await Assert.ThrowsAsync(() => client.Delete("owner", "")); } } diff --git a/Octokit.Tests/Clients/OrganizationCustomPropertyValuesClientTests.cs b/Octokit.Tests/Clients/OrganizationCustomPropertyValuesClientTests.cs index 9bda59ebe0..670312887b 100644 --- a/Octokit.Tests/Clients/OrganizationCustomPropertyValuesClientTests.cs +++ b/Octokit.Tests/Clients/OrganizationCustomPropertyValuesClientTests.cs @@ -28,7 +28,26 @@ public async Task RequestsTheCorrectUrl() await client.GetAll("org"); connection.Received() - .Get>(Arg.Is(u => u.ToString() == "orgs/org/properties/values")); + .GetAll(Arg.Is(u => u.ToString() == "orgs/org/properties/values"), Arg.Any>()); + } + + [Fact] + public void RequestsTheCorrectUrlWithApiOptions() + { + var connection = Substitute.For(); + var client = new OrganizationCustomPropertyValuesClient(connection); + + var options = new ApiOptions + { + PageCount = 1, + StartPage = 1, + PageSize = 1 + }; + + client.GetAll("org", options); + + connection.Received() + .GetAll(Arg.Is(u => u.ToString() == "orgs/org/properties/values"), options); } [Fact] @@ -37,7 +56,11 @@ public async Task EnsuresNonNullArguments() var client = new OrganizationCustomPropertyValuesClient(Substitute.For()); await Assert.ThrowsAsync(() => client.GetAll(null)); + await Assert.ThrowsAsync(() => client.GetAll(null, new OrganizationCustomPropertyValuesRequest())); + await Assert.ThrowsAsync(() => client.GetAll("org", repositoryQuery: null)); + await Assert.ThrowsAsync(() => client.GetAll("")); + await Assert.ThrowsAsync(() => client.GetAll("", new OrganizationCustomPropertyValuesRequest())); } } @@ -60,7 +83,7 @@ public async Task PatchTheCorrectUrl() await client.CreateOrUpdate("org", propertyValues); connection.Received() - .Patch>(Arg.Is(u => u.ToString() == "orgs/org/properties/values"), propertyValues); + .Patch(Arg.Is(u => u.ToString() == "orgs/org/properties/values"), propertyValues); } [Fact] diff --git a/Octokit.Tests/Clients/RepositoryCustomPropertiesClientTests.cs b/Octokit.Tests/Clients/RepositoryCustomPropertiesClientTests.cs index 23574e6f25..9c53cb2026 100644 --- a/Octokit.Tests/Clients/RepositoryCustomPropertiesClientTests.cs +++ b/Octokit.Tests/Clients/RepositoryCustomPropertiesClientTests.cs @@ -28,7 +28,7 @@ public async Task RequestsTheCorrectUrl() await client.GetAll("org", "repo"); connection.Received() - .Get(Arg.Is(u => u.ToString() == "repos/org/repo/properties/values")); + .Get>(Arg.Is(u => u.ToString() == "repos/org/repo/properties/values"), null); } [Fact] @@ -62,7 +62,7 @@ public async Task PatchTheCorrectUrl() await client.CreateOrUpdate("org", "repo", propertyValues); connection.Received() - .Patch>(Arg.Is(u => u.ToString() == "repos/org/repo/properties/values"), propertyValues); + .Patch(Arg.Is(u => u.ToString() == "repos/org/repo/properties/values"), propertyValues); } [Fact] diff --git a/Octokit.Tests/Reactive/ObservableOrganizationCustomPropertiesClientTests.cs b/Octokit.Tests/Reactive/ObservableOrganizationCustomPropertiesClientTests.cs index 089b8d9225..b3bc77fc29 100644 --- a/Octokit.Tests/Reactive/ObservableOrganizationCustomPropertiesClientTests.cs +++ b/Octokit.Tests/Reactive/ObservableOrganizationCustomPropertiesClientTests.cs @@ -23,12 +23,12 @@ public void EnsuresNonNullArguments() public class GetAllMethod { [Fact] - public async Task RequestsTheCorrectUrl() + public void RequestsTheCorrectUrl() { var gitHubClient = Substitute.For(); var client = new ObservableOrganizationCustomPropertiesClient(gitHubClient); - await client.GetAll("org"); + client.GetAll("org"); gitHubClient.Received().Organization.CustomProperty.GetAll("org"); } @@ -51,9 +51,9 @@ public async Task RequestsTheCorrectUrl() var gitHubClient = Substitute.For(); var client = new ObservableOrganizationCustomPropertiesClient(gitHubClient); - await client.Get("org", "custom_property_name"); + await client.Get("org", "property"); - gitHubClient.Received().Organization.CustomProperty.Get("org", "custom_property_name"); + gitHubClient.Received().Organization.CustomProperty.Get("org", "property"); } [Fact] @@ -61,10 +61,10 @@ public async Task EnsuresNonNullArguments() { var client = new ObservableOrganizationCustomPropertiesClient(Substitute.For()); - await Assert.ThrowsAsync(() => client.Get(null, "custom_property_name").ToTask()); + await Assert.ThrowsAsync(() => client.Get(null, "property").ToTask()); await Assert.ThrowsAsync(() => client.Get("org", null).ToTask()); - await Assert.ThrowsAsync(() => client.Get("", "custom_property_name").ToTask()); + await Assert.ThrowsAsync(() => client.Get("", "property").ToTask()); await Assert.ThrowsAsync(() => client.Get("org", "").ToTask()); } } @@ -72,7 +72,7 @@ public async Task EnsuresNonNullArguments() public class BatchCreateOrUpdateMethod { [Fact] - public async Task PostsTheCorrectUrl() + public void PostsTheCorrectUrl() { var gitHubClient = Substitute.For(); var client = new ObservableOrganizationCustomPropertiesClient(gitHubClient); @@ -83,7 +83,8 @@ public async Task PostsTheCorrectUrl() new OrganizationCustomPropertyUpdate { PropertyName = "name", DefaultValue = "value", ValueType = CustomPropertyValueType.String } } }; - await client.CreateOrUpdate("org", properties); + + client.CreateOrUpdate("org", properties); gitHubClient.Received().Organization.CustomProperty.CreateOrUpdate("org", properties); } @@ -92,7 +93,6 @@ public async Task PostsTheCorrectUrl() public async Task EnsuresNonNullArguments() { var client = new ObservableOrganizationCustomPropertiesClient(Substitute.For()); - var properties = new UpsertOrganizationCustomProperties { Properties = new List @@ -116,11 +116,11 @@ public async Task PostsTheCorrectUrl() { var gitHubClient = Substitute.For(); var client = new ObservableOrganizationCustomPropertiesClient(gitHubClient); - var update = new OrganizationCustomPropertyUpdate { PropertyName = "name", DefaultValue = "value", ValueType = CustomPropertyValueType.String }; + var update = new UpsertOrganizationCustomProperty { DefaultValue = "value", ValueType = CustomPropertyValueType.String }; - await client.CreateOrUpdate("org", "custom_property_name", update); + await client.CreateOrUpdate("org", "property", update); - gitHubClient.Received().Organization.CustomProperty.CreateOrUpdate("org", "custom_property_name", update); + gitHubClient.Received().Organization.CustomProperty.CreateOrUpdate("org", "property", update); } [Fact] @@ -128,14 +128,14 @@ public async Task EnsuresNonNullArguments() { var client = new ObservableOrganizationCustomPropertiesClient(Substitute.For()); - var update = new OrganizationCustomPropertyUpdate { PropertyName = "name", DefaultValue = "value", ValueType = CustomPropertyValueType.String }; + var update = new UpsertOrganizationCustomProperty { DefaultValue = "value", ValueType = CustomPropertyValueType.String }; - await Assert.ThrowsAsync(() => client.CreateOrUpdate(null, "custom_property_name", update).ToTask()); + await Assert.ThrowsAsync(() => client.CreateOrUpdate(null, "property", update).ToTask()); await Assert.ThrowsAsync(() => client.CreateOrUpdate("owner", null, update).ToTask()); - await Assert.ThrowsAsync(() => client.CreateOrUpdate("owner", "custom_property_name", null).ToTask()); - await Assert.ThrowsAsync(() => client.CreateOrUpdate("owner", "custom_property_name", new OrganizationCustomPropertyUpdate()).ToTask()); + await Assert.ThrowsAsync(() => client.CreateOrUpdate("owner", "property", null).ToTask()); + await Assert.ThrowsAsync(() => client.CreateOrUpdate("owner", "property", new UpsertOrganizationCustomProperty()).ToTask()); - await Assert.ThrowsAsync(() => client.CreateOrUpdate("", "custom_property_name", update).ToTask()); + await Assert.ThrowsAsync(() => client.CreateOrUpdate("", "property", update).ToTask()); await Assert.ThrowsAsync(() => client.CreateOrUpdate("owner", "", update).ToTask()); } } @@ -148,9 +148,9 @@ public async Task DeletesTheCorrectUrl() var gitHubClient = Substitute.For(); var client = new ObservableOrganizationCustomPropertiesClient(gitHubClient); - await client.Delete("org", "custom_property_name"); + await client.Delete("org", "property"); - gitHubClient.Received().Organization.CustomProperty.Delete("org", "custom_property_name"); + gitHubClient.Received().Organization.CustomProperty.Delete("org", "property"); } [Fact] @@ -158,10 +158,10 @@ public async Task EnsuresNonNullArguments() { var client = new ObservableOrganizationCustomPropertiesClient(Substitute.For()); - await Assert.ThrowsAsync(() => client.Delete(null, "custom_property_name").ToTask()); + await Assert.ThrowsAsync(() => client.Delete(null, "property").ToTask()); await Assert.ThrowsAsync(() => client.Delete("owner", null).ToTask()); - await Assert.ThrowsAsync(() => client.Delete("", "custom_property_name").ToTask()); + await Assert.ThrowsAsync(() => client.Delete("", "property").ToTask()); await Assert.ThrowsAsync(() => client.Delete("owner", "").ToTask()); } } diff --git a/Octokit.Tests/Reactive/ObservableOrganizationCustomPropertyValuesClientTests.cs b/Octokit.Tests/Reactive/ObservableOrganizationCustomPropertyValuesClientTests.cs index 6671760f8d..0cec50b06b 100644 --- a/Octokit.Tests/Reactive/ObservableOrganizationCustomPropertyValuesClientTests.cs +++ b/Octokit.Tests/Reactive/ObservableOrganizationCustomPropertyValuesClientTests.cs @@ -23,12 +23,12 @@ public void EnsuresNonNullArguments() public class GetAllMethod { [Fact] - public async Task RequestsTheCorrectUrl() + public void RequestsTheCorrectUrl() { var gitHubClient = Substitute.For(); var client = new ObservableOrganizationCustomPropertyValuesClient(gitHubClient); - await client.GetAll("org"); + client.GetAll("org"); gitHubClient.Received().Organization.CustomProperty.Values.GetAll("org"); } diff --git a/Octokit.Tests/Reactive/ObservableRepositoryCustomPropertiesClientTests.cs b/Octokit.Tests/Reactive/ObservableRepositoryCustomPropertiesClientTests.cs index 44c0a7ab13..3a7450c3bc 100644 --- a/Octokit.Tests/Reactive/ObservableRepositoryCustomPropertiesClientTests.cs +++ b/Octokit.Tests/Reactive/ObservableRepositoryCustomPropertiesClientTests.cs @@ -23,12 +23,12 @@ public void EnsuresNonNullArguments() public class GetAllMethod { [Fact] - public async Task RequestsTheCorrectUrl() + public void RequestsTheCorrectUrl() { var gitHubClient = Substitute.For(); var client = new ObservableRepositoryCustomPropertiesClient(gitHubClient); - await client.GetAll("org", "repo"); + client.GetAll("org", "repo"); gitHubClient.Received().Repository.CustomProperty.GetAll("org", "repo"); } diff --git a/Octokit/Clients/IOrganizationCustomPropertiesClient.cs b/Octokit/Clients/IOrganizationCustomPropertiesClient.cs index e203b702d6..8e5a866f60 100644 --- a/Octokit/Clients/IOrganizationCustomPropertiesClient.cs +++ b/Octokit/Clients/IOrganizationCustomPropertiesClient.cs @@ -50,7 +50,7 @@ public interface IOrganizationCustomPropertiesClient /// The name of the organization /// The name of the custom property /// The custom property to create or update - Task CreateOrUpdate(string org, string propertyName, OrganizationCustomPropertyUpdate property); + Task CreateOrUpdate(string org, string propertyName, UpsertOrganizationCustomProperty property); /// /// Removes a custom property that is defined for an organization. diff --git a/Octokit/Clients/IOrganizationCustomPropertyValuesClient.cs b/Octokit/Clients/IOrganizationCustomPropertyValuesClient.cs index 188ea03fc3..62bfb00e3c 100644 --- a/Octokit/Clients/IOrganizationCustomPropertyValuesClient.cs +++ b/Octokit/Clients/IOrganizationCustomPropertyValuesClient.cs @@ -38,8 +38,8 @@ public interface IOrganizationCustomPropertyValuesClient /// /// The name of the organization /// Finds repositories in the organization with a query containing one or more search keywords and qualifiers. - [ExcludeFromPaginationApiOptionsConventionTest("This API call uses the SearchRepositoriesRequest parameter for pagination")] - Task> GetAll(string org, SearchRepositoriesRequest repositoryQuery); + [ExcludeFromPaginationApiOptionsConventionTest("This API call uses the OrganizationCustomPropertyValuesRequest parameter for pagination")] + Task> GetAll(string org, OrganizationCustomPropertyValuesRequest repositoryQuery); /// /// Create new or update existing custom property values for repositories an organization. diff --git a/Octokit/Clients/OrganizationCustomPropertiesClient.cs b/Octokit/Clients/OrganizationCustomPropertiesClient.cs index 1f8a19b574..0e47e65e12 100644 --- a/Octokit/Clients/OrganizationCustomPropertiesClient.cs +++ b/Octokit/Clients/OrganizationCustomPropertiesClient.cs @@ -22,14 +22,14 @@ public OrganizationCustomPropertiesClient(IApiConnection apiConnection) /// See the API documentation for more information. /// /// The name of the organization - [ManualRoute("GET", "orgs/{org}/properties/schemas")] + [ManualRoute("GET", "orgs/{org}/properties/schema")] public Task> GetAll(string org) { Ensure.ArgumentNotNullOrEmptyString(org, nameof(org)); var url = ApiUrls.OrganizationCustomProperties(org); - return ApiConnection.GetAll(url); + return ApiConnection.Get>(url, null); } /// @@ -40,7 +40,7 @@ public Task> GetAll(string org) /// /// The name of the organization /// The name of the custom property - [ManualRoute("GET", "orgs/{org}/properties/schemas/{custom_property_name}")] + [ManualRoute("GET", "orgs/{org}/properties/schema/{propertyName}")] public Task Get(string org, string propertyName) { Ensure.ArgumentNotNullOrEmptyString(org, nameof(org)); @@ -59,11 +59,12 @@ public Task Get(string org, string propertyName) /// /// The name of the organization /// The custom properties to create or update - [ManualRoute("PATCH", "orgs/{org}/properties/schemas")] + [ManualRoute("PATCH", "orgs/{org}/properties/schema")] public Task> 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); @@ -79,12 +80,13 @@ public Task> CreateOrUpdate(string org /// The name of the organization /// The name of the custom property /// The custom property to create or update - [ManualRoute("PUT", "orgs/{org}/properties/schemas/{custom_property_name}")] - public Task CreateOrUpdate(string org, string propertyName, OrganizationCustomPropertyUpdate property) + [ManualRoute("PUT", "orgs/{org}/properties/schema/{propertyName}")] + public Task 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); @@ -99,7 +101,7 @@ public Task CreateOrUpdate(string org, string proper /// /// The name of the organization /// The name of the custom property - [ManualRoute("DELETE", "orgs/{org}/properties/schemas/{custom_property_name}")] + [ManualRoute("DELETE", "orgs/{org}/properties/schema/{propertyName}")] public Task Delete(string org, string propertyName) { Ensure.ArgumentNotNullOrEmptyString(org, nameof(org)); diff --git a/Octokit/Clients/OrganizationCustomPropertyValuesClient.cs b/Octokit/Clients/OrganizationCustomPropertyValuesClient.cs index 64f9766226..d3aa2c98d1 100644 --- a/Octokit/Clients/OrganizationCustomPropertyValuesClient.cs +++ b/Octokit/Clients/OrganizationCustomPropertyValuesClient.cs @@ -27,7 +27,7 @@ public Task> GetAll(string org) { Ensure.ArgumentNotNullOrEmptyString(org, nameof(org)); - return GetAll(org, ApiOptions.None); + return GetAll(org, new OrganizationCustomPropertyValuesRequest()); } /// @@ -60,7 +60,7 @@ public Task> GetAll(string org, /// Finds repositories in the organization with a query containing one or more search keywords and qualifiers. /// Thrown when a general API error occurs. [ManualRoute("GET", "orgs/{org}/properties/values")] - public Task> GetAll(string org, SearchRepositoriesRequest repositoryQuery) + public Task> GetAll(string org, OrganizationCustomPropertyValuesRequest repositoryQuery) { Ensure.ArgumentNotNullOrEmptyString(org, nameof(org)); Ensure.ArgumentNotNull(repositoryQuery, nameof(repositoryQuery)); diff --git a/Octokit/Clients/RepositoryCustomPropertiesClient.cs b/Octokit/Clients/RepositoryCustomPropertiesClient.cs index 9ee4da5b82..b86a03ec59 100644 --- a/Octokit/Clients/RepositoryCustomPropertiesClient.cs +++ b/Octokit/Clients/RepositoryCustomPropertiesClient.cs @@ -37,7 +37,7 @@ public Task> GetAll(string owner, string repo var url = ApiUrls.RepositoryCustomPropertyValues(owner, repoName); - return ApiConnection.GetAll(url); + return ApiConnection.Get>(url, null); } /// @@ -56,6 +56,7 @@ public Task CreateOrUpdate(string owner, string repoName, UpsertRepositoryCustom 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); diff --git a/Octokit/Models/Request/OrganizationCustomPropertyUpdate.cs b/Octokit/Models/Request/OrganizationCustomPropertyUpdate.cs index c1829402bf..574a85c39e 100644 --- a/Octokit/Models/Request/OrganizationCustomPropertyUpdate.cs +++ b/Octokit/Models/Request/OrganizationCustomPropertyUpdate.cs @@ -39,7 +39,7 @@ public OrganizationCustomPropertyUpdate(string propertyName, CustomPropertyValue /// /// The type of the value for the property /// - public StringEnum? ValueType { get; set; } + public StringEnum ValueType { get; set; } /// /// Whether the property is required diff --git a/Octokit/Models/Request/OrganizationCustomPropertyValuesRequest.cs b/Octokit/Models/Request/OrganizationCustomPropertyValuesRequest.cs new file mode 100644 index 0000000000..3dc7271712 --- /dev/null +++ b/Octokit/Models/Request/OrganizationCustomPropertyValuesRequest.cs @@ -0,0 +1,51 @@ +using System.Collections.Generic; +using System.Diagnostics; + +namespace Octokit +{ + [DebuggerDisplay("{DebuggerDisplay,nq}")] + public class OrganizationCustomPropertyValuesRequest : SearchRepositoriesRequest + { + /// + /// Initializes a new instance of the class. + /// + public OrganizationCustomPropertyValuesRequest() : base() + { } + + /// + /// Initializes a new instance of the class. + /// + public OrganizationCustomPropertyValuesRequest(string term) + : base(term) + { } + + public override string Sort => null; + + /// + /// Get the query parameters that will be appending onto the search + /// + public new IDictionary 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; + } + } + } +} diff --git a/Octokit/Models/Request/UpsertOrganizationCustomProperty.cs b/Octokit/Models/Request/UpsertOrganizationCustomProperty.cs new file mode 100644 index 0000000000..4cf02e4099 --- /dev/null +++ b/Octokit/Models/Request/UpsertOrganizationCustomProperty.cs @@ -0,0 +1,58 @@ +using System.Collections.Generic; +using System.Diagnostics; +using System.Globalization; + +namespace Octokit +{ + /// + /// Used to create or update a custom property value for a repository + /// + [DebuggerDisplay("{DebuggerDisplay,nq}")] + public class UpsertOrganizationCustomProperty + { + public UpsertOrganizationCustomProperty() { } + + public UpsertOrganizationCustomProperty(CustomPropertyValueType valueType) + { + ValueType = valueType; + } + + /// + /// The type of the value for the property + /// + public StringEnum ValueType { get; set; } + + /// + /// Whether the property is required + /// + public bool Required { get; set; } + + /// + /// Default value of the property + /// + public string DefaultValue { get; set; } + + /// + /// Default values of the property + /// + public IReadOnlyList DefaultValues { get; set; } + + /// + /// Short description of the property + /// + public string Description { get; set; } + + /// + /// An ordered list of the allowed values of the property. + /// The property can have up to 200 allowed values. + /// + public IEnumerable AllowedValues { get; set; } + + /// + /// Who can edit the values of the property + /// + public StringEnum? ValuesEditableBy { get; set; } + + internal string DebuggerDisplay => string.Format(CultureInfo.InvariantCulture, "ValueType: {0}", ValueType.DebuggerDisplay); + } +} From b1a7473ff3f673c2ed5b934668ca3076c287c1fa Mon Sep 17 00:00:00 2001 From: Colby Williams Date: Mon, 17 Jun 2024 15:49:18 -0500 Subject: [PATCH 10/11] (de)serialization and model tests --- ...OrganizationCustomPropertiesClientTests.cs | 4 +- ...nizationCustomPropertyValuesClientTests.cs | 2 +- .../RepositoryCustomPropertiesClientTests.cs | 2 +- ...OrganizationCustomPropertiesClientTests.cs | 8 +- ...nizationCustomPropertyValuesClientTests.cs | 4 +- .../RepositoryCustomPropertiesClientTests.cs | 4 +- .../Models/CustomPropertyValueTests.cs | 59 +++++++++ .../Models/CustomPropertyValueUpdateTests.cs | 62 +++++++++ .../OrganizationCustomPropertiesTests.cs | 104 +++++++++++++++ .../OrganizationCustomPropertyUpdateTests.cs | 70 ++++++++++ .../OrganizationCustomPropertyValuesTests.cs | 121 ++++++++++++++++++ .../UpsertOrganizationCustomPropertyTests.cs | 66 ++++++++++ ...OrganizationCustomPropertiesClientTests.cs | 8 +- ...nizationCustomPropertyValuesClientTests.cs | 4 +- ...leRepositoryCustomPropertiesClientTests.cs | 4 +- .../Request/CustomPropertyValueUpdate.cs | 12 +- .../OrganizationCustomPropertyUpdate.cs | 23 +--- .../UpsertOrganizationCustomProperty.cs | 21 ++- .../Models/Response/CustomPropertyValue.cs | 64 ++++++--- .../Response/OrganizationCustomProperty.cs | 68 ++++++---- 20 files changed, 616 insertions(+), 94 deletions(-) create mode 100644 Octokit.Tests/Models/CustomPropertyValueTests.cs create mode 100644 Octokit.Tests/Models/CustomPropertyValueUpdateTests.cs create mode 100644 Octokit.Tests/Models/OrganizationCustomPropertiesTests.cs create mode 100644 Octokit.Tests/Models/OrganizationCustomPropertyUpdateTests.cs create mode 100644 Octokit.Tests/Models/OrganizationCustomPropertyValuesTests.cs create mode 100644 Octokit.Tests/Models/UpsertOrganizationCustomPropertyTests.cs diff --git a/Octokit.Tests.Integration/Clients/OrganizationCustomPropertiesClientTests.cs b/Octokit.Tests.Integration/Clients/OrganizationCustomPropertiesClientTests.cs index e5e38df1d9..a49d538998 100644 --- a/Octokit.Tests.Integration/Clients/OrganizationCustomPropertiesClientTests.cs +++ b/Octokit.Tests.Integration/Clients/OrganizationCustomPropertiesClientTests.cs @@ -88,12 +88,12 @@ private static UpsertOrganizationCustomProperties GetCustomPropertiesForCreate(s private static OrganizationCustomPropertyUpdate GetCustomPropertyUpdateForCreate(string propertyName, string value) { - return new OrganizationCustomPropertyUpdate { PropertyName = propertyName, DefaultValue = value, ValueType = CustomPropertyValueType.String }; + return new OrganizationCustomPropertyUpdate(propertyName, CustomPropertyValueType.String, value); } private static UpsertOrganizationCustomProperty GetCustomPropertyUpdateForUpdate(string value) { - return new UpsertOrganizationCustomProperty { DefaultValue = value, ValueType = CustomPropertyValueType.String }; + return new UpsertOrganizationCustomProperty(CustomPropertyValueType.String, value); } #endif diff --git a/Octokit.Tests.Integration/Clients/OrganizationCustomPropertyValuesClientTests.cs b/Octokit.Tests.Integration/Clients/OrganizationCustomPropertyValuesClientTests.cs index 30ba3c4ce7..24169eb251 100644 --- a/Octokit.Tests.Integration/Clients/OrganizationCustomPropertyValuesClientTests.cs +++ b/Octokit.Tests.Integration/Clients/OrganizationCustomPropertyValuesClientTests.cs @@ -44,7 +44,7 @@ public async Task UpsertPropertyValues() RepositoryNames = new List { "repo" }, Properties = new List { - new CustomPropertyValueUpdate { PropertyName = "UPSERT_TEST", Value = "value" } + new CustomPropertyValueUpdate("UPSERT_TEST", "value") } }; diff --git a/Octokit.Tests.Integration/Clients/RepositoryCustomPropertiesClientTests.cs b/Octokit.Tests.Integration/Clients/RepositoryCustomPropertiesClientTests.cs index 3c66e89148..9b8994c4b9 100644 --- a/Octokit.Tests.Integration/Clients/RepositoryCustomPropertiesClientTests.cs +++ b/Octokit.Tests.Integration/Clients/RepositoryCustomPropertiesClientTests.cs @@ -44,7 +44,7 @@ public async Task UpsertPropertyValues() { Properties = new List { - new CustomPropertyValueUpdate { PropertyName = "TEST", Value = "UPSERT_TEST" } + new CustomPropertyValueUpdate("TEST", "UPSERT_TEST") } }; diff --git a/Octokit.Tests/Clients/OrganizationCustomPropertiesClientTests.cs b/Octokit.Tests/Clients/OrganizationCustomPropertiesClientTests.cs index c6c59d25b3..9675054051 100644 --- a/Octokit.Tests/Clients/OrganizationCustomPropertiesClientTests.cs +++ b/Octokit.Tests/Clients/OrganizationCustomPropertiesClientTests.cs @@ -79,7 +79,7 @@ public async Task PatchTheCorrectUrl() { Properties = new List { - new OrganizationCustomPropertyUpdate { PropertyName = "name", DefaultValue = "value", ValueType = CustomPropertyValueType.String } + new OrganizationCustomPropertyUpdate("name", CustomPropertyValueType.String, "default") } }; @@ -98,7 +98,7 @@ public async Task EnsuresNonNullArguments() { Properties = new List { - new OrganizationCustomPropertyUpdate { PropertyName = "name", DefaultValue = "value", ValueType = CustomPropertyValueType.String } + new OrganizationCustomPropertyUpdate("name", CustomPropertyValueType.String, "default") } }; @@ -117,7 +117,7 @@ public async Task PostsTheCorrectUrl() { var connection = Substitute.For(); var client = new OrganizationCustomPropertiesClient(connection); - var update = new UpsertOrganizationCustomProperty { DefaultValue = "value", ValueType = CustomPropertyValueType.String }; + var update = new UpsertOrganizationCustomProperty(CustomPropertyValueType.String, "value"); await client.CreateOrUpdate("org", "property", update); @@ -130,7 +130,7 @@ public async Task EnsuresNonNullArguments() { var client = new OrganizationCustomPropertiesClient(Substitute.For()); - var update = new UpsertOrganizationCustomProperty { DefaultValue = "value", ValueType = CustomPropertyValueType.String }; + var update = new UpsertOrganizationCustomProperty(CustomPropertyValueType.String, "value"); await Assert.ThrowsAsync(() => client.CreateOrUpdate(null, "property", update)); await Assert.ThrowsAsync(() => client.CreateOrUpdate("owner", null, update)); diff --git a/Octokit.Tests/Clients/OrganizationCustomPropertyValuesClientTests.cs b/Octokit.Tests/Clients/OrganizationCustomPropertyValuesClientTests.cs index 670312887b..1b363ab661 100644 --- a/Octokit.Tests/Clients/OrganizationCustomPropertyValuesClientTests.cs +++ b/Octokit.Tests/Clients/OrganizationCustomPropertyValuesClientTests.cs @@ -76,7 +76,7 @@ public async Task PatchTheCorrectUrl() RepositoryNames = new List { "repo" }, Properties = new List { - new CustomPropertyValueUpdate { PropertyName = "name", Value = "value" } + new CustomPropertyValueUpdate("name", "value") } }; @@ -95,7 +95,7 @@ public async Task EnsuresNonNullArguments() RepositoryNames = new List { "repo" }, Properties = new List { - new CustomPropertyValueUpdate { PropertyName = "name", Value = "value" } + new CustomPropertyValueUpdate("name", "value") } }; diff --git a/Octokit.Tests/Clients/RepositoryCustomPropertiesClientTests.cs b/Octokit.Tests/Clients/RepositoryCustomPropertiesClientTests.cs index 9c53cb2026..0ab1626fac 100644 --- a/Octokit.Tests/Clients/RepositoryCustomPropertiesClientTests.cs +++ b/Octokit.Tests/Clients/RepositoryCustomPropertiesClientTests.cs @@ -55,7 +55,7 @@ public async Task PatchTheCorrectUrl() { Properties = new List { - new CustomPropertyValueUpdate { PropertyName = "name", Value = "value" } + new CustomPropertyValueUpdate("name", "value") } }; @@ -73,7 +73,7 @@ public async Task EnsuresNonNullArguments() { Properties = new List { - new CustomPropertyValueUpdate { PropertyName = "name", Value = "value" } + new CustomPropertyValueUpdate("name", "value") } }; diff --git a/Octokit.Tests/Models/CustomPropertyValueTests.cs b/Octokit.Tests/Models/CustomPropertyValueTests.cs new file mode 100644 index 0000000000..184203810d --- /dev/null +++ b/Octokit.Tests/Models/CustomPropertyValueTests.cs @@ -0,0 +1,59 @@ +using System.Collections.Generic; +using Octokit.Internal; +using Xunit; + +namespace Octokit.Tests.Models +{ + public class CustomPropertyValuesTests + { + [Fact] + public void CanBeDeserialized() + { + const string json = @"[ + { + ""property_name"": ""test_ms"", + ""value"": [ + ""option_d"", + ""option_e"" + ] + }, + { + ""property_name"": ""test_ss"", + ""value"": ""option_c"" + }, + { + ""property_name"": ""test_str"", + ""value"": ""hello"" + }, + { + ""property_name"": ""test_tf"", + ""value"": ""unset"" + } +] +"; + var serializer = new SimpleJsonSerializer(); + + var properties = serializer.Deserialize>(json); + + Assert.NotNull(properties); + Assert.Equal(4, properties.Count); + + var testMs = properties[0]; + Assert.Equal("test_ms", testMs.PropertyName); + Assert.Equal(new List { "option_d", "option_e" }, testMs.Values); + + var testSs = properties[1]; + Assert.Equal("test_ss", testSs.PropertyName); + Assert.Equal("option_c", testSs.Value); + Assert.Equal(new List { "option_c" }, testSs.Values); + + var testStr = properties[2]; + Assert.Equal("test_str", testStr.PropertyName); + Assert.Equal("hello", testStr.Value); + + var testTf = properties[3]; + Assert.Equal("test_tf", testTf.PropertyName); + Assert.Equal("unset", testTf.Value); + } + } +} diff --git a/Octokit.Tests/Models/CustomPropertyValueUpdateTests.cs b/Octokit.Tests/Models/CustomPropertyValueUpdateTests.cs new file mode 100644 index 0000000000..c2a853c87e --- /dev/null +++ b/Octokit.Tests/Models/CustomPropertyValueUpdateTests.cs @@ -0,0 +1,62 @@ +using System.Collections.Generic; +using Octokit.Internal; +using Xunit; + +namespace Octokit.Tests.Models +{ + public class CustomPropertyValueUpdateTests + { + [Fact] + public void CanSerializeMultiSelect() + { + var expected = "{\"property_name\":\"test_ms\"," + + "\"value\":[\"option_d\",\"option_e\"]}"; + + + var update = new CustomPropertyValueUpdate("test_ms", new List { "option_d", "option_e" }); + + var json = new SimpleJsonSerializer().Serialize(update); + + Assert.Equal(expected, json); + } + + [Fact] + public void CanSerializeSingleSelect() + { + var expected = "{\"property_name\":\"test_ss\"," + + "\"value\":\"option_c\"}"; + + var update = new CustomPropertyValueUpdate("test_ss", "option_c"); + + var json = new SimpleJsonSerializer().Serialize(update); + + Assert.Equal(expected, json); + } + + [Fact] + public void CanSerializeString() + { + var expected = "{\"property_name\":\"test_str\"," + + "\"value\":\"hello\"}"; + + var update = new CustomPropertyValueUpdate("test_str", "hello"); + + var json = new SimpleJsonSerializer().Serialize(update); + + Assert.Equal(expected, json); + } + + [Fact] + public void CanSerializeTrueFalse() + { + var expected = "{\"property_name\":\"test_tf\"," + + "\"value\":\"true\"}"; + + var update = new CustomPropertyValueUpdate("test_tf", "true"); + + var json = new SimpleJsonSerializer().Serialize(update); + + Assert.Equal(expected, json); + } + } +} diff --git a/Octokit.Tests/Models/OrganizationCustomPropertiesTests.cs b/Octokit.Tests/Models/OrganizationCustomPropertiesTests.cs new file mode 100644 index 0000000000..1261abb5cf --- /dev/null +++ b/Octokit.Tests/Models/OrganizationCustomPropertiesTests.cs @@ -0,0 +1,104 @@ +using System.Collections.Generic; +using Octokit.Internal; +using Xunit; + +namespace Octokit.Tests.Models +{ + public class OrganizationCustomPropertiesTests + { + [Fact] + public void CanBeDeserialized() + { + const string json = @"[ + { + ""property_name"": ""test_ms"", + ""value_type"": ""multi_select"", + ""required"": true, + ""default_value"": [ + ""option_d"", + ""option_e"" + ], + ""description"": ""multi_select property"", + ""allowed_values"": [ + ""option_a"", + ""option_b"", + ""option_c"", + ""option_d"", + ""option_e"" + ], + ""values_editable_by"": ""org_actors"" + }, + { + ""property_name"": ""test_ss"", + ""value_type"": ""single_select"", + ""required"": true, + ""default_value"": ""option_c"", + ""description"": ""single_select property"", + ""allowed_values"": [ + ""option_a"", + ""option_b"", + ""option_c"", + ""option_d"", + ""option_e"" + ], + ""values_editable_by"": ""org_actors"" + }, + { + ""property_name"": ""test_str"", + ""value_type"": ""string"", + ""required"": false, + ""description"": ""string property"", + ""values_editable_by"": ""org_actors"" + }, + { + ""property_name"": ""test_tf"", + ""value_type"": ""true_false"", + ""required"": true, + ""default_value"": ""unset"", + ""description"": ""true_false property"", + ""values_editable_by"": ""org_actors"" + } +] +"; + var serializer = new SimpleJsonSerializer(); + + var properties = serializer.Deserialize>(json); + Assert.NotNull(properties); + Assert.Equal(4, properties.Count); + + var testMs = properties[0]; + Assert.Equal("test_ms", testMs.PropertyName); + Assert.Equal(CustomPropertyValueType.MultiSelect, testMs.ValueType); + Assert.True(testMs.Required); + Assert.Equal(new List { "option_d", "option_e" }, testMs.DefaultValues); + Assert.Equal("multi_select property", testMs.Description); + Assert.Equal(new List { "option_a", "option_b", "option_c", "option_d", "option_e" }, testMs.AllowedValues); + Assert.Equal(CustomPropertyValuesEditableBy.OrgActors, testMs.ValuesEditableBy); + + var testSs = properties[1]; + Assert.Equal("test_ss", testSs.PropertyName); + Assert.Equal(CustomPropertyValueType.SingleSelect, testSs.ValueType); + Assert.True(testSs.Required); + Assert.Equal("option_c", testSs.DefaultValue); + Assert.Equal(new List { "option_c" }, testSs.DefaultValues); + Assert.Equal("single_select property", testSs.Description); + Assert.Equal(new List { "option_a", "option_b", "option_c", "option_d", "option_e" }, testSs.AllowedValues); + Assert.Equal(CustomPropertyValuesEditableBy.OrgActors, testSs.ValuesEditableBy); + + var testStr = properties[2]; + Assert.Equal("test_str", testStr.PropertyName); + Assert.Equal(CustomPropertyValueType.String, testStr.ValueType); + Assert.False(testStr.Required); + Assert.Equal("string property", testStr.Description); + Assert.Equal(CustomPropertyValuesEditableBy.OrgActors, testStr.ValuesEditableBy); + + var testTf = properties[3]; + Assert.Equal("test_tf", testTf.PropertyName); + Assert.Equal(CustomPropertyValueType.TrueFalse, testTf.ValueType); + Assert.True(testTf.Required); + Assert.Equal("unset", testTf.DefaultValue); + Assert.Equal("true_false property", testTf.Description); + Assert.Equal(CustomPropertyValuesEditableBy.OrgActors, testTf.ValuesEditableBy); + } + } +} diff --git a/Octokit.Tests/Models/OrganizationCustomPropertyUpdateTests.cs b/Octokit.Tests/Models/OrganizationCustomPropertyUpdateTests.cs new file mode 100644 index 0000000000..bb98f61903 --- /dev/null +++ b/Octokit.Tests/Models/OrganizationCustomPropertyUpdateTests.cs @@ -0,0 +1,70 @@ +using System.Collections.Generic; +using Octokit.Internal; +using Xunit; + +namespace Octokit.Tests.Models +{ + public class OrganizationCustomPropertyUpdateTests + { + [Fact] + public void CanSerializeMultiSelect() + { + var expected = "{\"property_name\":\"test_ms\"," + + "\"value_type\":\"multi_select\"," + + "\"required\":true," + + "\"default_value\":[\"option_d\",\"option_e\"]}"; + + + var update = new OrganizationCustomPropertyUpdate("test_ms", CustomPropertyValueType.MultiSelect, new List { "option_d", "option_e" }); + + var json = new SimpleJsonSerializer().Serialize(update); + + Assert.Equal(expected, json); + } + + [Fact] + public void CanSerializeSingleSelect() + { + var expected = "{\"property_name\":\"test_ss\"," + + "\"value_type\":\"single_select\"," + + "\"required\":true," + + "\"default_value\":\"option_c\"}"; + + var update = new OrganizationCustomPropertyUpdate("test_ss", CustomPropertyValueType.SingleSelect, "option_c"); + + var json = new SimpleJsonSerializer().Serialize(update); + + Assert.Equal(expected, json); + } + + [Fact] + public void CanSerializeString() + { + var expected = "{\"property_name\":\"test_str\"," + + "\"value_type\":\"string\"," + + "\"required\":true," + + "\"default_value\":\"hello\"}"; + + var update = new OrganizationCustomPropertyUpdate("test_str", CustomPropertyValueType.String, "hello"); + + var json = new SimpleJsonSerializer().Serialize(update); + + Assert.Equal(expected, json); + } + + [Fact] + public void CanSerializeTrueFalse() + { + var expected = "{\"property_name\":\"test_tf\"," + + "\"value_type\":\"true_false\"," + + "\"required\":true," + + "\"default_value\":\"true\"}"; + + var update = new OrganizationCustomPropertyUpdate("test_tf", CustomPropertyValueType.TrueFalse, "true"); + + var json = new SimpleJsonSerializer().Serialize(update); + + Assert.Equal(expected, json); + } + } +} diff --git a/Octokit.Tests/Models/OrganizationCustomPropertyValuesTests.cs b/Octokit.Tests/Models/OrganizationCustomPropertyValuesTests.cs new file mode 100644 index 0000000000..5fc1e8e3ce --- /dev/null +++ b/Octokit.Tests/Models/OrganizationCustomPropertyValuesTests.cs @@ -0,0 +1,121 @@ +using System.Collections.Generic; +using Octokit.Internal; +using Xunit; + +namespace Octokit.Tests.Models +{ + public class OrganizationCustomPropertyValuesTests + { + [Fact] + public void CanBeDeserialized() + { + const string json = @"[ + { + ""repository_id"": 816170000, + ""repository_name"": ""somerepo"", + ""repository_full_name"": ""contoso/somerepo"", + ""properties"": [ + { + ""property_name"": ""test_ms"", + ""value"": [ + ""option_d"", + ""option_e"" + ] + }, + { + ""property_name"": ""test_ss"", + ""value"": ""option_c"" + }, + { + ""property_name"": ""test_str"", + ""value"": null + }, + { + ""property_name"": ""test_tf"", + ""value"": ""true"" + } + ] + }, + { + ""repository_id"": 813230000, + ""repository_name"": ""entities"", + ""repository_full_name"": ""contoso/entities"", + ""properties"": [ + { + ""property_name"": ""test_ms"", + ""value"": [ + ""option_d"", + ""option_e"" + ] + }, + { + ""property_name"": ""test_ss"", + ""value"": ""option_c"" + }, + { + ""property_name"": ""test_str"", + ""value"": ""hello"" + }, + { + ""property_name"": ""test_tf"", + ""value"": ""unset"" + } + ] + } +] +"; + var serializer = new SimpleJsonSerializer(); + + var properties = serializer.Deserialize>(json); + Assert.NotNull(properties); + Assert.Equal(2, properties.Count); + + var somerepo = properties[0]; + Assert.Equal(816170000, somerepo.RepositoryId); + Assert.Equal("somerepo", somerepo.RepositoryName); + Assert.Equal("contoso/somerepo", somerepo.RepositoryFullName); + Assert.Equal(4, somerepo.Properties.Count); + + var somerepoTestMs = somerepo.Properties[0]; + Assert.Equal("test_ms", somerepoTestMs.PropertyName); + Assert.Equal(new List { "option_d", "option_e" }, somerepoTestMs.Values); + + var somerepoTestSs = somerepo.Properties[1]; + Assert.Equal("test_ss", somerepoTestSs.PropertyName); + Assert.Equal("option_c", somerepoTestSs.Value); + Assert.Equal(new List { "option_c" }, somerepoTestSs.Values); + + var somerepoTestStr = somerepo.Properties[2]; + Assert.Equal("test_str", somerepoTestStr.PropertyName); + Assert.Null(somerepoTestStr.Value); + + var somerepoTestTf = somerepo.Properties[3]; + Assert.Equal("test_tf", somerepoTestTf.PropertyName); + Assert.Equal("true", somerepoTestTf.Value); + + + var entities = properties[1]; + Assert.Equal(813230000, entities.RepositoryId); + Assert.Equal("entities", entities.RepositoryName); + Assert.Equal("contoso/entities", entities.RepositoryFullName); + Assert.Equal(4, entities.Properties.Count); + + var entitiesTestMs = entities.Properties[0]; + Assert.Equal("test_ms", entitiesTestMs.PropertyName); + Assert.Equal(new List { "option_d", "option_e" }, entitiesTestMs.Values); + + var entitiesTestSs = entities.Properties[1]; + Assert.Equal("test_ss", entitiesTestSs.PropertyName); + Assert.Equal("option_c", entitiesTestSs.Value); + Assert.Equal(new List { "option_c" }, entitiesTestSs.Values); + + var entitiesTestStr = entities.Properties[2]; + Assert.Equal("test_str", entitiesTestStr.PropertyName); + Assert.Equal("hello", entitiesTestStr.Value); + + var entitiesTestTf = entities.Properties[3]; + Assert.Equal("test_tf", entitiesTestTf.PropertyName); + Assert.Equal("unset", entitiesTestTf.Value); + } + } +} diff --git a/Octokit.Tests/Models/UpsertOrganizationCustomPropertyTests.cs b/Octokit.Tests/Models/UpsertOrganizationCustomPropertyTests.cs new file mode 100644 index 0000000000..e00c9ed4d9 --- /dev/null +++ b/Octokit.Tests/Models/UpsertOrganizationCustomPropertyTests.cs @@ -0,0 +1,66 @@ +using System.Collections.Generic; +using Octokit.Internal; +using Xunit; + +namespace Octokit.Tests.Models +{ + public class UpsertOrganizationCustomPropertyTests + { + [Fact] + public void CanSerializeMultiSelect() + { + var expected = "{\"value_type\":\"multi_select\"," + + "\"required\":true," + + "\"default_value\":[\"option_d\",\"option_e\"]}"; + + + var update = new UpsertOrganizationCustomProperty(CustomPropertyValueType.MultiSelect, new List { "option_d", "option_e" }); + + var json = new SimpleJsonSerializer().Serialize(update); + + Assert.Equal(expected, json); + } + + [Fact] + public void CanSerializeSingleSelect() + { + var expected = "{\"value_type\":\"single_select\"," + + "\"required\":true," + + "\"default_value\":\"option_c\"}"; + + var update = new UpsertOrganizationCustomProperty(CustomPropertyValueType.SingleSelect, "option_c"); + + var json = new SimpleJsonSerializer().Serialize(update); + + Assert.Equal(expected, json); + } + + [Fact] + public void CanSerializeString() + { + var expected = "{\"value_type\":\"string\"," + + "\"required\":true," + + "\"default_value\":\"hello\"}"; + + var update = new UpsertOrganizationCustomProperty(CustomPropertyValueType.String, "hello"); + + var json = new SimpleJsonSerializer().Serialize(update); + + Assert.Equal(expected, json); + } + + [Fact] + public void CanSerializeTrueFalse() + { + var expected = "{\"value_type\":\"true_false\"," + + "\"required\":true," + + "\"default_value\":\"true\"}"; + + var update = new UpsertOrganizationCustomProperty(CustomPropertyValueType.TrueFalse, "true"); + + var json = new SimpleJsonSerializer().Serialize(update); + + Assert.Equal(expected, json); + } + } +} diff --git a/Octokit.Tests/Reactive/ObservableOrganizationCustomPropertiesClientTests.cs b/Octokit.Tests/Reactive/ObservableOrganizationCustomPropertiesClientTests.cs index b3bc77fc29..ced499f031 100644 --- a/Octokit.Tests/Reactive/ObservableOrganizationCustomPropertiesClientTests.cs +++ b/Octokit.Tests/Reactive/ObservableOrganizationCustomPropertiesClientTests.cs @@ -80,7 +80,7 @@ public void PostsTheCorrectUrl() { Properties = new List { - new OrganizationCustomPropertyUpdate { PropertyName = "name", DefaultValue = "value", ValueType = CustomPropertyValueType.String } + new OrganizationCustomPropertyUpdate("name", CustomPropertyValueType.String, "default") } }; @@ -97,7 +97,7 @@ public async Task EnsuresNonNullArguments() { Properties = new List { - new OrganizationCustomPropertyUpdate { PropertyName = "name", DefaultValue = "value", ValueType = CustomPropertyValueType.String } + new OrganizationCustomPropertyUpdate("name", CustomPropertyValueType.String, "default") } }; @@ -116,7 +116,7 @@ public async Task PostsTheCorrectUrl() { var gitHubClient = Substitute.For(); var client = new ObservableOrganizationCustomPropertiesClient(gitHubClient); - var update = new UpsertOrganizationCustomProperty { DefaultValue = "value", ValueType = CustomPropertyValueType.String }; + var update = new UpsertOrganizationCustomProperty(CustomPropertyValueType.String, "value"); await client.CreateOrUpdate("org", "property", update); @@ -128,7 +128,7 @@ public async Task EnsuresNonNullArguments() { var client = new ObservableOrganizationCustomPropertiesClient(Substitute.For()); - var update = new UpsertOrganizationCustomProperty { DefaultValue = "value", ValueType = CustomPropertyValueType.String }; + var update = new UpsertOrganizationCustomProperty(CustomPropertyValueType.String, "value"); await Assert.ThrowsAsync(() => client.CreateOrUpdate(null, "property", update).ToTask()); await Assert.ThrowsAsync(() => client.CreateOrUpdate("owner", null, update).ToTask()); diff --git a/Octokit.Tests/Reactive/ObservableOrganizationCustomPropertyValuesClientTests.cs b/Octokit.Tests/Reactive/ObservableOrganizationCustomPropertyValuesClientTests.cs index 0cec50b06b..f96913b1f4 100644 --- a/Octokit.Tests/Reactive/ObservableOrganizationCustomPropertyValuesClientTests.cs +++ b/Octokit.Tests/Reactive/ObservableOrganizationCustomPropertyValuesClientTests.cs @@ -56,7 +56,7 @@ public async Task PostsTheCorrectUrl() RepositoryNames = new List { "repo" }, Properties = new List { - new CustomPropertyValueUpdate { PropertyName = "name", Value = "value" } + new CustomPropertyValueUpdate("name", "value") } }; @@ -74,7 +74,7 @@ public async Task EnsuresNonNullArguments() RepositoryNames = new List { "repo" }, Properties = new List { - new CustomPropertyValueUpdate { PropertyName = "name", Value = "value" } + new CustomPropertyValueUpdate("name", "value") } }; diff --git a/Octokit.Tests/Reactive/ObservableRepositoryCustomPropertiesClientTests.cs b/Octokit.Tests/Reactive/ObservableRepositoryCustomPropertiesClientTests.cs index 3a7450c3bc..184e484620 100644 --- a/Octokit.Tests/Reactive/ObservableRepositoryCustomPropertiesClientTests.cs +++ b/Octokit.Tests/Reactive/ObservableRepositoryCustomPropertiesClientTests.cs @@ -57,7 +57,7 @@ public async Task PostsTheCorrectUrl() { Properties = new List { - new CustomPropertyValueUpdate { PropertyName = "name", Value = "value" } + new CustomPropertyValueUpdate("name", "value") } }; @@ -74,7 +74,7 @@ public async Task EnsuresNonNullArguments() { Properties = new List { - new CustomPropertyValueUpdate { PropertyName = "name", Value = "value" } + new CustomPropertyValueUpdate("name", "value") } }; diff --git a/Octokit/Models/Request/CustomPropertyValueUpdate.cs b/Octokit/Models/Request/CustomPropertyValueUpdate.cs index eb26f879b5..aa5c6ed8a5 100644 --- a/Octokit/Models/Request/CustomPropertyValueUpdate.cs +++ b/Octokit/Models/Request/CustomPropertyValueUpdate.cs @@ -1,6 +1,7 @@ using System.Collections.Generic; using System.Diagnostics; using System.Globalization; +using Octokit.Internal; namespace Octokit { @@ -21,7 +22,7 @@ public CustomPropertyValueUpdate(string propertyName, string value) public CustomPropertyValueUpdate(string propertyName, IReadOnlyList value) { PropertyName = propertyName; - Values = value; + Value = value; } /// @@ -32,12 +33,9 @@ public CustomPropertyValueUpdate(string propertyName, IReadOnlyList valu /// /// The value assigned to the property /// - public string Value { get; set; } - - /// - /// The values assigned to the property - /// - public IReadOnlyList Values { get; set; } + [SerializeNull] + [Parameter(Key = "value")] + public object Value { get; private set; } internal string DebuggerDisplay => string.Format(CultureInfo.InvariantCulture, "PropertyName: {0}", PropertyName); } diff --git a/Octokit/Models/Request/OrganizationCustomPropertyUpdate.cs b/Octokit/Models/Request/OrganizationCustomPropertyUpdate.cs index 574a85c39e..4e51fcbba5 100644 --- a/Octokit/Models/Request/OrganizationCustomPropertyUpdate.cs +++ b/Octokit/Models/Request/OrganizationCustomPropertyUpdate.cs @@ -9,26 +9,20 @@ public class OrganizationCustomPropertyUpdate { public OrganizationCustomPropertyUpdate() { } - public OrganizationCustomPropertyUpdate(string propertyName, CustomPropertyValueType valueType, bool required, IReadOnlyList defaultValue, string description, IReadOnlyList allowedValues, CustomPropertyValuesEditableBy? valuesEditableBy) + public OrganizationCustomPropertyUpdate(string propertyName, CustomPropertyValueType valueType, string defaultValue) { PropertyName = propertyName; ValueType = valueType; - Required = required; - DefaultValues = defaultValue; - Description = description; - AllowedValues = allowedValues; - ValuesEditableBy = valuesEditableBy; + Required = true; + DefaultValue = defaultValue; } - public OrganizationCustomPropertyUpdate(string propertyName, CustomPropertyValueType valueType, bool required, string defaultValue, string description, IReadOnlyList allowedValues, CustomPropertyValuesEditableBy? valuesEditableBy) + public OrganizationCustomPropertyUpdate(string propertyName, CustomPropertyValueType valueType, IReadOnlyList defaultValue) { PropertyName = propertyName; ValueType = valueType; - Required = required; + Required = true; DefaultValue = defaultValue; - Description = description; - AllowedValues = allowedValues; - ValuesEditableBy = valuesEditableBy; } /// @@ -49,12 +43,7 @@ public OrganizationCustomPropertyUpdate(string propertyName, CustomPropertyValue /// /// Default value of the property /// - public string DefaultValue { get; set; } - - /// - /// Default values of the property - /// - public IReadOnlyList DefaultValues { get; set; } + public object DefaultValue { get; private set; } /// /// Short description of the property diff --git a/Octokit/Models/Request/UpsertOrganizationCustomProperty.cs b/Octokit/Models/Request/UpsertOrganizationCustomProperty.cs index 4cf02e4099..ac0b042eb4 100644 --- a/Octokit/Models/Request/UpsertOrganizationCustomProperty.cs +++ b/Octokit/Models/Request/UpsertOrganizationCustomProperty.cs @@ -17,6 +17,20 @@ public UpsertOrganizationCustomProperty(CustomPropertyValueType valueType) ValueType = valueType; } + public UpsertOrganizationCustomProperty(CustomPropertyValueType valueType, string defaultValue) + { + ValueType = valueType; + Required = true; + DefaultValue = defaultValue; + } + + public UpsertOrganizationCustomProperty(CustomPropertyValueType valueType, IReadOnlyList defaultValue) + { + ValueType = valueType; + Required = true; + DefaultValue = defaultValue; + } + /// /// The type of the value for the property /// @@ -30,12 +44,7 @@ public UpsertOrganizationCustomProperty(CustomPropertyValueType valueType) /// /// Default value of the property /// - public string DefaultValue { get; set; } - - /// - /// Default values of the property - /// - public IReadOnlyList DefaultValues { get; set; } + public object DefaultValue { get; private set; } /// /// Short description of the property diff --git a/Octokit/Models/Response/CustomPropertyValue.cs b/Octokit/Models/Response/CustomPropertyValue.cs index 417940803f..7663833eaf 100644 --- a/Octokit/Models/Response/CustomPropertyValue.cs +++ b/Octokit/Models/Response/CustomPropertyValue.cs @@ -1,6 +1,7 @@ using System.Collections.Generic; using System.Diagnostics; using System.Globalization; +using Octokit.Internal; namespace Octokit { @@ -8,43 +9,70 @@ namespace Octokit /// Custom property name and associated value /// [DebuggerDisplay("{DebuggerDisplay,nq}")] + [ExcludeFromCtorWithAllPropertiesConventionTest(nameof(Values))] public class CustomPropertyValue { public CustomPropertyValue() { } - public CustomPropertyValue(string propertyName, string value) + public CustomPropertyValue(string propertyName, object value) { PropertyName = propertyName; - Value = value; - } - - public CustomPropertyValue(string propertyName, IReadOnlyList value) - { - PropertyName = propertyName; - Values = value; - } - - public CustomPropertyValue(string propertyName, string value, IReadOnlyList values) - { - PropertyName = propertyName; - Value = value; - Values = values; + this.value = value; } /// /// The name of the property /// + [Parameter(Key = "property_name")] public string PropertyName { get; private set; } + + [Parameter(Key = "value")] + public object value { get; private set; } + /// /// The value assigned to the property /// - public string Value { get; private set; } + 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; + } + } /// - /// The values assigned to the property + /// The array of values assigned to the property /// - public IReadOnlyList Values { get; private set; } + public IReadOnlyList Values { + get { + if (value is null) + { + return null; + } + else if (value is string stringValue) + { + return new List { 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); } diff --git a/Octokit/Models/Response/OrganizationCustomProperty.cs b/Octokit/Models/Response/OrganizationCustomProperty.cs index 423af93cb4..272eb08c17 100644 --- a/Octokit/Models/Response/OrganizationCustomProperty.cs +++ b/Octokit/Models/Response/OrganizationCustomProperty.cs @@ -1,47 +1,29 @@ 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, IReadOnlyList defaultValue, string description, IReadOnlyList allowedValues, CustomPropertyValuesEditableBy? valuesEditableBy) + public OrganizationCustomProperty(string propertyName, CustomPropertyValueType valueType, bool required, object defaultValue, string description, IReadOnlyList allowedValues, CustomPropertyValuesEditableBy? valuesEditableBy) { PropertyName = propertyName; ValueType = valueType; Required = required; - DefaultValues = defaultValue; + this.defaultValue = defaultValue; Description = description; AllowedValues = allowedValues; ValuesEditableBy = valuesEditableBy; } - public OrganizationCustomProperty(string propertyName, CustomPropertyValueType valueType, bool required, string defaultValue, string description, IReadOnlyList allowedValues, CustomPropertyValuesEditableBy? valuesEditableBy) - { - PropertyName = propertyName; - ValueType = valueType; - Required = required; - DefaultValue = defaultValue; - Description = description; - AllowedValues = allowedValues; - ValuesEditableBy = valuesEditableBy; - } - - public OrganizationCustomProperty(string propertyName, CustomPropertyValueType valueType, bool required, string defaultValue, IReadOnlyList defaultValues, string description, IReadOnlyList allowedValues, CustomPropertyValuesEditableBy? valuesEditableBy) - { - PropertyName = propertyName; - ValueType = valueType; - Required = required; - DefaultValue = defaultValue; - DefaultValues = defaultValues; - Description = description; - AllowedValues = allowedValues; - ValuesEditableBy = valuesEditableBy; - } + [Parameter(Key = "default_value")] + public object defaultValue { get; private set; } /// /// The name of the property @@ -61,12 +43,46 @@ public OrganizationCustomProperty(string propertyName, CustomPropertyValueType v /// /// Default value of the property /// - public string DefaultValue { get; private set; } + 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; + } + } /// /// Default values of the property /// - public IReadOnlyList DefaultValues { get; private set; } + public IReadOnlyList DefaultValues { + get { + if (defaultValue is null) + { + return null; + } + else if (defaultValue is string stringValue) + { + return new List { stringValue }; + } + else if (defaultValue is JsonArray stringValues) + { + return stringValues.ConvertAll(x => x.ToString()); + } + + return null; + } + } /// /// Short description of the property From ae21b1900c28ef279f19dd71e176e35522b5129c Mon Sep 17 00:00:00 2001 From: Colby Williams Date: Mon, 17 Jun 2024 15:58:40 -0500 Subject: [PATCH 11/11] Update Repository.cs --- Octokit/Models/Response/Repository.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Octokit/Models/Response/Repository.cs b/Octokit/Models/Response/Repository.cs index 6533643e07..7075c302ad 100644 --- a/Octokit/Models/Response/Repository.cs +++ b/Octokit/Models/Response/Repository.cs @@ -17,7 +17,7 @@ public Repository(long id) 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 topics, bool? allowAutoMerge, bool? allowUpdateBranch, bool? webCommitSignoffRequired, IReadOnlyDictionary customProperties) + 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 topics, bool? allowAutoMerge, bool? allowUpdateBranch, bool? webCommitSignoffRequired, IReadOnlyDictionary customProperties) { Url = url; HtmlUrl = htmlUrl; @@ -171,7 +171,7 @@ public Repository(string url, string htmlUrl, string cloneUrl, string gitUrl, st public bool? WebCommitSignoffRequired { get; private set; } - public IReadOnlyDictionary CustomProperties { get; private set; } + public IReadOnlyDictionary CustomProperties { get; private set; } internal string DebuggerDisplay {