name: Build and Deploy on: push: branches: - master # Change to your default branch if different workflow_dispatch: inputs: environment: description: 'Environment to deploy to' required: true default: 'prod' type: choice options: - prod - dev - test restart_iis: description: 'Restart IIS after deployment' required: true default: true type: boolean create_release: description: 'Create release' required: true default: true type: boolean jobs: build: runs-on: self-hosted # Ensure your self-hosted runner is configured environment: ${{ github.event.inputs.environment || 'prod' }} steps: - name: Get Current User run: | $env:USERNAME - name: Checkout Repository uses: actions/checkout@v2 with: fetch-depth: 0 # Fetches all history and tags for versioning - name: Set up .NET uses: actions/setup-dotnet@v2 with: dotnet-version: '9.0' # Change to your required .NET version - name: Restore .NET Dependencies run: dotnet restore ./HomeApi.sln - name: Build .NET Project run: dotnet build --configuration Release ./HomeApi/HomeApi.csproj - name: Publish .NET Project run: | dotnet publish ./HomeApi/HomeApi.csproj --configuration Release --output ./output/dotnet --self-contained false --no-restore /p:PublishTrimmed=false /p:CopyOutputSymbolsToPublishDirectory=false # Verify wwwroot was published if (Test-Path -Path "./output/dotnet/wwwroot") { Write-Host "wwwroot folder was published successfully" } else { Write-Host "WARNING: wwwroot folder was not found in published output!" } # Check for Chrome-related files if (Test-Path -Path "./output/dotnet/Chrome") { Write-Host "Chrome folder was published successfully" } else { Write-Host "Chrome folder not found in published output" } if (Test-Path -Path "./output/dotnet/ChromeHeadlessShell") { Write-Host "ChromeHeadlessShell was published successfully" } else { Write-Host "ChromeHeadlessShell not found in published output" } - name: Generate SemVer version if: ${{ github.event.inputs.create_release != 'false' }} id: semver uses: ietf-tools/semver-action@v1 with: token: ${{ secrets.GITHUB_TOKEN }} branch: master # ← change to "main" if that's your default patchAll: true # fallbackTag: v0.0.1 # ← optionally bootstrap from an existing tag - name: Create GitHub Release if: ${{ github.event.inputs.create_release != 'false' }} id: create_release # ← this is required uses: actions/create-release@v1 env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} with: tag_name: ${{ steps.semver.outputs.next }} release_name: Release ${{ steps.semver.outputs.next }} draft: false prerelease: false - name: Zip the build for GitHub Release if: ${{ github.event.inputs.create_release != 'false' }} run: | Compress-Archive \ -Path './output/*' \ -DestinationPath "./output/HomeScreen_Build_${{ steps.semver.outputs.next }}.zip" \ -CompressionLevel Optimal -Force - name: Upload Release Asset if: ${{ github.event.inputs.create_release != 'false' }} uses: actions/upload-release-asset@v1 env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} with: upload_url: ${{ steps.create_release.outputs.upload_url }} # ← now available asset_path: ./output/HomeScreen_Build_${{ steps.semver.outputs.next }}.zip asset_name: HomeScreen_Build_${{ steps.semver.outputs.next }}.zip asset_content_type: application/zip - name: Generate appsettings.json run: | $appSettings = @{ Logging = @{ LogLevel = @{ Default = "Information" "Microsoft.AspNetCore" = "Warning" } } ApiConfiguration = @{ EspConfiguration = @{ InformationBoardImageUrl = "${{ vars.ESP_IMAGE_URL }}" UpdateIntervalMinutes = [int]"${{ vars.ESP_UPDATE_INTERVAL }}" BlackTextThreshold = [int]"${{ vars.ESP_BLACK_TEXT_THRESHOLD }}" EnableDithering = [System.Convert]::ToBoolean("${{ vars.ESP_ENABLE_DITHERING }}") DitheringStrength = [int]"${{ vars.ESP_DITHERING_STRENGTH }}" EnhanceContrast = [System.Convert]::ToBoolean("${{ vars.ESP_ENHANCE_CONTRAST }}") ContrastStrength = [int]"${{ vars.ESP_CONTRAST_STRENGTH }}" IsHighContrastMode = [System.Convert]::ToBoolean("${{ vars.ESP_HIGH_CONTRAST_MODE }}") } Keys = @{ Weather = "${{ secrets.WEATHER_API_KEY }}" ResRobot = "${{ secrets.RES_ROBOT_API_KEY }}" } BaseUrls = @{ Nominatim = "${{ vars.NOMINATIM_URL }}" Aurora = "${{ vars.AURORA_URL }}" Weather = "${{ vars.WEATHER_URL }}" ResRobot = "${{ vars.RES_ROBOT_URL }}" } DefaultCity = "${{ vars.DEFAULT_CITY }}" DefaultStation = "${{ vars.DEFAULT_STATION }}" } AllowedHosts = "*" } $appSettings | ConvertTo-Json -Depth 10 | Set-Content -Path "./output/dotnet/appsettings.json" Write-Host "Generated appsettings.json successfully" # Check wwwroot and manually copy if missing - name: Ensure wwwroot is Included run: | if (-not (Test-Path -Path "./output/dotnet/wwwroot")) { Write-Host "wwwroot folder not found in published output, manually copying..." # Check if wwwroot exists in project directory $sourceWwwroot = "./HomeApi/wwwroot" if (Test-Path -Path $sourceWwwroot) { Write-Host "Found wwwroot directory in source, copying..." New-Item -ItemType Directory -Path "./output/dotnet/wwwroot" -Force Copy-Item -Path "$sourceWwwroot/*" -Destination "./output/dotnet/wwwroot" -Recurse -Force } else { Write-Host "WARNING: Could not find wwwroot in source directory!" } } - name: Upload Artifacts uses: actions/upload-artifact@v4 with: name: dotnet-artifacts path: ./output/dotnet deploy: runs-on: self-hosted # Ensure your self-hosted runner is configured needs: build environment: ${{ github.event.inputs.environment || 'prod' }} steps: - name: Download .NET Artifacts uses: actions/download-artifact@v4 with: name: dotnet-artifacts path: ./output/dotnet - name: Stop IIS Application Pool run: | Import-Module WebAdministration $appPoolName = "${{ vars.IIS_APP_POOL_NAME }}" if ([string]::IsNullOrEmpty($appPoolName)) { $appPoolName = "HomeApi" } Write-Host "Stopping application pool: $appPoolName" # Check if app pool exists if (Test-Path "IIS:\AppPools\$appPoolName") { # Stop app pool if ((Get-WebAppPoolState -Name $appPoolName).Value -ne "Stopped") { Stop-WebAppPool -Name $appPoolName Start-Sleep -Seconds 5 # Give it time to fully stop Write-Host "Application pool stopped successfully" } else { Write-Host "Application pool was already stopped" } } else { Write-Host "Warning: Application pool '$appPoolName' not found. Will attempt to copy files anyway." } - name: Copy .NET Publish Files to IIS Server run: | # Ensure destination directory exists if (-not (Test-Path "C:\inetpub\applications\HomeApi")) { New-Item -ItemType Directory -Path "C:\inetpub\applications\HomeApi" -Force Write-Host "Created destination directory" } # Copy files Write-Host "Copying files to destination..." Copy-Item -Path ".\output\dotnet\*" -Destination "C:\inetpub\applications\HomeApi" -Recurse -Force Write-Host "Files copied successfully" - name: Restart IIS Application Pool if: ${{ github.event.inputs.restart_iis != 'false' }} run: | Import-Module WebAdministration $appPoolName = "${{ vars.IIS_APP_POOL_NAME }}" if ([string]::IsNullOrEmpty($appPoolName)) { $appPoolName = "HomeApi" } Write-Host "Starting application pool: $appPoolName" # Check if app pool exists if (Test-Path "IIS:\AppPools\$appPoolName") { # Start app pool Start-WebAppPool -Name $appPoolName Write-Host "Application pool started successfully" } else { Write-Host "Warning: Application pool '$appPoolName' not found. Using IISReset instead." iisreset /restart Write-Host "IIS restarted successfully" }