From 7877f89d35b014e4de9e3c35727154df2012388d Mon Sep 17 00:00:00 2001 From: movingsam Date: Fri, 27 Feb 2026 13:58:09 +0800 Subject: [PATCH] =?UTF-8?q?feat(platform):=20=E5=A2=9E=E5=BC=BA=20Infrastr?= =?UTF-8?q?ucture=20=E5=B1=82=E5=8F=AF=E6=89=A9=E5=B1=95=E6=80=A7=EF=BC=8C?= =?UTF-8?q?=E6=B7=BB=E5=8A=A0=20NuGet=20=E5=8F=91=E5=B8=83=E8=84=9A?= =?UTF-8?q?=E6=9C=AC=E4=B8=8E=20CI/CD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## 主要变更 ### Infrastructure 层重构 - `PlatformDbContext`: 构造函数改为接受泛型 `DbContextOptions`,支持派生上下文 - `TenantStore`: 泛型化实现,支持不同的数据库上下文 - `Extensions`: 新增 `AddPlatformCore` 扩展方法,简化服务注册 ### 依赖调整 - 移除 Npgsql.EntityFrameworkCore.PostgreSQL 直接依赖,由使用方自行决定数据库提供程序 ### CI/CD 集成 - 新增 `.gitea/workflows/publish-nuget.yml` Gitea Actions 工作流 - 新增 `push-platform-nuget.sh` 脚本,支持: - 从 git tag 自动获取版本号 - HTTP/HTTPS 双模式支持 - 独立 NuGet 配置文件 - CI/CD 友好的环境变量配置 ### 其他 - `NuGet.Config`: 新增 NuGet 配置文件 - `Fengling.Platform.Domain`: 添加 Items 文件夹占位 --- .gitea/workflows/publish-nuget.yml | 26 ++ .../Fengling.Platform.Domain.csproj | 4 + .../Extensions.cs | 27 ++ .../Fengling.Platform.Infrastructure.csproj | 1 - .../PlatformDbContext.cs | 4 +- .../TenantManager.cs | 5 +- .../TenantStore.cs | 7 +- NuGet.Config | 8 + push-platform-nuget.sh | 311 ++++++++++++++++++ 9 files changed, 385 insertions(+), 8 deletions(-) create mode 100644 .gitea/workflows/publish-nuget.yml create mode 100644 Fengling.Platform.Infrastructure/Extensions.cs create mode 100644 NuGet.Config create mode 100755 push-platform-nuget.sh diff --git a/.gitea/workflows/publish-nuget.yml b/.gitea/workflows/publish-nuget.yml new file mode 100644 index 0000000..197afb6 --- /dev/null +++ b/.gitea/workflows/publish-nuget.yml @@ -0,0 +1,26 @@ +name: Publish NuGet Package + +on: + push: + tags: + - 'v*' + +jobs: + publish: + runs-on: ubuntu-latest + steps: + - name: Checkout code + uses: actions/checkout@v4 + + - name: Setup .NET + uses: actions/setup-dotnet@v4 + with: + dotnet-version: '10.0' + + - name: Publish NuGet packages + run: | + ./push-platform-nuget.sh all + env: + GITEA_HOST: gitea.shtao1.cn + GITEA_ORG: fengling + GITEA_API_TOKEN: ${{ secrets.GITEA_API_TOKEN }} diff --git a/Fengling.Platform.Domain/Fengling.Platform.Domain.csproj b/Fengling.Platform.Domain/Fengling.Platform.Domain.csproj index cbb48aa..5a90850 100644 --- a/Fengling.Platform.Domain/Fengling.Platform.Domain.csproj +++ b/Fengling.Platform.Domain/Fengling.Platform.Domain.csproj @@ -14,4 +14,8 @@ + + + + diff --git a/Fengling.Platform.Infrastructure/Extensions.cs b/Fengling.Platform.Infrastructure/Extensions.cs new file mode 100644 index 0000000..16dcdc5 --- /dev/null +++ b/Fengling.Platform.Infrastructure/Extensions.cs @@ -0,0 +1,27 @@ +using Microsoft.Extensions.DependencyInjection; + +namespace Fengling.Platform.Infrastructure; + +public static class Extensions +{ + public static IServiceCollection AddPlatformCore(this IServiceCollection services, + Action? optionsAction = null, + Action? serviceAction = null + ) + where TContext : PlatformDbContext + { + if (optionsAction != null) + { + var isRegistry = services.Any(x => x.ImplementationType == typeof(TContext)); + if (!isRegistry) + { + services.AddDbContext(optionsAction); + } + } + services.AddScoped>(); + services.AddScoped(); + serviceAction?.Invoke(services); + + return services; + } +} \ No newline at end of file diff --git a/Fengling.Platform.Infrastructure/Fengling.Platform.Infrastructure.csproj b/Fengling.Platform.Infrastructure/Fengling.Platform.Infrastructure.csproj index 5aef5b6..08493d9 100644 --- a/Fengling.Platform.Infrastructure/Fengling.Platform.Infrastructure.csproj +++ b/Fengling.Platform.Infrastructure/Fengling.Platform.Infrastructure.csproj @@ -13,7 +13,6 @@ - diff --git a/Fengling.Platform.Infrastructure/PlatformDbContext.cs b/Fengling.Platform.Infrastructure/PlatformDbContext.cs index 91f702d..4ee1efa 100644 --- a/Fengling.Platform.Infrastructure/PlatformDbContext.cs +++ b/Fengling.Platform.Infrastructure/PlatformDbContext.cs @@ -8,12 +8,12 @@ using Microsoft.EntityFrameworkCore; namespace Fengling.Platform.Infrastructure; -public partial class PlatformDbContext(DbContextOptions options) +public class PlatformDbContext(DbContextOptions options) : IdentityDbContext(options) { public DbSet Tenants => Set(); public DbSet AccessLogs => Set(); - public DbSet AuditLogs => Set(); + public DbSet AuditLogs => Set(); protected override void OnModelCreating(ModelBuilder modelBuilder) { diff --git a/Fengling.Platform.Infrastructure/TenantManager.cs b/Fengling.Platform.Infrastructure/TenantManager.cs index f338b1e..1251f61 100644 --- a/Fengling.Platform.Infrastructure/TenantManager.cs +++ b/Fengling.Platform.Infrastructure/TenantManager.cs @@ -1,8 +1,9 @@ -namespace Fengling.Platform.Infrastructure; - using Fengling.Platform.Domain.AggregatesModel.TenantAggregate; using Microsoft.AspNetCore.Identity; +namespace Fengling.Platform.Infrastructure; + + public interface ITenantManager { Task FindByIdAsync(long? tenantId, CancellationToken cancellationToken = default); diff --git a/Fengling.Platform.Infrastructure/TenantStore.cs b/Fengling.Platform.Infrastructure/TenantStore.cs index c358929..b464278 100644 --- a/Fengling.Platform.Infrastructure/TenantStore.cs +++ b/Fengling.Platform.Infrastructure/TenantStore.cs @@ -4,12 +4,13 @@ using Microsoft.AspNetCore.Identity; using Microsoft.EntityFrameworkCore; using Fengling.Platform.Domain.AggregatesModel.TenantAggregate; -public class TenantStore : ITenantStore +public class TenantStore : ITenantStore +where TContext : PlatformDbContext { - private readonly PlatformDbContext _context; + private readonly TContext _context; private readonly DbSet _tenants; - public TenantStore(PlatformDbContext context) + public TenantStore(TContext context) { _context = context; _tenants = context.Tenants; diff --git a/NuGet.Config b/NuGet.Config new file mode 100644 index 0000000..62a0353 --- /dev/null +++ b/NuGet.Config @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/push-platform-nuget.sh b/push-platform-nuget.sh new file mode 100755 index 0000000..15737e3 --- /dev/null +++ b/push-platform-nuget.sh @@ -0,0 +1,311 @@ +#!/bin/bash + +# ============================================================================= +# Fengling.Platform NuGet 包上传脚本 +# 用于上传 Fengling.Platform.Domain 和 Fengling.Platform.Infrastructure 到 Gitea NuGet +# 支持 CI/CD 集成,自动从 git tag 获取版本 +# ============================================================================= + +# =========================== 环境变量配置 =========================== +# CI/CD 时通过环境变量传入,本地可修改默认值 + +## TODO: 请在这里填入你的 Gitea API Token,或通过环境变量 GITEA_API_TOKEN 传入 +#export GITEA_HOST="${GITEA_HOST:-gitea.shtao1.cn}" # Gitea 域名 +#export GITEA_ORG="${GITEA_ORG:-fengling}" # 组织名称 +#export GITEA_API_TOKEN="${GITEA_API_TOKEN:-}" # Gitea API Token (必填) +#export GITEA_USE_HTTPS="${GITEA_USE_HTTPS:-true}" # 是否使用 HTTPS (外网用 true) +# CI/CD 时通过环境变量传入,本地可修改默认值 + +export GITEA_HOST="${GITEA_HOST:-gitea.shtao1.cn}" # Gitea 地址 (内网) +export GITEA_ORG="${GITEA_ORG:-fengling}" # 组织名称 +export GITEA_API_TOKEN="${GITEA_API_TOKEN:-}" # Gitea API Token (必填) +export GITEA_USE_HTTPS="${GITEA_USE_HTTPS:-true}" # 是否使用 HTTPS (内网用 false) + +# =========================== 内部变量 =========================== +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +NUGET_SOURCE_NAME="gitea" + +# 根据是否使用 HTTPS 构建 URL +if [ "$GITEA_USE_HTTPS" = "true" ]; then + NUGET_SOURCE_URL="https://${GITEA_HOST}/api/packages/${GITEA_ORG}/nuget/index.json" +else + NUGET_SOURCE_URL="http://${GITEA_HOST}/api/packages/${GITEA_ORG}/nuget" +fi + +# 输出目录 +NUPKG_DIR="${SCRIPT_DIR}/nupkg" +if [ "$GITEA_USE_HTTPS" = "true" ]; then + NUGET_SOURCE_URL="https://${GITEA_HOST}/api/packages/${GITEA_ORG}/nuget/index.json" +else + NUPKG_DIR="${SCRIPT_DIR}/nupkg" +NUGET_SOURCE_URL="http://${GITEA_HOST}/api/packages/${GITEA_ORG}/nuget" +fi + +# NuGet 配置文件路径 +NUGET_CONFIG_DIR="${SCRIPT_DIR}/.nuget" +NUGET_CONFIG_FILE="${NUGET_CONFIG_DIR}/NuGet.Config" + +# =========================== 版本获取 =========================== +get_version_from_git() { + # 优先使用环境变量中的版本 + if [ -n "$PACKAGE_VERSION" ]; then + echo "$PACKAGE_VERSION" + return + fi + + # 尝试从 git tag 获取版本 + local git_dir="${SCRIPT_DIR}/.git" + if [ -d "$git_dir" ]; then + local latest_tag=$(git -C "$SCRIPT_DIR" describe --tags --abbrev=0 2>/dev/null) + if [ -n "$latest_tag" ]; then + # 去掉 v 前缀 (如 v1.0.0 -> 1.0.0) + echo "${latest_tag#v}" + return + fi + fi + + # 默认版本 + echo "1.0.0" +} + +# =========================== 颜色输出 =========================== +RED='\033[0;31m' +GREEN='\033[0;32m' +YELLOW='\033[1;33m' +BLUE='\033[0;34m' +NC='\033[0m' + +log_info() { + echo -e "${GREEN}[INFO]${NC} $1" +} + +log_warn() { + echo -e "${YELLOW}[WARN]${NC} $1" +} + +log_error() { + echo -e "${RED}[ERROR]${NC} $1" +} + +log_debug() { + if [ "$DEBUG" = "true" ]; then + echo -e "${BLUE}[DEBUG]${NC} $1" + fi +} + +# =========================== 检查配置 =========================== +check_config() { + if [ -z "$GITEA_API_TOKEN" ]; then + log_error "请设置环境变量 GITEA_API_TOKEN" + echo "" + echo "设置方式:" + echo " export GITEA_API_TOKEN=你的GiteaToken" + echo "" + echo "或运行时传入:" + echo " GITEA_API_TOKEN=你的Token $0 all" + echo "" + echo "CI/CD 示例 (GitHub Actions):" + echo " env:" + echo " GITEA_API_TOKEN: \${{ secrets.GITEA_API_TOKEN }}" + echo " GITEA_ORG: fengling" + exit 1 + fi + + log_info "Gitea: ${GITEA_HOST}, Org: ${GITEA_ORG}, HTTPS: ${GITEA_USE_HTTPS}" +} + +# =========================== 创建 NuGet 配置 =========================== +create_nuget_config() { + # 创建 .nuget 目录 + mkdir -p "${NUGET_CONFIG_DIR}" + + # 创建 NuGet.Config,启用 HTTP 支持 + cat > "${NUGET_CONFIG_FILE}" << 'EOF' + + + + + + + + + +EOF + + log_info "已创建 NuGet 配置文件: ${NUGET_CONFIG_FILE}" +} + +# =========================== 还原并构建包 =========================== +restore_and_build() { + # 获取版本 + PACKAGE_VERSION=$(get_version_from_git) + log_info "包版本: ${PACKAGE_VERSION}" + + log_info "开始构建 NuGet 包..." + + local projects=( + "${SCRIPT_DIR}/Fengling.Platform.Domain/Fengling.Platform.Domain.csproj" + "${SCRIPT_DIR}/Fengling.Platform.Infrastructure/Fengling.Platform.Infrastructure.csproj" + ) + + for project in "${projects[@]}"; do + if [ ! -f "$project" ]; then + log_error "项目文件不存在: $project" + exit 1 + fi + + local project_name=$(basename $(dirname $project)) + log_info "正在构建: ${project_name}" + + # 还原依赖 + dotnet restore "$project" --configfile "${NUGET_CONFIG_FILE}" + if [ $? -ne 0 ]; then + log_error "还原失败: $project" + exit 1 + fi + + # 构建并打包 + dotnet build "$project" -c Release --no-restore + if [ $? -ne 0 ]; then + log_error "构建失败: $project" + exit 1 + fi + + dotnet pack "$project" -c Release --no-build -p:PackageVersion=${PACKAGE_VERSION} -o "${NUPKG_DIR}" + if [ $? -ne 0 ]; then + log_error "打包失败: $project" + exit 1 + fi + done + + log_info "NuGet 包构建完成!" +} + +# =========================== 配置 NuGet 源 =========================== +configure_nuget_source() { + log_info "配置 NuGet 源: ${NUGET_SOURCE_URL}" + + # 使用 configfile 参数添加源 + dotnet nuget add source \ + --name "${NUGET_SOURCE_NAME}" \ + --username "movingsam" \ + --password "${GITEA_API_TOKEN}" \ + --store-password-in-clear-text \ + "${NUGET_SOURCE_URL}" \ + --configfile "${NUGET_CONFIG_FILE}" + + if [ $? -eq 0 ]; then + log_info "NuGet 源配置成功!" + else + log_error "NuGet 源配置失败" + exit 1 + fi +} + +# =========================== 上传包 =========================== +push_packages() { + log_info "开始上传 NuGet 包..." + + if [ ! -d "$NUPKG_DIR" ]; then + log_error "nupkg 目录不存在,请先运行构建" + exit 1 + fi + + # 上传所有 nupkg 文件 + for nupkg in "${NUPKG_DIR}"/*.nupkg; do + [ -f "$nupkg" ] || continue + + local filename=$(basename $nupkg) + log_info "上传: $filename" + + dotnet nuget push "$nupkg" \ + --source "${NUGET_SOURCE_URL}" \ + --api-key "${GITEA_API_TOKEN}" \ + --configfile "${NUGET_CONFIG_FILE}" \ + --skip-duplicate + + if [ $? -eq 0 ]; then + log_info "上传成功: $filename" + else + log_warn "上传失败或包已存在: $filename" + fi + done +} + +# =========================== 显示帮助 =========================== +show_help() { + echo "用法: $0 [命令]" + echo "" + echo "命令:" + echo " all 执行全部步骤 (构建 -> 配置源 -> 上传)" + echo " build 仅构建 NuGet 包" + echo " config 仅配置 NuGet 源" + echo " push 仅上传包 (需要先构建)" + echo " clean 清理构建产物" + echo " help 显示帮助" + echo "" + echo "环境变量:" + echo " GITEA_HOST Gitea 地址 (默认: 192.168.100.120:8418)" + echo " GITEA_ORG 组织名称 (默认: fengling)" + echo " GITEA_API_TOKEN Gitea API Token (必填)" + echo " GITEA_USE_HTTPS 是否使用 HTTPS (默认: false, 内网用 false)" + echo " PACKAGE_VERSION 包版本 (自动从 git tag 获取)" + echo "" + echo "示例:" + echo " # 方式1: 设置环境变量" + echo " export GITEA_API_TOKEN=your_token" + echo " $0 all" + echo "" + echo " # 方式2: 运行时传入环境变量" + echo " GITEA_API_TOKEN=your_token $0 all" + echo "" + echo " # 使用 HTTPS (外网)" + echo " GITEA_API_TOKEN=your_token GITEA_USE_HTTPS=true GITEA_HOST=gitea.shtao1.cn $0 all" +} + +# =========================== 清理 =========================== +clean() { + log_info "清理构建产物..." + rm -rf "${NUPKG_DIR}" + rm -rf "${NUGET_CONFIG_DIR}" + log_info "清理完成" +} + +# =========================== 主程序 =========================== +main() { + local command="${1:-all}" + + check_config + create_nuget_config + + case "$command" in + all) + restore_and_build + configure_nuget_source + push_packages + log_info "全部完成!" + ;; + build) + restore_and_build + ;; + config) + configure_nuget_source + ;; + push) + push_packages + ;; + clean) + clean + ;; + help|--help|-h) + show_help + ;; + *) + log_error "未知命令: $command" + show_help + exit 1 + ;; + esac +} + +main "$@"