引言:为什么 CI/CD 对 C# 开发者很重要
在现代软件开发中,手动测试和部署效率低下且风险很高。每当开发者将代码推送到仓库时,都需要确保构建没有损坏、测试通过、应用程序已准备好部署。这正是 CI/CD(持续集成 / 持续部署)发挥作用的地方。
GitHub Actions 是 GitHub 内置的自动化工具,允许您直接在仓库中创建工作流程(workflows)。它非常适合 C# (.NET) 项目,因为它同时支持 Windows 和 Linux 运行器,并且拥有丰富的现成操作(actions)生态系统。
在本文中,我们将详细讲解如何使用 GitHub Actions 为 C# 项目配置一个完整的 CI/CD 流水线:从构建和测试到发布 NuGet 包或部署 Web 应用程序。
GitHub Actions 基础:YAML 和 workflow 结构
GitHub Actions 中的每个 workflow 都在 YAML 文件中描述,该文件存储在仓库的 .github/workflows/ 目录中。让我们来看一下基本结构:
name: .NET CI/CD
on: push: branches: [ main, develop ] pull_request: branches: [ main ]
jobs: build: runs-on: ubuntu-latest
steps: - name: Checkout code uses: actions/checkout@v4
- name: Setup .NET uses: actions/setup-dotnet@v4 with: dotnet-version: '8.x'
- name: Restore dependencies run: dotnet restore
- name: Build run: dotnet build --configuration Release --no-restore
- name: Run tests run: dotnet test --configuration Release --no-build --verbosity normal关键元素:
- on — 触发条件(push、pull_request、schedule 等)
- jobs — 并行或顺序执行的任务集合
- runs-on — 执行环境操作系统(ubuntu-latest、windows-latest、macos-latest)
- steps — 命令或现成 actions 的序列
重要提示:对于 .NET 项目,请使用 actions/setup-dotnet action 并指定 SDK 版本。这可以确保环境包含所需的 .NET 版本。
配置 C# 代码的测试和代码检查
高质量的 CI/CD 离不开自动化测试和代码风格检查。让我们在 workflow 中添加单元测试和静态分析的步骤。
使用 xUnit 进行单元测试和代码覆盖率
假设您有一个使用 xUnit 的测试项目。让我们添加一个步骤,使用 Coverlet 生成覆盖率报告:
- name: Run tests with coverage run: | dotnet test --configuration Release \ --no-build \ --verbosity normal \ /p:CollectCoverage=true \ /p:CoverletOutputFormat=opencover \ /p:CoverletOutput=./coverage.xml
- name: Upload coverage to Codecov uses: codecov/codecov-action@v3 with: files: ./coverage.xml flags: unittests fail_ci_if_error: false为此,您需要在测试项目中添加 coverlet.collector 包。示例命令:
dotnet add package coverlet.collector使用 Roslyn Analyzers 进行静态分析
让我们添加使用内置 .NET 分析器进行代码检查的步骤:
- name: Run Roslyn analyzers run: dotnet build --configuration Release --warnaserror -p:RunAnalyzersDuringBuild=true也可以使用第三方工具,例如 SonarCloud:
- name: SonarCloud Scan uses: SonarSource/sonarcloud-github-action@master env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} SONAR_TOKEN: ${{ secrets.SON