Skip to content

Commit 3d4d0ea

Browse files
committed
clean up and future proof
Excellent questions! Let me address both concerns: ## 1. Single Binary Releases with .NET 9 AOT Yes! .NET 9 with AOT (Ahead-of-Time compilation) can produce single, self-contained native binaries that don't require .NET runtime or Docker. Here's an updated GitHub Actions workflow that creates binary releases: ```yaml name: Build, Test, and Release on: push: branches: [ master, main ] tags: [ 'v*' ] pull_request: branches: [ master, main ] workflow_dispatch: jobs: test: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - name: Build and Test Docker run: | docker build -t tsp-solver:latest . echo -e "2\n5\n5\n" | timeout 10s docker run --rm -i tsp-solver:latest || true build-binaries: strategy: matrix: include: # Windows - os: windows-latest rid: win-x64 artifact: TSP-win-x64.exe build_cmd: dotnet publish -c Release -r win-x64 --self-contained -p:PublishAot=true -p:PublishSingleFile=true # Linux x64 - os: ubuntu-latest rid: linux-x64 artifact: TSP-linux-x64 build_cmd: dotnet publish -c Release -r linux-x64 --self-contained -p:PublishAot=true -p:PublishSingleFile=true # Linux ARM64 - os: ubuntu-latest rid: linux-arm64 artifact: TSP-linux-arm64 build_cmd: | sudo apt-get update sudo apt-get install -y gcc-aarch64-linux-gnu dotnet publish -c Release -r linux-arm64 --self-contained -p:PublishAot=true -p:PublishSingleFile=true # macOS x64 - os: macos-13 # Intel Mac rid: osx-x64 artifact: TSP-macos-x64 build_cmd: dotnet publish -c Release -r osx-x64 --self-contained -p:PublishAot=true -p:PublishSingleFile=true # macOS ARM64 (Apple Silicon) - os: macos-14 # M1/M2 Mac rid: osx-arm64 artifact: TSP-macos-arm64 build_cmd: dotnet publish -c Release -r osx-arm64 --self-contained -p:PublishAot=true -p:PublishSingleFile=true runs-on: ${{ matrix.os }} steps: - uses: actions/checkout@v4 - name: Setup .NET uses: actions/setup-dotnet@v4 with: dotnet-version: '9.0.x' - name: Install dependencies run: dotnet restore TSP.sln - name: Build AOT Binary shell: bash run: | cd TravelingSalesman.ConsoleApp ${{ matrix.build_cmd }} - name: Prepare artifact shell: bash run: | if [[ "${{ matrix.os }}" == "windows-latest" ]]; then mv TravelingSalesman.ConsoleApp/bin/Release/net9.0/${{ matrix.rid }}/publish/TravelingSalesman.ConsoleApp.exe ${{ matrix.artifact }} else mv TravelingSalesman.ConsoleApp/bin/Release/net9.0/${{ matrix.rid }}/publish/TravelingSalesman.ConsoleApp ${{ matrix.artifact }} chmod +x ${{ matrix.artifact }} fi # Create size info ls -lh ${{ matrix.artifact }} > size-info-${{ matrix.rid }}.txt - name: Upload binary uses: actions/upload-artifact@v4 with: name: binary-${{ matrix.rid }} path: | ${{ matrix.artifact }} size-info-${{ matrix.rid }}.txt create-release: if: startsWith(github.ref, 'refs/tags/v') needs: [test, build-binaries] runs-on: ubuntu-latest permissions: contents: write steps: - uses: actions/checkout@v4 - name: Download all artifacts uses: actions/download-artifact@v4 with: path: ./artifacts - name: Display structure run: ls -la ./artifacts/*/ - name: Create Release uses: softprops/action-gh-release@v1 with: files: | ./artifacts/binary-*/* body: | ## TSP Solver Release ### 🚀 Single Binary Executables No .NET runtime or Docker required! Just download and run. ### 📦 Available Platforms: - **Windows x64**: `TSP-win-x64.exe` - **Linux x64**: `TSP-linux-x64` - **Linux ARM64**: `TSP-linux-arm64` - **macOS x64 (Intel)**: `TSP-macos-x64` - **macOS ARM64 (M1/M2)**: `TSP-macos-arm64` ### 🏃 Usage: ```bash # Linux/macOS chmod +x TSP-linux-x64 ./TSP-linux-x64 # Windows TSP-win-x64.exe ``` draft: false prerelease: false ``` To trigger a release, create a git tag: ```powershell git tag v1.0.0 git push origin v1.0.0 ``` ## 2. .NET Version Management - Avoiding Annual Ceremony You're absolutely right about the version churn. Here's a better approach using MSBuild properties to centralize version management: ### Create a `Directory.Build.props` file in your repository root: ```xml <Project> <PropertyGroup> <!-- Centralized .NET version management --> <TargetFramework>net9.0</TargetFramework> <DotNetVersion>9.0</DotNetVersion> <DotNetChannel>9.0</DotNetChannel> <!-- When .NET 10 releases, just update these three lines --> <!-- <TargetFramework>net10.0</TargetFramework> --> <!-- <DotNetVersion>10.0</DotNetVersion> --> <!-- <DotNetChannel>10.0</DotNetChannel> --> <!-- Shared project settings --> <ImplicitUsings>enable</ImplicitUsings> <Nullable>enable</Nullable> <TreatWarningsAsErrors>true</TreatWarningsAsErrors> <AnalysisLevel>latest</AnalysisLevel> <!-- AOT settings for console apps --> <PublishAot Condition="'$(OutputType)' == 'Exe'">true</PublishAot> <InvariantGlobalization Condition="'$(PublishAot)' == 'true'">true</InvariantGlobalization> </PropertyGroup> </Project> ``` ### Simplified `TravelingSalesman.ConsoleApp.csproj`: ```xml <Project Sdk="Microsoft.NET.Sdk"> <PropertyGroup> <OutputType>Exe</OutputType> <!-- TargetFramework inherited from Directory.Build.props --> </PropertyGroup> <ItemGroup> <ProjectReference Include="..\TravelingSalesman.Core\TravelingSalesman.Core.csproj" /> </ItemGroup> </Project> ``` ### Simplified `TravelingSalesman.Core.csproj`: ```xml <Project Sdk="Microsoft.NET.Sdk"> <!-- Everything inherited from Directory.Build.props --> </Project> ``` ### Multi-version Dockerfile using build arguments: ```dockerfile # Default to .NET 9, but allow override ARG DOTNET_VERSION=9.0 FROM mcr.microsoft.com/dotnet/runtime:${DOTNET_VERSION} AS base USER $APP_UID WORKDIR /app FROM mcr.microsoft.com/dotnet/sdk:${DOTNET_VERSION} AS build RUN apt-get update && apt-get install -y --no-install-recommends clang zlib1g-dev ARG BUILD_CONFIGURATION=Release WORKDIR /src COPY ["*.sln", "./"] COPY ["Directory.Build.props", "./"] COPY ["TravelingSalesman.ConsoleApp/*.csproj", "TravelingSalesman.ConsoleApp/"] COPY ["TravelingSalesman.Core/*.csproj", "TravelingSalesman.Core/"] RUN dotnet restore COPY . . WORKDIR "/src/TravelingSalesman.ConsoleApp" RUN dotnet build -c $BUILD_CONFIGURATION -o /app/build FROM build AS publish RUN dotnet publish -c $BUILD_CONFIGURATION -o /app/publish /p:UseAppHost=true FROM mcr.microsoft.com/dotnet/runtime-deps:${DOTNET_VERSION} AS final WORKDIR /app COPY --from=publish /app/publish . ENTRYPOINT ["./TravelingSalesman.ConsoleApp"] ``` ### Future-proof GitHub Actions with matrix builds: ```yaml name: Multi-Version Build on: push: workflow_dispatch: jobs: build: strategy: matrix: dotnet: ['9.0', '10.0'] # Easy to add versions continue-on-error: true # Don't fail if 10.0 isn't out yet runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - name: Setup .NET ${{ matrix.dotnet }} uses: actions/setup-dotnet@v4 with: dotnet-version: ${{ matrix.dotnet }}.x continue-on-error: true - name: Build with .NET ${{ matrix.dotnet }} run: | dotnet --version dotnet build TSP.sln continue-on-error: ${{ matrix.dotnet == '10.0' }} ``` ## Summary of Benefits: 1. **Single Binary Releases**: Yes, AOT produces true single-file executables (~10-30MB) that work without any runtime 2. **Version Management**: With `Directory.Build.props`, updating to .NET 10 requires changing just 3 lines 3. **Future-Proof CI/CD**: Matrix builds can test multiple .NET versions simultaneously 4. **Cross-Platform**: Automatic builds for all major platforms The AOT binaries are perfect for distribution - users just download and run, no installation needed!
1 parent 3792624 commit 3d4d0ea

