Release #59
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: Release | |
| on: | |
| workflow_dispatch: | |
| inputs: | |
| tag: | |
| description: "Git tag to release (e.g., v1.0.0) - Leave empty to auto-calculate from GitVersion" | |
| required: false | |
| type: string | |
| create_docker: | |
| description: "Also create Docker image" | |
| required: false | |
| default: true | |
| type: boolean | |
| env: | |
| DOTNET_VERSION: "9.0.x" | |
| PROJECT_NAME: "KnxMonitor" | |
| DOTNET_NOLOGO: true | |
| DOTNET_CLI_TELEMETRY_OPTOUT: true | |
| jobs: | |
| calculate-version: | |
| runs-on: ubuntu-latest | |
| timeout-minutes: 5 | |
| outputs: | |
| version: ${{ steps.gitversion.outputs.semVer }} | |
| tag: ${{ steps.determine-tag.outputs.tag }} | |
| informational-version: ${{ steps.gitversion.outputs.informationalVersion }} | |
| assembly-version: ${{ steps.gitversion.outputs.assemblySemVer }} | |
| is-prerelease: ${{ steps.gitversion.outputs.preReleaseLabel != '' }} | |
| steps: | |
| - name: Checkout code | |
| uses: actions/checkout@v5.0.0 | |
| with: | |
| fetch-depth: 0 | |
| - name: Setup .NET | |
| uses: actions/setup-dotnet@v5.0.0 | |
| with: | |
| dotnet-version: ${{ env.DOTNET_VERSION }} | |
| - name: Install GitVersion | |
| uses: gittools/actions/gitversion/setup@v4.1.0 | |
| with: | |
| versionSpec: "6.x" | |
| - name: Determine Version | |
| id: gitversion | |
| uses: gittools/actions/gitversion/execute@v4.1.0 | |
| with: | |
| configFilePath: GitVersion.yml | |
| - name: Determine Tag | |
| id: determine-tag | |
| run: | | |
| if [[ -n "${{ needs.calculate-version.outputs.tag }}" ]]; then | |
| # Use provided tag | |
| TAG="${{ needs.calculate-version.outputs.tag }}" | |
| echo "Using provided tag: ${TAG}" | |
| else | |
| # Auto-calculate tag from GitVersion | |
| TAG="v${{ steps.gitversion.outputs.semVer }}" | |
| echo "Auto-calculated tag: ${TAG}" | |
| fi | |
| echo "tag=${TAG}" >> "$GITHUB_OUTPUT" | |
| - name: Display GitVersion outputs | |
| run: | | |
| echo "SemVer: ${{ steps.gitversion.outputs.semVer }}" | |
| echo "FullSemVer: ${{ steps.gitversion.outputs.fullSemVer }}" | |
| echo "InformationalVersion: ${{ steps.gitversion.outputs.informationalVersion }}" | |
| echo "AssemblySemVer: ${{ steps.gitversion.outputs.assemblySemVer }}" | |
| echo "PreReleaseLabel: ${{ steps.gitversion.outputs.preReleaseLabel }}" | |
| echo "Final Tag: ${{ steps.determine-tag.outputs.tag }}" | |
| build: | |
| needs: calculate-version | |
| runs-on: ${{ matrix.os }} | |
| timeout-minutes: 30 | |
| strategy: | |
| fail-fast: false | |
| matrix: | |
| include: | |
| - runtime: win-x64 | |
| os: ubuntu-latest | |
| - runtime: linux-x64 | |
| os: ubuntu-latest | |
| - runtime: linux-arm64 | |
| os: ubuntu-latest | |
| - runtime: osx-x64 | |
| os: macos-15-intel | |
| - runtime: osx-arm64 | |
| os: macos-latest | |
| steps: | |
| - name: Checkout code | |
| uses: actions/checkout@v5.0.0 | |
| with: | |
| fetch-depth: 0 | |
| - name: Setup .NET | |
| uses: actions/setup-dotnet@v5.0.0 | |
| with: | |
| dotnet-version: ${{ env.DOTNET_VERSION }} | |
| - name: Install GitVersion | |
| uses: gittools/actions/gitversion/setup@v4.1.0 | |
| with: | |
| versionSpec: "6.x" | |
| - name: Determine Version | |
| id: gitversion | |
| uses: gittools/actions/gitversion/execute@v4.1.0 | |
| with: | |
| configFilePath: GitVersion.yml | |
| - name: Cache NuGet packages | |
| uses: actions/cache@v4.3.0 | |
| with: | |
| path: ~/.nuget/packages | |
| key: ${{ runner.os }}-nuget-${{ hashFiles('**/*.csproj', '**/Directory.Packages.props') }} | |
| restore-keys: | | |
| ${{ runner.os }}-nuget- | |
| - name: Restore dependencies | |
| run: dotnet restore --verbosity minimal | |
| - name: Run tests | |
| run: dotnet test --configuration Release --verbosity normal --no-restore | |
| - name: Build and publish | |
| run: | | |
| echo "DEBUG: Building for runtime: ${{ matrix.runtime }}" | |
| echo "DEBUG: .NET SDK Version: $(dotnet --version)" | |
| echo "DEBUG: Available SDKs: $(dotnet --list-sdks)" | |
| # Ensure clean build environment | |
| dotnet clean --configuration Release --verbosity minimal | |
| if [[ "${{ matrix.runtime }}" == "linux-x64" || "${{ matrix.runtime }}" == "linux-arm64" ]]; then | |
| echo "DEBUG: Using enterprise-grade framework-dependent deployment for Docker (Linux)" | |
| # Framework-dependent deployment optimized for Docker containers | |
| # This creates KnxMonitor.dll for Docker and KnxMonitor executable for packaging | |
| dotnet publish ${{ env.PROJECT_NAME }} \ | |
| --configuration Release \ | |
| --runtime ${{ matrix.runtime }} \ | |
| --self-contained false \ | |
| --output ./publish/${{ matrix.runtime }} \ | |
| --verbosity normal \ | |
| --nologo | |
| # Also create a self-contained executable for Linux packaging | |
| dotnet publish ${{ env.PROJECT_NAME }} \ | |
| --configuration Release \ | |
| --runtime ${{ matrix.runtime }} \ | |
| --self-contained true \ | |
| --property:PublishSingleFile=true \ | |
| --output ./publish-packaging/${{ matrix.runtime }} \ | |
| --verbosity normal \ | |
| --nologo | |
| echo "DEBUG: Self-contained deployment for packaging completed" | |
| echo "DEBUG: Framework-dependent deployment completed" | |
| # Verify both DLL and executable are created | |
| if [[ ! -f "./publish/${{ matrix.runtime }}/KnxMonitor.dll" ]]; then | |
| echo "ERROR: KnxMonitor.dll not found in framework-dependent deployment" | |
| echo "Available files:" | |
| ls -la ./publish/${{ matrix.runtime }}/ | |
| exit 1 | |
| fi | |
| # Ensure executable has proper permissions | |
| if [[ -f "./publish/${{ matrix.runtime }}/KnxMonitor" ]]; then | |
| chmod +x "./publish/${{ matrix.runtime }}/KnxMonitor" | |
| echo "DEBUG: Made KnxMonitor executable" | |
| fi | |
| else | |
| echo "DEBUG: Using enterprise-grade self-contained deployment for native platforms" | |
| # Self-contained deployment with conservative settings for compatibility | |
| dotnet publish ${{ env.PROJECT_NAME }} \ | |
| --configuration Release \ | |
| --runtime ${{ matrix.runtime }} \ | |
| --self-contained true \ | |
| --property:PublishSingleFile=true \ | |
| --property:IncludeNativeLibrariesForSelfExtract=true \ | |
| --property:EnableCompressionInSingleFile=true \ | |
| --property:PublishTrimmed=false \ | |
| --property:PublishReadyToRun=false \ | |
| --output ./publish/${{ matrix.runtime }} \ | |
| --verbosity normal \ | |
| --nologo | |
| echo "DEBUG: Self-contained deployment completed" | |
| # Verify executable is created | |
| EXPECTED_EXE="KnxMonitor" | |
| if [[ "${{ matrix.runtime }}" == win-* ]]; then | |
| EXPECTED_EXE="KnxMonitor.exe" | |
| fi | |
| if [[ ! -f "./publish/${{ matrix.runtime }}/$EXPECTED_EXE" ]]; then | |
| echo "ERROR: $EXPECTED_EXE not found in self-contained deployment" | |
| echo "Available files:" | |
| ls -la ./publish/${{ matrix.runtime }}/ | |
| exit 1 | |
| fi | |
| # Ensure executable has proper permissions (Unix-like systems) | |
| if [[ "${{ matrix.runtime }}" != win-* ]]; then | |
| chmod +x "./publish/${{ matrix.runtime }}/$EXPECTED_EXE" | |
| echo "DEBUG: Made $EXPECTED_EXE executable" | |
| fi | |
| fi | |
| echo "DEBUG: Build validation completed successfully" | |
| echo "DEBUG: Final output verification:" | |
| ls -la ./publish/${{ matrix.runtime }}/ | head -20 | |
| # Additional validation: verify the application can show version | |
| echo "DEBUG: Testing application startup..." | |
| cd ./publish/${{ matrix.runtime }}/ | |
| if [[ -f "KnxMonitor.dll" ]] && command -v dotnet >/dev/null 2>&1; then | |
| echo "DEBUG: Testing DLL version..." | |
| timeout 10 dotnet KnxMonitor.dll --version || echo "DLL version test failed (non-critical)" | |
| fi | |
| if [[ -f "KnxMonitor" && -x "KnxMonitor" ]]; then | |
| echo "DEBUG: Testing executable version..." | |
| timeout 10 ./KnxMonitor --version || echo "Executable version test failed (non-critical)" | |
| elif [[ -f "KnxMonitor.exe" ]]; then | |
| echo "DEBUG: Testing Windows executable version..." | |
| timeout 10 ./KnxMonitor.exe --version || echo "Windows executable version test failed (non-critical)" | |
| fi | |
| echo "DEBUG: Application startup test completed" | |
| - name: Code sign macOS binaries | |
| if: startsWith(matrix.runtime, 'osx-') | |
| env: | |
| APPLE_CERTIFICATE_P12: ${{ secrets.APPLE_CERTIFICATE_P12 }} | |
| APPLE_CERTIFICATE_PASSWORD: ${{ secrets.APPLE_CERTIFICATE_PASSWORD }} | |
| APPLE_DEVELOPER_ID: ${{ secrets.APPLE_DEVELOPER_ID }} | |
| run: | | |
| # Create temporary keychain | |
| KEYCHAIN_PATH=$RUNNER_TEMP/app-signing.keychain-db | |
| KEYCHAIN_PASSWORD=$(openssl rand -base64 32) | |
| # Create keychain and set as default | |
| security create-keychain -p "$KEYCHAIN_PASSWORD" "$KEYCHAIN_PATH" | |
| security set-keychain-settings -lut 21600 "$KEYCHAIN_PATH" | |
| security unlock-keychain -p "$KEYCHAIN_PASSWORD" "$KEYCHAIN_PATH" | |
| security list-keychains -d user -s "$KEYCHAIN_PATH" | |
| # Import certificate | |
| if [ -z "$APPLE_CERTIFICATE_P12" ]; then | |
| echo "Error: APPLE_CERTIFICATE_P12 secret is empty" | |
| exit 1 | |
| fi | |
| echo "$APPLE_CERTIFICATE_P12" | base64 -D > certificate.p12 | |
| if [ ! -f certificate.p12 ] || [ ! -s certificate.p12 ]; then | |
| echo "Error: Failed to decode certificate" | |
| exit 1 | |
| fi | |
| security import certificate.p12 -k "$KEYCHAIN_PATH" -P "$APPLE_CERTIFICATE_PASSWORD" -T /usr/bin/codesign | |
| security set-key-partition-list -S apple-tool:,apple:,codesign: -s -k "$KEYCHAIN_PASSWORD" "$KEYCHAIN_PATH" | |
| # Sign the binary | |
| BINARY_PATH="./publish/${{ matrix.runtime }}/${{ env.PROJECT_NAME }}" | |
| codesign --sign "Developer ID Application: Fabian Schmieder ($APPLE_DEVELOPER_ID)" \ | |
| --verbose \ | |
| --force \ | |
| --options runtime \ | |
| --entitlements entitlements.plist \ | |
| --timestamp \ | |
| "$BINARY_PATH" | |
| # Verify signature | |
| codesign --verify --verbose "$BINARY_PATH" | |
| # Check Gatekeeper status (non-blocking - notarization not required for CLI tools) | |
| echo "Checking Gatekeeper status (informational only):" | |
| spctl --assess --type execute --verbose "$BINARY_PATH" || echo "Note: Binary is signed but not notarized (expected for CLI tools)" | |
| # Clean up | |
| rm certificate.p12 | |
| security delete-keychain "$KEYCHAIN_PATH" | |
| - name: Create archive | |
| run: | | |
| # Create a staging directory with all files for the archive | |
| mkdir -p ./archive-staging | |
| # Copy the binary (handle Windows .exe extension and Linux packaging) | |
| if [[ "${{ matrix.runtime }}" == "linux-x64" || "${{ matrix.runtime }}" == "linux-arm64" ]]; then | |
| # Use self-contained executable for Linux packaging | |
| cp ./publish-packaging/${{ matrix.runtime }}/KnxMonitor ./archive-staging/ | |
| elif [[ "${{ matrix.runtime }}" == win-* ]]; then | |
| cp ./publish/${{ matrix.runtime }}/KnxMonitor.exe ./archive-staging/ | |
| else | |
| cp ./publish/${{ matrix.runtime }}/KnxMonitor ./archive-staging/ | |
| fi | |
| # Copy documentation files | |
| cp README.md ./archive-staging/ 2>/dev/null || echo "README.md not found" | |
| cp LICENSE ./archive-staging/ 2>/dev/null || echo "LICENSE not found" | |
| # Copy man page | |
| if [ -f "docs/knxmonitor.1" ]; then | |
| mkdir -p ./archive-staging/docs | |
| cp docs/knxmonitor.1 ./archive-staging/docs/ | |
| fi | |
| # Copy example CSV file | |
| if [ -f "knx-addresses.csv" ]; then | |
| cp knx-addresses.csv ./archive-staging/ | |
| fi | |
| # Create the archive | |
| cd ./archive-staging | |
| if [[ "${{ matrix.runtime }}" == win-* ]]; then | |
| zip -r ../${{ env.PROJECT_NAME }}-${{ needs.calculate-version.outputs.version }}-${{ matrix.runtime }}.zip . | |
| else | |
| tar -czf ../${{ env.PROJECT_NAME }}-${{ needs.calculate-version.outputs.version }}-${{ matrix.runtime }}.tar.gz . | |
| fi | |
| - name: Upload artifacts | |
| uses: actions/upload-artifact@v5.0.0 | |
| with: | |
| name: ${{ env.PROJECT_NAME }}-${{ matrix.runtime }} | |
| path: | | |
| *.zip | |
| *.tar.gz | |
| retention-days: 1 | |
| compression-level: 9 | |
| - name: Upload Docker artifacts (framework-dependent) | |
| if: matrix.runtime == 'linux-x64' || matrix.runtime == 'linux-arm64' | |
| uses: actions/upload-artifact@v5.0.0 | |
| with: | |
| name: ${{ env.PROJECT_NAME }}-docker-${{ matrix.runtime }} | |
| path: ./publish/${{ matrix.runtime }}/ | |
| retention-days: 1 | |
| compression-level: 9 | |
| docker: | |
| needs: [calculate-version, build] | |
| if: inputs.create_docker | |
| runs-on: ubuntu-latest | |
| timeout-minutes: 20 | |
| permissions: | |
| contents: read | |
| packages: write | |
| steps: | |
| - name: Checkout code | |
| uses: actions/checkout@v5.0.0 | |
| with: | |
| fetch-depth: 0 | |
| - name: Set up Docker Buildx | |
| uses: docker/setup-buildx-action@v3.7.1 | |
| - name: Login to GitHub Container Registry | |
| uses: docker/login-action@v3.3.0 | |
| with: | |
| registry: ghcr.io | |
| username: ${{ github.actor }} | |
| password: ${{ secrets.GITHUB_TOKEN }} | |
| - name: Extract metadata | |
| id: meta | |
| uses: docker/metadata-action@v5.5.1 | |
| with: | |
| images: ghcr.io/${{ github.repository_owner }}/${{ env.PROJECT_NAME }} | |
| tags: | | |
| type=raw,value=${{ needs.calculate-version.outputs.version }} | |
| type=raw,value=latest,enable=${{ needs.calculate-version.outputs.is-prerelease == 'false' }} | |
| labels: | | |
| org.opencontainers.image.title=KNX Monitor | |
| org.opencontainers.image.description=KNX/EIB bus monitoring and debugging tool | |
| org.opencontainers.image.vendor=metaneutrons | |
| org.opencontainers.image.version=${{ needs.calculate-version.outputs.version }} | |
| org.opencontainers.image.revision=${{ github.sha }} | |
| org.opencontainers.image.source=${{ github.server_url }}/${{ github.repository }} | |
| org.opencontainers.image.documentation=${{ github.server_url }}/${{ github.repository }}/blob/main/README.md | |
| org.opencontainers.image.licenses=GPL-3.0 | |
| - name: Download Linux binaries for Docker | |
| uses: actions/download-artifact@v6.0.0 | |
| with: | |
| pattern: ${{ env.PROJECT_NAME }}-docker-linux-* | |
| path: ./docker-artifacts | |
| merge-multiple: false | |
| - name: Prepare Docker context for multi-arch build | |
| run: | | |
| echo "INFO: Preparing enterprise-grade Docker build context..." | |
| # Create clean build directories | |
| rm -rf docker-context | |
| mkdir -p docker-context/publish-amd64 docker-context/publish-arm64 | |
| echo "INFO: Processing AMD64 (x64) artifacts..." | |
| cd docker-artifacts/${{ env.PROJECT_NAME }}-docker-linux-x64 | |
| # Validate required files for AMD64 (direct directory, no archive) | |
| if [[ ! -f "KnxMonitor.dll" ]]; then | |
| echo "ERROR: KnxMonitor.dll not found in AMD64 deployment" | |
| echo "Available files:" | |
| ls -la | |
| exit 1 | |
| fi | |
| # Copy AMD64 deployment with validation | |
| cp -r * ../../docker-context/publish-amd64/ | |
| echo "INFO: AMD64 deployment copied to Docker context" | |
| echo "INFO: Processing ARM64 artifacts..." | |
| cd ../${{ env.PROJECT_NAME }}-docker-linux-arm64 | |
| # Validate required files for ARM64 (direct directory, no archive) | |
| if [[ ! -f "KnxMonitor.dll" ]]; then | |
| echo "ERROR: KnxMonitor.dll not found in ARM64 deployment" | |
| echo "Available files:" | |
| ls -la | |
| exit 1 | |
| fi | |
| # Copy ARM64 deployment with validation | |
| cp -r * ../../docker-context/publish-arm64/ | |
| echo "INFO: ARM64 deployment copied to Docker context" | |
| # Copy and validate Dockerfile | |
| cd ../.. | |
| if [[ ! -f "Dockerfile.ci" ]]; then | |
| echo "ERROR: Dockerfile.ci not found" | |
| exit 1 | |
| fi | |
| cp Dockerfile.ci docker-context/Dockerfile | |
| echo "INFO: Dockerfile copied to build context" | |
| # Comprehensive validation of Docker context | |
| echo "INFO: Validating Docker build context..." | |
| # Validate AMD64 deployment | |
| echo "INFO: AMD64 deployment validation:" | |
| if [[ ! -f "docker-context/publish-amd64/KnxMonitor.dll" ]]; then | |
| echo "ERROR: AMD64 KnxMonitor.dll missing" | |
| exit 1 | |
| fi | |
| AMD64_DLL_SIZE=$(stat -c%s "docker-context/publish-amd64/KnxMonitor.dll" 2>/dev/null || stat -f%z "docker-context/publish-amd64/KnxMonitor.dll") | |
| if [[ "$AMD64_DLL_SIZE" -lt 1000 ]]; then | |
| echo "ERROR: AMD64 KnxMonitor.dll appears to be too small ($AMD64_DLL_SIZE bytes)" | |
| exit 1 | |
| fi | |
| echo " ✓ KnxMonitor.dll: $AMD64_DLL_SIZE bytes" | |
| # Validate ARM64 deployment | |
| echo "INFO: ARM64 deployment validation:" | |
| if [[ ! -f "docker-context/publish-arm64/KnxMonitor.dll" ]]; then | |
| echo "ERROR: ARM64 KnxMonitor.dll missing" | |
| exit 1 | |
| fi | |
| ARM64_DLL_SIZE=$(stat -c%s "docker-context/publish-arm64/KnxMonitor.dll" 2>/dev/null || stat -f%z "docker-context/publish-arm64/KnxMonitor.dll") | |
| if [[ "$ARM64_DLL_SIZE" -lt 1000 ]]; then | |
| echo "ERROR: ARM64 KnxMonitor.dll appears to be too small ($ARM64_DLL_SIZE bytes)" | |
| exit 1 | |
| fi | |
| echo " ✓ KnxMonitor.dll: $ARM64_DLL_SIZE bytes" | |
| # Validate Dockerfile | |
| if [[ ! -f "docker-context/Dockerfile" ]]; then | |
| echo "ERROR: Dockerfile missing from build context" | |
| exit 1 | |
| fi | |
| # Check Dockerfile syntax | |
| if ! grep -q "ENTRYPOINT.*entrypoint.sh" docker-context/Dockerfile; then | |
| echo "ERROR: Dockerfile does not contain expected entrypoint configuration" | |
| exit 1 | |
| fi | |
| echo " ✓ Dockerfile syntax validated" | |
| # Final context summary | |
| echo "INFO: Docker build context prepared successfully:" | |
| echo " ✓ AMD64 deployment: $(ls docker-context/publish-amd64/ | wc -l) files" | |
| echo " ✓ ARM64 deployment: $(ls docker-context/publish-arm64/ | wc -l) files" | |
| echo " ✓ Dockerfile: $(wc -l < docker-context/Dockerfile) lines" | |
| # Show key files for debugging | |
| echo "INFO: Key files in build context:" | |
| echo "AMD64 files:" | |
| ls -la docker-context/publish-amd64/ | head -10 | |
| echo "ARM64 files:" | |
| ls -la docker-context/publish-arm64/ | head -10 | |
| echo "INFO: Docker context preparation completed successfully" | |
| - name: Build and push Docker image | |
| uses: docker/build-push-action@v6.18.0 | |
| with: | |
| context: ./docker-context | |
| platforms: linux/amd64,linux/arm64 | |
| push: true | |
| tags: ${{ steps.meta.outputs.tags }} | |
| labels: ${{ steps.meta.outputs.labels }} | |
| cache-from: type=gha | |
| cache-to: type=gha,mode=max | |
| build-args: | | |
| VERSION=${{ needs.calculate-version.outputs.version }} | |
| BUILD_DATE=${{ fromJSON(steps.meta.outputs.json).labels['org.opencontainers.image.created'] }} | |
| VCS_REF=${{ github.sha }} | |
| provenance: true | |
| sbom: true | |
| - name: Validate Docker image | |
| run: | | |
| echo "INFO: Validating built Docker images..." | |
| # Convert project name to lowercase for Docker image name | |
| IMAGE_NAME=$(echo "${{ env.PROJECT_NAME }}" | tr '[:upper:]' '[:lower:]') | |
| # Test AMD64 image | |
| echo "INFO: Testing AMD64 image..." | |
| docker run --rm --platform linux/amd64 \ | |
| ghcr.io/${{ github.repository_owner }}/${IMAGE_NAME}:${{ needs.calculate-version.outputs.version }} \ | |
| --version | |
| # Test ARM64 image (if running on compatible hardware) | |
| echo "INFO: Testing ARM64 image..." | |
| if docker run --rm --platform linux/arm64 \ | |
| ghcr.io/${{ github.repository_owner }}/${IMAGE_NAME}:${{ needs.calculate-version.outputs.version }} \ | |
| --version 2>/dev/null; then | |
| echo " ✓ ARM64 image validation successful" | |
| else | |
| echo " ⚠ ARM64 image validation skipped (incompatible host or emulation issues)" | |
| fi | |
| # Test help command | |
| echo "INFO: Testing help command..." | |
| docker run --rm --platform linux/amd64 \ | |
| ghcr.io/${{ github.repository_owner }}/${IMAGE_NAME}:${{ needs.calculate-version.outputs.version }} \ | |
| --help | head -5 | |
| echo "INFO: Docker image validation completed successfully" | |
| release: | |
| needs: [calculate-version, build, docker] | |
| if: always() && needs.calculate-version.result == 'success' && needs.build.result == 'success' && (needs.docker.result == 'success' || needs.docker.result == 'skipped') | |
| runs-on: ubuntu-latest | |
| timeout-minutes: 10 | |
| permissions: | |
| contents: write | |
| steps: | |
| - name: Checkout code | |
| uses: actions/checkout@v5.0.0 | |
| with: | |
| fetch-depth: 0 | |
| - name: Download release artifacts | |
| uses: actions/download-artifact@v6.0.0 | |
| with: | |
| pattern: KnxMonitor-* | |
| path: ./artifacts | |
| merge-multiple: false | |
| - name: Download AUR package | |
| uses: actions/download-artifact@v6.0.0 | |
| with: | |
| pattern: aur-package-* | |
| path: ./artifacts | |
| merge-multiple: false | |
| - name: Prepare release assets | |
| run: | | |
| mkdir -p ./release-assets | |
| find ./artifacts -name "*.zip" -o -name "*.tar.gz" | xargs -I {} cp {} ./release-assets/ | |
| ls -la ./release-assets/ | |
| - name: Create and push Git tag | |
| run: | | |
| git config user.name "github-actions[bot]" | |
| git config user.email "github-actions[bot]@users.noreply.github.com" | |
| # Check if tag already exists | |
| if git rev-parse "${{ needs.calculate-version.outputs.tag }}" >/dev/null 2>&1; then | |
| echo "Tag ${{ needs.calculate-version.outputs.tag }} already exists, skipping tag creation" | |
| else | |
| echo "Creating new tag ${{ needs.calculate-version.outputs.tag }}" | |
| git tag -a ${{ needs.calculate-version.outputs.tag }} -m "Release ${{ needs.calculate-version.outputs.tag }}" | |
| git push origin ${{ needs.calculate-version.outputs.tag }} | |
| fi | |
| - name: Generate release notes | |
| id: release_notes | |
| run: | | |
| cat << EOF > release_notes.md | |
| ## 🚀 KNX Monitor ${{ needs.calculate-version.outputs.version }} | |
| ### 📋 Version Information | |
| - **Version**: ${{ needs.calculate-version.outputs.version }} | |
| - **GitVersion**: ${{ needs.calculate-version.outputs.informational-version }} | |
| - **Assembly Version**: ${{ needs.calculate-version.outputs.assembly-version }} | |
| ### 📦 Installation | |
| #### Homebrew (macOS/Linux) | |
| \`\`\`bash | |
| brew install metaneutrons/tap/knxmonitor | |
| \`\`\` | |
| #### Docker | |
| \`\`\`bash | |
| docker run --rm -it ghcr.io/metaneutrons/knxmonitor:${{ needs.calculate-version.outputs.version }} --help | |
| \`\`\` | |
| #### Manual Installation | |
| Download the appropriate binary for your platform from the assets below. | |
| ### 🏗️ Build Information | |
| - **.NET Version**: 9.0 | |
| - **Build Date**: $(date -u +"%Y-%m-%d %H:%M:%S UTC") | |
| - **Commit**: ${{ github.sha }} | |
| - **Tag**: ${{ needs.calculate-version.outputs.tag }} | |
| ### 📋 Supported Platforms | |
| - **Windows x64** (knxmonitor-${{ needs.calculate-version.outputs.version }}-win-x64.zip) | |
| - **Linux x64** (knxmonitor-${{ needs.calculate-version.outputs.version }}-linux-x64.tar.gz) | |
| - **macOS x64** (knxmonitor-${{ needs.calculate-version.outputs.version }}-osx-x64.tar.gz) | |
| - **macOS ARM64** (knxmonitor-${{ needs.calculate-version.outputs.version }}-osx-arm64.tar.gz) | |
| - **Docker** (ghcr.io/metaneutrons/knxmonitor:${{ needs.calculate-version.outputs.version }}) | |
| ### 🔧 Quick Start | |
| \`\`\`bash | |
| # Show version | |
| knxmonitor --version | |
| # Monitor KNX bus via IP routing | |
| knxmonitor --connection-type routing | |
| # Monitor with IP tunneling | |
| knxmonitor --connection-type tunneling --host 192.168.1.100 | |
| \`\`\` | |
| --- | |
| **Full Changelog**: https://github.com/${{ github.repository }}/compare/${{ needs.calculate-version.outputs.tag }}...HEAD | |
| EOF | |
| - name: Create GitHub Release | |
| uses: softprops/action-gh-release@v2.0.8 | |
| with: | |
| tag_name: ${{ needs.calculate-version.outputs.tag }} | |
| name: "KNX Monitor ${{ needs.calculate-version.outputs.version }}" | |
| body_path: release_notes.md | |
| files: ./release-assets/* | |
| draft: false | |
| prerelease: ${{ needs.calculate-version.outputs.is-prerelease == 'true' }} | |
| generate_release_notes: true | |
| env: | |
| GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} | |
| package-linux: | |
| name: Package for Linux distributions | |
| needs: [calculate-version, build] | |
| runs-on: ubuntu-latest | |
| if: needs.calculate-version.outputs.is-prerelease == 'false' | |
| permissions: | |
| contents: write | |
| packages: read | |
| steps: | |
| - name: Checkout code | |
| uses: actions/checkout@v5.0.0 | |
| with: | |
| fetch-depth: 0 | |
| - name: Download Linux artifacts | |
| uses: actions/download-artifact@v6.0.0 | |
| with: | |
| pattern: KnxMonitor-linux-* | |
| path: ./artifacts | |
| merge-multiple: false | |
| - name: Extract Linux artifacts | |
| run: | | |
| echo "INFO: Extracting Linux artifacts for packaging..." | |
| # Extract AMD64 artifacts | |
| if [ -d "artifacts/KnxMonitor-linux-x64" ]; then | |
| cd artifacts/KnxMonitor-linux-x64 | |
| if [ -f "KnxMonitor-${{ needs.calculate-version.outputs.version }}-linux-x64.tar.gz" ]; then | |
| tar -xzf "KnxMonitor-${{ needs.calculate-version.outputs.version }}-linux-x64.tar.gz" | |
| echo "INFO: AMD64 artifacts extracted" | |
| ls -la | |
| else | |
| echo "ERROR: AMD64 archive not found" | |
| exit 1 | |
| fi | |
| cd ../.. | |
| fi | |
| # Extract ARM64 artifacts | |
| if [ -d "artifacts/KnxMonitor-linux-arm64" ]; then | |
| cd artifacts/KnxMonitor-linux-arm64 | |
| if [ -f "KnxMonitor-${{ needs.calculate-version.outputs.version }}-linux-arm64.tar.gz" ]; then | |
| tar -xzf "KnxMonitor-${{ needs.calculate-version.outputs.version }}-linux-arm64.tar.gz" | |
| echo "INFO: ARM64 artifacts extracted" | |
| ls -la | |
| else | |
| echo "ERROR: ARM64 archive not found" | |
| exit 1 | |
| fi | |
| cd ../.. | |
| fi | |
| echo "INFO: All Linux artifacts extracted successfully" | |
| - name: Install packaging tools | |
| run: | | |
| sudo apt-get update | |
| sudo apt-get install -y dpkg-dev | |
| - name: Make packaging scripts executable | |
| run: | | |
| chmod +x packaging/build-deb.sh | |
| - name: Build Debian packages | |
| run: | | |
| # Build for amd64 | |
| ./packaging/build-deb.sh ${{ needs.calculate-version.outputs.version }} amd64 | |
| # Build for arm64 | |
| ./packaging/build-deb.sh ${{ needs.calculate-version.outputs.version }} arm64 | |
| - name: Upload Debian packages to release | |
| uses: softprops/action-gh-release@v2.0.8 | |
| with: | |
| tag_name: ${{ needs.calculate-version.outputs.tag }} | |
| files: "*.deb" | |
| env: | |
| GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} | |
| - name: Create AUR package files | |
| run: | | |
| VERSION="${{ needs.calculate-version.outputs.version }}" | |
| # Calculate SHA256 for source tarball | |
| TARBALL_URL="https://github.com/metaneutrons/KnxMonitor/archive/refs/tags/v${VERSION}.tar.gz" | |
| TARBALL_SHA=$(curl -sL "$TARBALL_URL" | sha256sum | cut -d' ' -f1) | |
| # Update PKGBUILD with correct version and SHA | |
| sed -i "s/pkgver=.*/pkgver=${VERSION}/" packaging/arch/PKGBUILD | |
| sed -i "s/sha256sums=('SKIP')/sha256sums=('${TARBALL_SHA}')/" packaging/arch/PKGBUILD | |
| # Create .SRCINFO file | |
| cat > packaging/arch/.SRCINFO << EOF | |
| pkgbase = knxmonitor | |
| pkgdesc = KNX/EIB bus monitoring and debugging tool | |
| pkgver = ${VERSION} | |
| pkgrel = 1 | |
| url = https://github.com/metaneutrons/KnxMonitor | |
| arch = x86_64 | |
| arch = aarch64 | |
| license = GPL3 | |
| makedepends = dotnet-sdk>=9.0 | |
| depends = glibc | |
| depends = gcc-libs | |
| depends = openssl | |
| optdepends = knxd: KNX daemon for local KNX/IP gateway | |
| optdepends = docker: For containerized deployment | |
| source = knxmonitor-${VERSION}.tar.gz::https://github.com/metaneutrons/KnxMonitor/archive/refs/tags/v${VERSION}.tar.gz | |
| sha256sums = ${TARBALL_SHA} | |
| pkgname = knxmonitor | |
| EOF | |
| # Verify files were created | |
| echo "INFO: Verifying AUR package files..." | |
| ls -la packaging/arch/PKGBUILD packaging/arch/.SRCINFO | |
| - name: Upload AUR package files | |
| uses: actions/upload-artifact@v5.0.0 | |
| with: | |
| name: aur-package-${{ needs.calculate-version.outputs.version }} | |
| path: packaging/arch/ | |
| include-hidden-files: true | |
| retention-days: 90 | |
| - name: Create packaging summary | |
| run: | | |
| echo "## 📦 Linux Packaging Summary" >> $GITHUB_STEP_SUMMARY | |
| echo "" >> $GITHUB_STEP_SUMMARY | |
| echo "### Debian Packages" >> $GITHUB_STEP_SUMMARY | |
| echo "- ✅ knxmonitor_${{ needs.calculate-version.outputs.version }}_amd64.deb" >> $GITHUB_STEP_SUMMARY | |
| echo "- ✅ knxmonitor_${{ needs.calculate-version.outputs.version }}_arm64.deb" >> $GITHUB_STEP_SUMMARY | |
| echo "" >> $GITHUB_STEP_SUMMARY | |
| echo "### Arch Linux AUR" >> $GITHUB_STEP_SUMMARY | |
| echo "- ✅ PKGBUILD updated with version ${{ needs.calculate-version.outputs.version }}" >> $GITHUB_STEP_SUMMARY | |
| echo "- ✅ .SRCINFO generated" >> $GITHUB_STEP_SUMMARY | |
| echo "" >> $GITHUB_STEP_SUMMARY | |
| echo "### Installation Instructions" >> $GITHUB_STEP_SUMMARY | |
| echo "" >> $GITHUB_STEP_SUMMARY | |
| echo "**Debian/Ubuntu:**" >> $GITHUB_STEP_SUMMARY | |
| echo '```bash' >> $GITHUB_STEP_SUMMARY | |
| echo "wget https://github.com/metaneutrons/KnxMonitor/releases/download/v${{ needs.calculate-version.outputs.version }}/knxmonitor_${{ needs.calculate-version.outputs.version }}_amd64.deb" >> $GITHUB_STEP_SUMMARY | |
| echo "sudo dpkg -i knxmonitor_${{ needs.calculate-version.outputs.version }}_amd64.deb" >> $GITHUB_STEP_SUMMARY | |
| echo '```' >> $GITHUB_STEP_SUMMARY | |
| echo "" >> $GITHUB_STEP_SUMMARY | |
| echo "**Arch Linux:**" >> $GITHUB_STEP_SUMMARY | |
| echo '```bash' >> $GITHUB_STEP_SUMMARY | |
| echo "yay -S knxmonitor" >> $GITHUB_STEP_SUMMARY | |
| echo "# or" >> $GITHUB_STEP_SUMMARY | |
| echo "git clone https://aur.archlinux.org/knxmonitor.git" >> $GITHUB_STEP_SUMMARY | |
| echo "cd knxmonitor && makepkg -si" >> $GITHUB_STEP_SUMMARY | |
| echo '```' >> $GITHUB_STEP_SUMMARY | |
| publish-aur: | |
| needs: [calculate-version, package-linux, release] | |
| if: always() && needs.calculate-version.outputs.is-prerelease == 'false' && needs.release.result == 'success' | |
| runs-on: ubuntu-latest | |
| timeout-minutes: 15 | |
| continue-on-error: false | |
| steps: | |
| - name: Checkout repository | |
| uses: actions/checkout@v5.0.0 | |
| with: | |
| fetch-depth: 0 | |
| - name: Download AUR package artifact | |
| uses: actions/download-artifact@v6.0.0 | |
| with: | |
| pattern: aur-package-* | |
| path: ./aur-artifacts | |
| merge-multiple: false | |
| - name: Validate AUR package files | |
| run: | | |
| echo "INFO: Validating AUR package files..." | |
| # Debug: Show artifact structure | |
| echo "DEBUG: Artifact structure:" | |
| find ./aur-artifacts -type f -o -type d | |
| # Find the AUR package directory (handles nested structure from download-artifact) | |
| AUR_DIR=$(find ./aur-artifacts -name "PKGBUILD" -type f -exec dirname {} \; | head -1) | |
| if [ -z "$AUR_DIR" ]; then | |
| echo "ERROR: AUR package directory not found" | |
| echo "DEBUG: Contents of aur-artifacts:" | |
| find ./aur-artifacts -type f | |
| exit 1 | |
| fi | |
| echo "INFO: Found AUR package directory: $AUR_DIR" | |
| # Validate PKGBUILD exists | |
| if [ ! -f "$AUR_DIR/PKGBUILD" ]; then | |
| echo "ERROR: PKGBUILD not found in $AUR_DIR" | |
| exit 1 | |
| fi | |
| # Validate .SRCINFO exists | |
| if [ ! -f "$AUR_DIR/.SRCINFO" ]; then | |
| echo "ERROR: .SRCINFO not found in $AUR_DIR" | |
| exit 1 | |
| fi | |
| # Validate PKGBUILD syntax | |
| echo "INFO: Validating PKGBUILD syntax..." | |
| if ! bash -n "$AUR_DIR/PKGBUILD"; then | |
| echo "ERROR: PKGBUILD has syntax errors" | |
| exit 1 | |
| fi | |
| # Check required PKGBUILD variables | |
| echo "INFO: Checking required PKGBUILD variables..." | |
| for var in pkgname pkgver pkgrel pkgdesc arch url license source sha256sums; do | |
| if ! grep -q "^${var}=" "$AUR_DIR/PKGBUILD"; then | |
| echo "ERROR: Required variable '$var' not found in PKGBUILD" | |
| exit 1 | |
| fi | |
| done | |
| # Validate version matches | |
| PKGBUILD_VERSION=$(grep "^pkgver=" "$AUR_DIR/PKGBUILD" | cut -d'=' -f2) | |
| EXPECTED_VERSION="${{ needs.calculate-version.outputs.version }}" | |
| if [ "$PKGBUILD_VERSION" != "$EXPECTED_VERSION" ]; then | |
| echo "ERROR: PKGBUILD version ($PKGBUILD_VERSION) does not match expected version ($EXPECTED_VERSION)" | |
| exit 1 | |
| fi | |
| echo "✅ AUR package files validated successfully" | |
| echo " - PKGBUILD: $(wc -l < "$AUR_DIR/PKGBUILD") lines" | |
| echo " - .SRCINFO: $(wc -l < "$AUR_DIR/.SRCINFO") lines" | |
| echo " - Version: $PKGBUILD_VERSION" | |
| - name: Prepare AUR package for publishing | |
| run: | | |
| echo "INFO: Preparing AUR package for publishing..." | |
| # Find and copy AUR files to workspace root | |
| AUR_DIR=$(find ./aur-artifacts -name "PKGBUILD" -type f -exec dirname {} \; | head -1) | |
| cp "$AUR_DIR/PKGBUILD" ./PKGBUILD | |
| cp "$AUR_DIR/.SRCINFO" ./.SRCINFO | |
| echo "INFO: AUR package files prepared" | |
| echo "PKGBUILD content:" | |
| cat ./PKGBUILD | |
| echo "" | |
| echo ".SRCINFO content:" | |
| cat ./.SRCINFO | |
| - name: Publish to AUR | |
| uses: KSXGitHub/github-actions-deploy-aur@v3.0.1 | |
| with: | |
| pkgname: knxmonitor | |
| pkgbuild: ./PKGBUILD | |
| assets: ./.SRCINFO | |
| commit_username: metaneutrons | |
| commit_email: wohlhabend_gasherd_2r@icloud.com | |
| ssh_private_key: ${{ secrets.AUR_SSH_PRIVATE_KEY }} | |
| commit_message: "Update to version ${{ needs.calculate-version.outputs.version }}" | |
| ssh_keyscan_types: rsa,ecdsa,ed25519 | |
| updpkgsums: false | |
| test: false | |
| force_push: false | |
| allow_empty_commits: false | |
| - name: Create AUR publish summary | |
| if: always() | |
| run: | | |
| echo "## 📦 AUR Package Publishing" >> $GITHUB_STEP_SUMMARY | |
| echo "" >> $GITHUB_STEP_SUMMARY | |
| if [ "${{ job.status }}" = "success" ]; then | |
| echo "✅ **Successfully published to AUR**" >> $GITHUB_STEP_SUMMARY | |
| echo "" >> $GITHUB_STEP_SUMMARY | |
| echo "- **Package**: knxmonitor" >> $GITHUB_STEP_SUMMARY | |
| echo "- **Version**: ${{ needs.calculate-version.outputs.version }}" >> $GITHUB_STEP_SUMMARY | |
| echo "- **AUR URL**: https://aur.archlinux.org/packages/knxmonitor" >> $GITHUB_STEP_SUMMARY | |
| echo "" >> $GITHUB_STEP_SUMMARY | |
| echo "### Installation" >> $GITHUB_STEP_SUMMARY | |
| echo '```bash' >> $GITHUB_STEP_SUMMARY | |
| echo "# Using yay" >> $GITHUB_STEP_SUMMARY | |
| echo "yay -S knxmonitor" >> $GITHUB_STEP_SUMMARY | |
| echo "" >> $GITHUB_STEP_SUMMARY | |
| echo "# Using paru" >> $GITHUB_STEP_SUMMARY | |
| echo "paru -S knxmonitor" >> $GITHUB_STEP_SUMMARY | |
| echo "" >> $GITHUB_STEP_SUMMARY | |
| echo "# Manual installation" >> $GITHUB_STEP_SUMMARY | |
| echo "git clone https://aur.archlinux.org/knxmonitor.git" >> $GITHUB_STEP_SUMMARY | |
| echo "cd knxmonitor" >> $GITHUB_STEP_SUMMARY | |
| echo "makepkg -si" >> $GITHUB_STEP_SUMMARY | |
| echo '```' >> $GITHUB_STEP_SUMMARY | |
| else | |
| echo "❌ **AUR publishing failed**" >> $GITHUB_STEP_SUMMARY | |
| echo "" >> $GITHUB_STEP_SUMMARY | |
| echo "Please check the workflow logs for details." >> $GITHUB_STEP_SUMMARY | |
| echo "" >> $GITHUB_STEP_SUMMARY | |
| echo "### Manual Publishing" >> $GITHUB_STEP_SUMMARY | |
| echo "If automatic publishing fails, you can manually update the AUR package:" >> $GITHUB_STEP_SUMMARY | |
| echo '```bash' >> $GITHUB_STEP_SUMMARY | |
| echo "git clone ssh://aur@aur.archlinux.org/knxmonitor.git" >> $GITHUB_STEP_SUMMARY | |
| echo "cd knxmonitor" >> $GITHUB_STEP_SUMMARY | |
| echo "# Download PKGBUILD and .SRCINFO from artifacts" >> $GITHUB_STEP_SUMMARY | |
| echo "makepkg --printsrcinfo > .SRCINFO" >> $GITHUB_STEP_SUMMARY | |
| echo "git add PKGBUILD .SRCINFO" >> $GITHUB_STEP_SUMMARY | |
| echo "git commit -m 'Update to version ${{ needs.calculate-version.outputs.version }}'" >> $GITHUB_STEP_SUMMARY | |
| echo "git push" >> $GITHUB_STEP_SUMMARY | |
| echo '```' >> $GITHUB_STEP_SUMMARY | |
| fi | |
| update-homebrew: | |
| needs: [calculate-version, release] | |
| if: always() && needs.calculate-version.outputs.is-prerelease == 'false' && needs.release.result == 'success' | |
| runs-on: ubuntu-latest | |
| timeout-minutes: 10 | |
| continue-on-error: false # Don't fail the entire release if Homebrew update fails | |
| steps: | |
| - name: Download macOS artifacts | |
| uses: actions/download-artifact@v6.0.0 | |
| with: | |
| pattern: ${{ env.PROJECT_NAME }}-osx-* | |
| path: ./macos-artifacts | |
| - name: Calculate checksums | |
| id: checksums | |
| run: | | |
| # Calculate SHA256 for macOS x64 | |
| MACOS_X64_SHA=$(sha256sum ./macos-artifacts/${{ env.PROJECT_NAME }}-osx-x64/${{ env.PROJECT_NAME }}-${{ needs.calculate-version.outputs.version }}-osx-x64.tar.gz | cut -d' ' -f1) | |
| echo "macos_x64_sha=${MACOS_X64_SHA}" >> $GITHUB_OUTPUT | |
| # Calculate SHA256 for macOS ARM64 | |
| MACOS_ARM64_SHA=$(sha256sum ./macos-artifacts/${{ env.PROJECT_NAME }}-osx-arm64/${{ env.PROJECT_NAME }}-${{ needs.calculate-version.outputs.version }}-osx-arm64.tar.gz | cut -d' ' -f1) | |
| echo "macos_arm64_sha=${MACOS_ARM64_SHA}" >> $GITHUB_OUTPUT | |
| echo "macOS x64 SHA256: ${MACOS_X64_SHA}" | |
| echo "macOS ARM64 SHA256: ${MACOS_ARM64_SHA}" | |
| - name: Update Homebrew tap | |
| if: needs.calculate-version.outputs.is-prerelease == 'false' | |
| env: | |
| TAP_TOKEN: ${{ secrets.HOMEBREW_UPDATE_TOKEN }} | |
| run: | | |
| VERSION=${{ needs.calculate-version.outputs.version }} | |
| X64_SHA=${{ steps.checksums.outputs.macos_x64_sha }} | |
| ARM64_SHA=${{ steps.checksums.outputs.macos_arm64_sha }} | |
| git clone https://x-access-token:${TAP_TOKEN}@github.com/metaneutrons/homebrew-tap.git | |
| cd homebrew-tap | |
| mkdir -p Formula | |
| cat > Formula/knxmonitor.rb << EOF | |
| class Knxmonitor < Formula | |
| desc "KNX/EIB bus monitoring and debugging tool" | |
| homepage "https://github.com/metaneutrons/KnxMonitor" | |
| version "${VERSION}" | |
| license "GPL-3.0" | |
| on_macos do | |
| if Hardware::CPU.intel? | |
| url "https://github.com/metaneutrons/KnxMonitor/releases/download/v${VERSION}/KnxMonitor-${VERSION}-osx-x64.tar.gz" | |
| sha256 "${X64_SHA}" | |
| else | |
| url "https://github.com/metaneutrons/KnxMonitor/releases/download/v${VERSION}/KnxMonitor-${VERSION}-osx-arm64.tar.gz" | |
| sha256 "${ARM64_SHA}" | |
| end | |
| end | |
| def install | |
| bin.install "KnxMonitor" => "knxmonitor" | |
| man1.install "docs/knxmonitor.1" if File.exist?("docs/knxmonitor.1") | |
| end | |
| test do | |
| assert_match version.to_s, shell_output("#{bin}/knxmonitor --version") | |
| end | |
| end | |
| EOF | |
| git config user.name "github-actions[bot]" | |
| git config user.email "github-actions[bot]@users.noreply.github.com" | |
| git add Formula/knxmonitor.rb | |
| git commit -m "Update knxmonitor to ${VERSION}" | |
| git push | |
| - name: Create Homebrew update summary | |
| if: needs.calculate-version.outputs.is-prerelease == 'false' | |
| run: | | |
| echo "## 🍺 Homebrew Update Information" >> $GITHUB_STEP_SUMMARY | |
| echo "" >> $GITHUB_STEP_SUMMARY | |
| echo "**Version**: ${{ needs.calculate-version.outputs.version }}" >> $GITHUB_STEP_SUMMARY | |
| echo "**macOS x64 SHA256**: \`${{ steps.checksums.outputs.macos_x64_sha }}\`" >> $GITHUB_STEP_SUMMARY | |
| echo "**macOS ARM64 SHA256**: \`${{ steps.checksums.outputs.macos_arm64_sha }}\`" >> $GITHUB_STEP_SUMMARY | |
| echo "" >> $GITHUB_STEP_SUMMARY | |
| echo "✅ Homebrew formula updated automatically at Formula/knxmonitor.rb" >> $GITHUB_STEP_SUMMARY | |
| - name: Release Summary | |
| run: | | |
| echo "## 🎉 Release Summary" >> $GITHUB_STEP_SUMMARY | |
| echo "" >> $GITHUB_STEP_SUMMARY | |
| echo "**Version**: ${{ needs.calculate-version.outputs.version }}" >> $GITHUB_STEP_SUMMARY | |
| echo "**Tag**: ${{ needs.calculate-version.outputs.tag }}" >> $GITHUB_STEP_SUMMARY | |
| echo "**GitVersion**: ${{ needs.calculate-version.outputs.informational-version }}" >> $GITHUB_STEP_SUMMARY | |
| echo "**Prerelease**: ${{ needs.calculate-version.outputs.is-prerelease }}" >> $GITHUB_STEP_SUMMARY | |
| echo "" >> $GITHUB_STEP_SUMMARY | |
| echo "### 📦 Assets" >> $GITHUB_STEP_SUMMARY | |
| echo "- $(ls -1 ./release-assets/ | wc -l) platform binaries" >> $GITHUB_STEP_SUMMARY | |
| if [[ "${{ inputs.create_docker }}" == "true" ]]; then | |
| echo "- Docker image: \`ghcr.io/metaneutrons/knxmonitor:${{ needs.calculate-version.outputs.version }}\`" >> $GITHUB_STEP_SUMMARY | |
| fi | |
| if [[ "${{ needs.calculate-version.outputs.is-prerelease }}" == "false" ]]; then | |
| echo "- Homebrew formula will be updated automatically" >> $GITHUB_STEP_SUMMARY | |
| fi | |
| echo "" >> $GITHUB_STEP_SUMMARY | |
| echo "### 🔗 Links" >> $GITHUB_STEP_SUMMARY | |
| echo "- [Release Page](https://github.com/${{ github.repository }}/releases/tag/${{ needs.calculate-version.outputs.tag }})" >> $GITHUB_STEP_SUMMARY | |
| echo "- [Docker Image](https://github.com/${{ github.repository }}/pkgs/container/knxmonitor)" >> $GITHUB_STEP_SUMMARY | |
| echo "- [Homebrew Tap](https://github.com/metaneutrons/homebrew-tap)" >> $GITHUB_STEP_SUMMARY | |
| # Summary job to show overall status | |
| summary: | |
| needs: [calculate-version, build, docker, release, package-linux, update-homebrew, publish-aur] | |
| if: always() | |
| runs-on: ubuntu-latest | |
| steps: | |
| - name: Release Summary | |
| run: | | |
| echo "## 🎉 Release Summary" >> $GITHUB_STEP_SUMMARY | |
| echo "" >> $GITHUB_STEP_SUMMARY | |
| echo "**Version**: ${{ needs.calculate-version.outputs.version }}" >> $GITHUB_STEP_SUMMARY | |
| echo "**Tag**: ${{ needs.calculate-version.outputs.tag }}" >> $GITHUB_STEP_SUMMARY | |
| echo "**GitVersion**: ${{ needs.calculate-version.outputs.informational-version }}" >> $GITHUB_STEP_SUMMARY | |
| echo "**Prerelease**: ${{ needs.calculate-version.outputs.is-prerelease }}" >> $GITHUB_STEP_SUMMARY | |
| echo "" >> $GITHUB_STEP_SUMMARY | |
| echo "### 📊 Job Status" >> $GITHUB_STEP_SUMMARY | |
| echo "- **Version Calculation**: ${{ needs.calculate-version.result == 'success' && '✅' || '❌' }}" >> $GITHUB_STEP_SUMMARY | |
| echo "- **Build**: ${{ needs.build.result == 'success' && '✅' || '❌' }}" >> $GITHUB_STEP_SUMMARY | |
| echo "- **Linux Packaging**: ${{ needs.package-linux.result == 'success' && '✅' || needs.package-linux.result == 'skipped' && '⏭️' || '❌' }}" >> $GITHUB_STEP_SUMMARY | |
| echo "- **Docker**: ${{ needs.docker.result == 'success' && '✅' || needs.docker.result == 'skipped' && '⏭️' || '❌' }}" >> $GITHUB_STEP_SUMMARY | |
| echo "- **Release**: ${{ needs.release.result == 'success' && '✅' || '❌' }}" >> $GITHUB_STEP_SUMMARY | |
| echo "- **Homebrew**: ${{ needs.update-homebrew.result == 'success' && '✅' || needs.update-homebrew.result == 'skipped' && '⏭️' || '❌' }}" >> $GITHUB_STEP_SUMMARY | |
| echo "- **AUR**: ${{ needs.publish-aur.result == 'success' && '✅' || needs.publish-aur.result == 'skipped' && '⏭️' || '❌' }}" >> $GITHUB_STEP_SUMMARY | |
| echo "" >> $GITHUB_STEP_SUMMARY | |
| echo "### 📦 Assets" >> $GITHUB_STEP_SUMMARY | |
| if [[ "${{ needs.build.result }}" == "success" ]]; then | |
| echo "- ✅ Platform binaries created" >> $GITHUB_STEP_SUMMARY | |
| fi | |
| if [[ "${{ needs.package-linux.result }}" == "success" ]]; then | |
| echo "- ✅ Linux packages (.deb, AUR) created" >> $GITHUB_STEP_SUMMARY | |
| elif [[ "${{ needs.package-linux.result }}" == "failure" ]]; then | |
| echo "- ❌ Linux packaging failed" >> $GITHUB_STEP_SUMMARY | |
| fi | |
| if [[ "${{ needs.docker.result }}" == "success" ]]; then | |
| echo "- ✅ Docker image: \`ghcr.io/metaneutrons/knxmonitor:${{ needs.calculate-version.outputs.version }}\`" >> $GITHUB_STEP_SUMMARY | |
| elif [[ "${{ needs.docker.result }}" == "failure" ]]; then | |
| echo "- ❌ Docker image build failed" >> $GITHUB_STEP_SUMMARY | |
| fi | |
| if [[ "${{ needs.update-homebrew.result }}" == "success" ]]; then | |
| echo "- ✅ Homebrew formula updated automatically" >> $GITHUB_STEP_SUMMARY | |
| elif [[ "${{ needs.update-homebrew.result }}" == "failure" ]]; then | |
| echo "- ❌ Homebrew formula update failed (check artifacts for manual instructions)" >> $GITHUB_STEP_SUMMARY | |
| fi | |
| if [[ "${{ needs.publish-aur.result }}" == "success" ]]; then | |
| echo "- ✅ AUR package published automatically" >> $GITHUB_STEP_SUMMARY | |
| elif [[ "${{ needs.publish-aur.result }}" == "failure" ]]; then | |
| echo "- ❌ AUR package publishing failed (check artifacts for manual instructions)" >> $GITHUB_STEP_SUMMARY | |
| fi | |
| echo "" >> $GITHUB_STEP_SUMMARY | |
| echo "### 🔗 Links" >> $GITHUB_STEP_SUMMARY | |
| if [[ "${{ needs.release.result }}" == "success" ]]; then | |
| echo "- [Release Page](https://github.com/${{ github.repository }}/releases/tag/${{ needs.calculate-version.outputs.tag }})" >> $GITHUB_STEP_SUMMARY | |
| fi | |
| if [[ "${{ needs.docker.result }}" == "success" ]]; then | |
| echo "- [Docker Image](https://github.com/${{ github.repository }}/pkgs/container/knxmonitor)" >> $GITHUB_STEP_SUMMARY | |
| fi | |
| echo "- [Homebrew Tap](https://github.com/metaneutrons/homebrew-tap)" >> $GITHUB_STEP_SUMMARY | |
| if [[ "${{ needs.publish-aur.result }}" == "success" ]]; then | |
| echo "- [AUR Package](https://aur.archlinux.org/packages/knxmonitor)" >> $GITHUB_STEP_SUMMARY | |
| fi | |
| # Set overall workflow status | |
| if [[ "${{ needs.build.result }}" != "success" || "${{ needs.release.result }}" != "success" ]]; then | |
| echo "❌ Release failed - critical components failed" >> $GITHUB_STEP_SUMMARY | |
| exit 1 | |
| elif [[ "${{ needs.docker.result }}" == "failure" && "${{ inputs.create_docker }}" == "true" ]]; then | |
| echo "⚠️ Release completed with warnings - Docker build failed" >> $GITHUB_STEP_SUMMARY | |
| exit 1 | |
| else | |
| echo "✅ Release completed successfully" >> $GITHUB_STEP_SUMMARY | |
| fi |