Skip to content

Commit 88303a4

Browse files
Merge pull request #12 from TimeWarpEngineering/Cramer/2025-06-03/Task-001
Add CI/CD Pipeline with NuGet Publishing
2 parents 1fa1169 + 2d20d97 commit 88303a4

8 files changed

Lines changed: 562 additions & 2 deletions

File tree

.github/workflows/ci-cd.yml

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
name: CI/CD Pipeline
2+
3+
on:
4+
push:
5+
branches: [ master ]
6+
pull_request:
7+
branches: [ master ]
8+
release:
9+
types: [ published ]
10+
11+
jobs:
12+
build-and-test:
13+
runs-on: ubuntu-latest
14+
name: Build and Test
15+
16+
steps:
17+
- name: Checkout code
18+
uses: actions/checkout@v4
19+
20+
- name: Setup .NET
21+
uses: actions/setup-dotnet@v4
22+
with:
23+
dotnet-version: '9.0.x'
24+
25+
- name: Run build and test
26+
shell: pwsh
27+
run: ./CI-CD/ci-cd.ps1 -Phase build
28+
29+
- name: Upload artifacts
30+
uses: actions/upload-artifact@v4
31+
with:
32+
name: nuget-packages
33+
path: ./artifacts/*.nupkg
34+
35+
publish-nuget:
36+
runs-on: ubuntu-latest
37+
name: Publish to NuGet
38+
needs: build-and-test
39+
if: github.event_name == 'release' && github.event.action == 'published'
40+
41+
steps:
42+
- name: Checkout code
43+
uses: actions/checkout@v4
44+
45+
- name: Setup .NET
46+
uses: actions/setup-dotnet@v4
47+
with:
48+
dotnet-version: '9.0.x'
49+
50+
- name: Download artifacts
51+
uses: actions/download-artifact@v4
52+
with:
53+
name: nuget-packages
54+
path: ./artifacts
55+
56+
- name: Publish to NuGet
57+
shell: pwsh
58+
run: ./CI-CD/ci-cd.ps1 -Phase publish -PublishToNuGet $true
59+
env:
60+
NUGET_API_KEY: ${{ secrets.NUGET_API_KEY }}

CI-CD/README.md

Lines changed: 129 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,129 @@
1+
# CI/CD Pipeline for TimeWarp.Fixie
2+
3+
This folder contains the CI/CD pipeline scripts for the TimeWarp.Fixie project. The pipeline is designed to be testable locally using PowerShell scripts, with minimal GitHub Actions orchestration.
4+
5+
## Scripts
6+
7+
### `ci-cd.ps1` - Main Orchestration Script
8+
The main entry point for the CI/CD pipeline. Can run individual phases or the complete pipeline.
9+
10+
**Usage:**
11+
```powershell
12+
# Run complete pipeline (build + test only)
13+
./CI-CD/ci-cd.ps1
14+
15+
# Run only build and test
16+
./CI-CD/ci-cd.ps1 -Phase build
17+
18+
# Run complete pipeline with NuGet publishing
19+
./CI-CD/ci-cd.ps1 -PublishToNuGet $true
20+
21+
# Run only publish phase
22+
./CI-CD/ci-cd.ps1 -Phase publish -PublishToNuGet $true
23+
```
24+
25+
**Parameters:**
26+
- `Phase`: 'build', 'publish', or 'all' (default: 'all')
27+
- `Configuration`: 'Debug' or 'Release' (default: 'Release')
28+
- `PublishToNuGet`: Whether to publish to NuGet (default: false)
29+
- `NuGetApiKey`: NuGet API key (uses NUGET_API_KEY env var if not provided)
30+
31+
### `build-and-test.ps1` - Build and Test Phase
32+
Handles the build and test phase of the pipeline.
33+
34+
**What it does:**
35+
1. Restores dotnet tools
36+
2. Runs `dotnet cleanup`
37+
3. Restores dependencies
38+
4. Builds the project
39+
5. Runs tests
40+
6. Creates NuGet packages
41+
42+
**Usage:**
43+
```powershell
44+
./CI-CD/build-and-test.ps1 -Configuration Release -OutputPath ./artifacts
45+
```
46+
47+
### `publish-nuget.ps1` - NuGet Publishing Phase
48+
Handles publishing NuGet packages to NuGet.org.
49+
50+
**What it does:**
51+
1. Validates NuGet API key
52+
2. Finds packages in the specified directory
53+
3. Publishes packages to NuGet.org
54+
4. Supports skip-duplicate option
55+
56+
**Usage:**
57+
```powershell
58+
# Using environment variable
59+
$env:NUGET_API_KEY = "your-api-key"
60+
./CI-CD/publish-nuget.ps1
61+
62+
# Using parameter
63+
./CI-CD/publish-nuget.ps1 -NuGetApiKey "your-api-key"
64+
```
65+
66+
## GitHub Actions Integration
67+
68+
The pipeline integrates with GitHub Actions through [`.github/workflows/ci-cd.yml`](../.github/workflows/ci-cd.yml):
69+
70+
- **Build and Test**: Runs on every push and PR to master branch
71+
- **Publish**: Runs only on GitHub releases, publishes to NuGet.org
72+
73+
## Local Testing
74+
75+
You can test the entire pipeline locally:
76+
77+
```powershell
78+
# Test build and test phase
79+
./CI-CD/ci-cd.ps1 -Phase build
80+
81+
# Test complete pipeline (without publishing)
82+
./CI-CD/ci-cd.ps1
83+
84+
# Test with publishing (requires API key)
85+
$env:NUGET_API_KEY = "your-test-api-key"
86+
./CI-CD/ci-cd.ps1 -PublishToNuGet $true
87+
```
88+
89+
## Environment Variables
90+
91+
- `NUGET_API_KEY`: Required for publishing to NuGet.org
92+
93+
## Migration from Manual Process
94+
95+
The previous manual [`publish.ps1`](../publish.ps1) script functionality has been integrated into this CI/CD pipeline:
96+
97+
| Old Script Step | New Location |
98+
|----------------|--------------|
99+
| `Push-Location $PSScriptRoot` | Handled in each script |
100+
| `dotnet tool restore` | `build-and-test.ps1` |
101+
| `dotnet cleanup -y` | `build-and-test.ps1` |
102+
| `dotnet pack` | `build-and-test.ps1` |
103+
| `dotnet nuget push` | `publish-nuget.ps1` |
104+
| Error handling | Enhanced in all scripts |
105+
106+
## Security Considerations
107+
108+
- NuGet API key is handled through GitHub Secrets in CI/CD
109+
- Scripts validate API key presence before attempting to publish
110+
- Local testing can use environment variables
111+
- No API keys are stored in source code
112+
113+
## Troubleshooting
114+
115+
### Build Failures
116+
1. Check that all dependencies are properly restored
117+
2. Ensure .NET 9.0 SDK is installed
118+
3. Verify project builds locally with `dotnet build`
119+
120+
### Test Failures
121+
1. Run tests locally with `dotnet fixie`
122+
2. Check test output for specific failure details
123+
3. Ensure test dependencies are properly configured
124+
125+
### Publish Failures
126+
1. Verify NuGet API key is correctly set
127+
2. Check that packages don't already exist (unless using skip-duplicate)
128+
3. Ensure network connectivity to NuGet.org
129+
4. Verify package metadata is valid

CI-CD/build-and-test.ps1

Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
#!/usr/bin/env pwsh
2+
<#
3+
.SYNOPSIS
4+
Build and test the TimeWarp.Fixie project
5+
.DESCRIPTION
6+
This script handles the build and test phase of the CI/CD pipeline.
7+
It restores tools, cleans, restores dependencies, builds, and runs tests.
8+
.PARAMETER Configuration
9+
The build configuration (Debug or Release). Default is Release.
10+
.PARAMETER OutputPath
11+
The output path for build artifacts. Default is ./artifacts
12+
#>
13+
14+
param(
15+
[string]$Configuration = "Release",
16+
[string]$OutputPath = "./artifacts"
17+
)
18+
19+
$ErrorActionPreference = "Stop"
20+
$ProjectPath = "./source/TimeWarp.Fixie/TimeWarp.Fixie.csproj"
21+
22+
try {
23+
Push-Location $PSScriptRoot/..
24+
25+
Write-Host "Starting build and test process..." -ForegroundColor Green
26+
27+
# Restore tools
28+
Write-Host "Restoring tools..." -ForegroundColor Yellow
29+
dotnet tool restore
30+
if ($LASTEXITCODE -ne 0) { throw "Tool restore failed" }
31+
32+
# Clean
33+
Write-Host "Cleaning..." -ForegroundColor Yellow
34+
dotnet cleanup -y
35+
if ($LASTEXITCODE -ne 0) { throw "Clean failed" }
36+
37+
# Restore dependencies
38+
Write-Host "Restoring dependencies..." -ForegroundColor Yellow
39+
dotnet restore
40+
if ($LASTEXITCODE -ne 0) { throw "Restore failed" }
41+
42+
# Build
43+
Write-Host "Building..." -ForegroundColor Yellow
44+
dotnet build --no-restore --configuration $Configuration
45+
if ($LASTEXITCODE -ne 0) { throw "Build failed" }
46+
47+
# Test
48+
Write-Host "Running tests..." -ForegroundColor Yellow
49+
dotnet fixie ./tests/TimeWarp.Fixie.Tests --configuration $Configuration --no-build
50+
if ($LASTEXITCODE -ne 0) { throw "Tests failed" }
51+
52+
# Create output directory
53+
if (!(Test-Path $OutputPath)) {
54+
New-Item -ItemType Directory -Path $OutputPath -Force | Out-Null
55+
}
56+
57+
# Pack
58+
Write-Host "Creating NuGet package..." -ForegroundColor Yellow
59+
dotnet pack $ProjectPath --no-build --configuration $Configuration --output $OutputPath
60+
if ($LASTEXITCODE -ne 0) { throw "Pack failed" }
61+
62+
Write-Host "Build and test completed successfully!" -ForegroundColor Green
63+
64+
# List created packages
65+
$packages = Get-ChildItem -Path $OutputPath -Filter "*.nupkg"
66+
if ($packages) {
67+
Write-Host "Created packages:" -ForegroundColor Green
68+
foreach ($package in $packages) {
69+
Write-Host " - $($package.Name)" -ForegroundColor Cyan
70+
}
71+
}
72+
}
73+
catch {
74+
Write-Error "Build and test failed: $_"
75+
exit 1
76+
}
77+
finally {
78+
Pop-Location
79+
}

CI-CD/ci-cd.ps1

Lines changed: 94 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,94 @@
1+
#!/usr/bin/env pwsh
2+
<#
3+
.SYNOPSIS
4+
Main CI/CD orchestration script for TimeWarp.Fixie
5+
.DESCRIPTION
6+
This script orchestrates the complete CI/CD pipeline including build, test, and publish phases.
7+
It can be run locally for testing or called from GitHub Actions.
8+
.PARAMETER Phase
9+
The phase to run: 'build', 'publish', or 'all'. Default is 'all'.
10+
.PARAMETER Configuration
11+
The build configuration (Debug or Release). Default is Release.
12+
.PARAMETER PublishToNuGet
13+
Whether to publish to NuGet. Default is false for safety.
14+
.PARAMETER NuGetApiKey
15+
The NuGet API key. If not provided, will use the NUGET_API_KEY environment variable.
16+
#>
17+
18+
param(
19+
[ValidateSet("build", "publish", "all")]
20+
[string]$Phase = "all",
21+
[string]$Configuration = "Release",
22+
[bool]$PublishToNuGet = $false,
23+
[string]$NuGetApiKey = $env:NUGET_API_KEY
24+
)
25+
26+
$ErrorActionPreference = "Stop"
27+
$ArtifactsPath = "./artifacts"
28+
29+
function Write-PhaseHeader {
30+
param([string]$PhaseName)
31+
Write-Host ""
32+
Write-Host "=" * 60 -ForegroundColor Magenta
33+
Write-Host " $PhaseName" -ForegroundColor Magenta
34+
Write-Host "=" * 60 -ForegroundColor Magenta
35+
Write-Host ""
36+
}
37+
38+
try {
39+
Push-Location $PSScriptRoot
40+
41+
Write-Host "TimeWarp.Fixie CI/CD Pipeline" -ForegroundColor Green
42+
Write-Host "Phase: $Phase" -ForegroundColor Cyan
43+
Write-Host "Configuration: $Configuration" -ForegroundColor Cyan
44+
Write-Host "Publish to NuGet: $PublishToNuGet" -ForegroundColor Cyan
45+
46+
# Build and Test Phase
47+
if ($Phase -eq "build" -or $Phase -eq "all") {
48+
Write-PhaseHeader "BUILD AND TEST PHASE"
49+
50+
& ./build-and-test.ps1 -Configuration $Configuration -OutputPath $ArtifactsPath
51+
if ($LASTEXITCODE -ne 0) {
52+
throw "Build and test phase failed"
53+
}
54+
}
55+
56+
# Publish Phase
57+
if (($Phase -eq "publish" -or $Phase -eq "all") -and $PublishToNuGet) {
58+
Write-PhaseHeader "PUBLISH PHASE"
59+
60+
if ([string]::IsNullOrWhiteSpace($NuGetApiKey)) {
61+
Write-Warning "NuGet API key not provided. Skipping publish phase."
62+
Write-Host "To publish, provide the API key via -NuGetApiKey parameter or NUGET_API_KEY environment variable." -ForegroundColor Yellow
63+
} else {
64+
& ./publish-nuget.ps1 -PackagePath $ArtifactsPath -NuGetApiKey $NuGetApiKey
65+
if ($LASTEXITCODE -ne 0) {
66+
throw "Publish phase failed"
67+
}
68+
}
69+
} elseif ($Phase -eq "publish" -or $Phase -eq "all") {
70+
Write-Host "Publish phase skipped (PublishToNuGet = $PublishToNuGet)" -ForegroundColor Yellow
71+
}
72+
73+
Write-PhaseHeader "PIPELINE COMPLETED SUCCESSFULLY"
74+
Write-Host "All phases completed successfully!" -ForegroundColor Green
75+
76+
# Show artifacts
77+
if (Test-Path $ArtifactsPath) {
78+
$artifacts = Get-ChildItem -Path $ArtifactsPath -Filter "*.nupkg"
79+
if ($artifacts) {
80+
Write-Host ""
81+
Write-Host "Generated artifacts:" -ForegroundColor Green
82+
foreach ($artifact in $artifacts) {
83+
Write-Host " - $($artifact.Name)" -ForegroundColor Cyan
84+
}
85+
}
86+
}
87+
}
88+
catch {
89+
Write-Error "CI/CD Pipeline failed: $_"
90+
exit 1
91+
}
92+
finally {
93+
Pop-Location
94+
}

0 commit comments

Comments
 (0)