From c90665031979f11e3ac04bd74a0e4b9cad29a71e Mon Sep 17 00:00:00 2001 From: Thomas Labrecque Date: Wed, 15 May 2024 14:36:19 -0400 Subject: [PATCH 1/6] feat: Update Nuget Packages --- .editorconfig | 2 ++ APP_README.md | 3 ++- CHANGELOG.md | 3 +++ Directory.Build.props | 4 ++-- README.md | 4 ++-- .../AuthenticationRepositoryMock.cs | 9 ++------ .../ApplicationTemplate.Access.csproj | 2 +- ...zerToResponseContentSererializerAdapter.cs | 9 ++------ .../Framework/Serialization/JwtData.cs | 2 +- .../DadJokes/DadJokesQuote.cs | 5 +--- .../DadJokes/DadJokesService.cs | 5 +--- .../KillSwitch/KillSwitchService.cs | 2 +- .../ApplicationTemplate.Mobile.csproj | 23 ++++++++++--------- .../iOS/LinkerExclusions.xml | 2 +- .../ApplicationTemplate.Presentation.csproj | 15 ++++++------ .../ConfigurationConfiguration.cs | 12 +++------- .../Configuration/EnvironmentManager.cs | 9 ++------ .../DynamicData/IChangeSet.Extensions.cs | 11 ++------- ....Extensions.PropertyFromDynamicProperty.cs | 14 ++--------- ...dTaskDynamicPropertyFromDynamicProperty.cs | 7 +----- .../DadJokes/DadJokesPageViewModel.cs | 4 ++-- .../Diagnostics/DiagnosticsCountersService.cs | 9 +++----- .../HttpDebugger/HttpDebuggerViewModel.cs | 6 ++--- .../Content/DadJokes/DadJokesPage.xaml | 10 ++++---- ...pplicationTemplate.Tests.Functional.csproj | 7 +++--- .../FunctionalTestBase.cs | 4 ++-- .../ApplicationTemplate.Tests.Unit.csproj | 6 ++--- .../ApplicationTemplate.Windows.csproj | 10 ++++---- 28 files changed, 75 insertions(+), 124 deletions(-) diff --git a/.editorconfig b/.editorconfig index bb2905e0e..1ae715381 100644 --- a/.editorconfig +++ b/.editorconfig @@ -391,6 +391,8 @@ dotnet_diagnostic.SA1210.severity = suggestion dotnet_diagnostic.CA1308.severity = none # CS1587: XML comment is not placed on a valid language element dotnet_diagnostic.CS1587.severity = none +# CA1859: Use concrete types when possible for improved performance +dotnet_diagnostic.CA1859.severity = none # VSTHRD110: This one is bugged: https://github.com/microsoft/vs-threading/issues/899 dotnet_diagnostic.VSTHRD110.severity = none diff --git a/APP_README.md b/APP_README.md index 0531c9f31..3d45a2ece 100644 --- a/APP_README.md +++ b/APP_README.md @@ -20,12 +20,13 @@ This repository was generated using the **nventive Mobile Template**. ### Local Development Requirements All development is expected to be done from Visual Studio in a Windows environment. -- .Net 7 +- .NET 8 - Visual Studio 2022 (17.4 and above) - We recommend validating your components using this [Uno guide](https://platform.uno/docs/articles/get-started-vs-2022.html). - For mobile development, MAUI workloads are required. - You can install them using [`uno-check`](https://platform.uno/docs/articles/external/uno.check/doc/using-uno-check.html). - For local iOS compilation and debugging, you need access to Mac with Xcode 14.2 (more recent versions may work too). + > 💡 You'll need an [Apple provisioning profile](https://developer.apple.com/help/account/manage-profiles/create-a-development-provisioning-profile/) to start your application. ### Pipelines Requirements The pipelines (for continuous integration, testing, and delivery) of this project are made for [Azure Pipelines](https://learn.microsoft.com/en-us/azure/devops/pipelines/get-started/what-is-azure-pipelines?view=azure-devops). diff --git a/CHANGELOG.md b/CHANGELOG.md index 444792b6f..5833bec31 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,9 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/) Prefix your items with `(Template)` if the change is about the template and not the resulting application. +## 3.5.X +- Bump Uno packages to 5.2.121 to fix a crash on iOS. + ## 3.4.X - Added a kill switch feature to the app. - Bump Uno.WinUI, Uno.WinUI.DevServer, Uno.WinUI.Lottie and Uno.UI.Adapter.Microsoft.Extensions.Logging to 5.0.159 to fix backNavigation/CloseModal crash. diff --git a/Directory.Build.props b/Directory.Build.props index f95d199de..e81b7d0ce 100644 --- a/Directory.Build.props +++ b/Directory.Build.props @@ -4,13 +4,13 @@ all runtime; build; native; contentfiles; analyzers - + all runtime; build; native; contentfiles; analyzers - + diff --git a/README.md b/README.md index 61a3e86fc..033f0d760 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -# Uno Platform Application Template +# Uno Platform Application Template [![License](https://img.shields.io/badge/License-Apache%202.0-blue.svg?style=flat-square)](LICENSE) ![Version](https://img.shields.io/nuget/v/NV.Templates.Mobile?style=flat-square) ![Downloads](https://img.shields.io/nuget/dt/NV.Templates.Mobile?style=flat-square) @@ -21,7 +21,7 @@ From left to right: WinUI, iOS, and Android. ## Requirements -Visual Studio 2022 with .Net 7 are required. +Visual Studio 2022 with .NET 8 are required. This template largely relies on Uno Platform, if you want to make sure you got everything installed correctly on your machine, we encourage you to use `uno-check`, the documentation is available [here](https://platform.uno/docs/articles/uno-check.html) diff --git a/src/app/ApplicationTemplate.Access/ApiClients/Authentication/AuthenticationRepositoryMock.cs b/src/app/ApplicationTemplate.Access/ApiClients/Authentication/AuthenticationRepositoryMock.cs index c434bf974..1f5c8da43 100644 --- a/src/app/ApplicationTemplate.Access/ApiClients/Authentication/AuthenticationRepositoryMock.cs +++ b/src/app/ApplicationTemplate.Access/ApiClients/Authentication/AuthenticationRepositoryMock.cs @@ -1,15 +1,13 @@ using System; -using System.Collections.Generic; using System.Globalization; using System.IO; -using System.Text; using System.Text.Json; using System.Threading; using System.Threading.Tasks; namespace ApplicationTemplate.DataAccess; -public class AuthenticationRepositoryMock : IAuthenticationRepository +public sealed class AuthenticationRepositoryMock : IAuthenticationRepository { private readonly JsonSerializerOptions _serializerOptions; @@ -43,10 +41,7 @@ public async Task Login(CancellationToken ct, string email, public async Task RefreshToken(CancellationToken ct, AuthenticationData unauthorizedToken) { - if (unauthorizedToken is null) - { - throw new ArgumentNullException(nameof(unauthorizedToken)); - } + ArgumentNullException.ThrowIfNull(unauthorizedToken); // We add a delay to simulate a long API call await Task.Delay(TimeSpan.FromSeconds(2)); diff --git a/src/app/ApplicationTemplate.Access/ApplicationTemplate.Access.csproj b/src/app/ApplicationTemplate.Access/ApplicationTemplate.Access.csproj index 879c2b847..04bd5ee41 100644 --- a/src/app/ApplicationTemplate.Access/ApplicationTemplate.Access.csproj +++ b/src/app/ApplicationTemplate.Access/ApplicationTemplate.Access.csproj @@ -24,7 +24,7 @@ - + diff --git a/src/app/ApplicationTemplate.Access/Framework/Serialization/JsonSerializerToResponseContentSererializerAdapter.cs b/src/app/ApplicationTemplate.Access/Framework/Serialization/JsonSerializerToResponseContentSererializerAdapter.cs index 7c0a9c4e7..c510fe833 100644 --- a/src/app/ApplicationTemplate.Access/Framework/Serialization/JsonSerializerToResponseContentSererializerAdapter.cs +++ b/src/app/ApplicationTemplate.Access/Framework/Serialization/JsonSerializerToResponseContentSererializerAdapter.cs @@ -1,7 +1,5 @@ using System; -using System.Collections.Generic; using System.Net.Http; -using System.Text; using System.Text.Json; using System.Threading; using System.Threading.Tasks; @@ -9,7 +7,7 @@ namespace ApplicationTemplate; -public class JsonSerializerToResponseContentSererializerAdapter : IResponseContentDeserializer +public sealed class JsonSerializerToResponseContentSererializerAdapter : IResponseContentDeserializer { private readonly JsonSerializerOptions _serializerOptions; @@ -20,10 +18,7 @@ public JsonSerializerToResponseContentSererializerAdapter(JsonSerializerOptions public async Task Deserialize(CancellationToken ct, HttpContent content) { - if (content is null) - { - throw new ArgumentNullException(nameof(content)); - } + ArgumentNullException.ThrowIfNull(content); using (var stream = await content.ReadAsStreamAsync()) { diff --git a/src/app/ApplicationTemplate.Access/Framework/Serialization/JwtData.cs b/src/app/ApplicationTemplate.Access/Framework/Serialization/JwtData.cs index ab9e0de02..489e5e4e1 100644 --- a/src/app/ApplicationTemplate.Access/Framework/Serialization/JwtData.cs +++ b/src/app/ApplicationTemplate.Access/Framework/Serialization/JwtData.cs @@ -30,7 +30,7 @@ public JwtData(string token, JsonSerializerOptions jsonSerializerOptions = null) _jsonSerializerOptions = jsonSerializerOptions; Token = token; - var parts = token?.Split(new[] { '.' }); + var parts = token?.Split(['.']); RawHeader = parts?.Length > 0 ? Base64DecodeToString(parts[0]) : null; RawPayload = parts?.Length > 1 ? Base64DecodeToString(parts[1]) : null; Signature = parts?.Length > 2 ? Base64Decode(parts[2]) : null; diff --git a/src/app/ApplicationTemplate.Business/DadJokes/DadJokesQuote.cs b/src/app/ApplicationTemplate.Business/DadJokes/DadJokesQuote.cs index e375c2d67..907d40a9b 100644 --- a/src/app/ApplicationTemplate.Business/DadJokes/DadJokesQuote.cs +++ b/src/app/ApplicationTemplate.Business/DadJokes/DadJokesQuote.cs @@ -14,10 +14,7 @@ public DadJokesQuote(DadJokeContentData data, bool isFavorite) return; } - if (data is null) - { - throw new ArgumentNullException(nameof(data)); - } + ArgumentNullException.ThrowIfNull(data); Id = data.Id; Selftext = data.Selftext; diff --git a/src/app/ApplicationTemplate.Business/DadJokes/DadJokesService.cs b/src/app/ApplicationTemplate.Business/DadJokes/DadJokesService.cs index 76f0acb7e..f9f79ddd1 100644 --- a/src/app/ApplicationTemplate.Business/DadJokes/DadJokesService.cs +++ b/src/app/ApplicationTemplate.Business/DadJokes/DadJokesService.cs @@ -63,10 +63,7 @@ public async Task> GetFavorites(CancellationToken public async Task SetIsFavorite(CancellationToken ct, DadJokesQuote quote, bool isFavorite) { - if (quote is null) - { - throw new ArgumentNullException(nameof(quote)); - } + ArgumentNullException.ThrowIfNull(quote); var settings = await _applicationSettingsRepository.GetCurrent(ct); diff --git a/src/app/ApplicationTemplate.Business/KillSwitch/KillSwitchService.cs b/src/app/ApplicationTemplate.Business/KillSwitch/KillSwitchService.cs index 89d40584b..e1de08efd 100644 --- a/src/app/ApplicationTemplate.Business/KillSwitch/KillSwitchService.cs +++ b/src/app/ApplicationTemplate.Business/KillSwitch/KillSwitchService.cs @@ -26,5 +26,5 @@ public KillSwitchService(IKillSwitchRepository killSwitchRepository, ILogger public IObservable ObserveKillSwitchActivation() => _killSwitchRepository.ObserveKillSwitchActivation() - .Do(isActive => _logger.LogInformation("Kill switch is now {isActive}.", isActive)); + .Do(isActive => _logger.LogInformation("Kill switch is now {IsActive}.", isActive)); } diff --git a/src/app/ApplicationTemplate.Mobile/ApplicationTemplate.Mobile.csproj b/src/app/ApplicationTemplate.Mobile/ApplicationTemplate.Mobile.csproj index 520586f99..6678ad4b6 100644 --- a/src/app/ApplicationTemplate.Mobile/ApplicationTemplate.Mobile.csproj +++ b/src/app/ApplicationTemplate.Mobile/ApplicationTemplate.Mobile.csproj @@ -1,4 +1,4 @@ - + 12.0 net8.0-android;net8.0-ios @@ -18,8 +18,8 @@ - - + + @@ -28,14 +28,14 @@ - + - - - - - + + + + + @@ -100,7 +100,7 @@ - + @@ -156,6 +156,7 @@ + manual True $(MtouchExtraArgs) --setenv=MONO_LOG_LEVEL=debug --setenv=MONO_LOG_MASK=gc False @@ -199,7 +200,7 @@ - + diff --git a/src/app/ApplicationTemplate.Mobile/iOS/LinkerExclusions.xml b/src/app/ApplicationTemplate.Mobile/iOS/LinkerExclusions.xml index fd329b96c..8edb450a0 100644 --- a/src/app/ApplicationTemplate.Mobile/iOS/LinkerExclusions.xml +++ b/src/app/ApplicationTemplate.Mobile/iOS/LinkerExclusions.xml @@ -6,7 +6,7 @@ - + diff --git a/src/app/ApplicationTemplate.Presentation/ApplicationTemplate.Presentation.csproj b/src/app/ApplicationTemplate.Presentation/ApplicationTemplate.Presentation.csproj index 314bb5a2d..ea9273bbb 100644 --- a/src/app/ApplicationTemplate.Presentation/ApplicationTemplate.Presentation.csproj +++ b/src/app/ApplicationTemplate.Presentation/ApplicationTemplate.Presentation.csproj @@ -16,7 +16,7 @@ - + @@ -26,15 +26,15 @@ - - - - + + + + - - + + @@ -43,5 +43,4 @@ - diff --git a/src/app/ApplicationTemplate.Presentation/Configuration/ConfigurationConfiguration.cs b/src/app/ApplicationTemplate.Presentation/Configuration/ConfigurationConfiguration.cs index 239ea298a..36c244517 100644 --- a/src/app/ApplicationTemplate.Presentation/Configuration/ConfigurationConfiguration.cs +++ b/src/app/ApplicationTemplate.Presentation/Configuration/ConfigurationConfiguration.cs @@ -29,10 +29,7 @@ public static class ConfigurationConfiguration /// The environment manager. public static IHostBuilder AddConfiguration(this IHostBuilder hostBuilder, string folderPath, IEnvironmentManager environmentManager) { - if (hostBuilder is null) - { - throw new ArgumentNullException(nameof(hostBuilder)); - } + ArgumentNullException.ThrowIfNull(hostBuilder); return hostBuilder .AddConfiguration(environmentManager) @@ -124,10 +121,7 @@ private static IConfigurationBuilder AddUserOverrideConfiguration(this IConfigur /// The environment manager. private static IHostBuilder AddConfiguration(this IHostBuilder hostBuilder, IEnvironmentManager environmentManager) { - if (hostBuilder is null) - { - throw new ArgumentNullException(nameof(hostBuilder)); - } + ArgumentNullException.ThrowIfNull(hostBuilder); return hostBuilder.ConfigureServices((hostBuilderContext, serviceCollection) => serviceCollection .AddSingleton(serviceProvider => hostBuilderContext.Configuration) @@ -136,7 +130,7 @@ private static IHostBuilder AddConfiguration(this IHostBuilder hostBuilder, IEnv ); } - public class AppSettingsFile + public sealed class AppSettingsFile { private static AppSettingsFile[] _appSettingsFiles; diff --git a/src/app/ApplicationTemplate.Presentation/Configuration/EnvironmentManager.cs b/src/app/ApplicationTemplate.Presentation/Configuration/EnvironmentManager.cs index 79b693df0..24de1263b 100644 --- a/src/app/ApplicationTemplate.Presentation/Configuration/EnvironmentManager.cs +++ b/src/app/ApplicationTemplate.Presentation/Configuration/EnvironmentManager.cs @@ -1,8 +1,6 @@ using System; -using System.Collections.Generic; using System.IO; using System.Linq; -using System.Text; using static ApplicationTemplate.ConfigurationConfiguration; namespace ApplicationTemplate; @@ -10,7 +8,7 @@ namespace ApplicationTemplate; /// /// This implementation of uses local files to support the override features. /// -public class EnvironmentManager : IEnvironmentManager +public sealed class EnvironmentManager : IEnvironmentManager { //-:cnd:noEmit #if PRODUCTION @@ -58,10 +56,7 @@ public void ClearOverride() public void Override(string environment) { - if (environment == null) - { - throw new ArgumentNullException(nameof(environment)); - } + ArgumentNullException.ThrowIfNull(environment); environment = environment.ToUpperInvariant(); diff --git a/src/app/ApplicationTemplate.Presentation/Framework/DynamicData/IChangeSet.Extensions.cs b/src/app/ApplicationTemplate.Presentation/Framework/DynamicData/IChangeSet.Extensions.cs index c1a6aa987..dd5d85d84 100644 --- a/src/app/ApplicationTemplate.Presentation/Framework/DynamicData/IChangeSet.Extensions.cs +++ b/src/app/ApplicationTemplate.Presentation/Framework/DynamicData/IChangeSet.Extensions.cs @@ -1,6 +1,5 @@ using System; using System.Collections.Generic; -using System.Text; namespace DynamicData; @@ -8,10 +7,7 @@ public static class ChangeSetExtensions { public static IEnumerable GetAddedItems(this IChangeSet changeSet) { - if (changeSet is null) - { - throw new ArgumentNullException(nameof(changeSet)); - } + ArgumentNullException.ThrowIfNull(changeSet); foreach (var change in changeSet) { @@ -38,10 +34,7 @@ public static IEnumerable GetAddedItems(this IChangeSet changeSet) public static IEnumerable GetRemovedItems(this IChangeSet changeSet) { - if (changeSet is null) - { - throw new ArgumentNullException(nameof(changeSet)); - } + ArgumentNullException.ThrowIfNull(changeSet); foreach (var change in changeSet) { diff --git a/src/app/ApplicationTemplate.Presentation/Framework/ViewModels/IViewModel.Extensions.PropertyFromDynamicProperty.cs b/src/app/ApplicationTemplate.Presentation/Framework/ViewModels/IViewModel.Extensions.PropertyFromDynamicProperty.cs index 55901a91c..9753fea4a 100644 --- a/src/app/ApplicationTemplate.Presentation/Framework/ViewModels/IViewModel.Extensions.PropertyFromDynamicProperty.cs +++ b/src/app/ApplicationTemplate.Presentation/Framework/ViewModels/IViewModel.Extensions.PropertyFromDynamicProperty.cs @@ -1,9 +1,5 @@ using System; -using System.Collections.Generic; using System.Runtime.CompilerServices; -using System.Text; -using Chinook.DynamicMvvm; -using Chinook.DynamicMvvm.Implementations; namespace Chinook.DynamicMvvm; @@ -20,10 +16,7 @@ public static class ChinookViewModelExtensionsForPropertiesFromDynamicProperty /// The property's value. public static T GetFromDynamicProperty(this IViewModel viewModel, IDynamicProperty source, [CallerMemberName] string name = null) { - if (source is null) - { - throw new ArgumentNullException(nameof(source)); - } + ArgumentNullException.ThrowIfNull(source); return viewModel.Get(viewModel.GetOrCreateDynamicProperty(name, n => new ValueChangedOnBackgroundTaskDynamicPropertyFromDynamicProperty(name, source, viewModel, source.Value))); } @@ -41,10 +34,7 @@ public static T GetFromDynamicProperty(this IViewModel viewModel, IDynamicPro /// The property's value. public static TResult GetFromDynamicProperty(this IViewModel viewModel, IDynamicProperty source, Func selector, [CallerMemberName] string name = null) { - if (source is null) - { - throw new ArgumentNullException(nameof(source)); - } + ArgumentNullException.ThrowIfNull(source); return viewModel.Get(viewModel.GetOrCreateDynamicProperty(name, n => new ValueChangedOnBackgroundTaskDynamicPropertyFromDynamicProperty(name, source, viewModel, selector, selector(source.Value)))); diff --git a/src/app/ApplicationTemplate.Presentation/Framework/ViewModels/ValueChangedOnBackgroundTaskDynamicPropertyFromDynamicProperty.cs b/src/app/ApplicationTemplate.Presentation/Framework/ViewModels/ValueChangedOnBackgroundTaskDynamicPropertyFromDynamicProperty.cs index 07124fef0..3b71eff63 100644 --- a/src/app/ApplicationTemplate.Presentation/Framework/ViewModels/ValueChangedOnBackgroundTaskDynamicPropertyFromDynamicProperty.cs +++ b/src/app/ApplicationTemplate.Presentation/Framework/ViewModels/ValueChangedOnBackgroundTaskDynamicPropertyFromDynamicProperty.cs @@ -1,6 +1,4 @@ using System; -using System.Collections.Generic; -using System.Text; using Chinook.DynamicMvvm.Implementations; namespace Chinook.DynamicMvvm; @@ -35,10 +33,7 @@ public override object Value get => base.Value; set { - if (_isDisposed) - { - throw new ObjectDisposedException(Name); - } + ObjectDisposedException.ThrowIf(_isDisposed, this); if (!Equals(value, base.Value)) { diff --git a/src/app/ApplicationTemplate.Presentation/ViewModels/DadJokes/DadJokesPageViewModel.cs b/src/app/ApplicationTemplate.Presentation/ViewModels/DadJokes/DadJokesPageViewModel.cs index b17138e27..8d705115f 100644 --- a/src/app/ApplicationTemplate.Presentation/ViewModels/DadJokes/DadJokesPageViewModel.cs +++ b/src/app/ApplicationTemplate.Presentation/ViewModels/DadJokes/DadJokesPageViewModel.cs @@ -14,7 +14,7 @@ namespace ApplicationTemplate.Presentation; -public partial class DadJokesPageViewModel : ViewModel +public sealed partial class DadJokesPageViewModel : ViewModel { [Inject] private IDadJokesService _dadJokesService; [Inject] private ISectionsNavigator _sectionsNavigator; @@ -67,7 +67,7 @@ private async Task SetupFavoritesUpdate(CancellationToken ct) void UpdateItemViewModels(IChangeSet changeSet) { var quotesVMs = Jokes.State.Data; - if (quotesVMs != null && quotesVMs.Any()) + if (quotesVMs != null && quotesVMs.Length != 0) { var addedItems = changeSet.GetAddedItems(); var removedItems = changeSet.GetRemovedItems(); diff --git a/src/app/ApplicationTemplate.Presentation/ViewModels/Diagnostics/DiagnosticsCountersService.cs b/src/app/ApplicationTemplate.Presentation/ViewModels/Diagnostics/DiagnosticsCountersService.cs index 2c0afd4c0..d2e44aafa 100644 --- a/src/app/ApplicationTemplate.Presentation/ViewModels/Diagnostics/DiagnosticsCountersService.cs +++ b/src/app/ApplicationTemplate.Presentation/ViewModels/Diagnostics/DiagnosticsCountersService.cs @@ -4,7 +4,7 @@ namespace ApplicationTemplate.Presentation; -public class DiagnosticsCountersService +public sealed class DiagnosticsCountersService { public event EventHandler CountersChanged; @@ -92,7 +92,7 @@ private void OnCommandNotification(KeyValuePair notification) } } -public partial class CountersData +public sealed partial class CountersData { public CountersData() { @@ -100,10 +100,7 @@ public CountersData() public CountersData(CountersData source) { - if (source is null) - { - throw new ArgumentNullException(nameof(source)); - } + ArgumentNullException.ThrowIfNull(source); CreatedViewModels = source.CreatedViewModels; DisposedViewModels = source.DisposedViewModels; diff --git a/src/app/ApplicationTemplate.Presentation/ViewModels/Diagnostics/HttpDebugger/HttpDebuggerViewModel.cs b/src/app/ApplicationTemplate.Presentation/ViewModels/Diagnostics/HttpDebugger/HttpDebuggerViewModel.cs index 49f2f3c7b..9725dc815 100644 --- a/src/app/ApplicationTemplate.Presentation/ViewModels/Diagnostics/HttpDebugger/HttpDebuggerViewModel.cs +++ b/src/app/ApplicationTemplate.Presentation/ViewModels/Diagnostics/HttpDebugger/HttpDebuggerViewModel.cs @@ -1,5 +1,4 @@ using System; -using System.Collections.Generic; using System.Collections.ObjectModel; using System.Globalization; using System.Reactive.Concurrency; @@ -9,7 +8,6 @@ using System.Text.Json; using ApplicationTemplate.DataAccess; using Chinook.DynamicMvvm; -using Chinook.DynamicMvvm.Deactivation; using DynamicData; using Uno; using Uno.Extensions; @@ -18,6 +16,8 @@ namespace ApplicationTemplate.Presentation; public sealed partial class HttpDebuggerViewModel : TabViewModel { + private static readonly JsonSerializerOptions _jsonSerializerOptions = new JsonSerializerOptions { WriteIndented = true }; + [Inject] private IHttpDebuggerService _httpDebuggerService; public HttpDebuggerViewModel() @@ -261,7 +261,7 @@ private static string TryFormatContent(string content, bool indentJson) var reader = new Utf8JsonReader(Encoding.UTF8.GetBytes(content)); if (JsonDocument.TryParseValue(ref reader, out var jsonDoc)) { - return JsonSerializer.Serialize(jsonDoc, new JsonSerializerOptions { WriteIndented = true }); + return JsonSerializer.Serialize(jsonDoc, _jsonSerializerOptions); } } diff --git a/src/app/ApplicationTemplate.Shared.Views/Content/DadJokes/DadJokesPage.xaml b/src/app/ApplicationTemplate.Shared.Views/Content/DadJokes/DadJokesPage.xaml index 9272332cb..76561d6a8 100644 --- a/src/app/ApplicationTemplate.Shared.Views/Content/DadJokes/DadJokesPage.xaml +++ b/src/app/ApplicationTemplate.Shared.Views/Content/DadJokes/DadJokesPage.xaml @@ -1,10 +1,10 @@ - @@ -103,18 +103,16 @@ - - - + - + diff --git a/src/app/ApplicationTemplate.Tests.Functional/ApplicationTemplate.Tests.Functional.csproj b/src/app/ApplicationTemplate.Tests.Functional/ApplicationTemplate.Tests.Functional.csproj index a11e79160..03082a82d 100644 --- a/src/app/ApplicationTemplate.Tests.Functional/ApplicationTemplate.Tests.Functional.csproj +++ b/src/app/ApplicationTemplate.Tests.Functional/ApplicationTemplate.Tests.Functional.csproj @@ -11,7 +11,7 @@ - + @@ -25,11 +25,11 @@ all runtime; build; native; contentfiles; analyzers; buildtransitive - + all runtime; build; native; contentfiles; analyzers; buildtransitive - + all runtime; build; native; contentfiles; analyzers; buildtransitive @@ -38,5 +38,4 @@ - diff --git a/src/app/ApplicationTemplate.Tests.Functional/FunctionalTestBase.cs b/src/app/ApplicationTemplate.Tests.Functional/FunctionalTestBase.cs index 7edb9625b..062bbba10 100644 --- a/src/app/ApplicationTemplate.Tests.Functional/FunctionalTestBase.cs +++ b/src/app/ApplicationTemplate.Tests.Functional/FunctionalTestBase.cs @@ -1,4 +1,5 @@ using System.Collections.Generic; +using System.Globalization; using System.Reactive.Concurrency; using System.Reactive.Linq; using System.Threading; @@ -180,7 +181,7 @@ private void ConfigureLogging(HostBuilderContext hostBuilderContext, ILoggingBui var serilogConfiguration = new LoggerConfiguration() .ReadFrom.Configuration(hostBuilderContext.Configuration) .Enrich.With(new ThreadIdEnricher()) - .WriteTo.TestOutput(_output, outputTemplate: "{Timestamp:HH:mm:ss.fff} Thread:{ThreadId} {Level:u1}/{SourceContext}: {Message:lj} {Exception}{NewLine}"); + .WriteTo.TestOutput(_output, outputTemplate: "{Timestamp:HH:mm:ss.fff} Thread:{ThreadId} {Level:u1}/{SourceContext}: {Message:lj} {Exception}{NewLine}", formatProvider: CultureInfo.InvariantCulture); var logger = serilogConfiguration.CreateLogger(); loggingBuilder.AddSerilog(logger); @@ -209,7 +210,6 @@ protected virtual IServiceCollection ReplaceWithMock(IServiceCollectio return services.Replace(ServiceDescriptor.Singleton(mockedService)); } - /// /// Gets the application settings to use for this test. /// diff --git a/src/app/ApplicationTemplate.Tests.Unit/ApplicationTemplate.Tests.Unit.csproj b/src/app/ApplicationTemplate.Tests.Unit/ApplicationTemplate.Tests.Unit.csproj index d27f9a97c..e52dbe62c 100644 --- a/src/app/ApplicationTemplate.Tests.Unit/ApplicationTemplate.Tests.Unit.csproj +++ b/src/app/ApplicationTemplate.Tests.Unit/ApplicationTemplate.Tests.Unit.csproj @@ -10,7 +10,7 @@ - + @@ -24,11 +24,11 @@ all runtime; build; native; contentfiles; analyzers; buildtransitive - + all runtime; build; native; contentfiles; analyzers; buildtransitive - + all runtime; build; native; contentfiles; analyzers; buildtransitive diff --git a/src/app/ApplicationTemplate.Windows/ApplicationTemplate.Windows.csproj b/src/app/ApplicationTemplate.Windows/ApplicationTemplate.Windows.csproj index 9fa56137c..474dcd92b 100644 --- a/src/app/ApplicationTemplate.Windows/ApplicationTemplate.Windows.csproj +++ b/src/app/ApplicationTemplate.Windows/ApplicationTemplate.Windows.csproj @@ -70,8 +70,8 @@ - - + + @@ -86,8 +86,8 @@ - - + + @@ -128,5 +128,5 @@ - + From 1d5b64982b871aac091c6cdabbee6ea1d4d05e4d Mon Sep 17 00:00:00 2001 From: Ariel De Los Santos Date: Thu, 16 May 2024 15:12:10 -0400 Subject: [PATCH 2/6] fix(293338): fix changeLog file url on PR template --- .github/PULL_REQUEST_TEMPLATE.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md index fffbf5274..aa24fcf81 100644 --- a/.github/PULL_REQUEST_TEMPLATE.md +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -32,7 +32,7 @@ GitHub Issue: # ### Always applicable No matter your changes, these checks always apply. - [ ] Your conventional commits are aligned with the **Impact on version** section. -- [ ] Updated [CHANGELOG.md](../CHANGELOG.md). +- [ ] Updated [CHANGELOG.md](../blob/main/CHANGELOG.md). - Use the latest Major.Minor.X header if you do a **Patch** change. - Create a new Major.Minor.X header if you do a **Minor** or **Major** change. - If you create a new header, it aligns with the **Impact on version** section and matches what is generated in the build pipeline. From 2ac36b402c850dfa9c369283731012f3e7b17eb5 Mon Sep 17 00:00:00 2001 From: Kevin Takla Date: Thu, 16 May 2024 14:02:49 -0400 Subject: [PATCH 3/6] ci: ensure nuget release is only executed from the main branch --- .azure-pipelines.yml | 6 +++++- CHANGELOG.md | 1 + 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/.azure-pipelines.yml b/.azure-pipelines.yml index 2a4689ac9..7453f813b 100644 --- a/.azure-pipelines.yml +++ b/.azure-pipelines.yml @@ -23,6 +23,10 @@ trigger: - main variables: +#-if false +- name: IsReleaseBranch + value: $[eq(variables['Build.SourceBranch'], 'refs/heads/main')] +#-endif - template: build/variables.yml stages: @@ -49,7 +53,7 @@ stages: iosVariableGroup: 'ApplicationTemplate.Distribution.Internal.iOS' - stage: Publish_Template_Package - condition: and(succeeded(), eq(variables['IsLightBuild'], 'false')) + condition: and(succeeded(), eq(variables['IsLightBuild'], 'false'), eq(variables['IsReleaseBranch'], 'true')) dependsOn: - Build_Staging_GeneratedApp - Build_Staging diff --git a/CHANGELOG.md b/CHANGELOG.md index 5833bec31..2f751a069 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,7 @@ Prefix your items with `(Template)` if the change is about the template and not ## 3.5.X - Bump Uno packages to 5.2.121 to fix a crash on iOS. +- Ensure NV.Template.Mobile nuget is only deployed from the main branch. ## 3.4.X - Added a kill switch feature to the app. From d59474dc866f22925fa792cb847ba95f8c8caf58 Mon Sep 17 00:00:00 2001 From: Kevin Takla Date: Thu, 16 May 2024 11:45:11 -0400 Subject: [PATCH 4/6] chore: temporary disable internal testflight --- .azure-pipelines.yml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/.azure-pipelines.yml b/.azure-pipelines.yml index 7453f813b..05b9fc6fd 100644 --- a/.azure-pipelines.yml +++ b/.azure-pipelines.yml @@ -92,10 +92,10 @@ stages: appCenterServiceConnectionName: $(AppCenterServiceConnection) appCenterDistributionGroup: $(AppCenterDistributionGroup) - - template: build/stage-release-appstore.yml - parameters: - applicationEnvironment: Staging - deploymentEnvironment: TestFlight + # - template: build/stage-release-appstore.yml + # parameters: + # applicationEnvironment: Staging + # deploymentEnvironment: TestFlight - stage: Build_Production dependsOn: Build_Staging From d4e5617f12f0349fe9f3c6eb8b6c9e4a085a7519 Mon Sep 17 00:00:00 2001 From: Kevin Takla Date: Thu, 16 May 2024 11:45:20 -0400 Subject: [PATCH 5/6] feat!: swap appcenter for firebase --- .azure-pipelines-canary.yml | 25 ++++--- .azure-pipelines.yml | 35 ++------- build/stage-release-appcenter.yml | 110 ---------------------------- build/stage-release-firebase.yml | 42 +++++++++++ build/templates/firebase-deploy.yml | 50 +++++++++++++ build/variables.yml | 27 ++----- src/ApplicationTemplate.sln | 2 +- 7 files changed, 119 insertions(+), 172 deletions(-) delete mode 100644 build/stage-release-appcenter.yml create mode 100644 build/stage-release-firebase.yml create mode 100644 build/templates/firebase-deploy.yml diff --git a/.azure-pipelines-canary.yml b/.azure-pipelines-canary.yml index fcd8692b5..a0cfc9ad5 100644 --- a/.azure-pipelines-canary.yml +++ b/.azure-pipelines-canary.yml @@ -27,18 +27,19 @@ stages: condition: and(succeeded(), eq(variables['IsCanary'], 'true')) dependsOn: Build_Canary - jobs: - - template: build/stage-release-appcenter.yml - parameters: - applicationEnvironment: Staging - deploymentEnvironment: AppCenter - appCenterWindowsSlug: $(AppCenterWindowsSlug_Canary) - appCenteriOSSlug: $(AppCenteriOSSlug_Canary) - appCenterAndroidSlug: $(AppCenterAndroidSlug_Canary) - androidKeyStoreFile: $(InternalKeystore) - androidVariableGroup: 'ApplicationTemplate.Distribution.Internal.Android' - appCenterServiceConnectionName: $(AppCenterCanaryServiceConnection) - appCenterDistributionGroup: $(AppCenterCanaryDistributionGroup) + # TODO create firebase project for the canary app + # jobs: + # - template: build/stage-release-appcenter.yml + # parameters: + # applicationEnvironment: Staging + # deploymentEnvironment: AppCenter + # appCenterWindowsSlug: $(AppCenterWindowsSlug_Canary) + # appCenteriOSSlug: $(AppCenteriOSSlug_Canary) + # appCenterAndroidSlug: $(AppCenterAndroidSlug_Canary) + # androidKeyStoreFile: $(InternalKeystore) + # androidVariableGroup: 'ApplicationTemplate.Distribution.Internal.Android' + # appCenterServiceConnectionName: $(AppCenterCanaryServiceConnection) + # appCenterDistributionGroup: $(AppCenterCanaryDistributionGroup) - template: build/stage-release-appstore.yml parameters: diff --git a/.azure-pipelines.yml b/.azure-pipelines.yml index 05b9fc6fd..6d4b7e088 100644 --- a/.azure-pipelines.yml +++ b/.azure-pipelines.yml @@ -76,26 +76,21 @@ stages: iosVariableGroup: 'ApplicationTemplate.Distribution.Internal.iOS' BannerVersionNameText: "STAGING" -- stage: AppCenter_TestFlight_Staging +- stage: Firebase_TestFlight_Staging condition: and(succeeded(), eq(variables['IsLightBuild'], 'false')) dependsOn: Build_Staging jobs: - - template: build/stage-release-appcenter.yml + - template: build/stage-release-firebase.yml parameters: applicationEnvironment: Staging deploymentEnvironment: AppCenter - appCenterWindowsSlug: $(AppCenterWindowsSlug) - appCenteriOSSlug: $(AppCenteriOSSlug) - appCenterAndroidSlug: $(AppCenterAndroidSlug) - androidKeyStoreFile: $(InternalKeystore) androidVariableGroup: 'ApplicationTemplate.Distribution.Internal.Android' - appCenterServiceConnectionName: $(AppCenterServiceConnection) - appCenterDistributionGroup: $(AppCenterDistributionGroup) + iosVariableGroup: 'ApplicationTemplate.Distribution.Internal.Ios' - # - template: build/stage-release-appstore.yml - # parameters: - # applicationEnvironment: Staging - # deploymentEnvironment: TestFlight + - template: build/stage-release-appstore.yml + parameters: + applicationEnvironment: Staging + deploymentEnvironment: TestFlight - stage: Build_Production dependsOn: Build_Staging @@ -110,22 +105,6 @@ stages: iosCertificateFile: $(AppStoreCertificate) iosVariableGroup: 'ApplicationTemplate.Distribution.AppStore' -- stage: AppCenter_Production - condition: and(succeeded(), eq(variables['IsLightBuild'], 'false')) - dependsOn: Build_Production - jobs: - - template: build/stage-release-appcenter.yml - parameters: - applicationEnvironment: Production - deploymentEnvironment: 'AppCenter Prod' - appCenterWindowsSlug: $(AppCenterWindowsSlug_Production) - appCenteriOSSlug: $(AppCenteriOSSlug_Production) - appCenterAndroidSlug: $(AppCenterAndroidSlug_Production) - androidKeyStoreFile: $(GooglePlayKeystore) - androidVariableGroup: 'ApplicationTemplate.Distribution.GooglePlay' - appCenterServiceConnectionName: $(AppCenterServiceConnection) - appCenterDistributionGroup: $(AppCenterDistributionGroup) - - stage: AppStore condition: and(succeeded(), eq(variables['IsLightBuild'], 'false')) dependsOn: Build_Production diff --git a/build/stage-release-appcenter.yml b/build/stage-release-appcenter.yml deleted file mode 100644 index 694963230..000000000 --- a/build/stage-release-appcenter.yml +++ /dev/null @@ -1,110 +0,0 @@ -parameters: - applicationEnvironment: '' # e.g. "Staging", "Production" - deploymentEnvironment: '' # e.g. "GooglePlay", "AppStore", "AppCenter" - appCenterWindowsSlug: '' - appCenteriOSSlug: '' - appCenterAndroidSlug: '' - androidKeyStoreFile: '' - androidVariableGroup: '' - appCenterServiceConnectionName: '' - appCenterDistributionGroup: '' - -jobs: -- deployment: AppCenter_Android - pool: - vmImage: $(windowsHostedAgentImage) - variables: - - name: artifactName - value: $(AndroidArtifactName)_${{ parameters.applicationEnvironment }} - - name: releaseNotesArtifactName - value: ReleaseNotes_${{ parameters.applicationEnvironment }} - - group: ${{ parameters.androidVariableGroup }} - environment: ${{ parameters.deploymentEnvironment }} - strategy: - runOnce: - deploy: - steps: - - download: current - displayName: "Download Artifact" - artifact: $(artifactName) - - - download: current - displayName: "Download Release Notes" - artifact: $(releaseNotesArtifactName) - - - task: AppCenterDistribute@3 - displayName: Deploy Android to AppCenter - inputs: - serverEndpoint: ${{ parameters.appCenterServiceConnectionName }} - distributionGroupId: ${{ parameters.appCenterDistributionGroup }} - appSlug: ${{ parameters.appCenterAndroidSlug }} - appFile: '$(Pipeline.Workspace)/$(artifactName)/*Signed.aab' - releaseNotesOption: file - releaseNotesFile: "$(Pipeline.Workspace)/$(releaseNotesArtifactName)/ReleaseNotes-Excerpt.md" - isSilent: true - - - task: DeleteFiles@1 - displayName: "Remove Downloaded Artifacts (Build)" - condition: always() - inputs: - SourceFolder: $(Pipeline.Workspace)/$(artifactName) - RemoveSourceFolder: true - Contents: '**' - - - task: DeleteFiles@1 - displayName: "Remove Downloaded Artifacts (Release Notes)" - condition: always() - inputs: - SourceFolder: $(Pipeline.Workspace)/$(releaseNotesArtifactName) - RemoveSourceFolder: true - Contents: '**' - -- deployment: AppCenter_iOS - pool: - vmImage: $(macOSHostedAgentImage) - variables: - - name: artifactName - value: $(iOSArtifactName)_${{ parameters.applicationEnvironment }} - - name: releaseNotesArtifactName - value: ReleaseNotes_${{ parameters.applicationEnvironment }} - environment: ${{ parameters.deploymentEnvironment }} - strategy: - runOnce: - deploy: - steps: - - download: current - displayName: "Download Artifact" - artifact: $(artifactName) - - - download: current - displayName: "Download Release Notes" - artifact: $(releaseNotesArtifactName) - - - task: AppCenterDistribute@3 - displayName: Deploy iOS to AppCenter - inputs: - serverEndpoint: ${{ parameters.appCenterServiceConnectionName }} - appSlug: ${{ parameters.appCenteriOSSlug }} - appFile: $(Pipeline.Workspace)/$(artifactName)/*.ipa - symbolsDsymFiles: $(Pipeline.Workspace)/$(artifactName)/*.dSYM - symbolsIncludeParentDirectory: true - distributionGroupId: ${{ parameters.appCenterDistributionGroup }} - releaseNotesOption: file - releaseNotesFile: "$(Pipeline.Workspace)/$(releaseNotesArtifactName)/ReleaseNotes-Excerpt.md" - isSilent: true - - - task: DeleteFiles@1 - displayName: "Remove Downloaded Artifacts (Build)" - condition: always() - inputs: - SourceFolder: $(Pipeline.Workspace)/$(artifactName) - RemoveSourceFolder: true - Contents: '**' - - - task: DeleteFiles@1 - displayName: "Remove Downloaded Artifacts (Release Notes)" - condition: always() - inputs: - SourceFolder: $(Pipeline.Workspace)/$(releaseNotesArtifactName) - RemoveSourceFolder: true - Contents: '**' diff --git a/build/stage-release-firebase.yml b/build/stage-release-firebase.yml new file mode 100644 index 000000000..31b776df7 --- /dev/null +++ b/build/stage-release-firebase.yml @@ -0,0 +1,42 @@ +parameters: + applicationEnvironment: '' # e.g. "Staging", "Production" + deploymentEnvironment: '' # e.g. "GooglePlay", "AppStore", "Firebase" + androidVariableGroup: '' + iosVariableGroup: '' + +jobs: +- deployment: Firebase_Android + pool: + vmImage: $(linuxHostedAgentImage) + variables: + - name: artifactName + value: $(AndroidArtifactName)_${{ parameters.applicationEnvironment }} + - name: releaseNotesArtifactName + value: ReleaseNotes_${{ parameters.applicationEnvironment }} + - group: ${{ parameters.androidVariableGroup }} + environment: ${{ parameters.deploymentEnvironment }} + strategy: + runOnce: + deploy: + steps: + - template: ./templates/firebase-deploy.yml + parameters: + fileName: '$(ApplicationIdentifier)-Signed.apk' + +- deployment: Firebase_iOS + pool: + vmImage: $(linuxHostedAgentImage) + variables: + - name: artifactName + value: $(iOSArtifactName)_${{ parameters.applicationEnvironment }} + - name: releaseNotesArtifactName + value: ReleaseNotes_${{ parameters.applicationEnvironment }} + - group: ${{ parameters.iosVariableGroup }} + environment: ${{ parameters.deploymentEnvironment }} + strategy: + runOnce: + deploy: + steps: + - template: ./templates/firebase-deploy.yml + parameters: + fileName: '$(SolutionName).Mobile.ipa' \ No newline at end of file diff --git a/build/templates/firebase-deploy.yml b/build/templates/firebase-deploy.yml new file mode 100644 index 000000000..9fe6132a5 --- /dev/null +++ b/build/templates/firebase-deploy.yml @@ -0,0 +1,50 @@ +parameters: + fileName: '' + +steps: +# Install Firebase tools +- script: 'npm install -g firebase-tools' + displayName: 'Install Firebase Tools' + +- download: current + displayName: "Download Artifact" + artifact: $(artifactName) + +- download: current + displayName: "Download Release Notes" + artifact: $(releaseNotesArtifactName) + +- task: DownloadSecureFile@1 + inputs: + secureFile: $(FirebaseDistributionServiceConnectionFile) + name: DistributionServiceConnection + displayName: "Download Firebase Service connection" + +- script: | + firebase appdistribution:distribute '$(Pipeline.Workspace)/$(artifactName)/${{ parameters.fileName }}' \ + --app '$(FirebaseAppId)' \ + --release-notes-file '$(Pipeline.Workspace)/$(releaseNotesArtifactName)/ReleaseNotes-Excerpt.md' \ + --groups "nventive" + env: + GOOGLE_APPLICATION_CREDENTIALS: $(DistributionServiceConnection.secureFilePath) + displayName: 'Deploy to Firebase' + +- task: DeleteFiles@1 + displayName: "Remove Downloaded Artifacts (Build)" + condition: always() + inputs: + SourceFolder: $(Pipeline.Workspace)/$(artifactName) + RemoveSourceFolder: true + Contents: '**' + +- task: DeleteFiles@1 + displayName: "Remove Downloaded Artifacts (Release Notes)" + condition: always() + inputs: + SourceFolder: $(Pipeline.Workspace)/$(releaseNotesArtifactName) + RemoveSourceFolder: true + Contents: '**' + +- task: PostBuildCleanup@3 + displayName: 'Post-Build Cleanup: Cleanup files to keep build server clean!' + condition: always() \ No newline at end of file diff --git a/build/variables.yml b/build/variables.yml index b71d01b40..1e9963874 100644 --- a/build/variables.yml +++ b/build/variables.yml @@ -3,7 +3,7 @@ # Make sure you have the following variable groups in your Azure pipeline library: # # ApplicationTemplate.Distribution.Internal.Android - # ApplicationIdentifier: This is the internal application id of the app for AppCenter releases. Note that this variable is used by Nimue to automatically change the package name. + # ApplicationIdentifier: This is the internal application id of the app for Firebase releases. Note that this variable is used by Nimue to automatically change the package name. # AndroidSigningKeyAlias: This is the keystore alias. # AndroidSigningKeyPass: This is the keystore keypass (secured). # AndroidSigningStorePass: This is the keystore storepass (secured). @@ -15,7 +15,7 @@ # AndroidSigningStorePass: This is the keystore storepass (secured). # # ApplicationTemplate.Distribution.Internal.iOS - # ApplicationIdentifier: This is the internal application id of the app for AppCenter releases. Note that this variable is used by Nimue to automatically change the bundle id. + # ApplicationIdentifier: This is the internal application id of the app for Firebase releases. Note that this variable is used by Nimue to automatically change the bundle id. # AppleCertificatePassword: The certificate password (secured). # # ApplicationTemplate.Distribution.AppStore @@ -31,7 +31,7 @@ InternalKeystore: com.nventive.internal.applicationtemplate.jks # This is the internal keystore used for internal builds. GooglePlayKeystore: com.nventive.applicationtemplate.jks # This is the official keystore used for Google Play. # iOS - InternalProvisioningProfile: com.nventive.applicationtemplate.mobileprovision # This is the internal provisioning profile for internal builds. + InternalProvisioningProfile: com.nventive.applicationtemplate-adhoc.mobileprovision # This is the internal provisioning profile for internal builds. InternalCertificate: nventive.p12 # This is the certificate from the nventive Apple account used to sign internal builds. AppStoreProvisioningProfile: com.nventive.applicationtemplate.mobileprovision # This is the client provisioning profile for the AppStore (Production distribution). AppStoreCertificate: nventive.p12 # This is the client production certificate used to sign AppStore builds. @@ -39,26 +39,10 @@ # Prerequisites - Service connections # Make sure you have the following service connections in your Azure pipeline library. GooglePlayServiceConnection: GooglePlay-nventive-ApplicationTemplate - AppCenterServiceConnection: AppCenter-nventive-framework AppStoreServiceConnection: AppStore-nventive - AppCenterCanaryServiceConnection: AppCenter-nventive-framework - # AppCenter slugs - # The "app slug" corresponds to the identifiers of the app in AppCenter; to find it, navigate to the app in a browser and; - # the URL should look like this: https://appcenter.ms/orgs/{orgId}/apps/{appId}; the slug is simply: "{orgId}/{appId}". - AppCenterAndroidSlug: 'nventive-framework/Application-Template-1' - AppCenteriOSSlug: 'nventive-framework/Application-Template' - AppCenterWindowsSlug: 'nventive-framework/Application-Template-2' - AppCenterAndroidSlug_Production: 'nventive-framework/ApplicationTemplate-Production-1' - AppCenteriOSSlug_Production: 'nventive-framework/ApplicationTemplate-Production' - AppCenterWindowsSlug_Production: 'nventive-framework/ApplicationTemplate-Production-2' - AppCenterAndroidSlug_Canary: 'nventive-framework/Application-Template-Canary-1' - AppCenteriOSSlug_Canary: 'nventive-framework/Application-Template-Canary' - AppCenterWindowsSlug_Canary: 'nventive-framework/Application-Template-Canary-2' - - # AppCenter Distribution Groups - AppCenterDistributionGroup: '00000000-0000-0000-0000-000000000000' - AppCenterCanaryDistributionGroup: '00000000-0000-0000-0000-000000000000' + # Firebase distribution + FirebaseDistributionServiceConnectionFile: 'firebase_unoapptemplate_dist.json' # Azure subscription # AzureSubscriptionName: @@ -74,6 +58,7 @@ # Virtual machine images windowsHostedAgentImage: 'windows-2022' macOSHostedAgentImage: 'macOS-13' + linuxHostedAgentImage: 'ubuntu-22.04' # SDK versions DotNetVersion: '7.0.400' diff --git a/src/ApplicationTemplate.sln b/src/ApplicationTemplate.sln index fcc4a9db8..3e6323924 100644 --- a/src/ApplicationTemplate.sln +++ b/src/ApplicationTemplate.sln @@ -64,7 +64,7 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "build", "build", "{6E8378CB ..\build\canary-merge.yml = ..\build\canary-merge.yml ..\build\gitversion-config.yml = ..\build\gitversion-config.yml ..\build\stage-build.yml = ..\build\stage-build.yml - ..\build\stage-release-appcenter.yml = ..\build\stage-release-appcenter.yml + ..\build\stage-release-firebase.yml = ..\build\stage-release-firebase.yml ..\build\stage-release-appstore.yml = ..\build\stage-release-appstore.yml ..\build\stage-release-googleplay.yml = ..\build\stage-release-googleplay.yml ..\build\steps-build-android.yml = ..\build\steps-build-android.yml From 80e8734332a92ad62c0b9f9a5af731a626e0fbcc Mon Sep 17 00:00:00 2001 From: Kevin Takla Date: Thu, 13 Jun 2024 15:17:53 -0400 Subject: [PATCH 6/6] docs: update documentation to reference firebase instead of AppCenter --- APP_README.md | 4 ++-- CHANGELOG.md | 3 +++ build/stage-release-appstore.yml | 2 +- build/stage-release-googleplay.yml | 2 +- doc/AzurePipelines.md | 6 +++--- 5 files changed, 10 insertions(+), 7 deletions(-) diff --git a/APP_README.md b/APP_README.md index 3d45a2ece..b05f9313d 100644 --- a/APP_README.md +++ b/APP_README.md @@ -81,10 +81,10 @@ TODO: Fill the following table with your own pipelines. | Link | Code Entry Point | Goal | Triggers | |-|-|-|-| | [Name of Main Pipeline](link-to-pipeline)| [`.azure-pipelines.yml`](.azure-pipelines.yml)| Build validation during pull request.| Pull requests. -| [Name of Main Pipeline](link-to-pipeline)| [`.azure-pipelines.yml`](.azure-pipelines.yml)| Build and deploy the application to AppCenter, TestFlight, and GooglePlay. | Changes on the `main` branch.
Manual trigger. +| [Name of Main Pipeline](link-to-pipeline)| [`.azure-pipelines.yml`](.azure-pipelines.yml)| Build and deploy the application to Firebase, TestFlight, and GooglePlay. | Changes on the `main` branch.
Manual trigger. | [Name of API Integration Tests Pipeline](link-to-pipeline)| [`.azure-pipelines-api-integration-tests.yml`](.azure-pipelines.yml)| Run all tests, including APIs integration tests. | Daily cron job.
Manual trigger. | [Name of Canary Merge Pipeline](link-to-pipeline)| [`build/canary-merge.yml`](.azure-pipelines.yml)| Creation of canary branches (`canary/build/*`). | Daily cron job. -| [Name of Canary Pipeline](link-to-pipeline)| [`.azure-pipelines-canary.yml`](.azure-pipelines.yml)| Build and deploy canary versions of the app to AppCenter and TestFlight. | Upon creation of branches with the `canary/build/*` pattern. +| [Name of Canary Pipeline](link-to-pipeline)| [`.azure-pipelines-canary.yml`](.azure-pipelines.yml)| Build and deploy canary versions of the app to Firebase and TestFlight. | Upon creation of branches with the `canary/build/*` pattern. ## Additional Information diff --git a/CHANGELOG.md b/CHANGELOG.md index 2f751a069..6122f305d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,9 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/) Prefix your items with `(Template)` if the change is about the template and not the resulting application. +## 4.0.x +- Using Firebase app distribution instead of AppCenter for internal distribution. + ## 3.5.X - Bump Uno packages to 5.2.121 to fix a crash on iOS. - Ensure NV.Template.Mobile nuget is only deployed from the main branch. diff --git a/build/stage-release-appstore.yml b/build/stage-release-appstore.yml index d6c91a2bd..16348d0ac 100644 --- a/build/stage-release-appstore.yml +++ b/build/stage-release-appstore.yml @@ -1,6 +1,6 @@ parameters: applicationEnvironment: '' # e.g. "Staging", "Production" - deploymentEnvironment: '' # e.g. "GooglePlay", "AppStore", "AppCenter" + deploymentEnvironment: '' # e.g. "GooglePlay", "AppStore", "Firebase" jobs: - deployment: AppStore_iOS_${{ parameters.deploymentEnvironment}} diff --git a/build/stage-release-googleplay.yml b/build/stage-release-googleplay.yml index 2f8fd4006..38e22f255 100644 --- a/build/stage-release-googleplay.yml +++ b/build/stage-release-googleplay.yml @@ -1,6 +1,6 @@ parameters: applicationEnvironment: '' # e.g. "Staging", "Production" - deploymentEnvironment: '' # e.g. "GooglePlay", "AppStore", "AppCenter" + deploymentEnvironment: '' # e.g. "GooglePlay", "AppStore", "Firebase" jobs: - deployment: GooglePlay_Android diff --git a/doc/AzurePipelines.md b/doc/AzurePipelines.md index 356efde3a..3273c1983 100644 --- a/doc/AzurePipelines.md +++ b/doc/AzurePipelines.md @@ -18,7 +18,7 @@ These pipelines rely on a few variable groups and secrets in order to fully work At high level, the CI/CD pipelines do the following: - **Build** the app in **staging**. - - **Deploy** the staging app (to AppCenter and/or TestFlight and GooglePlay). + - **Deploy** the staging app (to Firebase and/or TestFlight and GooglePlay). - **Build** the app in **production**. - **Deploy** the production app (to TestFlight and GooglePlay). @@ -68,8 +68,8 @@ This is where the exact build steps are defined. These vary depending on the pla The release stages are even more straigtforward than the build ones. One thing to note is that, for the same reason as it is done at the end of the build steps, a clean-up step is included in every stage. -### AppCenter Release Stage ([stage-release-appcenter.yml](../build/stage-release-appcenter.yml)) -This stage is in charge of pushing the application to AppCenter. It's divided into 2 jobs, one for each platform. +### Firebase Release Stage ([stage-release-firebase.yml](../build/stage-release-firebase.yml)) +This stage is in charge of pushing the application to Firebase. It's divided into 2 jobs, one for each platform. ### Apple AppStore Release Stage ([stage-release-appstore.yml](../build/stage-release-appstore.yml)) This stage is in charge of pushing the iOS version to the Apple AppStore. Given that the build stage signs the application, this is as simple as using the proper task and pushing the **IPA** file. This should only be run for configurations that properly sign the application.