Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
92 changes: 92 additions & 0 deletions .editorconfig
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
# top-most EditorConfig file
root = true

# Default settings:
[*]
indent_style = space
trim_trailing_whitespace = true
trim_trailing_white_space_on_save = true
end_of_line = crlf

# Code files
[*.{cs,vb}]
indent_style = tab

[*.cs]
# New line preferences
csharp_new_line_before_open_brace = none
csharp_new_line_before_else = true
csharp_new_line_before_catch = true
csharp_new_line_before_finally = true
csharp_new_line_before_members_in_object_initializers = true
csharp_new_line_before_members_in_anonymous_types = true
csharp_new_line_within_query_expression_clauses = true

# Space preferences
csharp_space_after_cast = false
csharp_space_after_colon_in_inheritance_clause = true
csharp_space_after_comma = true
csharp_space_after_dot = false
csharp_space_after_keywords_in_control_flow_statements = true
csharp_space_after_semicolon_in_for_statement = true
csharp_space_around_binary_operators = before_and_after
csharp_space_around_declaration_statements = do_not_ignore
csharp_space_before_colon_in_inheritance_clause = true
csharp_space_before_comma = false
csharp_space_before_dot = false
csharp_space_before_open_square_brackets = false
csharp_space_before_semicolon_in_for_statement = false
csharp_space_between_empty_square_brackets = false
csharp_space_between_method_call_empty_parameter_list_parentheses = false
csharp_space_between_method_call_name_and_opening_parenthesis = false
csharp_space_between_method_call_parameter_list_parentheses = false
csharp_space_between_method_declaration_empty_parameter_list_parentheses = false
csharp_space_between_method_declaration_name_and_open_parenthesis = false
csharp_space_between_method_declaration_parameter_list_parentheses = false
csharp_space_between_parentheses = false
csharp_space_between_square_brackets = false

# Instance fields are camelCase and start with m_
dotnet_naming_rule.camel_case_for_private_internal_fields.severity = silent
dotnet_naming_rule.camel_case_for_private_internal_fields.symbols = private_internal_fields
dotnet_naming_rule.camel_case_for_private_internal_fields.style = camel_case_underscore_style

dotnet_naming_symbols.private_internal_fields.applicable_kinds = field
dotnet_naming_symbols.private_internal_fields.applicable_accessibilities = private, internal

dotnet_naming_style.camel_case_underscore_style.required_prefix = m_
dotnet_naming_style.camel_case_underscore_style.capitalization = camel_case

# Locals and parameters are camelCase
dotnet_naming_rule.locals_should_be_camel_case.severity = error
dotnet_naming_rule.locals_should_be_camel_case.symbols = locals_and_parameters
dotnet_naming_rule.locals_should_be_camel_case.style = camel_case_style

dotnet_naming_symbols.locals_and_parameters.applicable_kinds = parameter, local

dotnet_naming_style.camel_case_style.capitalization = camel_case

#### .NET naming conventions

# Async methods should have "Async" suffix
dotnet_naming_rule.async_methods_end_in_async.symbols = any_async_methods
dotnet_naming_rule.async_methods_end_in_async.style = end_in_async
dotnet_naming_rule.async_methods_end_in_async.severity = suggestion

dotnet_naming_symbols.any_async_methods.applicable_kinds = method
dotnet_naming_symbols.any_async_methods.applicable_accessibilities = *
dotnet_naming_symbols.any_async_methods.required_modifiers = async

dotnet_naming_style.end_in_async.required_suffix = Async
dotnet_naming_style.end_in_async.capitalization = pascal_case

# private variables should be underscored
dotnet_naming_rule.private_members_with_underscore.symbols = private_fields
dotnet_naming_rule.private_members_with_underscore.style = prefix_underscore
dotnet_naming_rule.private_members_with_underscore.severity = suggestion

dotnet_naming_symbols.private_fields.applicable_kinds = field
dotnet_naming_symbols.private_fields.applicable_accessibilities = private

