Skip to content

Commit 9a9f947

Browse files
authored
Merge pull request #224 from Vulthil/chore/prepare-public-nuget-release
chore: prepare first public NuGet.org release (v1.0.0)
2 parents dee7d58 + 931fd75 commit 9a9f947

8 files changed

Lines changed: 159 additions & 38 deletions

File tree

.github/workflows/claude.yml

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -40,8 +40,9 @@ jobs:
4040
additional_permissions: |
4141
actions: read
4242
43-
# Optional: Give a custom prompt to Claude. If this is not specified, Claude will perform the instructions specified in the comment that tagged it.
44-
prompt: 'Update the pull request description to include a summary of changes.'
43+
# No prompt is set on purpose: Claude follows the instructions in the
44+
# comment, review, or issue that tagged it (e.g. "@claude fix the build").
45+
# Set `prompt:` only if you want every trigger to run one fixed instruction.
4546

4647
# Optional: Add claude_args to customize behavior and configuration
4748
# See https://github.com/anthropics/claude-code-action/blob/main/docs/usage.md

.github/workflows/codeql.yml

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
name: CodeQL
2+
3+
on:
4+
workflow_dispatch:
5+
push:
6+
branches: [main]
7+
pull_request:
8+
branches: [main]
9+
schedule:
10+
- cron: '32 4 * * 1' # weekly, Monday 04:32 UTC
11+
12+
concurrency:
13+
group: codeql-${{ github.ref }}
14+
cancel-in-progress: true
15+
16+
jobs:
17+
analyze:
18+
name: Analyze (${{ matrix.language }})
19+
runs-on: ubuntu-latest
20+
permissions:
21+
security-events: write
22+
packages: read
23+
contents: read
24+
strategy:
25+
fail-fast: false
26+
matrix:
27+
include:
28+
# build-mode: none uses CodeQL's buildless C# analysis, so the Aspire
29+
# workload and a full restore/build aren't needed just to scan.
30+
- language: csharp
31+
build-mode: none
32+
33+
steps:
34+
- name: Checkout repository
35+
uses: actions/checkout@v6
36+
37+
- name: Initialize CodeQL
38+
uses: github/codeql-action/init@v3
39+
with:
40+
languages: ${{ matrix.language }}
41+
build-mode: ${{ matrix.build-mode }}
42+
43+
- name: Perform CodeQL Analysis
44+
uses: github/codeql-action/analyze@v3
45+
with:
46+
category: "/language:${{ matrix.language }}"

.github/workflows/dependabot-approve-and-automerge.yml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,12 +15,17 @@ jobs:
1515
uses: dependabot/fetch-metadata@v3.1.0
1616
with:
1717
github-token: "${{ secrets.GITHUB_TOKEN }}"
18+
# Only auto-approve/merge patch and minor updates. A major bump can carry
19+
# breaking changes that still compile and pass tests, then ship to consumers
20+
# unnoticed -- leave majors for a human to review and merge.
1821
- name: Approve a PR
22+
if: steps.metadata.outputs.update-type == 'version-update:semver-patch' || steps.metadata.outputs.update-type == 'version-update:semver-minor'
1923
run: gh pr review --approve "$PR_URL"
2024
env:
2125
PR_URL: ${{github.event.pull_request.html_url}}
2226
GITHUB_TOKEN: ${{secrets.GITHUB_TOKEN}}
2327
- name: Enable auto-merge for Dependabot PRs
28+
if: steps.metadata.outputs.update-type == 'version-update:semver-patch' || steps.metadata.outputs.update-type == 'version-update:semver-minor'
2429
run: gh pr merge --auto --merge "$PR_URL"
2530
env:
2631
PR_URL: ${{github.event.pull_request.html_url}}

.github/workflows/release.yml

Lines changed: 23 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -7,12 +7,18 @@ env:
77
DOTNET_SKIP_FIRST_TIME_EXPERIENCE: 1
88
DOTNET_NOLOGO: true
99

