CI/CD Integration
JD.Efcpt.Build is designed to work seamlessly in continuous integration and deployment pipelines. This guide covers integration with popular CI/CD platforms.
Overview
The package requires no special configuration for CI/CD. Models are generated deterministically from your database project or connection, ensuring consistent results across environments.
Prerequisites
Ensure your CI/CD environment has:
- .NET SDK 8.0 or later
- EF Core Power Tools CLI (not required for .NET 10+)
- For DACPAC mode: SQL Server Data Tools components
GitHub Actions
.NET 10+ (Recommended)
No tool installation required - the CLI is executed via dnx:
name: Build
on: [push, pull_request]
jobs:
build:
runs-on: windows-latest
steps:
- uses: actions/checkout@v4
- name: Setup .NET
uses: actions/setup-dotnet@v4
with:
dotnet-version: '10.0.x'
- name: Restore dependencies
run: dotnet restore
- name: Build
run: dotnet build --configuration Release --no-restore
- name: Test
run: dotnet test --configuration Release --no-build
.NET 8-9
Requires tool installation:
name: Build
on: [push, pull_request]
jobs:
build:
runs-on: windows-latest
steps:
- uses: actions/checkout@v4
- name: Setup .NET
uses: actions/setup-dotnet@v4
with:
dotnet-version: '8.0.x'
- name: Restore tools
run: dotnet tool restore
- name: Restore dependencies
run: dotnet restore
- name: Build
run: dotnet build --configuration Release --no-restore
- name: Test
run: dotnet test --configuration Release --no-build
With Caching
Speed up builds by caching the efcpt intermediate directory:
name: Build with Cache
on: [push, pull_request]
jobs:
build:
runs-on: windows-latest
steps:
- uses: actions/checkout@v4
- name: Setup .NET
uses: actions/setup-dotnet@v4
with:
dotnet-version: '10.0.x'
- name: Cache efcpt outputs
uses: actions/cache@v4
with:
path: |
**/obj/efcpt/
key: efcpt-${{ runner.os }}-${{ hashFiles('**/*.sqlproj', '**/efcpt-config.json') }}
restore-keys: |
efcpt-${{ runner.os }}-
- name: Restore dependencies
run: dotnet restore
- name: Build
run: dotnet build --configuration Release --no-restore
- name: Test
run: dotnet test --configuration Release --no-build
Azure DevOps
Basic Pipeline
trigger:
- main
pool:
vmImage: 'windows-latest'
steps:
- task: UseDotNet@2
displayName: 'Setup .NET SDK'
inputs:
version: '10.0.x'
- task: DotNetCoreCLI@2
displayName: 'Restore'
inputs:
command: 'restore'
- task: DotNetCoreCLI@2
displayName: 'Build'
inputs:
command: 'build'
arguments: '--configuration Release --no-restore'
- task: DotNetCoreCLI@2
displayName: 'Test'
inputs:
command: 'test'
arguments: '--configuration Release --no-build'
With Tool Manifest (.NET 8-9)
trigger:
- main
pool:
vmImage: 'windows-latest'
steps:
- task: UseDotNet@2
displayName: 'Setup .NET SDK'
inputs:
version: '8.0.x'
- task: DotNetCoreCLI@2
displayName: 'Restore tools'
inputs:
command: 'custom'
custom: 'tool'
arguments: 'restore'
- task: DotNetCoreCLI@2
displayName: 'Restore'
inputs:
command: 'restore'
- task: DotNetCoreCLI@2
displayName: 'Build'
inputs:
command: 'build'
arguments: '--configuration Release --no-restore'
- task: DotNetCoreCLI@2
displayName: 'Test'
inputs:
command: 'test'
arguments: '--configuration Release --no-build'
With Caching
trigger:
- main
pool:
vmImage: 'windows-latest'
variables:
NUGET_PACKAGES: $(Pipeline.Workspace)/.nuget/packages
steps:
- task: Cache@2
displayName: 'Cache NuGet packages'
inputs:
key: 'nuget | "$(Agent.OS)" | **/packages.lock.json'
restoreKeys: |
nuget | "$(Agent.OS)"
path: $(NUGET_PACKAGES)
- task: Cache@2
displayName: 'Cache efcpt outputs'
inputs:
key: 'efcpt | "$(Agent.OS)" | **/*.sqlproj | **/efcpt-config.json'
restoreKeys: |
efcpt | "$(Agent.OS)"
path: '**/obj/efcpt'
- task: UseDotNet@2
inputs:
version: '10.0.x'
- task: DotNetCoreCLI@2
displayName: 'Restore'
inputs:
command: 'restore'
- task: DotNetCoreCLI@2
displayName: 'Build'
inputs:
command: 'build'
arguments: '--configuration Release --no-restore'
Docker
Multi-Stage Dockerfile
# Build stage
FROM mcr.microsoft.com/dotnet/sdk:10.0 AS build
WORKDIR /src
# Copy solution and project files
COPY *.sln .
COPY src/**/*.csproj ./src/
COPY database/**/*.sqlproj ./database/
# Restore dependencies
RUN dotnet restore
# Copy everything else
COPY . .
# Build
RUN dotnet build --configuration Release --no-restore
# Publish
RUN dotnet publish src/MyApp/MyApp.csproj --configuration Release --no-build -o /app/publish
# Runtime stage
FROM mcr.microsoft.com/dotnet/aspnet:10.0 AS runtime
WORKDIR /app
COPY --from=build /app/publish .
ENTRYPOINT ["dotnet", "MyApp.dll"]
With Tool Manifest (.NET 8-9)
FROM mcr.microsoft.com/dotnet/sdk:8.0 AS build
WORKDIR /src
# Copy tool manifest and restore tools
COPY .config/dotnet-tools.json .config/
RUN dotnet tool restore
# Copy and restore
COPY *.sln .
COPY src/**/*.csproj ./src/
COPY database/**/*.sqlproj ./database/
RUN dotnet restore
# Copy everything and build
COPY . .
RUN dotnet build --configuration Release --no-restore
# Publish
RUN dotnet publish src/MyApp/MyApp.csproj --configuration Release --no-build -o /app/publish
FROM mcr.microsoft.com/dotnet/aspnet:8.0 AS runtime
WORKDIR /app
COPY --from=build /app/publish .
ENTRYPOINT ["dotnet", "MyApp.dll"]
GitLab CI
stages:
- build
- test
variables:
DOTNET_VERSION: "10.0"
build:
stage: build
image: mcr.microsoft.com/dotnet/sdk:10.0
script:
- dotnet restore
- dotnet build --configuration Release --no-restore
artifacts:
paths:
- "**/bin/"
- "**/obj/"
expire_in: 1 hour
test:
stage: test
image: mcr.microsoft.com/dotnet/sdk:10.0
dependencies:
- build
script:
- dotnet test --configuration Release --no-build
Jenkins
Jenkinsfile (Declarative)
pipeline {
agent {
docker {
image 'mcr.microsoft.com/dotnet/sdk:10.0'
}
}
stages {
stage('Restore') {
steps {
sh 'dotnet restore'
}
}
stage('Build') {
steps {
sh 'dotnet build --configuration Release --no-restore'
}
}
stage('Test') {
steps {
sh 'dotnet test --configuration Release --no-build'
}
}
}
}
Connection String Mode in CI/CD
When using connection string mode, you'll need a database available during build.
Using Environment Variables
# GitHub Actions
env:
DB_CONNECTION_STRING: ${{ secrets.DB_CONNECTION_STRING }}
steps:
- name: Build
run: dotnet build --configuration Release
<!-- .csproj -->
<PropertyGroup>
<EfcptConnectionString>$(DB_CONNECTION_STRING)</EfcptConnectionString>
</PropertyGroup>
Using a Container Database
# GitHub Actions with SQL Server container
services:
sqlserver:
image: mcr.microsoft.com/mssql/server:2022-latest
env:
ACCEPT_EULA: Y
SA_PASSWORD: YourStrong!Passw0rd
ports:
- 1433:1433
options: >-
--health-cmd "/opt/mssql-tools/bin/sqlcmd -S localhost -U sa -P YourStrong!Passw0rd -Q 'SELECT 1'"
--health-interval 10s
--health-timeout 5s
--health-retries 5
steps:
- name: Setup database
run: |
sqlcmd -S localhost -U sa -P YourStrong!Passw0rd -i scripts/setup.sql
- name: Build
env:
EfcptConnectionString: "Server=localhost;Database=MyDb;User Id=sa;Password=YourStrong!Passw0rd;TrustServerCertificate=True;"
run: dotnet build --configuration Release
Windows vs Linux Agents
DACPAC Mode Requirements
Modern SDK-style SQL Projects (Microsoft.Build.Sql or MSBuild.Sdk.SqlProj) build cross-platform:
# GitHub Actions - Linux works with modern SQL SDKs
jobs:
build:
runs-on: ubuntu-latest # Works with Microsoft.Build.Sql and MSBuild.Sdk.SqlProj
Traditional SQL Projects (legacy .sqlproj format) require Windows with SQL Server Data Tools:
# GitHub Actions - Windows required for traditional .sqlproj
jobs:
build:
runs-on: windows-latest
Connection String Mode
Connection string mode works on both Windows and Linux:
# GitHub Actions - Any platform works
jobs:
build:
runs-on: ubuntu-latest
Troubleshooting CI/CD
Build fails with "efcpt not found"
For .NET 8-9, ensure tool restore runs before build:
- name: Restore tools
run: dotnet tool restore
DACPAC build fails
For traditional SQL Projects, use Windows with SQL Server Data Tools:
pool:
vmImage: 'windows-latest'
For modern SDK-style projects (Microsoft.Build.Sql or MSBuild.Sdk.SqlProj), Linux works fine - verify your project SDK is configured correctly.
Inconsistent generated code
Clear the cache to force regeneration:
- name: Clear efcpt cache
run: rm -rf **/obj/efcpt
Slow builds
Enable caching for the efcpt intermediate directory to skip regeneration when schema hasn't changed.
Best Practices
- Use .NET 10+ when possible to eliminate tool installation steps
- Use local tool manifests (.NET 8-9) for version consistency
- Cache intermediate directories to speed up incremental builds
- Use modern SQL SDKs (
Microsoft.Build.SqlorMSBuild.Sdk.SqlProj) for cross-platform DACPAC builds - Use environment variables for connection strings
- Never commit credentials to source control
efcpt Compatibility
The Provider Compatibility workflow runs the task unit suite on .NET 8, 9, and 10 on Windows, Linux, and macOS. Each of its nine jobs checks passing connection and schema-reader tests for SQL Server, PostgreSQL, MySQL, Oracle, Snowflake, Firebird, and SQLite, covering 63 provider/runtime/OS combinations. TRX reports are uploaded as artifacts; missing or skipped provider cases fail verification.
This matrix exercises driver loading, connection construction, and schema-reader logic. Live database tests remain in the Linux integration suite; Snowflake live tests require an account. The separate upstream-tool workflow below tests actual efcpt execution.
To reproduce one runtime locally:
dotnet test tests/JD.Efcpt.Build.Tests/JD.Efcpt.Build.Tests.csproj -c Release -p:EfcptTestFramework=net8.0 --filter "Category!=Integration"
Install the .NET 8/9/10 SDKs first. EfcptTestFramework selects the task test host and its fixture; the default remains net10.0.
The efcpt CLI is an external tool whose release lines track EF Core versions, so an upstream release can change scaffolding behavior. A scheduled workflow guards against this by weekly rebuilding a sample against the latest efcpt per supported EF Core line. See efcpt Compatibility for the supported version matrix and how the guard works.
Next Steps
- efcpt Compatibility - Supported efcpt versions and the weekly compat guard
- Troubleshooting - Solve common problems
- Configuration - Complete configuration reference
- Advanced Topics - Complex scenarios