diff --git a/.docfx/Dockerfile.docfx b/.docfx/Dockerfile.docfx index 3897848..0e78ce5 100644 --- a/.docfx/Dockerfile.docfx +++ b/.docfx/Dockerfile.docfx @@ -1,4 +1,4 @@ -FROM nginx:1.27.1-alpine AS base +FROM nginx:1.27.3-alpine AS base RUN rm -rf /usr/share/nginx/html/* FROM codebeltnet/docfx:2.77.0 AS build diff --git a/.docfx/docfx.json b/.docfx/docfx.json index a3d34f5..1fce029 100644 --- a/.docfx/docfx.json +++ b/.docfx/docfx.json @@ -12,7 +12,7 @@ "dest": "api", "filter": "filterConfig.yml", "properties": { - "TargetFramework": "net8.0" + "TargetFramework": "net9.0" } } ], @@ -45,7 +45,7 @@ ], "globalMetadata": { "_appTitle": "Extensions for Globalization by Codebelt", - "_appFooter": "Generated by DocFX. Copyright 2024 ClassLibrary1. All rights reserved.", + "_appFooter": "Generated by DocFX. Copyright 2024-2025 Geekle. All rights reserved.", "_appLogoPath": "images/50x50.png", "_appFaviconPath": "images/favicon.ico", "_googleAnalyticsTagId": "G-R07CSX4Z91", diff --git a/.github/workflows/pipelines.yml b/.github/workflows/pipelines.yml index 37bebd6..70e34f8 100644 --- a/.github/workflows/pipelines.yml +++ b/.github/workflows/pipelines.yml @@ -26,7 +26,7 @@ jobs: strategy: matrix: configuration: [Debug, Release] - framework: [net8.0,net6.0,netstandard2.0] + framework: [net9.0,net8.0,netstandard2.0] outputs: version: ${{ steps.minver-calculate.outputs.version }} steps: diff --git a/.github/workflows/scorecard.yml b/.github/workflows/scorecard.yml new file mode 100644 index 0000000..aabea97 --- /dev/null +++ b/.github/workflows/scorecard.yml @@ -0,0 +1,42 @@ +name: Scorecard supply-chain security +on: + branch_protection_rule: + schedule: + - cron: '45 17 * * 2' + push: + branches: [ "main" ] + +permissions: read-all + +jobs: + analysis: + name: Scorecard analysis + runs-on: ubuntu-latest + permissions: + security-events: write + id-token: write + + steps: + - name: "Checkout code" + uses: actions/checkout@v4 + with: + persist-credentials: false + + - name: "Run analysis" + uses: ossf/scorecard-action@v2.4.0 + with: + results_file: results.sarif + results_format: sarif + publish_results: true + + - name: "Upload artifact" + uses: actions/upload-artifact@v4 + with: + name: SARIF file + path: results.sarif + retention-days: 5 + + - name: "Upload to code-scanning" + uses: github/codeql-action/upload-sarif@v3 + with: + sarif_file: results.sarif diff --git a/.nuget/Codebelt.Extensions.Globalization/PackageReleaseNotes.txt b/.nuget/Codebelt.Extensions.Globalization/PackageReleaseNotes.txt index cfcf325..bdb5d66 100644 --- a/.nuget/Codebelt.Extensions.Globalization/PackageReleaseNotes.txt +++ b/.nuget/Codebelt.Extensions.Globalization/PackageReleaseNotes.txt @@ -1,4 +1,11 @@ -Version 8.4.0 +Version 9.0.1 +Availability: .NET 9, .NET 8 and .NET Standard 2.0 +  +# ALM +- CHANGED Dependencies to latest and greatest with respect to TFMs +- REMOVED Support for TFM .NET 6 (LTS) +  +Version 8.4.0 Availability: .NET 8, .NET 6 and .NET Standard 2.0   # ALM diff --git a/CHANGELOG.md b/CHANGELOG.md index 9e84b36..1f59665 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,13 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), For more details, please refer to `PackageReleaseNotes.txt` on a per assembly basis in the `.nuget` folder. +> [!NOTE] +> Changelog entries prior to version 9.0.1 was migrated from previous versions of Cuemon.Extensions.Globalization. + +## [9.0.1] - 2025-01-29 + +This is a service update that primarily focuses on package dependencies and minor improvements. + ## [8.4.0] - 2024-09-28 ### Changed diff --git a/Directory.Build.props b/Directory.Build.props index f8a4bde..17dc0f7 100644 --- a/Directory.Build.props +++ b/Directory.Build.props @@ -15,8 +15,8 @@ - net8.0;net6.0;netstandard2.0 - Copyright © Geekle 2024. All rights reserved. + net9.0;net8.0;netstandard2.0 + Copyright © Geekle 2025. All rights reserved. gimlichael Geekle Extensions for Globalization API by Codebelt @@ -35,6 +35,7 @@ true $(MSBuildThisFileDirectory)globalization.snk 7035,CA2260 + v @@ -42,18 +43,17 @@ - - + - net8.0;net6.0 + net9.0;net8.0 - net8.0;net6.0;net48 + net9.0;net8.0;net48 @@ -69,19 +69,19 @@ - - - - - + + + + + all runtime; build; native; contentfiles; analyzers; buildtransitive - + all runtime; build; native; contentfiles; analyzers; buildtransitive - + diff --git a/Directory.Build.targets b/Directory.Build.targets index bf44e11..05374a0 100644 --- a/Directory.Build.targets +++ b/Directory.Build.targets @@ -14,8 +14,8 @@ - 00000 - $(MinVerMajor).$(MinVerMinor).$(MinVerPatch).$(BUILD_BUILDNUMBER) + 0 + $(MinVerMajor).$(MinVerMinor).$(MinVerPatch).$(GITHUB_RUN_NUMBER) diff --git a/Directory.Packages.props b/Directory.Packages.props new file mode 100644 index 0000000..f1b9a41 --- /dev/null +++ b/Directory.Packages.props @@ -0,0 +1,16 @@ + + + true + + + + + + + + + + + + + \ No newline at end of file diff --git a/LICENSE b/LICENSE index d188e75..fd45efc 100644 --- a/LICENSE +++ b/LICENSE @@ -1,6 +1,6 @@ MIT License -Copyright (c) 2024 Geekle +Copyright (c) 2024-2025 Geekle Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/src/Codebelt.Extensions.Globalization/Codebelt.Extensions.Globalization.csproj b/src/Codebelt.Extensions.Globalization/Codebelt.Extensions.Globalization.csproj index 204afd7..fe2cd92 100644 --- a/src/Codebelt.Extensions.Globalization/Codebelt.Extensions.Globalization.csproj +++ b/src/Codebelt.Extensions.Globalization/Codebelt.Extensions.Globalization.csproj @@ -1200,8 +1200,7 @@ - - + diff --git a/test/Codebelt.Extensions.Globalization.Tests/YamlSerializerTest.cs b/test/Codebelt.Extensions.Globalization.Tests/YamlSerializerTest.cs new file mode 100644 index 0000000..ab77a2c --- /dev/null +++ b/test/Codebelt.Extensions.Globalization.Tests/YamlSerializerTest.cs @@ -0,0 +1,441 @@ +using System; +using System.Globalization; +using System.Linq; +using System.Runtime.InteropServices; +using Codebelt.Extensions.Xunit; +using Codebelt.Extensions.YamlDotNet; +using Codebelt.Extensions.YamlDotNet.Formatters; +using Cuemon; +using Cuemon.Extensions.IO; +using Xunit; +using Xunit.Abstractions; +using YamlDotNet.Core; +using YamlDotNet.Serialization.NamingConventions; + +namespace Codebelt.Extensions.Globalization +{ + public class YamlSerializerTest : Test + { + private static readonly CultureInfo DanishCulture = new CultureInfo("da-DK").UseNationalLanguageSupport(); // from .NET6+ this is needed for both Windows and Linux; at least from pipeline (worked locally for Windows without Merge ...) + + public YamlSerializerTest(ITestOutputHelper output) : base(output) + { + } + + [Fact] + public void Serialize_ShouldSerializeDateFormatInfo() + { + var sut2 = DanishCulture; + var sut3 = YamlFormatter.SerializeObject(sut2.DateTimeFormat, o => + { + o.Settings.NamingConvention = PascalCaseNamingConvention.Instance; + o.Settings.ScalarStyle = ScalarStyle.Plain; + o.Settings.IndentSequences = false; + o.Settings.FormatProvider = DanishCulture; + o.Settings.Converters.Add(YamlConverterFactory.Create((writer, dt, _) => writer.WriteValue(dt.ToString(DanishCulture)))); + }); + var sut4 = sut3.ToEncodedString(); + + TestOutput.WriteLine(sut4); + + var expected = @"AMDesignator: '' +Calendar: + MinSupportedDateTime: 01-01-0001 00:00:00 + MaxSupportedDateTime: 31-12-9999 23:59:59 + AlgorithmType: SolarCalendar + CalendarType: Localized + Eras: + - 1 + TwoDigitYearMax: {0} +DateSeparator: '-' +FirstDayOfWeek: Monday +CalendarWeekRule: FirstFourDayWeek +FullDateTimePattern: d. MMMM yyyy HH:mm:ss +LongDatePattern: d. MMMM yyyy +LongTimePattern: HH:mm:ss +MonthDayPattern: d. MMMM +PMDesignator: '' +RFC1123Pattern: ddd, dd MMM yyyy HH':'mm':'ss 'GMT' +ShortDatePattern: dd-MM-yyyy +ShortTimePattern: HH:mm +SortableDateTimePattern: yyyy'-'MM'-'dd'T'HH':'mm':'ss +TimeSeparator: ':' +UniversalSortableDateTimePattern: yyyy'-'MM'-'dd HH':'mm':'ss'Z' +YearMonthPattern: MMMM yyyy +AbbreviatedDayNames: +- sø +- ma +- ti +- on +- to +- fr +- lø +ShortestDayNames: +- sø +- ma +- ti +- on +- to +- fr +- lø +DayNames: +- søndag +- mandag +- tirsdag +- onsdag +- torsdag +- fredag +- lørdag +AbbreviatedMonthNames: +- jan +- feb +- mar +- apr +- maj +- jun +- jul +- aug +- sep +- okt +- nov +- dec +- '' +MonthNames: +- januar +- februar +- marts +- april +- maj +- juni +- juli +- august +- september +- oktober +- november +- december +- '' +NativeCalendarName: gregoriansk kalender +AbbreviatedMonthGenitiveNames: +- jan +- feb +- mar +- apr +- maj +- jun +- jul +- aug +- sep +- okt +- nov +- dec +- '' +MonthGenitiveNames: +- januar +- februar +- marts +- april +- maj +- juni +- juli +- august +- september +- oktober +- november +- december +- '' +".ReplaceLineEndings(); + +#if NET8_0_OR_GREATER + expected = string.Format(expected, "2049"); +#elif NET48_OR_GREATER + if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux)) + { + expected = StringReplacePair.ReplaceAll(expected, "gregoriansk kalender", "dansk (Danmark)", StringComparison.Ordinal); + expected = string.Format(expected, "2029"); + } + else + { + expected = StringReplacePair.ReplaceAll(expected, "gregoriansk", "Gregoriansk", StringComparison.Ordinal); + expected = string.Format(expected, "2049"); + } +#endif + + Assert.Equal(expected, sut4); + } + + [Fact] + public void Serialize_ShouldSerializeNumberFormatInfo() + { + var sut2 = DanishCulture; + var sut3 = YamlFormatter.SerializeObject(sut2.NumberFormat, o => + { + o.Settings.ScalarStyle = ScalarStyle.DoubleQuoted; + o.Settings.IndentSequences = false; + o.Settings.FormatProvider = DanishCulture; + o.Settings.NamingConvention = PascalCaseNamingConvention.Instance; + }); + var sut4 = sut3.ToEncodedString(); + + TestOutput.WriteLine(sut4); + + Assert.Equal(@"CurrencyDecimalDigits: 2 +CurrencyDecimalSeparator: "","" +CurrencyGroupSizes: +- 3 +NumberGroupSizes: +- 3 +PercentGroupSizes: +- 3 +CurrencyGroupSeparator: ""."" +CurrencySymbol: ""kr."" +NaNSymbol: ""NaN"" +CurrencyNegativePattern: 8 +NumberNegativePattern: 1 +PercentPositivePattern: 0 +PercentNegativePattern: 0 +NegativeInfinitySymbol: ""-∞"" +NegativeSign: ""-"" +NumberDecimalDigits: 2 +NumberDecimalSeparator: "","" +NumberGroupSeparator: ""."" +CurrencyPositivePattern: 3 +PositiveInfinitySymbol: ""∞"" +PositiveSign: ""+"" +PercentDecimalDigits: 2 +PercentDecimalSeparator: "","" +PercentGroupSeparator: ""."" +PercentSymbol: ""%"" +PerMilleSymbol: ""‰"" +NativeDigits: +- ""0"" +- ""1"" +- ""2"" +- ""3"" +- ""4"" +- ""5"" +- ""6"" +- ""7"" +- ""8"" +- ""9"" +DigitSubstitution: ""None"" +".ReplaceLineEndings(), sut4); + } + + + [Fact] + public void Serialize_ShouldSerializeCultureInfo() + { + var sut2 = DanishCulture; + var sut3 = YamlFormatter.SerializeObject(sut2, o => + { + o.Settings.IndentSequences = false; + o.Settings.NamingConvention = PascalCaseNamingConvention.Instance; + o.Settings.Converters.Add(YamlConverterFactory.Create((writer, dt, _) => writer.WriteValue(dt.ToString(DanishCulture)))); + }); + var sut4 = sut3.ToEncodedString().ReplaceLineEndings().Split(new[] { Environment.NewLine }, StringSplitOptions.None).ToList(); + + sut4.RemoveRange(sut4.FindIndex(s => s.StartsWith("CompareInfo")), 6); + sut4.RemoveRange(sut4.FindIndex(s => s.StartsWith("CultureTypes")), 1); + + var expected = @"LCID: 1030 +KeyboardLayoutId: 1030 +Name: da-DK +IetfLanguageTag: da-DK +DisplayName: Danish (Denmark) +NativeName: dansk (Danmark) +EnglishName: Danish (Denmark) +TwoLetterISOLanguageName: da +ThreeLetterISOLanguageName: dan +ThreeLetterWindowsLanguageName: DAN +TextInfo: + ANSICodePage: 1252 + OEMCodePage: 850 + MacCodePage: 10000 + EBCDICCodePage: 20277 + LCID: 1030 + CultureName: da-DK + ListSeparator: ; + IsRightToLeft: false +IsNeutralCulture: false +NumberFormat: + CurrencyDecimalDigits: 2 + CurrencyDecimalSeparator: ',' + CurrencyGroupSizes: + - 3 + NumberGroupSizes: + - 3 + PercentGroupSizes: + - 3 + CurrencyGroupSeparator: . + CurrencySymbol: kr. + NaNSymbol: NaN + CurrencyNegativePattern: 8 + NumberNegativePattern: 1 + PercentPositivePattern: 0 + PercentNegativePattern: 0 + NegativeInfinitySymbol: -∞ + NegativeSign: '-' + NumberDecimalDigits: 2 + NumberDecimalSeparator: ',' + NumberGroupSeparator: . + CurrencyPositivePattern: 3 + PositiveInfinitySymbol: ∞ + PositiveSign: + + PercentDecimalDigits: 2 + PercentDecimalSeparator: ',' + PercentGroupSeparator: . + PercentSymbol: '%' + PerMilleSymbol: ‰ + NativeDigits: + - 0 + - 1 + - 2 + - 3 + - 4 + - 5 + - 6 + - 7 + - 8 + - 9 + DigitSubstitution: None +DateTimeFormat: + AMDesignator: '' + Calendar: + MinSupportedDateTime: 01-01-0001 00:00:00 + MaxSupportedDateTime: 31-12-9999 23:59:59 + AlgorithmType: SolarCalendar + CalendarType: Localized + Eras: + - 1 + TwoDigitYearMax: {0} + DateSeparator: '-' + FirstDayOfWeek: Monday + CalendarWeekRule: FirstFourDayWeek + FullDateTimePattern: d. MMMM yyyy HH:mm:ss + LongDatePattern: d. MMMM yyyy + LongTimePattern: HH:mm:ss + MonthDayPattern: d. MMMM + PMDesignator: '' + RFC1123Pattern: ddd, dd MMM yyyy HH':'mm':'ss 'GMT' + ShortDatePattern: dd-MM-yyyy + ShortTimePattern: HH:mm + SortableDateTimePattern: yyyy'-'MM'-'dd'T'HH':'mm':'ss + TimeSeparator: ':' + UniversalSortableDateTimePattern: yyyy'-'MM'-'dd HH':'mm':'ss'Z' + YearMonthPattern: MMMM yyyy + AbbreviatedDayNames: + - sø + - ma + - ti + - on + - to + - fr + - lø + ShortestDayNames: + - sø + - ma + - ti + - on + - to + - fr + - lø + DayNames: + - søndag + - mandag + - tirsdag + - onsdag + - torsdag + - fredag + - lørdag + AbbreviatedMonthNames: + - jan + - feb + - mar + - apr + - maj + - jun + - jul + - aug + - sep + - okt + - nov + - dec + - '' + MonthNames: + - januar + - februar + - marts + - april + - maj + - juni + - juli + - august + - september + - oktober + - november + - december + - '' + NativeCalendarName: gregoriansk kalender + AbbreviatedMonthGenitiveNames: + - jan + - feb + - mar + - apr + - maj + - jun + - jul + - aug + - sep + - okt + - nov + - dec + - '' + MonthGenitiveNames: + - januar + - februar + - marts + - april + - maj + - juni + - juli + - august + - september + - oktober + - november + - december + - '' +Calendar: + MinSupportedDateTime: 01-01-0001 00:00:00 + MaxSupportedDateTime: 31-12-9999 23:59:59 + AlgorithmType: SolarCalendar + CalendarType: Localized + Eras: + - 1 + TwoDigitYearMax: {0} +OptionalCalendars: +- MinSupportedDateTime: 01-01-0001 00:00:00 + MaxSupportedDateTime: 31-12-9999 23:59:59 + AlgorithmType: SolarCalendar + CalendarType: Localized + Eras: + - 1 + TwoDigitYearMax: {0} +UseUserOverride: true +"; + +#if NET8_0_OR_GREATER || NET48_OR_GREATER + expected = string.Format(expected, "2049"); +#else + expected = string.Format(expected, "2029"); +#endif + +#if NET48_OR_GREATER + expected = StringReplacePair.ReplaceAll(expected, "gregoriansk", "Gregoriansk", StringComparison.Ordinal); +#endif + + TestOutput.WriteLines(sut4); + + Assert.Equal(expected.ReplaceLineEndings().Split(new[] { Environment.NewLine }, StringSplitOptions.None).ToList(), sut4); + } + } +} diff --git a/testenvironments.json b/testenvironments.json index 046978a..e296d68 100644 --- a/testenvironments.json +++ b/testenvironments.json @@ -9,7 +9,7 @@ { "name": "Docker-Ubuntu", "type": "docker", - "dockerImage": "gimlichael/ubuntu-testrunner:net6.0.424-net8.0.303" + "dockerImage": "gimlichael/ubuntu-testrunner:net8.0.405-9.0.102" } ] } diff --git a/tooling/gse/gse.csproj b/tooling/gse/gse.csproj index c4734f3..2ff16da 100644 --- a/tooling/gse/gse.csproj +++ b/tooling/gse/gse.csproj @@ -19,7 +19,7 @@ - +