10+
# Serialize releases so two manual dispatches can't publish the same version twice.
11+
concurrency:
12+
group: release
13+
cancel-in-progress: false
14+
1015
jobs:
1116
release:
1217
runs-on: ubuntu-latest
1318
permissions:
1419
contents: write
1520
packages: write
21+
id-token: write # required for NuGet.org trusted publishing (OIDC)
1622
outputs:
1723
version: ${{ steps.version.outputs.version }}
1824
steps:
@@ -75,13 +81,23 @@ jobs:
7581
--source https://nuget.pkg.github.com/${{ github.repository_owner }}/index.json \
7682
--skip-duplicate
7783
78-
# Uncomment when ready to publish to NuGet.org (requires NUGET_API_KEY secret)
79-
# - name: Publish to NuGet.org
80-
# run: >
81-
# dotnet nuget push "./artifacts/*.nupkg"
82-
# -k ${{ secrets.NUGET_API_KEY }}
83-
# -s https://api.nuget.org/v3/index.json
84-
# --skip-duplicate
84+
# Publish to NuGet.org via Trusted Publishing (OIDC) -- no long-lived API
85+
# key is stored in GitHub. One-time setup on NuGet.org: create a trusted
86+
# publisher policy for this repo + the Release workflow, then set the
87+
# NUGET_USER secret to the owning NuGet.org account/organization name.
88+
# https://learn.microsoft.com/nuget/nuget-org/trusted-publishing
89+
- name: NuGet login (trusted publishing)
90+
id: nuget-login
91+
uses: NuGet/login@v1
92+
with:
93+
user: ${{ secrets.NUGET_USER }}
94+
95+
- name: Publish to NuGet.org
96+
run: >
97+
dotnet nuget push "./artifacts/*.nupkg"
98+
--api-key ${{ steps.nuget-login.outputs.NUGET_API_KEY }}
99+
--source https://api.nuget.org/v3/index.json
100+
--skip-duplicate
85101
86102
# Publish the released version as the default (stable) documentation. Reuses
87103
# docs.yml so the gh-pages layout and version manifest stay in one place.

.github/workflows/version-bump.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ on:
1111
options:
1212
- major
1313
- minor
14+
- patch
1415

1516
jobs:
1617
bump:

README.md

Lines changed: 48 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -28,19 +28,56 @@ infrastructure — so you can adopt only what you need.
2828

2929
## Packages
3030

31+
Adopt only what you need — every package is independently versioned and focused on a single concern.
32+
33+
**Core**
34+
35+
| Package | Description |
36+
|---|---|
37+
| **Vulthil.Results** | Result primitives for explicit success/failure flows without exceptions. |
38+
| **Vulthil.SharedKernel** | Domain primitives — aggregate roots, entities, domain events, and domain exceptions. |
39+
40+
**Application & API**
41+
42+
| Package | Description |
43+
|---|---|
44+
| **Vulthil.SharedKernel.Application** | CQRS handlers, pipeline behaviors, and FluentValidation integration. |
45+
| **Vulthil.SharedKernel.Api** | Minimal-API endpoint helpers and `Result`-to-HTTP conversion. |
46+
47+
**Persistence & Outbox**
48+
49+
| Package | Description |
50+
|---|---|
51+
| **Vulthil.SharedKernel.Outbox** | Transactional domain-event outbox engine; persistence-agnostic. |
52+
| **Vulthil.SharedKernel.Outbox.EntityFrameworkCore** | EF Core implementation of the domain-event outbox. |
53+
| **Vulthil.SharedKernel.Infrastructure** | EF Core persistence, transactions, and outbox wiring. |
54+
| **Vulthil.SharedKernel.Infrastructure.Relational** | Shared relational helpers for the provider packages. |
55+
| **Vulthil.SharedKernel.Infrastructure.Npgsql** | PostgreSQL/Npgsql EF Core mappings and optimizations. |
56+
| **Vulthil.SharedKernel.Infrastructure.MySql** | MySQL EF Core mappings and optimizations. |
57+
| **Vulthil.SharedKernel.Infrastructure.Cosmos** | Azure Cosmos DB EF Core mappings and optimizations. |
58+
59+
**Messaging**
60+
61+
| Package | Description |
62+
|---|---|
63+
| **Vulthil.Messaging.Abstractions** | Contracts for producers, consumers, and request/reply boundaries. |
64+
| **Vulthil.Messaging** | Composition APIs for consumers, queues, and hosted processing. |
65+
| **Vulthil.Messaging.RabbitMq** | RabbitMQ transport for the messaging abstractions. |
66+
| **Vulthil.Messaging.Outbox** | Transactional bus-publish outbox that eliminates the dual-write problem. |
67+
| **Vulthil.Messaging.Inbox** | Idempotent-receiver (inbox) consume filter for exactly-once processing. |
68+
| **Vulthil.Messaging.Inbox.EntityFrameworkCore** | Shared EF Core primitives for the inbox idempotency store. |
69+
| **Vulthil.Messaging.Inbox.Relational** | Relational EF Core idempotency store (transactional exactly-once). |
70+
| **Vulthil.Messaging.Inbox.Cosmos** | Azure Cosmos DB idempotency store (effectively-once). |
71+
| **Vulthil.Messaging.TestHarness** | In-memory harness for asserting messaging flows in tests. |
72+
73+
**Hosting & Testing**
74+
3175
| Package | Description |
3276
|---|---|
33-
| **Vulthil.Results** | Small result primitives for explicit success/failure flows without exceptions. |
34-
| **Vulthil.SharedKernel** | Core domain primitives and base abstractions for shared domain logic. |
35-
| **Vulthil.SharedKernel.Application** | Application-layer building blocks such as handlers, pipelines, and validation helpers. |
36-
| **Vulthil.SharedKernel.Infrastructure** | Infrastructure helpers for persistence, transactions, outbox, and EF Core integration. |
37-
| **Vulthil.SharedKernel.Api** | API-layer helpers for endpoints, controllers, and cross-cutting HTTP concerns. |
38-
| **Vulthil.Messaging.Abstractions** | Messaging contracts for producers/consumers and request/reply boundaries. |
39-
| **Vulthil.Messaging** | Messaging composition APIs for configuring consumers, queues, and hosted processing. |
40-
| **Vulthil.Messaging.RabbitMq** | RabbitMQ implementation for the Vulthil messaging abstractions. |
41-
| **Vulthil.Messaging.TestHarness** | Test utilities for validating messaging flows in integration and component tests. |
42-
| **Vulthil.Extensions.Testing** | Testing-oriented extensions for asserting and composing application behaviors. |
43-
| **Vulthil.xUnit** | Reusable xUnit base infrastructure for integration and unit test composition. |
77+
| **Vulthil.Extensions.Hosting** | Hosting abstractions, including `IRestartableHostedService`. |
78+
| **Vulthil.Extensions.Testing** | Testing helpers such as polling utilities for eventual consistency. |
79+
| **Vulthil.xUnit** | xUnit base classes with Testcontainers, Respawn, and AutoMocker. |
80+
| **Vulthil.xUnit.Cosmos** | Cosmos DB emulator fixture for xUnit integration tests. |
4481

