1+ name : Deterministic Build
2+
3+ on :
4+ # Trigger on push and pull requests to main branch
5+ push :
6+ branches : [ main ]
7+ paths :
8+ - ' src/**'
9+ - ' .github/workflows/deterministic-build.yml'
10+ pull_request :
11+ branches : [ main ]
12+ paths :
13+ - ' src/**'
14+ - ' .github/workflows/deterministic-build.yml'
15+
16+ # Allow manual trigger
17+ workflow_dispatch :
18+
19+ env :
20+ DOTNET_VERSION : ' 9.0.x'
21+ CI : true
22+
23+ jobs :
24+ deterministic-build :
25+ name : Deterministic Build
26+ runs-on : ubuntu-latest
27+
28+ strategy :
29+ matrix :
30+ solution :
31+ - name : Analyzers
32+ path : src/Codebreaker.Analyzers.slnx
33+ project : src/services/common/Codebreaker.GameAPIs.Analyzers/Codebreaker.Analyzers.csproj
34+ - name : Backend-Models
35+ path : src/Codebreaker.Backend.Models.slnx
36+ project : src/services/common/Codebreaker.GameAPIs.Models/Codebreaker.GameAPIs.Models.csproj
37+ - name : Cosmos
38+ path : src/Codebreaker.Backend.Cosmos.slnx
39+ project : src/services/common/Codebreaker.Data.Cosmos/Codebreaker.Data.Cosmos.csproj
40+ - name : SqlServer
41+ path : src/Codebreaker.Backend.SqlServer.slnx
42+ project : src/services/common/Codebreaker.Data.SqlServer/Codebreaker.Data.SqlServer.csproj
43+ - name : Postgres
44+ path : src/Codebreaker.Backend.Postgres.slnx
45+ project : src/services/common/Codebreaker.Data.Postgres/Codebreaker.Data.Postgres.csproj
46+ - name : GameAPIs-Client
47+ path : src/Codebreaker.GameAPIs.Client.slnx
48+ project : src/clients/Codebreaker.GameAPIs.Client/Codebreaker.GameAPIs.Client.csproj
49+
50+ steps :
51+ - name : Checkout repository
52+ uses : actions/checkout@v5
53+ with :
54+ # Fetch all history for proper source control information
55+ fetch-depth : 0
56+
57+ - name : Setup .NET
58+ uses : actions/setup-dotnet@v5
59+ with :
60+ dotnet-version : ${{ env.DOTNET_VERSION }}
61+
62+ - name : Restore dependencies
63+ run : dotnet restore ${{ matrix.solution.path }}
64+
65+ - name : Build solution (deterministic)
66+ run : |
67+ echo "Building ${{ matrix.solution.name }} with deterministic settings..."
68+ dotnet build ${{ matrix.solution.path }} \
69+ --configuration Release \
70+ --no-restore \
71+ --verbosity normal \
72+ /p:ContinuousIntegrationBuild=true \
73+ /p:Deterministic=true \
74+ /p:EmbedUntrackedSources=true \
75+ /p:DebugType=embedded \
76+ /p:PublishRepositoryUrl=true
77+
78+ - name : Run tests
79+ run : dotnet test ${{ matrix.solution.path }} --configuration Release --no-build --verbosity normal
80+
81+ - name : Create NuGet package (deterministic)
82+ run : |
83+ echo "Creating deterministic NuGet package for ${{ matrix.solution.name }}..."
84+ dotnet pack ${{ matrix.solution.project }} \
85+ --configuration Release \
86+ --no-build \
87+ --output ./packages \
88+ /p:ContinuousIntegrationBuild=true \
89+ /p:Deterministic=true \
90+ /p:EmbedUntrackedSources=true \
91+ /p:DebugType=embedded \
92+ /p:PublishRepositoryUrl=true
93+
94+ - name : Verify deterministic build
95+ shell : bash
96+ run : |
97+ echo "Verifying deterministic build for ${{ matrix.solution.name }}..."
98+
99+ # Create a second build to compare determinism
100+ rm -rf ./packages-verify
101+ mkdir ./packages-verify
102+
103+ echo "Building second time for verification..."
104+ dotnet pack ${{ matrix.solution.project }} \
105+ --configuration Release \
106+ --no-build \
107+ --output ./packages-verify \
108+ /p:ContinuousIntegrationBuild=true \
109+ /p:Deterministic=true \
110+ /p:EmbedUntrackedSources=true \
111+ /p:DebugType=embedded \
112+ /p:PublishRepositoryUrl=true
113+
114+ # Compare the packages (basic check - file sizes should be identical)
115+ echo "Comparing package files..."
116+ ls -la ./packages/
117+ ls -la ./packages-verify/
118+
119+ # Check if the files have the same size
120+ for file in ./packages/*.nupkg; do
121+ filename=$(basename "$file")
122+ if [ -f "./packages-verify/$filename" ]; then
123+ size1=$(stat -c%s "./packages/$filename")
124+ size2=$(stat -c%s "./packages-verify/$filename")
125+ echo "Package $filename: Original size=$size1, Verify size=$size2"
126+ if [ "$size1" != "$size2" ]; then
127+ echo "ERROR: Package sizes differ! Build is not deterministic."
128+ exit 1
129+ fi
130+ else
131+ echo "ERROR: Verification package $filename not found!"
132+ exit 1
133+ fi
134+ done
135+
136+ echo "✅ Deterministic build verification passed for ${{ matrix.solution.name }}"
137+
138+ - name : Upload build artifacts
139+ uses : actions/upload-artifact@v4
140+ with :
141+ name : deterministic-packages-${{ matrix.solution.name }}
142+ path : |
143+ ./packages/*.nupkg
144+ ./packages/*.snupkg
145+ retention-days : 7
146+ compression-level : 6
147+
148+ summary :
149+ name : Build Summary
150+ runs-on : ubuntu-latest
151+ needs : deterministic-build
152+ if : always()
153+
154+ steps :
155+ - name : Build Summary
156+ run : |
157+ echo "## Deterministic Build Summary" >> $GITHUB_STEP_SUMMARY
158+ echo "" >> $GITHUB_STEP_SUMMARY
159+ echo "All library solutions have been built with deterministic settings:" >> $GITHUB_STEP_SUMMARY
160+ echo "- ✅ ContinuousIntegrationBuild=true" >> $GITHUB_STEP_SUMMARY
161+ echo "- ✅ Deterministic=true" >> $GITHUB_STEP_SUMMARY
162+ echo "- ✅ EmbedUntrackedSources=true" >> $GITHUB_STEP_SUMMARY
163+ echo "- ✅ DebugType=embedded" >> $GITHUB_STEP_SUMMARY
164+ echo "- ✅ PublishRepositoryUrl=true" >> $GITHUB_STEP_SUMMARY
165+ echo "" >> $GITHUB_STEP_SUMMARY
166+ echo "Build artifacts have been uploaded and are available for download." >> $GITHUB_STEP_SUMMARY
167+ echo "" >> $GITHUB_STEP_SUMMARY
168+ echo "### Solutions Built:" >> $GITHUB_STEP_SUMMARY
169+ echo "- Analyzers" >> $GITHUB_STEP_SUMMARY
170+ echo "- Backend Models" >> $GITHUB_STEP_SUMMARY
171+ echo "- Cosmos DB Library" >> $GITHUB_STEP_SUMMARY
172+ echo "- SQL Server Library" >> $GITHUB_STEP_SUMMARY
173+ echo "- PostgreSQL Library" >> $GITHUB_STEP_SUMMARY
174+ echo "- GameAPIs Client Library" >> $GITHUB_STEP_SUMMARY
0 commit comments