diff --git a/.gitignore b/.gitignore index 1cc79deab..13600933e 100644 --- a/.gitignore +++ b/.gitignore @@ -1,7 +1,10 @@ ## Ignore Visual Studio temporary files, build results, and ## files generated by popular Visual Studio add-ons. ## -## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore +## Get latest from `dotnet new gitignore` + +# dotenv files +.env # User-specific files *.rsuser @@ -23,6 +26,7 @@ mono_crash.* [Rr]eleases/ x64/ x86/ +[Ww][Ii][Nn]32/ [Aa][Rr][Mm]/ [Aa][Rr][Mm]64/ bld/ @@ -31,6 +35,12 @@ bld/ [Ll]og/ [Ll]ogs/ +# Npm build results +[Aa]ssets/ + +# Appdata +[Aa]pp_[Dd]ata + # Visual Studio 2015/2017 cache/options directory .vs/ # Uncomment if you have tasks that create the project's static files in wwwroot @@ -56,11 +66,17 @@ dlldata.c # Benchmark Results BenchmarkDotNet.Artifacts/ -# .NET Core +# .NET project.lock.json project.fragment.lock.json artifacts/ +# Tye +.tye/ + +# ASP.NET Scaffolding +ScaffoldingReadMe.txt + # StyleCop StyleCopReport.xml @@ -86,6 +102,7 @@ StyleCopReport.xml *.tmp_proj *_wpftmp.csproj *.log +*.tlog *.vspscc *.vssscc .builds @@ -137,6 +154,11 @@ _TeamCity* .axoCover/* !.axoCover/settings.json +# Coverlet is a free, cross platform Code Coverage Tool +coverage*.json +coverage*.xml +coverage*.info + # Visual Studio code coverage results *.coverage *.coveragexml @@ -284,6 +306,17 @@ node_modules/ # Visual Studio 6 auto-generated workspace file (contains which files were open etc.) *.vbw +# Visual Studio 6 auto-generated project file (contains which files were open etc.) +*.vbp + +# Visual Studio 6 workspace and project file (working project files containing files to include in project) +*.dsw +*.dsp + +# Visual Studio 6 technical files +*.ncb +*.aps + # Visual Studio LightSwitch build output **/*.HTMLClient/GeneratedArtifacts **/*.DesktopClient/GeneratedArtifacts @@ -340,6 +373,9 @@ ASALocalRun/ # Local History for Visual Studio .localhistory/ +# Visual Studio History (VSHistory) files +.vshistory/ + # BeatPulse healthcheck temp database healthchecksdb @@ -349,14 +385,106 @@ MigrationBackup/ # Ionide (cross platform F# VS Code tools) working folder .ionide/ -.DS_Store -Blog.db-shm -Blog.db-wal +# Fody - auto-generated XML schema +FodyWeavers.xsd + +# VS Code files for those working on multiple tools +.vscode/* +!.vscode/settings.json +!.vscode/tasks.json +!.vscode/launch.json +!.vscode/extensions.json +*.code-workspace + +# Local History for Visual Studio Code +.history/ -App_Data/ +# Windows Installer files from build outputs +*.cab +*.msi +*.msix +*.msm +*.msp -appsettings.Development.json +# JetBrains Rider +*.sln.iml +.idea + +## +## Visual studio for Mac +## -dist -package-lock.json +# globs +Makefile.in +*.userprefs +*.usertasks +config.make +config.status +aclocal.m4 +install-sh +autom4te.cache/ +*.tar.gz +tarballs/ +test-results/ + +# Mac bundle stuff +*.dmg +*.app + +# content below from: https://github.com/github/gitignore/blob/master/Global/macOS.gitignore +# General +.DS_Store +.AppleDouble +.LSOverride + +# Icon must end with two \r +Icon + + +# Thumbnails +._* + +# Files that might appear in the root of a volume +.DocumentRevisions-V100 +.fseventsd +.Spotlight-V100 +.TemporaryItems +.Trashes +.VolumeIcon.icns +.com.apple.timemachine.donotpresent + +# Directories potentially created on remote AFP share +.AppleDB +.AppleDesktop +Network Trash Folder +Temporary Items +.apdisk + +# content below from: https://github.com/github/gitignore/blob/master/Global/Windows.gitignore +# Windows thumbnail cache files +Thumbs.db +ehthumbs.db +ehthumbs_vista.db + +# Dump file +*.stackdump + +# Folder config file +[Dd]esktop.ini + +# Recycle Bin used on file shares +$RECYCLE.BIN/ + +# Windows Installer files +*.cab +*.msi +*.msix +*.msm +*.msp + +# Windows shortcuts +*.lnk + +# Vim temporary swap files +*.swp diff --git a/Blogifier.sln b/Blogifier.sln index e18df9b95..ebc3d8697 100644 --- a/Blogifier.sln +++ b/Blogifier.sln @@ -35,6 +35,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Blogifier.Themes.Standard", EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "themes", "themes", "{4155E512-4F91-48D3-823A-45B7C71125A0}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Blogifier.UI.Tests", "tests\Blogifier.UI.Tests\Blogifier.UI.Tests.csproj", "{666E5A94-758C-4432-84C6-0FF83EE30003}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -105,6 +107,18 @@ Global {7784DF02-6BCF-40A9-B327-C1F173975714}.Release|x64.Build.0 = Release|Any CPU {7784DF02-6BCF-40A9-B327-C1F173975714}.Release|x86.ActiveCfg = Release|Any CPU {7784DF02-6BCF-40A9-B327-C1F173975714}.Release|x86.Build.0 = Release|Any CPU + {666E5A94-758C-4432-84C6-0FF83EE30003}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {666E5A94-758C-4432-84C6-0FF83EE30003}.Debug|Any CPU.Build.0 = Debug|Any CPU + {666E5A94-758C-4432-84C6-0FF83EE30003}.Debug|x64.ActiveCfg = Debug|Any CPU + {666E5A94-758C-4432-84C6-0FF83EE30003}.Debug|x64.Build.0 = Debug|Any CPU + {666E5A94-758C-4432-84C6-0FF83EE30003}.Debug|x86.ActiveCfg = Debug|Any CPU + {666E5A94-758C-4432-84C6-0FF83EE30003}.Debug|x86.Build.0 = Debug|Any CPU + {666E5A94-758C-4432-84C6-0FF83EE30003}.Release|Any CPU.ActiveCfg = Release|Any CPU + {666E5A94-758C-4432-84C6-0FF83EE30003}.Release|Any CPU.Build.0 = Release|Any CPU + {666E5A94-758C-4432-84C6-0FF83EE30003}.Release|x64.ActiveCfg = Release|Any CPU + {666E5A94-758C-4432-84C6-0FF83EE30003}.Release|x64.Build.0 = Release|Any CPU + {666E5A94-758C-4432-84C6-0FF83EE30003}.Release|x86.ActiveCfg = Release|Any CPU + {666E5A94-758C-4432-84C6-0FF83EE30003}.Release|x86.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -112,6 +126,7 @@ Global GlobalSection(NestedProjects) = preSolution {27EB38D0-E275-4033-93B6-3ED6E6B7B442} = {8DDBCDEC-BFD8-4737-93BD-5259C3AE9CAE} {7784DF02-6BCF-40A9-B327-C1F173975714} = {4155E512-4F91-48D3-823A-45B7C71125A0} + {666E5A94-758C-4432-84C6-0FF83EE30003} = {8DDBCDEC-BFD8-4737-93BD-5259C3AE9CAE} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {8AA706E7-D820-4892-9F60-FCEEDC51FF5E} diff --git a/Dockerfile b/Dockerfile index 3e237e2bb..f5fd9263a 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,4 +1,4 @@ -FROM mcr.microsoft.com/dotnet/sdk:7.0-alpine as sdk +FROM mcr.microsoft.com/dotnet/sdk:9.0-alpine as sdk # TOTO zh-CH RUN sed -i 's/dl-cdn.alpinelinux.org/mirrors.aliyun.com/g' /etc/apk/repositories RUN apk add --no-cache npm @@ -7,7 +7,7 @@ COPY ./ /opt/blogifier WORKDIR /opt/blogifier RUN ["dotnet","publish", "-c", "Release","/p:RuntimeIdentifier=linux-musl-x64", "./src/Blogifier/Blogifier.csproj","-o","dist" ] -FROM mcr.microsoft.com/dotnet/aspnet:7.0-alpine as run +FROM mcr.microsoft.com/dotnet/aspnet:9.0-alpine as run # TOTO zh-CH RUN sed -i 's/dl-cdn.alpinelinux.org/mirrors.aliyun.com/g' /etc/apk/repositories RUN apk add --no-cache icu-libs diff --git a/build.sh b/build.sh index c46c071bf..fc138d04a 100644 --- a/build.sh +++ b/build.sh @@ -1,2 +1,2 @@ # dotnet clean -dotnet build -c Debug /p:RuntimeIdentifier=win-x64 ./src/Blogifier/Blogifier.csproj --output dist +dotnet build -c Debug ./src/Blogifier/Blogifier.csproj --output dist diff --git a/global.json b/global.json index d54915e8d..a02bac5a2 100644 --- a/global.json +++ b/global.json @@ -1,5 +1,6 @@ { "sdk": { - "version": "8.0.101" + "version": "9.0.200", + "rollForward": "latestFeature" } } diff --git a/src/Blogifier.Admin/Blogifier.Admin.csproj b/src/Blogifier.Admin/Blogifier.Admin.csproj index 97cc65f58..7d8c206ce 100644 --- a/src/Blogifier.Admin/Blogifier.Admin.csproj +++ b/src/Blogifier.Admin/Blogifier.Admin.csproj @@ -1,6 +1,6 @@ - net8.0 + net9.0 enable + false - - - - + + + + diff --git a/src/Blogifier.Shared/Blogifier.Shared.csproj b/src/Blogifier.Shared/Blogifier.Shared.csproj index 0677f380e..eb3035261 100644 --- a/src/Blogifier.Shared/Blogifier.Shared.csproj +++ b/src/Blogifier.Shared/Blogifier.Shared.csproj @@ -1,12 +1,12 @@ - net8.0 + net9.0 enable - + diff --git a/src/Blogifier.Themes.Standard/Blogifier.Themes.Standard.csproj b/src/Blogifier.Themes.Standard/Blogifier.Themes.Standard.csproj index fbfc7d793..d73dbf36f 100644 --- a/src/Blogifier.Themes.Standard/Blogifier.Themes.Standard.csproj +++ b/src/Blogifier.Themes.Standard/Blogifier.Themes.Standard.csproj @@ -1,13 +1,16 @@ - net8.0 + net9.0 enable enable true assets\ npm i npm run build:$(Configuration) + + false diff --git a/src/Blogifier/Blogifier.csproj b/src/Blogifier/Blogifier.csproj index 4dfc1eb3e..3f5ef4272 100644 --- a/src/Blogifier/Blogifier.csproj +++ b/src/Blogifier/Blogifier.csproj @@ -1,7 +1,7 @@ - net8.0 + net9.0 enable false true @@ -12,26 +12,26 @@ - - - - - - + + + + + + all runtime; build; native; contentfiles; analyzers; buildtransitive - - - - + + + + - - + + - + - + @@ -41,4 +41,8 @@ + + + + diff --git a/src/Blogifier/Data/AppDbContextExtensions.cs b/src/Blogifier/Data/AppDbContextExtensions.cs index 5fe105000..74fcf802e 100644 --- a/src/Blogifier/Data/AppDbContextExtensions.cs +++ b/src/Blogifier/Data/AppDbContextExtensions.cs @@ -9,6 +9,7 @@ using System.IO; using System.Linq; using System.Threading.Tasks; +using Microsoft.EntityFrameworkCore.Diagnostics; namespace Blogifier.Data; @@ -27,20 +28,45 @@ public static IServiceCollection AddDbContext(this IServiceCollection services, var dataSourcePath = Path.Combine(environment.ContentRootPath, sonnectionStringBuilder.DataSource); var dataSourceDirectory = Path.GetDirectoryName(dataSourcePath); if (!string.IsNullOrEmpty(dataSourceDirectory) && !Directory.Exists(dataSourceDirectory)) Directory.CreateDirectory(dataSourceDirectory); - services.AddDbContext(o => o.UseSqlite(sonnectionStringBuilder.ToString())); + services.AddDbContext(o => + { + o.UseSqlite(sonnectionStringBuilder.ToString()); + o.ConfigureWarnings(w => + w.Ignore(RelationalEventId.NonTransactionalMigrationOperationWarning)); + o.ConfigureWarnings(w => w.Ignore(RelationalEventId.PendingModelChangesWarning)); + }); } else if ("SqlServer".Equals(provider, StringComparison.OrdinalIgnoreCase)) { - services.AddDbContext(o => o.UseSqlServer(connectionString)); + services.AddDbContext(o => + { + o.UseSqlServer(connectionString); + o.ConfigureWarnings(w => + w.Ignore(RelationalEventId.NonTransactionalMigrationOperationWarning)); + o.ConfigureWarnings(w => w.Ignore(RelationalEventId.PendingModelChangesWarning)); + + }); } else if ("MySql".Equals(provider, StringComparison.OrdinalIgnoreCase)) { var version = ServerVersion.AutoDetect(connectionString); - services.AddDbContext(o => o.UseMySql(connectionString, version)); + services.AddDbContext(o => + { + o.UseMySql(connectionString, version); + o.ConfigureWarnings(w => + w.Ignore(RelationalEventId.NonTransactionalMigrationOperationWarning)); + o.ConfigureWarnings(w => w.Ignore(RelationalEventId.PendingModelChangesWarning)); + }); } else if ("Postgres".Equals(provider, StringComparison.OrdinalIgnoreCase)) { - services.AddDbContext(o => o.UseNpgsql(connectionString)); + services.AddDbContext(o => + { + o.UseNpgsql(connectionString); + o.ConfigureWarnings(w => + w.Ignore(RelationalEventId.NonTransactionalMigrationOperationWarning)); + o.ConfigureWarnings(w => w.Ignore(RelationalEventId.PendingModelChangesWarning)); + }); } else { diff --git a/tests/Blogifier.Tests/Blogifier.Tests.csproj b/tests/Blogifier.Tests/Blogifier.Tests.csproj index f9fa3a620..b529b23e3 100644 --- a/tests/Blogifier.Tests/Blogifier.Tests.csproj +++ b/tests/Blogifier.Tests/Blogifier.Tests.csproj @@ -1,18 +1,18 @@ - net8.0 + net9.0 - - - - + + + + runtime; build; native; contentfiles; analyzers; buildtransitive all - + runtime; build; native; contentfiles; analyzers; buildtransitive all diff --git a/tests/Blogifier.UI.Tests/Blogifier.UI.Tests.csproj b/tests/Blogifier.UI.Tests/Blogifier.UI.Tests.csproj new file mode 100644 index 000000000..1bac18434 --- /dev/null +++ b/tests/Blogifier.UI.Tests/Blogifier.UI.Tests.csproj @@ -0,0 +1,28 @@ + + + + net8.0 + enable + enable + + false + true + + + + + + + + + + + + + + + + + + + diff --git a/tests/Blogifier.UI.Tests/UnitTest1.cs b/tests/Blogifier.UI.Tests/UnitTest1.cs new file mode 100644 index 000000000..6cf2a7d59 --- /dev/null +++ b/tests/Blogifier.UI.Tests/UnitTest1.cs @@ -0,0 +1,27 @@ +namespace Blogifier.UI.Tests; + +[Parallelizable(ParallelScope.Self)] +[TestFixture] +public class Tests : PageTest +{ + [Test] + public async Task HomepageHasPlaywrightInTitleAndGetStartedLinkLinkingtoTheIntroPage() + { + await Page.GotoAsync("https://playwright.dev"); + + // Expect a title "to contain" a substring. + await Expect(Page).ToHaveTitleAsync(new Regex("Playwright")); + + // create a locator + var getStarted = Page.Locator("text=Get Started"); + + // Expect an attribute "to be strictly equal" to the value. + await Expect(getStarted).ToHaveAttributeAsync("href", "/docs/intro"); + + // Click the get started link. + await getStarted.ClickAsync(); + + // Expects the URL to contain intro. + await Expect(Page).ToHaveURLAsync(new Regex(".*intro")); + } +}