From 08f73eff05306058e6fa93806ba1376b33666ea2 Mon Sep 17 00:00:00 2001 From: gizdatullin Date: Thu, 14 Nov 2024 16:01:35 +0300 Subject: [PATCH] Test lower dotnet --- .editorconfig | 5 +- Directory.Build.props | 2 +- .../Dtos/CustomFieldDtos.cs | 16 ++-- .../Dtos/CustomFieldsHelper.cs | 10 +-- .../Mindbox.YandexTracker.Tests.csproj | 1 + .../Mindbox.YandexTracker.csproj | 1 - Mindbox.YandexTracker/YandexTrackerClient.cs | 80 ++++++++++++++----- 7 files changed, 79 insertions(+), 36 deletions(-) diff --git a/.editorconfig b/.editorconfig index 7b98489..93e5d6e 100644 --- a/.editorconfig +++ b/.editorconfig @@ -145,7 +145,10 @@ dotnet_diagnostic.IDE0130.severity = none # IDE0220 'foreach' statement implicitly converts 'object' to '{1}'. Add an explicit cast to make intent clearer, as it may fail at runtime dotnet_diagnostic.IDE0220.severity = none -# JSON002 Enable json support +# IDE0220 Use range operator +dotnet_diagnostic.IDE0057.severity = none + +# IDE0057 Enable json support dotnet_diagnostic.JSON002.severity = none # Naming convention - Private and internal fields should start with _ and be camelCased diff --git a/Directory.Build.props b/Directory.Build.props index 34e27e2..5b29a5e 100644 --- a/Directory.Build.props +++ b/Directory.Build.props @@ -1,6 +1,6 @@ - net8.0 + net7.0;net8.0 latest Mindbox Copyright 2024 © Mindbox diff --git a/Mindbox.YandexTracker.Abstractions/Dtos/CustomFieldDtos.cs b/Mindbox.YandexTracker.Abstractions/Dtos/CustomFieldDtos.cs index 489110a..640afd3 100644 --- a/Mindbox.YandexTracker.Abstractions/Dtos/CustomFieldDtos.cs +++ b/Mindbox.YandexTracker.Abstractions/Dtos/CustomFieldDtos.cs @@ -1,11 +1,11 @@ // Copyright 2024 Mindbox Ltd -// +// // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at -// +// // http://www.apache.org/licenses/LICENSE-2.0 -// +// // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @@ -31,13 +31,13 @@ public record CustomFieldsRequest /// public bool TryGetCustomField(string customFieldId, out T? value) { - ArgumentException.ThrowIfNullOrWhiteSpace(customFieldId); + ArgumentException.ThrowIfNullOrEmpty(customFieldId); return CustomFieldsHelper.TryGetCustomField(Fields, customFieldId, out value); } public T GetCustomField(string customFieldId) { - ArgumentException.ThrowIfNullOrWhiteSpace(customFieldId); + ArgumentException.ThrowIfNullOrEmpty(customFieldId); return CustomFieldsHelper.GetCustomField(Fields, customFieldId); } @@ -47,7 +47,7 @@ public T GetCustomField(string customFieldId) /// public void SetCustomField(string customFieldId, T value) { - ArgumentException.ThrowIfNullOrWhiteSpace(customFieldId); + ArgumentException.ThrowIfNullOrEmpty(customFieldId); CustomFieldsHelper.SetCustomField(Fields, customFieldId, value); } } @@ -64,13 +64,13 @@ public record CustomFieldsResponse /// public bool TryGetCustomField(string customFieldId, out T? value) { - ArgumentException.ThrowIfNullOrWhiteSpace(customFieldId); + ArgumentException.ThrowIfNullOrEmpty(customFieldId); return CustomFieldsHelper.TryGetCustomField(Fields, customFieldId, out value); } public T GetCustomField(string customFieldId) { - ArgumentException.ThrowIfNullOrWhiteSpace(customFieldId); + ArgumentException.ThrowIfNullOrEmpty(customFieldId); return CustomFieldsHelper.GetCustomField(Fields, customFieldId); } } \ No newline at end of file diff --git a/Mindbox.YandexTracker.Abstractions/Dtos/CustomFieldsHelper.cs b/Mindbox.YandexTracker.Abstractions/Dtos/CustomFieldsHelper.cs index 51d5d8d..ce67c6f 100644 --- a/Mindbox.YandexTracker.Abstractions/Dtos/CustomFieldsHelper.cs +++ b/Mindbox.YandexTracker.Abstractions/Dtos/CustomFieldsHelper.cs @@ -1,11 +1,11 @@ // Copyright 2024 Mindbox Ltd -// +// // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at -// +// // http://www.apache.org/licenses/LICENSE-2.0 -// +// // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @@ -25,7 +25,7 @@ public static bool TryGetCustomField( string customFieldId, out T? customField) { - ArgumentException.ThrowIfNullOrWhiteSpace(customFieldId); + ArgumentException.ThrowIfNullOrEmpty(customFieldId); customField = default; if (fields.TryGetValue(customFieldId, out var value)) @@ -49,7 +49,7 @@ public static T GetCustomField(IDictionary fields, strin public static void SetCustomField(IDictionary fields, string customFieldId, T value) { - ArgumentException.ThrowIfNullOrWhiteSpace(customFieldId); + ArgumentException.ThrowIfNullOrEmpty(customFieldId); fields[customFieldId] = JsonSerializer.SerializeToElement(value); } diff --git a/Mindbox.YandexTracker.Tests/Mindbox.YandexTracker.Tests.csproj b/Mindbox.YandexTracker.Tests/Mindbox.YandexTracker.Tests.csproj index 6ba6c07..e25d5fb 100644 --- a/Mindbox.YandexTracker.Tests/Mindbox.YandexTracker.Tests.csproj +++ b/Mindbox.YandexTracker.Tests/Mindbox.YandexTracker.Tests.csproj @@ -1,6 +1,7 @@  + net8.0 false true diff --git a/Mindbox.YandexTracker/Mindbox.YandexTracker.csproj b/Mindbox.YandexTracker/Mindbox.YandexTracker.csproj index 0d9848a..cbf1ef1 100644 --- a/Mindbox.YandexTracker/Mindbox.YandexTracker.csproj +++ b/Mindbox.YandexTracker/Mindbox.YandexTracker.csproj @@ -3,7 +3,6 @@ true - diff --git a/Mindbox.YandexTracker/YandexTrackerClient.cs b/Mindbox.YandexTracker/YandexTrackerClient.cs index e6f40ab..e294064 100644 --- a/Mindbox.YandexTracker/YandexTrackerClient.cs +++ b/Mindbox.YandexTracker/YandexTrackerClient.cs @@ -1,11 +1,11 @@ // Copyright 2024 Mindbox Ltd -// +// // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at -// +// // http://www.apache.org/licenses/LICENSE-2.0 -// +// // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @@ -21,11 +21,11 @@ using System.Net.Http.Headers; using System.Reflection; using System.Text; +using System.Text.Encodings.Web; using System.Text.Json; using System.Text.Json.Serialization; using System.Threading; using System.Threading.Tasks; -using Microsoft.AspNetCore.WebUtilities; using Microsoft.Extensions.Options; using Mindbox.YandexTracker.JsonConverters; @@ -96,7 +96,7 @@ public async Task GetQueueAsync( QueueExpandData? expand = null, CancellationToken cancellationToken = default) { - ArgumentException.ThrowIfNullOrWhiteSpace(queueKey); + ArgumentException.ThrowIfNullOrEmpty(queueKey); var parameters = new Dictionary(); @@ -140,7 +140,7 @@ public async Task GetIssueAsync( IssueExpandData? expand = null, CancellationToken cancellationToken = default) { - ArgumentException.ThrowIfNullOrWhiteSpace(issueKey); + ArgumentException.ThrowIfNullOrEmpty(issueKey); var parameters = new Dictionary(); @@ -164,7 +164,7 @@ public async Task> GetIssuesFr PaginationSettings? paginationSettings = null, CancellationToken cancellationToken = default) { - ArgumentException.ThrowIfNullOrWhiteSpace(queueKey); + ArgumentException.ThrowIfNullOrEmpty(queueKey); var parameters = new Dictionary(); @@ -249,7 +249,7 @@ public async Task> GetIssuesBy PaginationSettings? paginationSettings = null, CancellationToken cancellationToken = default) { - ArgumentException.ThrowIfNullOrWhiteSpace(query); + ArgumentException.ThrowIfNullOrEmpty(query); var parameters = new Dictionary(); @@ -320,7 +320,7 @@ public async Task> GetComme PaginationSettings? paginationSettings = null, CancellationToken cancellationToken = default) { - ArgumentException.ThrowIfNullOrWhiteSpace(issueKey); + ArgumentException.ThrowIfNullOrEmpty(issueKey); var parameters = new Dictionary(); @@ -344,7 +344,7 @@ public async Task CreateCommentAsync( bool? addAuthorToFollowers = null, CancellationToken cancellationToken = default) { - ArgumentException.ThrowIfNullOrWhiteSpace(issueKey); + ArgumentException.ThrowIfNullOrEmpty(issueKey); ArgumentNullException.ThrowIfNull(request); var parameters = new Dictionary(); @@ -368,7 +368,7 @@ public async Task> GetAtt PaginationSettings? paginationSettings = null, CancellationToken cancellationToken = default) { - ArgumentException.ThrowIfNullOrWhiteSpace(issueKey); + ArgumentException.ThrowIfNullOrEmpty(issueKey); return await ExecuteYandexTrackerCollectionRequestAsync( $"issues/{issueKey}/attachments", @@ -384,7 +384,7 @@ public async Task CreateAttachmentAsync( string? newFileName = null, CancellationToken cancellationToken = default) { - ArgumentException.ThrowIfNullOrWhiteSpace(issueKey); + ArgumentException.ThrowIfNullOrEmpty(issueKey); ArgumentNullException.ThrowIfNull(fileStream); var parameters = new Dictionary(); @@ -429,7 +429,7 @@ public async Task> GetTagsAsync( PaginationSettings? paginationSettings = null, CancellationToken cancellationToken = default) { - ArgumentException.ThrowIfNullOrWhiteSpace(queueKey); + ArgumentException.ThrowIfNullOrEmpty(queueKey); return await ExecuteYandexTrackerCollectionRequestAsync( $"queues/{queueKey}/tags", @@ -527,7 +527,7 @@ public async Task> GetLo PaginationSettings? paginationSettings = null, CancellationToken cancellationToken = default) { - ArgumentException.ThrowIfNullOrWhiteSpace(queueKey); + ArgumentException.ThrowIfNullOrEmpty(queueKey); return await ExecuteYandexTrackerCollectionRequestAsync( $"queues/{queueKey}/localFields", @@ -624,7 +624,7 @@ public async Task CreateLocalFieldInQueueAsync( CreateQueueLocalFieldRequest request, CancellationToken cancellationToken = default) { - ArgumentException.ThrowIfNullOrWhiteSpace(queueKey); + ArgumentException.ThrowIfNullOrEmpty(queueKey); ArgumentNullException.ThrowIfNull(request); return await ExecuteYandexTrackerApiRequestAsync( @@ -663,7 +663,7 @@ public async Task CreateQueueAsync( /// public async Task DeleteQueueAsync(string queueKey, CancellationToken cancellationToken = default) { - ArgumentException.ThrowIfNullOrWhiteSpace(queueKey); + ArgumentException.ThrowIfNullOrEmpty(queueKey); await ExecuteYandexTrackerApiRequestAsync( $"queues/{queueKey}", @@ -678,7 +678,7 @@ public async Task DeleteCommentAsync( int commentId, CancellationToken cancellationToken = default) { - ArgumentException.ThrowIfNullOrWhiteSpace(issueKey); + ArgumentException.ThrowIfNullOrEmpty(issueKey); await ExecuteYandexTrackerApiRequestAsync( $"issues/{issueKey}/comments/{commentId}", @@ -690,8 +690,8 @@ await ExecuteYandexTrackerApiRequestAsync( /// public async Task DeleteAttachmentAsync(string issueKey, string attachmentKey, CancellationToken cancellationToken = default) { - ArgumentException.ThrowIfNullOrWhiteSpace(issueKey); - ArgumentException.ThrowIfNullOrWhiteSpace(attachmentKey); + ArgumentException.ThrowIfNullOrEmpty(issueKey); + ArgumentException.ThrowIfNullOrEmpty(attachmentKey); await ExecuteYandexTrackerApiRequestAsync( $"issues/{issueKey}/attachments/{attachmentKey}", @@ -756,7 +756,7 @@ private async Task ExecuteYandexTrackerApiRawRequestAsync( var requestUri = new Uri(baseAddress, effectivePath); if (parameters is not null) { - requestUri = new Uri(QueryHelpers.AddQueryString(requestUri.ToString(), parameters!)); + requestUri = new Uri(AddQueryString(requestUri.ToString(), parameters!)); } using var request = new HttpRequestMessage(method, requestUri); @@ -879,6 +879,46 @@ private async Task ExecuteYandexTrackerApiRequestAsync( cancellationToken); } + private static string AddQueryString( + string uri, + IEnumerable> queryString) + { + ArgumentNullException.ThrowIfNull(uri); + ArgumentNullException.ThrowIfNull(queryString); + + var anchorIndex = uri.IndexOf('#', StringComparison.Ordinal); + var uriToBeAppended = uri.AsSpan(); + var anchorText = ReadOnlySpan.Empty; + // If there is an anchor, then the query string must be inserted before its first occurrence. + if (anchorIndex != -1) + { + anchorText = uriToBeAppended.Slice(anchorIndex); + uriToBeAppended = uriToBeAppended.Slice(0, anchorIndex); + } + + var queryIndex = uriToBeAppended.IndexOf('?'); + var hasQuery = queryIndex != -1; + + var sb = new StringBuilder(); + sb.Append(uriToBeAppended); + foreach (var parameter in queryString) + { + if (parameter.Value == null) + { + continue; + } + + sb.Append(hasQuery ? '&' : '?'); + sb.Append(UrlEncoder.Default.Encode(parameter.Key)); + sb.Append('='); + sb.Append(UrlEncoder.Default.Encode(parameter.Value)); + hasQuery = true; + } + + sb.Append(anchorText); + return sb.ToString(); + } + public void Dispose() { _httpClient.Dispose();