diff --git a/.github/workflows/build-dev-stage.yml b/.github/workflows/build-dev-stage.yml new file mode 100644 index 0000000..96c3715 --- /dev/null +++ b/.github/workflows/build-dev-stage.yml @@ -0,0 +1,53 @@ +name: 'Build dev stage' + +on: + pull_request: + +jobs: + build: + runs-on: ubuntu-22.04 + timeout-minutes: 10 + + steps: + - name: Prepare + run: echo "NUGET_URL=https://nuget.pkg.github.com/${{ github.repository_owner }}/index.json" >> $GITHUB_ENV + + - name: Checkout repository + uses: actions/checkout@v3 + with: + token: ${{ secrets.REPOS_ACCESS_TOKEN }} + fetch-depth: 0 + + - name: Setup .NET + uses: actions/setup-dotnet@v3 + with: + global-json-file: global.json + + - name: Restore dependencies + run: dotnet restore . + + - name: Install GitVersion + uses: gittools/actions/gitversion/setup@v0.9.15 + with: + versionSpec: '5.x' + + - name: Determine Version + id: gitversion + uses: gittools/actions/gitversion/execute@v0.9.15 + with: + useConfigFile: true + + - name: Build + run: dotnet build -c Release --no-restore -p:Version=$GitVersion_SemVer . -p:RepositoryUrl=${{ github.server_url }}/${{ github.repository }} + + - name: Test + run: dotnet test -c Release --no-build --verbosity normal . + + - name: Pack + run: dotnet pack -c Release --no-build -p:Version=$GitVersion_SemVer --verbosity normal . + + - name: Upload artifacts + uses: actions/upload-artifact@v3 + with: + path: Build/*.nupkg + retention-days: 5 \ No newline at end of file diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml new file mode 100644 index 0000000..d5c18a6 --- /dev/null +++ b/.github/workflows/release.yml @@ -0,0 +1,61 @@ +name: 'Release' + +on: + workflow_dispatch: + push: + branches: + - master + - release** + +jobs: + build: + runs-on: ubuntu-22.04 + timeout-minutes: 10 + + steps: + - name: Prepare + run: echo "NUGET_URL=https://nuget.pkg.github.com/${{ github.repository_owner }}/index.json" >> $GITHUB_ENV + + - name: Checkout repository + uses: actions/checkout@v3 + with: + token: ${{ secrets.REPOS_ACCESS_TOKEN }} + submodules: true + fetch-depth: 0 + + - name: Setup .NET + uses: actions/setup-dotnet@v3 + with: + global-json-file: global.json + + - name: Restore dependencies + run: dotnet restore . + + - name: Install GitVersion + uses: gittools/actions/gitversion/setup@v0.9.15 + with: + versionSpec: '5.x' + + - name: Determine Version + id: gitversion + uses: gittools/actions/gitversion/execute@v0.9.15 + with: + useConfigFile: true + + - name: Build + run: dotnet build -c Release --no-restore . -p:RepositoryUrl=${{ github.server_url }}/${{ github.repository }} + + - name: Test + run: dotnet test -c Release --no-build --verbosity normal . + + - name: Pack nugets + run: dotnet pack -c Release -o ./Output/ -p:Version=$GitVersion_SemVer --verbosity normal --no-build . + + - name: Push nugets + run: dotnet nuget push "./Output/*.nupkg" --skip-duplicate --source "github" --api-key "${{ secrets.WRITE_PACKAGES_TOKEN }}" + + - name: Tag the commit + run: git tag -f v$GitVersion_SemVer + + - name: Push the tag + run: git push -f --tags \ No newline at end of file diff --git a/BleBoxNetSdk.Tests/BleBoxNetSdk.Tests.csproj b/BleBoxNetSdk.Tests/BleBoxNetSdk.Tests.csproj new file mode 100644 index 0000000..67f7a26 --- /dev/null +++ b/BleBoxNetSdk.Tests/BleBoxNetSdk.Tests.csproj @@ -0,0 +1,34 @@ + + + + net8.0 + enable + enable + + false + true + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/BleBoxNetSdk.Tests/Common/JsonConverters/IntSecondsToTimeSpanConverterTests.cs b/BleBoxNetSdk.Tests/Common/JsonConverters/IntSecondsToTimeSpanConverterTests.cs new file mode 100644 index 0000000..a59fb6b --- /dev/null +++ b/BleBoxNetSdk.Tests/Common/JsonConverters/IntSecondsToTimeSpanConverterTests.cs @@ -0,0 +1,45 @@ +using BleBoxNetSdk.Common.JsonConverters; +using FluentAssertions; +using System.Text; +using System.Text.Json; + +namespace BleBoxNetSdk.Tests.Common.JsonConverters; + +internal class IntSecondsToTimeSpanConverterTests +{ + [TestCase(12)] + [TestCase(0)] + [TestCase(45389)] + [TestCase(1)] + public void should_read_value(int seconds) + { + var bytes = Encoding.UTF8.GetBytes(seconds.ToString()); + var reader = new Utf8JsonReader(bytes.AsSpan()); + reader.Read(); + var converter = PrepareConverter(); + + var value = converter.Read(ref reader, typeof(TimeSpan), JsonSerializerOptions.Default); + + value.TotalSeconds.Should().Be(seconds); + } + + [TestCase(87832)] + [TestCase(0)] + [TestCase(99)] + [TestCase(1)] + public void should_write_value(int seconds) + { + var converter = PrepareConverter(); + var buffer = new byte[64]; + using var memoryStream = new MemoryStream(buffer); + using var writer = new Utf8JsonWriter(memoryStream); + converter.Write(writer, TimeSpan.FromSeconds(seconds), JsonSerializerOptions.Default); + writer.Flush(); + + var value = Encoding.UTF8.GetString(buffer, 0, seconds.ToString().Length); + + value.Should().Be($"{seconds}"); + } + + internal IntSecondsToTimeSpanConverter PrepareConverter() => new IntSecondsToTimeSpanConverter(); +} diff --git a/BleBoxNetSdk.sln b/BleBoxNetSdk.sln new file mode 100644 index 0000000..e992c78 --- /dev/null +++ b/BleBoxNetSdk.sln @@ -0,0 +1,31 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 17 +VisualStudioVersion = 17.9.34607.119 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "BleBoxNetSdk", "BleBoxNetSdk\BleBoxNetSdk.csproj", "{EE09EC89-906A-41EB-8538-5C5A64036F88}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "BleBoxNetSdk.Tests", "BleBoxNetSdk.Tests\BleBoxNetSdk.Tests.csproj", "{DC8A6BD6-7788-4CFD-942A-144F497D0E15}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {EE09EC89-906A-41EB-8538-5C5A64036F88}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {EE09EC89-906A-41EB-8538-5C5A64036F88}.Debug|Any CPU.Build.0 = Debug|Any CPU + {EE09EC89-906A-41EB-8538-5C5A64036F88}.Release|Any CPU.ActiveCfg = Release|Any CPU + {EE09EC89-906A-41EB-8538-5C5A64036F88}.Release|Any CPU.Build.0 = Release|Any CPU + {DC8A6BD6-7788-4CFD-942A-144F497D0E15}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {DC8A6BD6-7788-4CFD-942A-144F497D0E15}.Debug|Any CPU.Build.0 = Debug|Any CPU + {DC8A6BD6-7788-4CFD-942A-144F497D0E15}.Release|Any CPU.ActiveCfg = Release|Any CPU + {DC8A6BD6-7788-4CFD-942A-144F497D0E15}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {A145D61A-6E20-462B-A5E0-9727F15A188C} + EndGlobalSection +EndGlobal diff --git a/BleBoxNetSdk/BleBoxNetSdk.csproj b/BleBoxNetSdk/BleBoxNetSdk.csproj new file mode 100644 index 0000000..099645a --- /dev/null +++ b/BleBoxNetSdk/BleBoxNetSdk.csproj @@ -0,0 +1,18 @@ + + + + net8.0 + enable + enable + + + + + + + + + + + + diff --git a/BleBoxNetSdk/Common/CommonApiClient.cs b/BleBoxNetSdk/Common/CommonApiClient.cs new file mode 100644 index 0000000..224c3b0 --- /dev/null +++ b/BleBoxNetSdk/Common/CommonApiClient.cs @@ -0,0 +1,33 @@ +using BleBoxNetSdk.Common.Endpoints; +using BleBoxNetSdk.Common.Models; +using BleBoxNetSdk.Services; + +namespace BleBoxNetSdk.Common; + +internal class CommonApiClient(IApiHttpClient apiHttpClient) : ICommonApiClient +{ + public async Task Info(Uri deviceAddress, CancellationToken cancellationToken = default) + { + var request = new Info.Request(); + + var response = await apiHttpClient.Send(deviceAddress, request, cancellationToken); + + return response.Device; + } + + public async Task GetDeviceUptime(Uri deviceAddress, CancellationToken cancellationToken = default) + { + var request = new DeviceUptime.Request(); + + var response = await apiHttpClient.Send(deviceAddress, request, cancellationToken); + + return response.UpTimeS; + } + + public async Task PerformDeviceUpdate(Uri deviceAddress, CancellationToken cancellationToken = default) + { + var request = new PerformUpdate.Request(); + + await apiHttpClient.Send(deviceAddress, request, cancellationToken); + } +} \ No newline at end of file diff --git a/BleBoxNetSdk/Common/Endpoints/DeviceUptime.cs b/BleBoxNetSdk/Common/Endpoints/DeviceUptime.cs new file mode 100644 index 0000000..9b8e6ef --- /dev/null +++ b/BleBoxNetSdk/Common/Endpoints/DeviceUptime.cs @@ -0,0 +1,11 @@ +namespace BleBoxNetSdk.Common.Endpoints; + +internal class DeviceUptime +{ + internal class Request() : RequestBase(HttpMethod.Get, "/api/device/uptime") { } + + internal class ResponseResult + { + public TimeSpan UpTimeS { get; set; } + } +} diff --git a/BleBoxNetSdk/Common/Endpoints/Info.cs b/BleBoxNetSdk/Common/Endpoints/Info.cs new file mode 100644 index 0000000..09a5c00 --- /dev/null +++ b/BleBoxNetSdk/Common/Endpoints/Info.cs @@ -0,0 +1,13 @@ +using BleBoxNetSdk.Common.Models; + +namespace BleBoxNetSdk.Common.Endpoints; + +internal static class Info +{ + internal class Request() : RequestBase(HttpMethod.Get, "/info") { } + + internal class ResponseResult + { + public Device? Device { get; set; } + } +} diff --git a/BleBoxNetSdk/Common/Endpoints/PerformUpdate.cs b/BleBoxNetSdk/Common/Endpoints/PerformUpdate.cs new file mode 100644 index 0000000..2e7d56e --- /dev/null +++ b/BleBoxNetSdk/Common/Endpoints/PerformUpdate.cs @@ -0,0 +1,8 @@ +namespace BleBoxNetSdk.Common.Endpoints; + +internal class PerformUpdate +{ + internal class Request() : RequestBase(HttpMethod.Post, "/api/ota/update") { } + + internal class ResponseResult { } +} diff --git a/BleBoxNetSdk/Common/Enums/ApiType.cs b/BleBoxNetSdk/Common/Enums/ApiType.cs new file mode 100644 index 0000000..0f7e583 --- /dev/null +++ b/BleBoxNetSdk/Common/Enums/ApiType.cs @@ -0,0 +1,18 @@ +namespace BleBoxNetSdk.Common.Enums; + +public enum ApiType +{ + Unknown, + AirSensor, + ButtonBox, + GateBox, + MultiSensor, + ShutterBox, + SmartWindowBox, + SwitchBoxD, + SwitchBox, + TempSensor, + ThermoBox, + TvLiftBox, + WLightBox +} diff --git a/BleBoxNetSdk/Common/ICommonApiClient.cs b/BleBoxNetSdk/Common/ICommonApiClient.cs new file mode 100644 index 0000000..77e2ee0 --- /dev/null +++ b/BleBoxNetSdk/Common/ICommonApiClient.cs @@ -0,0 +1,42 @@ +using BleBoxNetSdk.Common.Models; + +namespace BleBoxNetSdk.Common +{ + public interface ICommonApiClient + { + /// + /// Returns general information about device + /// + /// Url to desired device + /// Cancellation token + /// Nullable object that contains all information about the device + /// Received json is null + /// Deserialization failed + /// There is no compatible converter + /// Request to API failed + Task Info(Uri deviceAddress, CancellationToken cancellationToken = default); + + /// + /// Returns information about number of seconds from boot + /// + /// Url to desired device + /// Cancellation token + /// TimeSpan of desired device uptime + /// Received json is null + /// Deserialization failed + /// There is no compatible converter + /// Request to API failed + Task GetDeviceUptime(Uri deviceAddress, CancellationToken cancellationToken = default); + + /// + /// Perform firmware update. Return conflict if update is in progress + /// + /// Url to desired device + /// Cancellation token + /// Received json is null + /// Deserialization failed + /// There is no compatible converter + /// Request to API failed. Device update may be in progress + Task PerformDeviceUpdate(Uri deviceAddress, CancellationToken cancellationToken = default); + } +} \ No newline at end of file diff --git a/BleBoxNetSdk/Common/JsonConverters/IntSecondsToTimeSpanConverter.cs b/BleBoxNetSdk/Common/JsonConverters/IntSecondsToTimeSpanConverter.cs new file mode 100644 index 0000000..fd32e89 --- /dev/null +++ b/BleBoxNetSdk/Common/JsonConverters/IntSecondsToTimeSpanConverter.cs @@ -0,0 +1,20 @@ +using System.Text.Json; +using System.Text.Json.Serialization; + +namespace BleBoxNetSdk.Common.JsonConverters; + +internal class IntSecondsToTimeSpanConverter : JsonConverter +{ + public override TimeSpan Read( + ref Utf8JsonReader reader, + Type typeToConvert, + JsonSerializerOptions options) => + TimeSpan.FromSeconds(reader.GetInt32()); + + public override void Write( + Utf8JsonWriter writer, + TimeSpan value, + JsonSerializerOptions options) => + writer.WriteNumberValue(value.TotalSeconds); +} + diff --git a/BleBoxNetSdk/Common/Models/Device.cs b/BleBoxNetSdk/Common/Models/Device.cs new file mode 100644 index 0000000..ec1a659 --- /dev/null +++ b/BleBoxNetSdk/Common/Models/Device.cs @@ -0,0 +1,15 @@ +using BleBoxNetSdk.Common.Enums; + +namespace BleBoxNetSdk.Common.Models; + +public record Device +{ + public string? DeviceName { get; set; } + public string? Product { get; set; } + public ApiType Type { get; set; } + public string? ApiLevel { get; set; } + public string? Hv { get; set; } + public string? Fv { get; set; } + public string? Id { get; set; } + public string? Ip { get; set; } +} \ No newline at end of file diff --git a/BleBoxNetSdk/Common/RequestBase.cs b/BleBoxNetSdk/Common/RequestBase.cs new file mode 100644 index 0000000..e9f6fd3 --- /dev/null +++ b/BleBoxNetSdk/Common/RequestBase.cs @@ -0,0 +1,29 @@ +using System.Text.Json.Serialization; + +namespace BleBoxNetSdk.Common; + +public interface IRequest +{ + HttpMethod HttpMethod { get; } + string Uri { get; } + bool HaveContent { get; } +} + +internal abstract class RequestBase : IRequest +{ + internal RequestBase(HttpMethod method, string uri, bool haveContent = false) + { + HttpMethod = method; + Uri = uri; + HaveContent = haveContent; + } + + [JsonIgnore] + public HttpMethod HttpMethod { get; } + + [JsonIgnore] + public string Uri { get; } + + [JsonIgnore] + public bool HaveContent { get; } +} diff --git a/BleBoxNetSdk/ServiceExtensions.cs b/BleBoxNetSdk/ServiceExtensions.cs new file mode 100644 index 0000000..2f77eb6 --- /dev/null +++ b/BleBoxNetSdk/ServiceExtensions.cs @@ -0,0 +1,18 @@ +using BleBoxNetSdk.Common; +using BleBoxNetSdk.Services; +using Microsoft.Extensions.DependencyInjection; + +namespace BleBoxNetSdk; + +public static class ServiceExtensions +{ + public static IServiceCollection RegisterSdkServices(this IServiceCollection services) + { + services + .AddSingleton() + .AddSingleton() + .AddSingleton(); + + return services; + } +} diff --git a/BleBoxNetSdk/Services/ApiHttpClient.cs b/BleBoxNetSdk/Services/ApiHttpClient.cs new file mode 100644 index 0000000..e713128 --- /dev/null +++ b/BleBoxNetSdk/Services/ApiHttpClient.cs @@ -0,0 +1,106 @@ +using BleBoxNetSdk.Common; +using Microsoft.Extensions.Logging; +using System.Text; +using System.Text.Json; + +namespace BleBoxNetSdk.Services; + +public interface IApiHttpClient +{ + Task Send(Uri baseUri, IRequest requestObject, CancellationToken cancellationToken); +} + +internal class ApiHttpClient : IApiHttpClient +{ + private const int MaxResendCount = 3; + private const string JsonContentType = "application/json"; + + private readonly HttpClient _httpClient; + private readonly ILogger _logger; + private readonly ISerializer _serializer; + private readonly Encoding _encoding = Encoding.UTF8; + + internal ApiHttpClient( + ILogger logger, + ISerializer serializer) + { + _httpClient = new HttpClient(); + _logger = logger; + _serializer = serializer; + } + + public async Task Send( + Uri baseUri, + IRequest requestObject, + CancellationToken cancellationToken) + { + var response = await Send(baseUri, requestObject, cancellationToken); + + var serializedResult = await response.Content.ReadAsStringAsync(); + + _logger.LogDebug("<- Received response: {response}", serializedResult); + + var deserializedResult = _serializer.DeserializeJson(serializedResult) + ?? throw new JsonException($"Could not deserialize {serializedResult} to {typeof(TResult)}"); + + return deserializedResult; + } + + private async Task Send( + Uri baseUri, + IRequest requestObject, + CancellationToken cancellationToken) + { + for (int count = 1; count <= MaxResendCount; count++) + { + try + { + var request = PrepareRequest(baseUri, requestObject); + + var response = await _httpClient.SendAsync(request, cancellationToken); + + response.EnsureSuccessStatusCode(); + + return response; + } + catch (Exception ex) when (count < MaxResendCount) + { + await Task.Delay(TimeSpan.FromSeconds(3)); + + _logger.LogWarning("Request to API failed with exception: {ex}. Resending request {count}", ex, count); + } + } + + throw new Exception($"Request to API {requestObject.Uri} failed"); + } + + private HttpRequestMessage PrepareRequest( + Uri baseUri, + IRequest requestObject) + { + var request = new HttpRequestMessage(requestObject.HttpMethod, BuildUri(baseUri, requestObject.Uri)); + + _logger.LogDebug("-> Sending http request to: {uri}", request.RequestUri?.ToString()); + + if (requestObject.HaveContent) + { + var serializedContent = _serializer.SerializeJson(requestObject); + + + _logger.LogDebug("-> With body: {body}", serializedContent); + request.Content = new StringContent(serializedContent, _encoding, JsonContentType); + } + + return request; + } + + private Uri BuildUri(Uri baseUri, string endpoint) + { + var builder = new UriBuilder(baseUri); + + builder.Path.TrimEnd('/'); + builder.Path += endpoint; + + return builder.Uri; + } +} diff --git a/BleBoxNetSdk/Services/Serializer.cs b/BleBoxNetSdk/Services/Serializer.cs new file mode 100644 index 0000000..06dcd0b --- /dev/null +++ b/BleBoxNetSdk/Services/Serializer.cs @@ -0,0 +1,36 @@ +using System.Text.Json.Serialization; +using System.Text.Json; +using BleBoxNetSdk.Common.JsonConverters; + +namespace BleBoxNetSdk.Services; + +public interface ISerializer +{ + TResult? DeserializeJson(string jsonResult); + string SerializeJson(object? content); +} + +internal class Serializer : ISerializer +{ + private JsonSerializerOptions _jsonOptions; + + internal Serializer() + { + _jsonOptions = new JsonSerializerOptions() + { + PropertyNamingPolicy = JsonNamingPolicy.CamelCase, + DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull, + Converters = { new IntSecondsToTimeSpanConverter() } + }; + } + + public string SerializeJson(object? content) + { + return JsonSerializer.Serialize(content, _jsonOptions); + } + + public TResult? DeserializeJson(string jsonResult) + { + return JsonSerializer.Deserialize(jsonResult, _jsonOptions); + } +} diff --git a/GitVersion.yml b/GitVersion.yml new file mode 100644 index 0000000..92be825 --- /dev/null +++ b/GitVersion.yml @@ -0,0 +1,105 @@ +assembly-versioning-scheme: MajorMinorPatch +assembly-file-versioning-scheme: MajorMinorPatch +assembly-informational-format: '{InformationalVersion}' +mode: ContinuousDelivery +increment: None +continuous-delivery-fallback-tag: ci +tag-prefix: v +major-version-bump-message: '^(breaking|major)' +minor-version-bump-message: '^(feat|minor)' +patch-version-bump-message: '^(fix|patch|chore)' +no-bump-message: '\+semver:\s?(none|skip)' +legacy-semver-padding: 1 +build-metadata-padding: 1 +commits-since-version-source-padding: 1 +tag-pre-release-weight: 60000 +commit-message-incrementing: Enabled +merge-message-formats: {} +update-build-number: true +increment: None +branches: + main: + regex: ^master$|^main$ + mode: ContinuousDelivery + tag: '' + increment: None + prevent-increment-of-merged-branch-version: true + track-merge-target: false + source-branches: [ 'develop', 'release' ] + tracks-release-branches: false + is-release-branch: false + is-mainline: true + pre-release-weight: 55000 + develop: + regex: ^dev(elop)?(ment)?$ + mode: ContinuousDeployment + tag: alpha + increment: None + prevent-increment-of-merged-branch-version: false + track-merge-target: true + source-branches: [] + tracks-release-branches: true + is-release-branch: false + is-mainline: false + pre-release-weight: 0 + release: + regex: '^release.*' + mode: ContinuousDelivery + tag: beta + increment: None + prevent-increment-of-merged-branch-version: true + track-merge-target: false + source-branches: [ 'develop', 'main', 'support', 'release' ] + tracks-release-branches: false + is-release-branch: true + is-mainline: false + pre-release-weight: 30000 + feature: + regex: '^(INT-\d+\/|GSDK-\d+\/|feat|fix|chore)' + mode: ContinuousDelivery + tag: useBranchName + increment: None + prevent-increment-of-merged-branch-version: false + track-merge-target: false + source-branches: [ 'develop', 'main' ] + tracks-release-branches: false + is-release-branch: false + is-mainline: false + pre-release-weight: 30000 + pull-request: + regex: ^(pull|pull\-requests|pr)[/-] + mode: ContinuousDelivery + tag: pr + increment: None + prevent-increment-of-merged-branch-version: false + tag-number-pattern: '[/-](?\d+)[-/]' + track-merge-target: false + source-branches: [ 'develop', 'main', 'release', 'feature', 'support', 'hotfix' ] + tracks-release-branches: false + is-release-branch: false + is-mainline: false + pre-release-weight: 30000 + hotfix: + regex: ^hotfix(es)?[/-] + mode: ContinuousDelivery + tag: beta + increment: None + prevent-increment-of-merged-branch-version: false + track-merge-target: false + source-branches: [ 'develop', 'main', 'support' ] + tracks-release-branches: false + is-release-branch: false + is-mainline: false + pre-release-weight: + support: + regex: ^support[/-] + mode: ContinuousDelivery + tag: '' + increment: None + prevent-increment-of-merged-branch-version: true + track-merge-target: false + source-branches: [ 'main' ] + tracks-release-branches: false + is-release-branch: false + is-mainline: true + pre-release-weight: 55000 diff --git a/global.json b/global.json new file mode 100644 index 0000000..fd01ae7 --- /dev/null +++ b/global.json @@ -0,0 +1,6 @@ +{ + "sdk": { + "version": "8.0.0", + "rollForward": "latestFeature" + } +} \ No newline at end of file