dotnet_naming_style.prefix_underscore.capitalization = camel_case
dotnet_naming_style.prefix_underscore.required_prefix = _
37 changes: 37 additions & 0 deletions .github/dependabot.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
version: 2
updates:
# Keep NuGet packages updated
- package-ecosystem: "nuget"
directory: "/"
schedule:
interval: "weekly" # Check weekly (not daily - less noise)
day: "monday"
time: "09:00"
# Group related packages together in one PR
groups:
# Microsoft Extensions packages
microsoft-extensions:
patterns:
- "Microsoft.Extensions.*"
# Testing packages
testing:
patterns:
- "xunit"
- "xunit.*"
- "FluentAssertions"
- "Microsoft.NET.Test.Sdk"
- "coverlet.*"
# Build tools
build-tools:
patterns:
- "Microsoft.SourceLink.*"
- "MinVer"
# Limit open PRs (avoid spam)
open-pull-requests-limit: 5

# Keep GitHub Actions updated
- package-ecosystem: "github-actions"
directory: "/"
schedule:
interval: "monthly" # Actions don't change often
open-pull-requests-limit: 3
185 changes: 185 additions & 0 deletions .github/workflows/ci-cd.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,185 @@
name: CI/CD Pipeline

on:
push:
branches: [ develop, master ]
tags:
- 'v*'
pull_request:
branches: [ develop, master ]

env:
DOTNET_VERSION: '10.0.x'
CONFIGURATION: Release
DOTNET_NOLOGO: true
DOTNET_SKIP_FIRST_TIME_EXPERIENCE: true
MINVERBUILDMETADATA: build.${{ github.run_number }}
MINVERVERBOSITY: diagnostic

jobs:
build-and-test:
name: Build and Test
runs-on: ubuntu-latest

steps:
- name: Checkout code
uses: actions/checkout@v5
with:
fetch-depth: 0 # Full history for versioning
ref: ${{ github.ref }} # Checkout the exact ref (tag or branch)

- name: Setup .NET
uses: actions/setup-dotnet@v4
with:
dotnet-version: ${{ env.DOTNET_VERSION }}

- name: Verify Git tags for MinVer
run: |
git fetch --tags --force
git describe --tags
git tag --points-at HEAD

- name: Restore dependencies
run: dotnet restore

- name: Build library projects
run: |
dotnet build src/CountryData.Globalization/CountryData.Globalization.csproj --configuration ${{ env.CONFIGURATION }} --no-restore
dotnet build src/CountryData.Globalization.Hosting/CountryData.Globalization.Hosting.csproj --configuration ${{ env.CONFIGURATION }} --no-restore
dotnet build tests/CountryData.Globalization.Tests/CountryData.Globalization.Tests.csproj --configuration ${{ env.CONFIGURATION }} --no-restore

- name: Run tests
run: dotnet test --configuration ${{ env.CONFIGURATION }} --no-build --verbosity normal --logger "trx;LogFileName=test-results.trx"

- name: Upload test results
if: always()
uses: actions/upload-artifact@v4
with:
name: test-results
path: '**/TestResults/*.trx'

- name: Pack NuGet packages
if: github.event_name == 'push' && (github.ref == 'refs/heads/develop' || github.ref == 'refs/heads/master' || startsWith(github.ref, 'refs/tags/v'))
run: |
dotnet pack src/CountryData.Globalization/CountryData.Globalization.csproj --configuration ${{ env.CONFIGURATION }} --no-build --output ./artifacts
dotnet pack src/CountryData.Globalization.Hosting/CountryData.Globalization.Hosting.csproj --configuration ${{ env.CONFIGURATION }} --no-build --output ./artifacts