4582
## Documentation
4683

eng/bump_version.py

Lines changed: 32 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,36 +1,52 @@
11
#!/usr/bin/env python3
2-
"""Bumps the Major.Minor base version in version.json without committing.
2+
"""Bumps the pinned Major.Minor.Patch version in version.json without committing.
33
4-
Only the "version" field is touched; every other nbgv setting (such as
5-
versionHeightOffset and the release config) is preserved verbatim. The new
6-
version is written to the GITHUB_OUTPUT "version" key for the calling workflow.
4+
Only the "version" field is touched; every other nbgv setting (the release
5+
config and cloud-build options) is preserved verbatim. The version is written as
6+
a full three-segment value so the released NuGet package version is exactly that
7+
value -- nbgv puts the git height in the unused fourth integer, which never
8+
appears in the package version. The new version is also written to the
9+
GITHUB_OUTPUT "version" key for the calling workflow.
10+
11+
Bump types:
12+
major 1.4.2 -> 2.0.0
13+
minor 1.4.2 -> 1.5.0
14+
patch 1.4.2 -> 1.4.3
715
"""
816
import json
917
import os
1018
import sys
1119

1220
VERSION_FILE = "version.json"
21+
VALID_BUMPS = ("major", "minor", "patch")
1322

1423

15-
def main():
16-
bump_type = sys.argv[1] if len(sys.argv) > 1 else "minor"
17-
18-
with open(VERSION_FILE, encoding="utf-8") as handle:
19-
data = json.load(handle)
20-
21-
raw = str(data.get("version", "0.0"))
24+
def next_version(raw, bump_type):
2225
core = raw.split("-", 1)[0]
2326
parts = core.split(".")
2427
major = int(parts[0]) if len(parts) > 0 and parts[0] else 0
2528
minor = int(parts[1]) if len(parts) > 1 and parts[1] else 0
29+
patch = int(parts[2]) if len(parts) > 2 and parts[2] else 0
2630

2731
if bump_type == "major":
28-
major += 1
29-
minor = 0
30-
else:
31-
minor += 1
32+
return f"{major + 1}.0.0"
33+
if bump_type == "minor":
34+
return f"{major}.{minor + 1}.0"
35+
return f"{major}.{minor}.{patch + 1}"
36+
37+
38+
def main():
39+
bump_type = sys.argv[1] if len(sys.argv) > 1 else "minor"
40+
if bump_type not in VALID_BUMPS:
41+
sys.exit(
42+
f"Unknown bump type '{bump_type}'; expected one of {', '.join(VALID_BUMPS)}."
43+
)
44+
45+
with open(VERSION_FILE, encoding="utf-8") as handle:
46+
data = json.load(handle)
3247

33-
new_version = f"{major}.{minor}"
48+
raw = str(data.get("version", "0.0.0"))
49+
new_version = next_version(raw, bump_type)
3450
data["version"] = new_version
3551

3652
with open(VERSION_FILE, "w", encoding="utf-8") as handle:

version.json

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
{
2-
"version": "0.0",
3-
"versionHeightOffset": 7,
2+
"version": "1.0.0",
43
"release": {
54
"firstUnstableTag": "preview"
65
},

0 commit comments

Comments
 (0)