CI/CD Pipeline¶
This document describes the LBS Foundry continuous integration and deployment pipeline, implemented in .github/workflows/Build-Container-Apps.yml.
Overview¶
The pipeline is triggered on:
- Push to main branch: Builds production releases
- Pull requests to main: Builds prerelease versions with -pr suffix
Pipeline Flow¶
graph TD
A[Push/PR to main] --> B[build-and-test]
B --> C[build-lbs-api]
B --> D[build-ballr-api]
B --> E[build-mcp-server]
B --> F[build-python-sdk]
B --> G[build-typescript-sdk]
B --> I[build-foundry-web]
C --> H[create-release]
D --> H
E --> H
F --> H
G --> H
I --> H
Jobs¶
1. build-and-test (Main Job)¶
The foundation job that builds everything and provides artifacts for downstream jobs.
Version Generation¶
Generates timestamp-based semantic versions:
Version Properties:
- VERSION: Full version with -pr suffix for PRs
- NUMERIC_VERSION: Numeric-only version for assemblies
- ASSEMBLY_VERSION: Assembly version number
- FILE_VERSION: File version number
- INFORMATIONAL_VERSION: Version with -github suffix
Build Steps¶
1. Setup Environment
2. Build .NET Solution
dotnet restore LBS.slnx
dotnet build LBS.slnx --configuration Release --no-restore \
/p:Version=$VERSION \
/p:AssemblyVersion=$NUMERIC_VERSION \
/p:FileVersion=$NUMERIC_VERSION \
/p:InformationalVersion=$INFORMATIONAL_VERSION \
/p:PackageVersion=$VERSION
Builds all projects in the solution: - Core libraries (Anchor, Augment, EventSourcing) - Domain projects (Core, Sport, Fantasy) - Integration projects - APIs (LBS.Api, Ballr.WebApi) - Tools (SDK Generator) - Tests
3. Run Unit Tests
cd src/Tests/LBS.UnitTests
dotnet run --configuration Release --no-build -- -trx ../../../TestResults/test-results.trx
- Executes all unit tests
- Generates TRX format test results
- Uploads test results as artifacts (always, even on failure)
4. Publish NuGet Packages
dotnet pack LBS.slnx --configuration Release --no-build \
/p:Version=$VERSION \
/p:PackageVersion=$VERSION \
--output ./nupkgs
dotnet nuget push "./nupkgs/*.nupkg" \
--source "https://nuget.pkg.github.com/$REPO_OWNER/index.json" \
--api-key $NUGET_PUBLISH_TOKEN \
--skip-duplicate
Publishes all packable projects to GitHub Packages:
- LBS.Anchor
- LBS.Augment
- LBS.EventSourcing
- LBS.Domain.*
- LBS.*.Integration
5. Generate SDK Source Code
Uses the LBS.Tools.SdkGenerator to analyze API contracts and generate client SDKs.
TypeScript SDK:
dotnet run --project src/Tools/LBS.Tools.SdkGenerator/LBS.Tools.SdkGenerator.csproj \
--configuration Release --no-build -- \
"src/Apps/Ballr.WebApi/bin/Release/net10.0" \
"/usr/share/dotnet/packs/Microsoft.NETCore.App.Ref/10.0.0/ref/net10.0" \
"sdk/typescript/generated" \
--language typescript
Python SDK:
dotnet run --project src/Tools/LBS.Tools.SdkGenerator/LBS.Tools.SdkGenerator.csproj \
--configuration Release --no-build -- \
"src/Apps/Ballr.WebApi/bin/Release/net10.0" \
"/usr/share/dotnet/packs/Microsoft.NETCore.App.Ref/10.0.0/ref/net10.0" \
"sdk/python/src/foundry_sdk/generated" \
--language python
Generates: - TypeScript interfaces and API client - Python classes and API client - Type definitions for all DTOs - Client methods for all API endpoints - Generation logs for troubleshooting
6. Upload SDK Artifacts
Uploads generated SDK source code as temporary artifacts (1-day retention) for downstream jobs.
Outputs¶
Exports version information for all downstream jobs:
- version: Full version string
- numeric-version: Numeric version
- assembly-version: Assembly version
- file-version: File version
- informational-version: Informational version
2. build-lbs-api¶
Builds and pushes the LBS Foundry API Docker container.
docker build \
--target final-api \
--build-arg VERSION=$VERSION \
--build-arg ASSEMBLY_VERSION=$ASSEMBLY_VERSION \
--build-arg FILE_VERSION=$FILE_VERSION \
--build-arg INFORMATIONAL_VERSION=$INFORMATIONAL_VERSION \
-t $REGISTRY/lbs-foundry-api:$VERSION \
-t $REGISTRY/lbs-foundry-api:latest \
.
Pushes to Azure Container Registry with tags:
- $VERSION (e.g., 2025.1015.0308.577)
- latest
3. build-ballr-api¶
Builds and pushes the Ballr WebAPI Docker container.
docker build \
--target final-ballr \
--build-arg VERSION=$VERSION \
-t $REGISTRY/ballr-web-api:$VERSION \
-t $REGISTRY/ballr-web-api:latest \
.
Pushes to Azure Container Registry with tags:
- $VERSION
- latest
4. build-mcp-server¶
Builds and pushes the MCP Server Docker container.
docker build \
--target final-mcpserver \
--build-arg VERSION=$VERSION \
-t $REGISTRY/lbs-foundry-mcpserver:$VERSION \
-t $REGISTRY/lbs-foundry-mcpserver:latest \
.
Pushes to Azure Container Registry with tags:
- $VERSION
- latest
5. build-foundry-web¶
Builds the Foundry Web UI (SvelteKit frontend) and runs quality checks.
Steps¶
1. Download Generated TypeScript SDK Source
Downloads the TypeScript SDK source from build-and-test artifacts into the sdk/typescript/ workspace package.
2. Install Workspace Dependencies
Installs all workspace dependencies. The @luckboxstudios/foundry-sdk dependency resolves via workspace:* link to the local SDK.
3. Build TypeScript SDK
Compiles the generated TypeScript SDK so the workspace link provides built artifacts to foundry-web.
4. Lint
Runs Prettier formatting checks and ESLint.
5. Type Check
Runs svelte-check for TypeScript and Svelte type validation.
6. Build
Runs vite build producing the Cloudflare Workers-compatible output in .svelte-kit/cloudflare/.
6. build-python-sdk¶
Builds Python SDK packages for distribution.
Steps¶
1. Download Generated Source Downloads the Python SDK source from build-and-test artifacts.
2. Version Conversion Converts version to PEP 440 format:
# Production: 2025.1015.0308.577 -> 2025.1015.0308.577
# PR builds: 2025.1015.0308.577-pr -> 2025.1015.0308.577.dev0
VERSION="2025.1015.0308.577-pr"
PYTHON_VERSION="${VERSION//-pr/.dev0}"
sed -i "s/^version = .*/version = \"$PYTHON_VERSION\"/" pyproject.toml
3. Build Packages
Creates:
- foundry_sdk-$VERSION-py3-none-any.whl (wheel distribution)
- foundry_sdk-$VERSION.tar.gz (source distribution)
4. Upload Artifacts Uploads packages as artifacts (90-day retention) for release attachment.
Outputs¶
sdk-version: PEP 440 compliant version string
7. build-typescript-sdk¶
Builds and publishes TypeScript SDK to GitHub Packages npm registry.
Steps¶
1. Download Generated Source Downloads the TypeScript SDK source from build-and-test artifacts.
2. Version Update
3. Build Package
Compiles TypeScript to JavaScript, generates type definitions, and creates distributable package.
4. Publish to GitHub Packages
Publishes to https://npm.pkg.github.com/@luckboxstudios/foundry-sdk
npm Tags:
- Production builds: Tagged as latest (default install)
- PR builds: Tagged as pr (requires explicit version or tag)
Installation:
# Latest production version
npm install @luckboxstudios/foundry-sdk
# Specific PR version
npm install @luckboxstudios/foundry-sdk@2025.1015.0308.577-pr
# Latest PR build
npm install @luckboxstudios/foundry-sdk@pr
8. create-release¶
Creates GitHub Release with SDK packages and comprehensive release notes.
Steps¶
1. Download Python SDK Packages Downloads Python SDK artifacts for release attachment.
2. Create and Push Git Tag
TAG_NAME="v$VERSION"
git tag -a "$TAG_NAME" -m "Release version $VERSION"
git push origin "$TAG_NAME"
3. Create GitHub Release
Uses softprops/action-gh-release@v1 to create release with:
Release Notes Template:
## LBS Foundry Release {VERSION}
### Container Images
- **LBS API**: `{REGISTRY}/lbs-foundry-api:{VERSION}`
- **Ballr API**: `{REGISTRY}/ballr-web-api:{VERSION}`
- **MCP Server**: `{REGISTRY}/lbs-foundry-mcpserver:{VERSION}`
### SDK Packages
- **TypeScript SDK**: Published to GitHub Packages npm registry
```bash
npm install @luckboxstudios/foundry-sdk@{VERSION}
```
- **Python SDK**: Download from release assets below
```bash
pip install foundry_sdk-{VERSION}-py3-none-any.whl
```
### NuGet Packages
Published to GitHub Packages
Release Properties: - Prerelease: Automatically marked for PR builds - Assets: Python SDK packages (.whl and .tar.gz) - Notes: Auto-generated from commits since last release
Environment Variables¶
Required secrets in GitHub repository settings:
| Secret | Description | Used By |
|---|---|---|
ACR_REGISTRY |
Azure Container Registry URL | Container builds |
ACR_USERNAME |
ACR username | Container builds |
ACR_PASSWORD |
ACR password | Container builds |
NUGET_PUBLISH_TOKEN |
GitHub token for NuGet publishing | NuGet push |
GITHUB_TOKEN |
Automatic GitHub token | SDK publishing, releases |
Build Artifacts¶
Temporary Artifacts (1-day retention)¶
typescript-sdk-source: Generated TypeScript SDK source codepython-sdk-source: Generated Python SDK source code
Permanent Artifacts (90-day retention)¶
test-results: Unit test results (TRX format)typescript-generation-log: TypeScript SDK generation logpython-generation-log: Python SDK generation logpython-sdk-{VERSION}: Python SDK packages
Package Distribution¶
NuGet Packages¶
Location: GitHub Packages
URL: https://nuget.pkg.github.com/luckboxstudios/index.json
Authentication: Required (GitHub PAT)
Installation:
dotnet add package LBS.Anchor --version {VERSION}
dotnet add package LBS.EventSourcing --version {VERSION}
TypeScript SDK¶
Location: GitHub Packages (npm registry)
URL: https://npm.pkg.github.com/@luckboxstudios
Authentication: Required (GitHub PAT)
Installation:
# Configure npm registry
echo "@luckboxstudios:registry=https://npm.pkg.github.com" >> .npmrc
echo "//npm.pkg.github.com/:_authToken=${GITHUB_TOKEN}" >> .npmrc
# Install package
npm install @luckboxstudios/foundry-sdk@{VERSION}
Python SDK¶
Location: GitHub Releases (downloadable assets)
URL: https://github.com/luckboxstudios/LBS.Foundry/releases
Authentication: Not required for public releases
Installation:
Container Images¶
Location: Azure Container Registry
URL: Configured in ACR_REGISTRY secret
Authentication: Required (ACR credentials)
Pull Images:
docker pull {REGISTRY}/lbs-foundry-api:{VERSION}
docker pull {REGISTRY}/ballr-web-api:{VERSION}
docker pull {REGISTRY}/lbs-foundry-mcpserver:{VERSION}
Troubleshooting¶
Build Failures¶
Tests Failing
# Run locally to reproduce (xUnit v3 — use `dotnet run`, not `dotnet test`)
dotnet run --project src/Tests/LBS.UnitTests/LBS.UnitTests.csproj
# Check test results artifact in GitHub Actions
SDK Generation Fails
# Run locally
dotnet run --project src/Tools/LBS.Tools.SdkGenerator/LBS.Tools.SdkGenerator.csproj \
--configuration Release -- \
"src/Apps/Ballr.WebApi/bin/Release/net10.0" \
"/path/to/dotnet/ref/net10.0" \
"sdk/typescript/generated" \
--language typescript
# Check generation logs in artifacts
Docker Build Fails
# Test Docker build locally
docker build --target final-api -t test-api .
# Check Dockerfile and build context
Publishing Failures¶
NuGet Push Fails
- Verify NUGET_PUBLISH_TOKEN is valid
- Check package version doesn't already exist
- Ensure GitHub Packages is enabled
npm Publish Fails
- Verify GITHUB_TOKEN has package write permissions
- Check package version doesn't already exist
- Ensure package.json has correct registry configuration
Release Creation Fails - Verify all prerequisite jobs succeeded - Check Python SDK artifacts exist - Ensure tag doesn't already exist
Version Strategy¶
Production Releases (main branch)¶
Components:
- YYYY: 4-digit year
- MM: 2-digit month
- DD: 2-digit day
- HH: 2-digit hour (UTC)
- mm: 2-digit minute (UTC)
- RUN_NUMBER: GitHub Actions run number
Benefits: - Sortable by version number - Identifies build time instantly - Unique for every build - Compatible with semantic versioning tools
Prerelease Versions (PRs)¶
Characteristics:
- Marked as prerelease in GitHub
- Not considered stable
- Automatically cleaned up
- Python uses PEP 440 .dev0 suffix
Workflow Modifications¶
Adding a New Job¶
-
Define job in
.github/workflows/Build-Container-Apps.yml: -
Add to
create-releasedependencies:
Adding a New Package¶
-
Ensure project is packable in
.csproj: -
Add to solution:
-
Build pipeline automatically packs and publishes
Modifying SDK Generation¶
Edit generation commands in build-and-test job:
- name: Generate TypeScript SDK
run: |
dotnet run --project src/Tools/LBS.Tools.SdkGenerator/... \
"src/Apps/Ballr.WebApi/bin/Release/net10.0" \
... \
--language typescript \
--new-option value # Add new options here
Performance Optimization¶
Parallel Job Execution¶
Jobs run in parallel when possible:
build-and-test (sequential steps)
↓
├─ build-lbs-api ────────┐
├─ build-ballr-api ──────┤
├─ build-mcp-server ─────┤ (parallel)
├─ build-foundry-web ────┤
├─ build-python-sdk ─────┤
└─ build-typescript-sdk ─┘
↓
create-release
Caching Strategy¶
Docker Layer Caching: - Uses Docker BuildKit - Caches intermediate layers - Reduces rebuild time
NuGet Caching:
npm Caching:
Build Time Optimization¶
Current build times (approximate): - build-and-test: 4-6 minutes - Container builds: 2-3 minutes each (parallel) - SDK builds: 1-2 minutes each (parallel) - Total pipeline: 6-10 minutes
Optimization tips:
- Keep Docker images small
- Use --no-build for already-built projects
- Minimize test execution time
- Use efficient test runners
Security Considerations¶
Secret Management¶
- Never log secrets
- Rotate secrets regularly
- Use minimal required permissions
- Audit secret access
Container Security¶
- Images scanned by Azure Security Center
- Base images regularly updated
- No secrets in container images
- Runtime security monitoring
Package Security¶
- Dependency scanning enabled
- Vulnerability alerts configured
- Regular dependency updates
- Code signing for packages
Monitoring and Alerts¶
Build Health¶
- GitHub Actions dashboard
- Email notifications on failure
- Slack/Teams integration (optional)
Package Health¶
- NuGet package stats
- npm download metrics
- Container pull statistics
Release Tracking¶
- GitHub Release notes
- Version tags in Git
- Changelog generation
Related Documentation¶
- SDK Generation - Detailed SDK generation process
- Common Tasks - Development workflows
- Development Workflow - Team practices
- Security - Authentication and authorization
Quick Reference¶
Check Pipeline Status¶
# View recent runs
gh run list --workflow="Build and Push Container Images"
# View specific run
gh run view RUN_ID
# View failed jobs
gh run view RUN_ID --log-failed
Trigger Manual Run¶
Download Artifacts¶
# List artifacts for a run
gh run view RUN_ID --json artifacts
# Download specific artifact
gh run download RUN_ID --name python-sdk-VERSION