- name: Upload NuGet artifacts
if: github.event_name == 'push' && (github.ref == 'refs/heads/develop' || github.ref == 'refs/heads/master' || startsWith(github.ref, 'refs/tags/v'))
uses: actions/upload-artifact@v4
with:
name: nuget-packages
path: ./artifacts/*.nupkg

publish-develop:
name: Publish to GitHub Packages (Develop)
needs: build-and-test
if: github.event_name == 'push' && github.ref == 'refs/heads/develop'
runs-on: ubuntu-latest
permissions:
packages: write
contents: read

steps:
- name: Download NuGet artifacts
uses: actions/download-artifact@v5
with:
name: nuget-packages
path: ./artifacts

- name: Setup .NET
uses: actions/setup-dotnet@v4
with:
dotnet-version: ${{ env.DOTNET_VERSION }}

- name: Publish to GitHub Packages
run: |
dotnet nuget add source --username ${{ github.repository_owner }} \
--password ${{ secrets.GITHUB_TOKEN }} \
--store-password-in-clear-text \
--name github "https://nuget.pkg.github.com/${{ github.repository_owner }}/index.json"

dotnet nuget push "./artifacts/*.nupkg" \
--source "github" \
--api-key ${{ secrets.GITHUB_TOKEN }} \
--skip-duplicate

publish-release:
name: Publish to NuGet.org (Release)
needs: build-and-test
if: github.event_name == 'push' && startsWith(github.ref, 'refs/tags/v')
runs-on: ubuntu-latest

steps:
- name: Download NuGet artifacts
uses: actions/download-artifact@v5
with:
name: nuget-packages
path: ./artifacts

- name: Setup .NET
uses: actions/setup-dotnet@v4
with:
dotnet-version: ${{ env.DOTNET_VERSION }}

- name: Publish to NuGet.org
run: |
dotnet nuget push "./artifacts/*.nupkg" \
--source https://api.nuget.org/v3/index.json \
--api-key ${{ secrets.NUGET_API_KEY }} \
--skip-duplicate
env:
NUGET_API_KEY: ${{ secrets.NUGET_API_KEY }}

create-release:
name: Create GitHub Release
needs: publish-release
if: startsWith(github.ref, 'refs/tags/v')
runs-on: ubuntu-latest
permissions:
contents: write

steps:
- name: Checkout code
uses: actions/checkout@v5

- name: Download NuGet artifacts
uses: actions/download-artifact@v5
with:
name: nuget-packages
path: ./artifacts

- name: Extract version from tag
id: version
run: echo "VERSION=${GITHUB_REF#refs/tags/v}" >> $GITHUB_OUTPUT

- name: Create Release
uses: softprops/action-gh-release@v2
with:
name: Release ${{ steps.version.outputs.VERSION }}
body: |
## CountryData.Globalization v${{ steps.version.outputs.VERSION }}

### NuGet Packages Published

- ✅ CountryData.Globalization
- ✅ CountryData.Globalization.Hosting

### Installation

```bash
# Core package
dotnet add package CountryData.Globalization

# Hosting package (for DI support)
dotnet add package CountryData.Globalization.Hosting
```

### What's Changed

See [CHANGELOG.md](CHANGELOG.md) for detailed release notes.
files: ./artifacts/*.nupkg
draft: false
prerelease: false
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
37 changes: 37 additions & 0 deletions .github/workflows/codeql.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
name: CodeQL Security Analysis

on:
push:
branches: [ develop, master ]
pull_request:
branches: [ develop, master ]
schedule:
# Run weekly on Sundays at 4:43 AM UTC
- cron: '43 4 * * 0'

permissions:
actions: read
contents: read
security-events: write

jobs:
analyze:
name: Analyze C# Code
runs-on: ubuntu-latest

steps:
- name: Checkout repository
uses: actions/checkout@v5

- name: Initialize CodeQL
uses: github/codeql-action/init@v3
with:
languages: csharp
# Use default queries + security-extended queries
queries: security-extended

- name: Autobuild
uses: github/codeql-action/autobuild@v3

- name: Perform CodeQL Analysis
uses: github/codeql-action/analyze@v3
27 changes: 27 additions & 0 deletions Directory.Packages.props
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
<Project>
<PropertyGroup>
<ManagePackageVersionsCentrally>true</ManagePackageVersionsCentrally>
<CentralPackageTransitivePinningEnabled>true</CentralPackageTransitivePinningEnabled>
</PropertyGroup>

<!-- Build Tools -->
<ItemGroup>
<PackageVersion Include="MinVer" Version="6.0.0" />
<PackageVersion Include="Microsoft.SourceLink.GitHub" Version="8.0.0" />
</ItemGroup>

<!-- Microsoft Extensions -->
<ItemGroup>
<PackageVersion Include="Microsoft.Extensions.DependencyInjection.Abstractions" Version="9.0.0" />
</ItemGroup>

<!-- Testing Packages -->
<ItemGroup>
<PackageVersion Include="Microsoft.NET.Test.Sdk" Version="17.12.0" />
<PackageVersion Include="xunit" Version="2.9.2" />
<PackageVersion Include="xunit.runner.visualstudio" Version="2.8.2" />
<PackageVersion Include="coverlet.collector" Version="6.0.2" />
<PackageVersion Include="FluentAssertions" Version="7.0.0" />
</ItemGroup>

</Project>
File renamed without changes.
Loading
Loading