add all files #36
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| name: Continuous Release | |
| on: | |
| push: | |
| branches: [ master ] | |
| pull_request: | |
| branches: [ master ] | |
| workflow_dispatch: | |
| env: | |
| DOTNET_VERSION: '9.0.x' | |
| DOTNET_CLI_TELEMETRY_OPTOUT: 1 | |
| DOTNET_SKIP_FIRST_TIME_EXPERIENCE: 1 | |
| jobs: | |
| build-and-release: | |
| strategy: | |
| fail-fast: false | |
| matrix: | |
| include: | |
| - os: windows-latest | |
| rid: win-x64 | |
| binary_extension: .exe | |
| - os: ubuntu-latest | |
| rid: linux-x64 | |
| binary_extension: "" | |
| - os: macos-latest | |
| rid: osx-x64 | |
| binary_extension: "" | |
| - os: macos-latest | |
| rid: osx-arm64 | |
| binary_extension: "" | |
| runs-on: ${{ matrix.os }} | |
| steps: | |
| - uses: actions/checkout@v4 | |
| with: | |
| fetch-depth: 0 | |
| - name: Generate version info | |
| id: version | |
| shell: bash | |
| run: | | |
| # Generate a more stable version format | |
| YEAR_SHORT=$(($(date +'%Y') - 2000)) | |
| MONTH=$((10#$(date +'%m'))) | |
| DAY=$((10#$(date +'%d'))) | |
| # Get build number from commits, but keep it reasonable | |
| RAW_BUILD=$(git rev-list --count HEAD) | |
| BUILD_NUMBER=$((RAW_BUILD % 10000 + 1000)) # Keep between 1000-10999 | |
| SHORT_SHA=$(git rev-parse --short=8 HEAD) | |
| # Create semantic version (max 4 parts for .NET) | |
| VERSION="${YEAR_SHORT}.${MONTH}.${DAY}.${BUILD_NUMBER}" | |
| FULL_VERSION="${VERSION}-${SHORT_SHA}" | |
| echo "version=${VERSION}" >> $GITHUB_OUTPUT | |
| echo "full_version=${FULL_VERSION}" >> $GITHUB_OUTPUT | |
| echo "sha=${SHORT_SHA}" >> $GITHUB_OUTPUT | |
| echo "build_number=${BUILD_NUMBER}" >> $GITHUB_OUTPUT | |
| echo "Generated versions:" | |
| echo " Assembly version: ${VERSION}" | |
| echo " Full version: ${FULL_VERSION}" | |
| echo " Commit: ${SHORT_SHA}" | |
| - name: Setup .NET | |
| uses: actions/setup-dotnet@v4 | |
| with: | |
| dotnet-version: ${{ env.DOTNET_VERSION }} | |
| - name: Update version in Directory.Build.props | |
| shell: bash | |
| run: | | |
| echo "Updating version information..." | |
| # Create a new Directory.Build.props with updated versions | |
| cat > Directory.Build.props.new << 'EOF' | |
| <Project> | |
| <PropertyGroup> | |
| <Version>${{ steps.version.outputs.version }}</Version> | |
| <AssemblyVersion>${{ steps.version.outputs.version }}</AssemblyVersion> | |
| <FileVersion>${{ steps.version.outputs.version }}</FileVersion> | |
| <InformationalVersion>${{ steps.version.outputs.full_version }}</InformationalVersion> | |
| EOF | |
| # Append the rest of the original file (skip the first few version lines) | |
| tail -n +8 Directory.Build.props >> Directory.Build.props.new | |
| mv Directory.Build.props.new Directory.Build.props | |
| echo "Updated Directory.Build.props:" | |
| head -10 Directory.Build.props | |
| - name: Restore dependencies | |
| run: dotnet restore TSP.sln | |
| - name: Build native binary | |
| shell: bash | |
| run: | | |
| echo "Building for ${{ matrix.rid }}..." | |
| # Ensure output directory exists | |
| mkdir -p artifacts | |
| dotnet publish TravelingSalesman.ConsoleApp/TravelingSalesman.ConsoleApp.csproj \ | |
| -c Release \ | |
| -r ${{ matrix.rid }} \ | |
| --self-contained \ | |
| -p:PublishAot=true \ | |
| -p:PublishSingleFile=true \ | |
| -p:PublishTrimmed=true \ | |
| -o ./publish-${{ matrix.rid }} \ | |
| --verbosity minimal | |
| echo "Build completed. Files in publish directory:" | |
| ls -la ./publish-${{ matrix.rid }}/ | |
| # Create final binary name | |
| BINARY_NAME="TSP-${{ matrix.rid }}-${{ steps.version.outputs.sha }}${{ matrix.binary_extension }}" | |
| # Move and rename the binary | |
| if [[ "${{ matrix.rid }}" == win-* ]]; then | |
| mv "./publish-${{ matrix.rid }}/TravelingSalesman.ConsoleApp.exe" "./artifacts/${BINARY_NAME}" | |
| else | |
| mv "./publish-${{ matrix.rid }}/TravelingSalesman.ConsoleApp" "./artifacts/${BINARY_NAME}" | |
| chmod +x "./artifacts/${BINARY_NAME}" | |
| fi | |
| echo "Binary created: ${BINARY_NAME}" | |
| ls -lah ./artifacts/ | |
| - name: Test binary functionality | |
| shell: bash | |
| continue-on-error: true | |
| run: | | |
| echo "Testing binary functionality..." | |
| cd artifacts | |
| BINARY_NAME="TSP-${{ matrix.rid }}-${{ steps.version.outputs.sha }}${{ matrix.binary_extension }}" | |
| if [ ! -f "$BINARY_NAME" ]; then | |
| echo "❌ Binary not found: $BINARY_NAME" | |
| ls -la | |
| exit 1 | |
| fi | |
| echo "✅ Binary exists: $BINARY_NAME ($(du -h "$BINARY_NAME" | cut -f1))" | |
| # Test execution with timeout and error handling | |
| echo "Testing binary execution..." | |
| if timeout 30s sh -c "echo -e '4\n5\n' | ./'$BINARY_NAME'" > test_output.log 2>&1; then | |
| echo "✅ Binary executed successfully" | |
| # Check for log directory creation | |
| if [ -d "logs" ]; then | |
| echo "✅ Logs directory created" | |
| if [ "$(ls -A logs 2>/dev/null)" ]; then | |
| echo "✅ Log files created:" | |
| ls -la logs/ | |
| echo "Sample log content (first 3 lines):" | |
| head -3 logs/* 2>/dev/null | head -10 || echo "No readable log content" | |
| else | |
| echo "⚠️ Logs directory empty" | |
| fi | |
| else | |
| echo "⚠️ Logs directory not created" | |
| fi | |
| # Show some output | |
| echo "Test output (first 20 lines):" | |
| head -20 test_output.log || echo "No output captured" | |
| else | |
| echo "⚠️ Binary test failed or timed out" | |
| echo "Test output:" | |
| cat test_output.log 2>/dev/null || echo "No output captured" | |
| fi | |
| - name: Upload build artifact | |
| uses: actions/upload-artifact@v4 | |
| with: | |
| name: binary-${{ matrix.rid }} | |
| path: | | |
| ./artifacts/TSP-${{ matrix.rid }}-${{ steps.version.outputs.sha }}${{ matrix.binary_extension }} | |
| ./artifacts/logs/ | |
| ./artifacts/test_output.log | |
| if-no-files-found: warn | |
| create-release: | |
| if: github.event_name == 'push' && github.ref == 'refs/heads/master' | |
| needs: build-and-release | |
| runs-on: ubuntu-latest | |
| permissions: | |
| contents: write | |
| steps: | |
| - uses: actions/checkout@v4 | |
| with: | |
| fetch-depth: 0 | |
| - name: Generate version info | |
| id: version | |
| shell: bash | |
| run: | | |
| # Use same logic as build job | |
| YEAR_SHORT=$(($(date +'%Y') - 2000)) | |
| MONTH=$((10#$(date +'%m'))) | |
| DAY=$((10#$(date +'%d'))) | |
| RAW_BUILD=$(git rev-list --count HEAD) | |
| BUILD_NUMBER=$((RAW_BUILD % 10000 + 1000)) | |
| SHORT_SHA=$(git rev-parse --short=8 HEAD) | |
| VERSION="${YEAR_SHORT}.${MONTH}.${DAY}.${BUILD_NUMBER}" | |
| FULL_VERSION="${VERSION}-${SHORT_SHA}" | |
| echo "version=${VERSION}" >> $GITHUB_OUTPUT | |
| echo "full_version=${FULL_VERSION}" >> $GITHUB_OUTPUT | |
| echo "sha=${SHORT_SHA}" >> $GITHUB_OUTPUT | |
| - name: Download all artifacts | |
| uses: actions/download-artifact@v4 | |
| with: | |
| path: ./artifacts | |
| - name: Debug artifact structure | |
| run: | | |
| echo "Downloaded artifacts structure:" | |
| find ./artifacts -type f -ls | head -30 | |
| echo "" | |
| echo "Looking for binaries:" | |
| find ./artifacts -name "TSP-*" -type f -ls | |
| - name: Prepare release assets | |
| run: | | |
| mkdir -p ./release-assets | |
| # Copy all binaries | |
| echo "Copying binaries..." | |
| find ./artifacts -name "TSP-*" -type f \( -name "*.exe" -o ! -name "*.*" \) -exec cp -v {} ./release-assets/ \; | |
| # Copy any log files that exist | |
| echo "Copying log files..." | |
| find ./artifacts -name "*.log" -type f -exec cp -v {} ./release-assets/ \; 2>/dev/null || echo "No log files found" | |
| # Create comprehensive version info | |
| cat > ./release-assets/version.txt << EOF | |
| TSP Solver Release Information | |
| ============================ | |
| Version: ${{ steps.version.outputs.full_version }} | |
| Assembly Version: ${{ steps.version.outputs.version }} | |
| Commit: ${{ github.sha }} | |
| Short SHA: ${{ steps.version.outputs.sha }} | |
| Branch: ${{ github.ref_name }} | |
| Build Date: $(date -u +'%Y-%m-%d %H:%M:%S UTC') | |
| Build Trigger: ${{ github.event_name }} | |
| Supported Platforms: | |
| - Windows x64 (Native AOT) | |
| - Linux x64 (Native AOT) | |
| - macOS x64 (Intel, Native AOT) | |
| - macOS ARM64 (Apple Silicon, Native AOT) | |
| Features: | |
| - Multiple TSP algorithms (Nearest Neighbor, 2-Opt, Simulated Annealing, Genetic Algorithm) | |
| - Comprehensive logging with Serilog (console + file) | |
| - Interactive and benchmark modes | |
| - Cross-platform native AOT compilation | |
| - Docker support | |
| - Single-file deployment | |
| Logging Details: | |
| - Console output for user interaction | |
| - Detailed file logging in logs/ directory | |
| - Daily rotating log files (30 day retention) | |
| - Structured logging for performance analysis | |
| - Debug-level logging for algorithm internals | |
| Usage Examples: | |
| # Interactive mode | |
| ./TSP-linux-x64-${{ steps.version.outputs.sha }} | |
| # Check version | |
| ./TSP-linux-x64-${{ steps.version.outputs.sha }} --version 2>/dev/null || echo "Run interactively" | |
| # View logs | |
| ls -la logs/ | |
| tail -f logs/tsp-solver-*.log | |
| EOF | |
| # Create checksums | |
| echo "Creating checksums..." | |
| cd ./release-assets | |
| find . -name "TSP-*" -type f -exec sha256sum {} \; > checksums.txt | |
| cd .. | |
| echo "Release assets prepared:" | |
| ls -la ./release-assets/ | |
| echo "" | |
| echo "Checksums:" | |
| cat ./release-assets/checksums.txt | |
| - name: Create Release | |
| uses: softprops/action-gh-release@v1 | |
| with: | |
| tag_name: v${{ steps.version.outputs.full_version }} | |
| name: TSP Solver v${{ steps.version.outputs.full_version }} | |
| draft: false | |
| prerelease: false | |
| generate_release_notes: true | |
| fail_on_unmatched_files: false | |
| files: | | |
| ./release-assets/* | |
| body: | | |
| ## 🚀 TSP Solver v${{ steps.version.outputs.full_version }} | |
| **Automated Release** - Built from commit [${{ steps.version.outputs.sha }}](${{ github.server_url }}/${{ github.repository }}/commit/${{ github.sha }}) | |
| ### 📦 Downloads | |
| | Platform | Download | Size | | |
| |----------|----------|------| | |
| | Windows x64 | [`TSP-win-x64-${{ steps.version.outputs.sha }}.exe`](../../releases/download/v${{ steps.version.outputs.full_version }}/TSP-win-x64-${{ steps.version.outputs.sha }}.exe) | Single executable | | |
| | Linux x64 | [`TSP-linux-x64-${{ steps.version.outputs.sha }}`](../../releases/download/v${{ steps.version.outputs.full_version }}/TSP-linux-x64-${{ steps.version.outputs.sha }}) | Single executable | | |
| | macOS Intel | [`TSP-osx-x64-${{ steps.version.outputs.sha }}`](../../releases/download/v${{ steps.version.outputs.full_version }}/TSP-osx-x64-${{ steps.version.outputs.sha }}) | Single executable | | |
| | macOS Apple Silicon | [`TSP-osx-arm64-${{ steps.version.outputs.sha }}`](../../releases/download/v${{ steps.version.outputs.full_version }}/TSP-osx-arm64-${{ steps.version.outputs.sha }}) | Single executable | | |
| 📋 **[version.txt](../../releases/download/v${{ steps.version.outputs.full_version }}/version.txt)** - Release information | |
| 📋 **[checksums.txt](../../releases/download/v${{ steps.version.outputs.full_version }}/checksums.txt)** - SHA256 checksums | |
| ### ✨ Key Features | |
| - 🧠 **Multiple Algorithms**: Nearest Neighbor, 2-Opt, Simulated Annealing, Genetic Algorithm | |
| - 📊 **Comprehensive Logging**: Console + file logging with Serilog | |
| - 🎯 **Interactive Mode**: Solve custom TSP instances with different city patterns | |
| - 🏆 **Benchmark Mode**: Compare all algorithms performance | |
| - 📈 **Performance Tracking**: Detailed metrics and algorithm progress reporting | |
| - 🐳 **Docker Support**: Containerized execution environment | |
| - ⚡ **Native AOT**: Fast startup, single-file deployment, no .NET runtime required | |
| - 🔄 **Cross-Platform**: Windows, Linux, macOS (Intel & ARM64) | |
| ### 📋 Quick Start | |
| ```bash | |
| # Download and run (Linux/macOS example) | |
| wget https://github.com/kusl/tsp/releases/download/v${{ steps.version.outputs.full_version }}/TSP-linux-x64-${{ steps.version.outputs.sha }} | |
| chmod +x TSP-linux-x64-${{ steps.version.outputs.sha }} | |
| ./TSP-linux-x64-${{ steps.version.outputs.sha }} | |
| # Check logs after running | |
| ls -la logs/ | |
| ``` | |
| ### 🔄 Recent Changes | |
| ${{ github.event.head_commit.message }} | |
| ### 📊 Algorithm Performance | |
| | Algorithm | Best For | Time Complexity | Quality | | |
| |-----------|----------|----------------|---------| | |
| | Nearest Neighbor | Quick results | O(n²) | Good | | |
| | 2-Opt | Improved solutions | O(n²) per iteration | Better | | |
| | Simulated Annealing | Avoiding local optima | O(n) per iteration | Very Good | | |
| | Genetic Algorithm | Large problems | O(p×g×n) | Best | | |
| --- | |
| 🔧 **Built with**: .NET 9 | Native AOT | Serilog Logging | GitHub Actions | |
| 📝 **License**: MIT | 🐛 **Issues**: [Report here](../../issues) | |
| - name: Workflow Summary | |
| if: always() | |
| run: | | |
| echo "## Release Workflow Summary" >> $GITHUB_STEP_SUMMARY | |
| echo "- **Version**: ${{ steps.version.outputs.full_version }}" >> $GITHUB_STEP_SUMMARY | |
| echo "- **Commit**: ${{ steps.version.outputs.sha }}" >> $GITHUB_STEP_SUMMARY | |
| echo "- **Release**: [v${{ steps.version.outputs.full_version }}](../../releases/tag/v${{ steps.version.outputs.full_version }})" >> $GITHUB_STEP_SUMMARY | |
| echo "- **Assets**: $(find ./release-assets -type f | wc -l) files prepared" >> $GITHUB_STEP_SUMMARY |