File tree

3 files changed

+405
-1492
lines changed

3 files changed

+405
-1492
lines changed
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
name: Multi-Version Build
2+
3+
on:
4+
push:
5+
workflow_dispatch:
6+
7+
jobs:
8+
build:
9+
strategy:
10+
matrix:
11+
dotnet: ['9.0', '10.0'] # Easy to add versions
12+
continue-on-error: true # Don't fail if 10.0 isn't out yet
13+
14+
runs-on: ubuntu-latest
15+
16+
steps:
17+
- uses: actions/checkout@v4
18+
19+
- name: Setup .NET ${{ matrix.dotnet }}
20+
uses: actions/setup-dotnet@v4
21+
with:
22+
dotnet-version: ${{ matrix.dotnet }}.x
23+
continue-on-error: true
24+
25+
- name: Build with .NET ${{ matrix.dotnet }}
26+
run: |
27+
dotnet --version
28+
dotnet build TSP.sln
29+
continue-on-error: ${{ matrix.dotnet == '10.0' }}

.github/workflows/release.yml

Lines changed: 144 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,144 @@
1+
name: Build, Test, and Release
2+
3+
on:
4+
push:
5+
branches: [ master, main ]
6+
tags: [ 'v*' ]
7+
pull_request:
8+
branches: [ master, main ]
9+
workflow_dispatch:
10+
11+
jobs:
12+
test:
13+
runs-on: ubuntu-latest
14+
steps:
15+
- uses: actions/checkout@v4
16+
- name: Build and Test Docker
17+
run: |
18+
docker build -t tsp-solver:latest .
19+
echo -e "2\n5\n5\n" | timeout 10s docker run --rm -i tsp-solver:latest || true
20+
21+
build-binaries:
22+
strategy:
23+
matrix:
24+
include:
25+
# Windows
26+
- os: windows-latest
27+
rid: win-x64
28+
artifact: TSP-win-x64.exe
29+
build_cmd: dotnet publish -c Release -r win-x64 --self-contained -p:PublishAot=true -p:PublishSingleFile=true
30+
31+
# Linux x64
32+
- os: ubuntu-latest
33+
rid: linux-x64
34+
artifact: TSP-linux-x64
35+
build_cmd: dotnet publish -c Release -r linux-x64 --self-contained -p:PublishAot=true -p:PublishSingleFile=true
36+
37+
# Linux ARM64
38+
- os: ubuntu-latest
39+
rid: linux-arm64
40+
artifact: TSP-linux-arm64
41+
build_cmd: |
42+
sudo apt-get update
43+
sudo apt-get install -y gcc-aarch64-linux-gnu
44+
dotnet publish -c Release -r linux-arm64 --self-contained -p:PublishAot=true -p:PublishSingleFile=true
45+
46+
# macOS x64
47+
- os: macos-13 # Intel Mac
48+
rid: osx-x64
49+
artifact: TSP-macos-x64
50+
build_cmd: dotnet publish -c Release -r osx-x64 --self-contained -p:PublishAot=true -p:PublishSingleFile=true
51+
52+
# macOS ARM64 (Apple Silicon)
53+
- os: macos-14 # M1/M2 Mac
54+
rid: osx-arm64
55+
artifact: TSP-macos-arm64
56+
build_cmd: dotnet publish -c Release -r osx-arm64 --self-contained -p:PublishAot=true -p:PublishSingleFile=true
57+
58+
runs-on: ${{ matrix.os }}
59+
60+
steps:
61+
- uses: actions/checkout@v4
62+
63+
- name: Setup .NET
64+
uses: actions/setup-dotnet@v4
65+
with:
66+
dotnet-version: '9.0.x'
67+
68+
- name: Install dependencies
69+
run: dotnet restore TSP.sln
70+
71+
- name: Build AOT Binary
72+
shell: bash
73+
run: |
74+
cd TravelingSalesman.ConsoleApp
75+
${{ matrix.build_cmd }}
76+
77+
- name: Prepare artifact
78+
shell: bash
79+
run: |
80+
if [[ "${{ matrix.os }}" == "windows-latest" ]]; then
81+
mv TravelingSalesman.ConsoleApp/bin/Release/net9.0/${{ matrix.rid }}/publish/TravelingSalesman.ConsoleApp.exe ${{ matrix.artifact }}
82+
else
83+
mv TravelingSalesman.ConsoleApp/bin/Release/net9.0/${{ matrix.rid }}/publish/TravelingSalesman.ConsoleApp ${{ matrix.artifact }}
84+
chmod +x ${{ matrix.artifact }}
85+
fi
86+
87+
# Create size info
88+
ls -lh ${{ matrix.artifact }} > size-info-${{ matrix.rid }}.txt
89+
90+
- name: Upload binary
91+
uses: actions/upload-artifact@v4
92+
with:
93+
name: binary-${{ matrix.rid }}
94+
path: |
95+
${{ matrix.artifact }}
96+
size-info-${{ matrix.rid }}.txt
97+
98+
create-release:
99+
if: startsWith(github.ref, 'refs/tags/v')
100+
needs: [test, build-binaries]
101+
runs-on: ubuntu-latest
102+
permissions:
103+
contents: write
104+
105+
steps:
106+
- uses: actions/checkout@v4
107+
108+
- name: Download all artifacts
109+
uses: actions/download-artifact@v4
110+
with:
111+
path: ./artifacts
112+
113+
- name: Display structure
114+
run: ls -la ./artifacts/*/
115+
116+
- name: Create Release
117+
uses: softprops/action-gh-release@v1
118+
with:
119+
files: |
120+
./artifacts/binary-*/*
121+
body: |
122+
## TSP Solver Release
123+
124+
### 🚀 Single Binary Executables
125+
No .NET runtime or Docker required! Just download and run.
126+
127+
### 📦 Available Platforms:
128+
- **Windows x64**: `TSP-win-x64.exe`
129+
- **Linux x64**: `TSP-linux-x64`
130+
- **Linux ARM64**: `TSP-linux-arm64`
131+
- **macOS x64 (Intel)**: `TSP-macos-x64`
132+
- **macOS ARM64 (M1/M2)**: `TSP-macos-arm64`
133+
134+
### 🏃 Usage:
135+
```bash
136+
# Linux/macOS
137+
chmod +x TSP-linux-x64
138+
./TSP-linux-x64
139+
140+
# Windows
141+
TSP-win-x64.exe
142+
```
143+
draft: false
144+
prerelease: false

0 commit comments

Comments
 (0)