From 316a70207874e4625ea427edba6d3dd658b32b19 Mon Sep 17 00:00:00 2001 From: mubeda <1380447+mubeda@users.noreply.github.com> Date: Thu, 25 Jun 2026 10:06:14 -0300 Subject: [PATCH] ci: add github binary release pipeline --- .github/workflows/ci.yml | 64 ++++ .github/workflows/dotnet-desktop.yml | 115 ------- .github/workflows/release.yml | 293 +++++++++++++++++ .gitignore | 1 - README.md | 52 ++- deploy/README.md | 182 ----------- deploy/linux/AppImageBuilder.yml | 53 ---- deploy/linux/package-linux.sh | 282 ----------------- deploy/macos/package-macos.sh | 295 ------------------ deploy/scripts/publish-all.ps1 | 240 -------------- deploy/scripts/publish-all.sh | 167 ---------- deploy/windows/package-windows.ps1 | 134 -------- docs/AVALONIA_MIGRATION_STATUS.md | 52 ++- docs/RELEASE_PIPELINE.md | 62 ++++ scripts/Installer/Info.plist.template | 36 --- .../Installer/build-macos-from-windows.bat | 177 ----------- scripts/Installer/build-macos.sh | 200 ------------ scripts/Installer/create-icns.sh | 109 ------- 18 files changed, 458 insertions(+), 2056 deletions(-) create mode 100644 .github/workflows/ci.yml delete mode 100644 .github/workflows/dotnet-desktop.yml create mode 100644 .github/workflows/release.yml delete mode 100644 deploy/README.md delete mode 100644 deploy/linux/AppImageBuilder.yml delete mode 100644 deploy/linux/package-linux.sh delete mode 100644 deploy/macos/package-macos.sh delete mode 100644 deploy/scripts/publish-all.ps1 delete mode 100644 deploy/scripts/publish-all.sh delete mode 100644 deploy/windows/package-windows.ps1 create mode 100644 docs/RELEASE_PIPELINE.md delete mode 100644 scripts/Installer/Info.plist.template delete mode 100644 scripts/Installer/build-macos-from-windows.bat delete mode 100644 scripts/Installer/build-macos.sh delete mode 100644 scripts/Installer/create-icns.sh diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 0000000..61ff2e9 --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,64 @@ +name: CI + +on: + push: + branches: + - master + pull_request: + branches: + - master + workflow_dispatch: + +permissions: + contents: read + +concurrency: + group: ci-${{ github.ref }} + cancel-in-progress: true + +env: + APP_PROJECT: src/Logbert/Logbert.csproj + TEST_PROJECT: tests/Logbert.Tests/Logbert.Tests.csproj + +jobs: + validate: + name: Build and test + runs-on: windows-latest + + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Setup .NET + uses: actions/setup-dotnet@v4 + with: + global-json-file: global.json + + - name: Show .NET SDK + shell: pwsh + run: dotnet --info + + - name: Restore + shell: pwsh + run: dotnet restore "$env:TEST_PROJECT" + + - name: Build + shell: pwsh + run: dotnet build "$env:APP_PROJECT" --configuration Release --no-restore + + - name: Test + shell: pwsh + run: dotnet test "$env:TEST_PROJECT" --configuration Release --no-restore --logger trx --results-directory TestResults + + - name: NuGet vulnerability report + shell: pwsh + run: dotnet list "$env:APP_PROJECT" package --include-transitive --vulnerable + + - name: Upload test results + if: always() + uses: actions/upload-artifact@v4 + with: + name: test-results-windows + path: TestResults/*.trx + if-no-files-found: ignore + retention-days: 14 diff --git a/.github/workflows/dotnet-desktop.yml b/.github/workflows/dotnet-desktop.yml deleted file mode 100644 index 99531b8..0000000 --- a/.github/workflows/dotnet-desktop.yml +++ /dev/null @@ -1,115 +0,0 @@ -# This workflow uses actions that are not certified by GitHub. -# They are provided by a third-party and are governed by -# separate terms of service, privacy policy, and support -# documentation. - -# This workflow will build, test, sign and package a WPF or Windows Forms desktop application -# built on .NET Core. -# To learn how to migrate your existing application to .NET Core, -# refer to https://docs.microsoft.com/en-us/dotnet/desktop-wpf/migration/convert-project-from-net-framework -# -# To configure this workflow: -# -# 1. Configure environment variables -# GitHub sets default environment variables for every workflow run. -# Replace the variables relative to your project in the "env" section below. -# -# 2. Signing -# Generate a signing certificate in the Windows Application -# Packaging Project or add an existing signing certificate to the project. -# Next, use PowerShell to encode the .pfx file using Base64 encoding -# by running the following Powershell script to generate the output string: -# -# $pfx_cert = Get-Content '.\SigningCertificate.pfx' -Encoding Byte -# [System.Convert]::ToBase64String($pfx_cert) | Out-File 'SigningCertificate_Encoded.txt' -# -# Open the output file, SigningCertificate_Encoded.txt, and copy the -# string inside. Then, add the string to the repo as a GitHub secret -# and name it "Base64_Encoded_Pfx." -# For more information on how to configure your signing certificate for -# this workflow, refer to https://github.com/microsoft/github-actions-for-desktop-apps#signing -# -# Finally, add the signing certificate password to the repo as a secret and name it "Pfx_Key". -# See "Build the Windows Application Packaging project" below to see how the secret is used. -# -# For more information on GitHub Actions, refer to https://github.com/features/actions -# For a complete CI/CD sample to get started with GitHub Action workflows for Desktop Applications, -# refer to https://github.com/microsoft/github-actions-for-desktop-apps - -name: .NET Core Desktop - -on: - push: - branches: [ "master" ] - pull_request: - branches: [ "master" ] - -jobs: - - build: - - strategy: - matrix: - configuration: [Debug, Release] - - runs-on: windows-latest # For a list of available runner types, refer to - # https://help.github.com/en/actions/reference/workflow-syntax-for-github-actions#jobsjob_idruns-on - - env: - Solution_Name: src/Logbert.sln - Test_Project_Path: your-test-project-path # Replace with the path to your test project, i.e. MyWpfApp.Tests\MyWpfApp.Tests.csproj. - Wap_Project_Directory: /src # Replace with the Wap project directory relative to the solution, i.e. MyWpfApp.Package. - Wap_Project_Path: your-wap-project-path # Replace with the path to your Wap project, i.e. MyWpf.App.Package\MyWpfApp.Package.wapproj. - - steps: - - name: Checkout - uses: actions/checkout@v4 - with: - fetch-depth: 0 - - # Install the .NET Core workload - - name: Install .NET Core - uses: actions/setup-dotnet@v4 - with: - dotnet-version: 9.0.x - - # Add MSBuild to the PATH: https://github.com/microsoft/setup-msbuild - - name: Setup MSBuild.exe - uses: microsoft/setup-msbuild@v2 - - # Execute all unit tests in the solution - - name: Execute unit tests - run: dotnet test - - # Restore the application to populate the obj folder with RuntimeIdentifiers - - name: Restore the application - run: msbuild $env:Solution_Name /t:Restore /p:Configuration=$env:Configuration - env: - Configuration: ${{ matrix.configuration }} - - # Decode the base 64 encoded pfx and save the Signing_Certificate - - name: Decode the pfx - run: | - $pfx_cert_byte = [System.Convert]::FromBase64String("${{ secrets.Base64_Encoded_Pfx }}") - $certificatePath = Join-Path -Path $env:Wap_Project_Directory -ChildPath GitHubActionsWorkflow.pfx - [IO.File]::WriteAllBytes("$certificatePath", $pfx_cert_byte) - - # Create the app package by building and packaging the Windows Application Packaging project - - name: Create the app package - run: msbuild $env:Wap_Project_Path /p:Configuration=$env:Configuration /p:UapAppxPackageBuildMode=$env:Appx_Package_Build_Mode /p:AppxBundle=$env:Appx_Bundle /p:PackageCertificateKeyFile=GitHubActionsWorkflow.pfx /p:PackageCertificatePassword=${{ secrets.Pfx_Key }} - env: - Appx_Bundle: Always - Appx_Bundle_Platforms: x86|x64 - Appx_Package_Build_Mode: StoreUpload - Configuration: ${{ matrix.configuration }} - - # Remove the pfx - - name: Remove the pfx - run: Remove-Item -path $env:Wap_Project_Directory\GitHubActionsWorkflow.pfx - - # Upload the MSIX package: https://github.com/marketplace/actions/upload-a-build-artifact - - name: Upload build artifacts - uses: actions/upload-artifact@v4 - with: - name: MSIX Package - path: ${{ env.Wap_Project_Directory }}\AppPackages diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml new file mode 100644 index 0000000..a6e7423 --- /dev/null +++ b/.github/workflows/release.yml @@ -0,0 +1,293 @@ +name: Release + +on: + push: + tags: + - "v*" + - "[0-9]*" + workflow_dispatch: + inputs: + version: + description: Version to build. Must match src/Logbert/Logbert.csproj. + required: true + type: string + create_release: + description: Create or update a GitHub Release. Use false for dry runs. + required: true + default: false + type: boolean + +permissions: + contents: read + +concurrency: + group: release-${{ github.ref }} + cancel-in-progress: false + +env: + APP_PROJECT: src/Logbert/Logbert.csproj + TEST_PROJECT: tests/Logbert.Tests/Logbert.Tests.csproj + +jobs: + prepare: + name: Validate release version + runs-on: windows-latest + outputs: + version: ${{ steps.version.outputs.version }} + release_tag: ${{ steps.version.outputs.release_tag }} + create_release: ${{ steps.version.outputs.create_release }} + + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Setup .NET + uses: actions/setup-dotnet@v4 + with: + global-json-file: global.json + + - name: Resolve version + id: version + shell: pwsh + run: | + [xml]$csproj = Get-Content -LiteralPath "$env:APP_PROJECT" + $projectVersion = $csproj.Project.PropertyGroup.Version | Where-Object { $_ } | Select-Object -First 1 + if ([string]::IsNullOrWhiteSpace($projectVersion)) { + throw "No found in $env:APP_PROJECT" + } + + $refType = "${{ github.ref_type }}" + $refName = "${{ github.ref_name }}" + $dispatchVersion = "${{ inputs.version }}" + $createRelease = "${{ inputs.create_release }}" + + if ($refType -eq "tag") { + $requestedVersion = $refName.TrimStart("v") + $releaseTag = $refName + $createRelease = "true" + } else { + $requestedVersion = $dispatchVersion.TrimStart("v") + $releaseTag = $requestedVersion + } + + if ($requestedVersion -notmatch '^\d+\.\d+\.\d+$') { + throw "Version must be semantic version x.y.z. Received: $requestedVersion" + } + + if ($requestedVersion -ne $projectVersion) { + throw "Requested version $requestedVersion does not match csproj version $projectVersion" + } + + "version=$projectVersion" >> $env:GITHUB_OUTPUT + "release_tag=$releaseTag" >> $env:GITHUB_OUTPUT + "create_release=$createRelease" >> $env:GITHUB_OUTPUT + + - name: Restore + shell: pwsh + run: dotnet restore "$env:TEST_PROJECT" + + - name: Build + shell: pwsh + run: dotnet build "$env:APP_PROJECT" --configuration Release --no-restore + + - name: Test + shell: pwsh + run: dotnet test "$env:TEST_PROJECT" --configuration Release --no-restore + + package: + name: Package ${{ matrix.rid }} + needs: prepare + runs-on: ${{ matrix.os }} + strategy: + fail-fast: false + matrix: + include: + - rid: win-x64 + os: windows-latest + - rid: win-arm64 + os: windows-latest + - rid: linux-x64 + os: ubuntu-latest + - rid: linux-arm64 + os: ubuntu-latest + - rid: osx-arm64 + os: macos-latest + + env: + PACKAGE_DIR: ${{ github.workspace }}/release-artifacts + PUBLISH_DIR: ${{ github.workspace }}/artifacts/${{ matrix.rid }}/publish + RID: ${{ matrix.rid }} + VERSION: ${{ needs.prepare.outputs.version }} + + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Setup .NET + uses: actions/setup-dotnet@v4 + with: + global-json-file: global.json + + - name: Install zip + if: runner.os == 'Linux' + shell: bash + run: sudo apt-get update && sudo apt-get install -y zip + + - name: Publish + shell: pwsh + run: | + New-Item -ItemType Directory -Force -Path "$env:PUBLISH_DIR" | Out-Null + dotnet publish "$env:APP_PROJECT" ` + --configuration Release ` + --runtime "$env:RID" ` + --self-contained true ` + -p:PublishSingleFile=true ` + -p:PublishTrimmed=false ` + -p:Version="$env:VERSION" ` + -p:IncludeNativeLibrariesForSelfExtract=true ` + --output "$env:PUBLISH_DIR" + + - name: Package Windows ZIP + if: runner.os == 'Windows' + shell: pwsh + run: | + New-Item -ItemType Directory -Force -Path "$env:PACKAGE_DIR" | Out-Null + $zipPath = Join-Path "$env:PACKAGE_DIR" "Logbert-$env:VERSION-$env:RID.zip" + if (Test-Path -LiteralPath $zipPath) { + Remove-Item -LiteralPath $zipPath -Force + } + Compress-Archive -Path (Join-Path "$env:PUBLISH_DIR" "*") -DestinationPath $zipPath -CompressionLevel Optimal + + - name: Package Linux ZIP + if: runner.os == 'Linux' + shell: bash + run: | + set -euo pipefail + mkdir -p "$PACKAGE_DIR" + chmod +x "$PUBLISH_DIR/Logbert" + (cd "$PUBLISH_DIR" && zip -r "$PACKAGE_DIR/Logbert-$VERSION-$RID.zip" .) + + - name: Package macOS app ZIP + if: runner.os == 'macOS' + shell: bash + run: | + set -euo pipefail + mkdir -p "$PACKAGE_DIR" + + WORK_DIR="$RUNNER_TEMP/logbert-macos-$RID" + APP_BUNDLE="$WORK_DIR/Logbert.app" + rm -rf "$WORK_DIR" + mkdir -p "$APP_BUNDLE/Contents/MacOS" "$APP_BUNDLE/Contents/Resources" + + cp -R "$PUBLISH_DIR/"* "$APP_BUNDLE/Contents/MacOS/" + chmod +x "$APP_BUNDLE/Contents/MacOS/Logbert" + + if [ -f "$GITHUB_WORKSPACE/src/Logbert/Resources/AppIcon.png" ]; then + cp "$GITHUB_WORKSPACE/src/Logbert/Resources/AppIcon.png" "$APP_BUNDLE/Contents/Resources/AppIcon.png" + fi + + cat > "$APP_BUNDLE/Contents/Info.plist" << EOF + + + + + CFBundleInfoDictionaryVersion + 6.0 + CFBundleDevelopmentRegion + en + CFBundlePackageType + APPL + CFBundleIdentifier + com.couchcoding.logbert + CFBundleExecutable + Logbert + CFBundleIconFile + AppIcon + CFBundleDisplayName + Logbert + CFBundleName + Logbert + CFBundleVersion + $VERSION + CFBundleShortVersionString + $VERSION + LSMinimumSystemVersion + 11.0 + NSHighResolutionCapable + + + + EOF + + cd "$WORK_DIR" + ditto -c -k --sequesterRsrc --keepParent "Logbert.app" "$PACKAGE_DIR/Logbert-$VERSION-$RID.zip" + + - name: Verify package + shell: pwsh + run: | + $zipPath = Join-Path "$env:PACKAGE_DIR" "Logbert-$env:VERSION-$env:RID.zip" + if (-not (Test-Path -LiteralPath $zipPath)) { + throw "Package was not created: $zipPath" + } + + $package = Get-Item -LiteralPath $zipPath + if ($package.Length -lt 10MB) { + throw "Package is unexpectedly small: $($package.Length) bytes" + } + + tar -tf $package.FullName | Select-Object -First 20 + + - name: Upload package + uses: actions/upload-artifact@v4 + with: + name: Logbert-${{ needs.prepare.outputs.version }}-${{ matrix.rid }} + path: release-artifacts/Logbert-${{ needs.prepare.outputs.version }}-${{ matrix.rid }}.zip + if-no-files-found: error + retention-days: 30 + + publish-release: + name: Publish GitHub Release + needs: + - prepare + - package + if: needs.prepare.outputs.create_release == 'true' + runs-on: ubuntu-latest + permissions: + contents: write + + steps: + - name: Download packages + uses: actions/download-artifact@v4 + with: + pattern: Logbert-${{ needs.prepare.outputs.version }}-* + path: dist + merge-multiple: true + + - name: Create checksums + shell: bash + run: | + set -euo pipefail + cd dist + sha256sum *.zip > SHA256SUMS.txt + ls -lh + + - name: Create release notes + shell: bash + run: | + cat > RELEASE_BODY.md <<'EOF' + Automated unsigned Logbert binaries. + + Assets are self-contained ZIP packages. No .NET runtime installation is required. + + Code signing and notarization are not configured yet, so macOS may require manual approval on first launch. Verify downloads with SHA256SUMS.txt. + EOF + + - name: Create GitHub Release + env: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + shell: bash + run: | + gh release create "${{ needs.prepare.outputs.release_tag }}" dist/* \ + --verify-tag \ + --title "Logbert ${{ needs.prepare.outputs.version }}" \ + --notes-file RELEASE_BODY.md diff --git a/.gitignore b/.gitignore index 09bbffc..c507b82 100644 --- a/.gitignore +++ b/.gitignore @@ -7,7 +7,6 @@ src/Couchcoding.Logbert.Theme/obj/ packages/ publish/ .claude/ -scripts/Installer/Output/ tests/Logbert.Tests/bin/ tests/Logbert.Tests/obj/ nul diff --git a/README.md b/README.md index 6557891..98128c3 100644 --- a/README.md +++ b/README.md @@ -86,36 +86,21 @@ dotnet build dotnet run --project src/Logbert/Logbert.csproj ``` -### Build Status -``` -Build succeeded. - 0 Warning(s) - 0 Error(s) -``` - -### Publishing for Distribution - -```bash -# Windows (x64) -dotnet publish -c Release -r win-x64 --self-contained - -# Windows (ARM64) -dotnet publish -c Release -r win-arm64 --self-contained - -# macOS (Intel) -dotnet publish -c Release -r osx-x64 --self-contained - -# macOS (Apple Silicon) -dotnet publish -c Release -r osx-arm64 --self-contained - -# Linux (x64) -dotnet publish -c Release -r linux-x64 --self-contained - -# Linux (ARM64) -dotnet publish -c Release -r linux-arm64 --self-contained -``` - -Published applications will be in `src/Logbert/bin/Release/net10.0/{runtime}/publish/` +### Build Status + +[![CI](https://github.com/mubeda/Logbert/actions/workflows/ci.yml/badge.svg)](https://github.com/mubeda/Logbert/actions/workflows/ci.yml) + +### Automated Release Builds + +```bash +# Create a release build by pushing a version tag that matches src/Logbert/Logbert.csproj +git tag 2.1.2 +git push origin 2.1.2 +``` + +GitHub Actions generates unsigned, self-contained ZIP assets for Windows x64, +Windows ARM64, Linux x64, Linux ARM64, and macOS ARM64. See +[Release Pipeline](docs/RELEASE_PIPELINE.md) for details. ## Architecture @@ -155,9 +140,10 @@ Detailed documentation is available in the [docs/](docs/) directory: - [Migration Status](docs/AVALONIA_MIGRATION_STATUS.md) - Project status, migration progress, and Phase 6 roadmap - [Testing Checklist](docs/TESTING_CHECKLIST.md) - Comprehensive test procedures - [User Guide](docs/USER_GUIDE.md) - How to use Logbert -- [Developer Guide](docs/DEVELOPER_GUIDE.md) - Contributing and development -- [Receivers](docs/RECEIVERS.md) - Receiver configuration details -- [Scripting](docs/SCRIPTING.md) - Lua API reference +- [Developer Guide](docs/DEVELOPER_GUIDE.md) - Contributing and development +- [Release Pipeline](docs/RELEASE_PIPELINE.md) - Automated CI and binary releases +- [Receivers](docs/RECEIVERS.md) - Receiver configuration details +- [Scripting](docs/SCRIPTING.md) - Lua API reference ## Contributing diff --git a/deploy/README.md b/deploy/README.md deleted file mode 100644 index 56017e3..0000000 --- a/deploy/README.md +++ /dev/null @@ -1,182 +0,0 @@ -# Logbert Deployment Scripts - -This directory contains scripts for building and packaging Logbert for distribution across multiple platforms. - -## Prerequisites - -- .NET 10.0 SDK or later -- Platform-specific tools (see below) - -## Directory Structure - -``` -deploy/ -├── scripts/ # Cross-platform build scripts -│ ├── publish-all.sh # Bash script for all platforms -│ └── publish-all.ps1 # PowerShell script for all platforms -├── windows/ # Windows-specific packaging -│ └── package-windows.ps1 -├── linux/ # Linux-specific packaging -│ ├── package-linux.sh -│ └── AppImageBuilder.yml -└── macos/ # macOS-specific packaging - └── package-macos.sh -``` - -## Quick Start - -### Build for All Platforms - -**On Linux/macOS:** -```bash -cd deploy/scripts -./publish-all.sh -``` - -**On Windows (PowerShell):** -```powershell -cd deploy\scripts -.\publish-all.ps1 -``` - -### Build for Specific Platforms - -```bash -# Windows only -./publish-all.sh -w - -# Linux only -./publish-all.sh -l - -# macOS only -./publish-all.sh -m - -# Combine flags -./publish-all.sh -w -l -``` - -## Platform-Specific Packaging - -After running the publish script, use the platform-specific packaging scripts: - -### Windows - -Creates ZIP archives for distribution: - -```powershell -cd deploy\windows -.\package-windows.ps1 --version 2.0.0 -``` - -**Output:** -- `packages/Logbert-2.0.0-win-x64.zip` -- `packages/Logbert-2.0.0-win-arm64.zip` - -### Linux - -Creates tar.gz archives and .deb packages: - -```bash -cd deploy/linux -./package-linux.sh --version 2.0.0 -``` - -**Output:** -- `packages/Logbert-2.0.0-linux-x64.tar.gz` -- `packages/Logbert-2.0.0-linux-arm64.tar.gz` -- `packages/Logbert-2.0.0-linux-x64.deb` (if dpkg-deb available) -- `packages/Logbert-2.0.0-linux-arm64.deb` (if dpkg-deb available) - -**For AppImage (requires appimage-builder):** -```bash -cd deploy/linux -appimage-builder --recipe AppImageBuilder.yml -``` - -### macOS - -Creates .app bundle and .dmg installer: - -```bash -cd deploy/macos -./package-macos.sh --version 2.0.0 -``` - -**Options:** -- `--app` - Create .app bundle only -- `--dmg` - Create .dmg installer only -- `--sign IDENTITY` - Code sign with specified identity - -**Output:** -- `packages/Logbert.app` -- `packages/Logbert-2.0.0-macos-arm64.dmg` (on macOS) -- `packages/Logbert-2.0.0-macos-arm64.tar.gz` (fallback on non-macOS) - -## Supported Architectures - -| Platform | Architectures | -|----------|---------------| -| Windows | x64, ARM64 | -| Linux | x64, ARM64 | -| macOS | ARM64 (Apple Silicon) | - -## Build Output - -All publish output goes to the `publish/` directory in the repository root: - -``` -publish/ -├── win-x64/ -├── win-arm64/ -├── linux-x64/ -├── linux-arm64/ -└── osx-arm64/ -``` - -Packaged distributions go to the `packages/` directory: - -``` -packages/ -├── Logbert-2.0.0-win-x64.zip -├── Logbert-2.0.0-win-arm64.zip -├── Logbert-2.0.0-linux-x64.tar.gz -├── Logbert-2.0.0-linux-arm64.tar.gz -├── Logbert-2.0.0-linux-x64.deb -├── Logbert-2.0.0-linux-arm64.deb -├── Logbert.app/ -└── Logbert-2.0.0-macos-arm64.dmg -``` - -## Version Numbers - -Set the version using the `--version` flag or `VERSION` environment variable: - -```bash -VERSION=2.1.0 ./publish-all.sh -# or -./publish-all.sh --version 2.1.0 -``` - -## Troubleshooting - -### Linux .deb Creation Fails -Install `dpkg-deb`: -```bash -sudo apt-get install dpkg -``` - -### macOS .dmg Creation Fails -DMG creation requires `hdiutil`, which is only available on macOS. On other platforms, a tar.gz archive is created instead. - -### AppImage Creation Fails -Install appimage-builder: -```bash -pip3 install appimage-builder -``` - -## Notes - -- All builds are self-contained (no .NET runtime required on target machine) -- Single-file deployment is enabled for cleaner distribution -- macOS builds target Apple Silicon (ARM64) only -- For Intel Mac support, modify the scripts to include `osx-x64` RID diff --git a/deploy/linux/AppImageBuilder.yml b/deploy/linux/AppImageBuilder.yml deleted file mode 100644 index 902a9ca..0000000 --- a/deploy/linux/AppImageBuilder.yml +++ /dev/null @@ -1,53 +0,0 @@ -# Logbert AppImage Builder Configuration -# Use with appimage-builder: https://appimage-builder.readthedocs.io/ - -version: 1 -script: - - rm -rf AppDir || true - - mkdir -p AppDir/usr/bin - - mkdir -p AppDir/usr/share/applications - - mkdir -p AppDir/usr/share/icons/hicolor/256x256/apps - # Copy application files from publish directory - - cp -r ../../publish/linux-x64/* AppDir/usr/bin/ - - chmod +x AppDir/usr/bin/Logbert - -AppDir: - path: ./AppDir - - app_info: - id: com.logbert.Logbert - name: Logbert - icon: logbert - version: "2.0.0" - exec: usr/bin/Logbert - exec_args: $@ - - apt: - arch: amd64 - sources: - - sourceline: 'deb [arch=amd64] http://archive.ubuntu.com/ubuntu/ jammy main restricted universe multiverse' - key_url: 'http://keyserver.ubuntu.com/pks/lookup?op=get&search=0x871920D1991BC93C' - - include: - - libicu70 - - libssl3 - - runtime: - env: - DOTNET_SYSTEM_GLOBALIZATION_INVARIANT: "1" - - test: - fedora-30: - image: appimagecrafters/tests-env:fedora-30 - command: ./AppRun --version - debian-stable: - image: appimagecrafters/tests-env:debian-stable - command: ./AppRun --version - ubuntu-xenial: - image: appimagecrafters/tests-env:ubuntu-xenial - command: ./AppRun --version - -AppImage: - arch: x86_64 - update-information: "gh-releases-zsync|logbert|logbert|latest|Logbert-*x86_64.AppImage.zsync" - sign-key: None diff --git a/deploy/linux/package-linux.sh b/deploy/linux/package-linux.sh deleted file mode 100644 index c3bd30e..0000000 --- a/deploy/linux/package-linux.sh +++ /dev/null @@ -1,282 +0,0 @@ -#!/bin/bash -# Logbert Linux Packaging Script -# Creates tar.gz and .deb packages for Linux x64 and ARM64 - -set -e - -SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" -ROOT_DIR="$(cd "$SCRIPT_DIR/../.." && pwd)" -PUBLISH_DIR="${PUBLISH_DIR:-$ROOT_DIR/publish}" -PACKAGE_DIR="$ROOT_DIR/packages" -VERSION="${VERSION:-2.0.0}" - -show_help() { - cat << EOF -Logbert Linux Packaging Script - -Usage: $0 [options] - -Options: - --version VERSION Version number for the package (default: 2.0.0) - --publish-dir DIR Path to the publish directory (default: ../../publish) - --tar Create tar.gz packages only - --deb Create .deb packages only - --all Create all package types (default) - --help Show this help message - -Prerequisites: - Run publish-all.sh first to build the executables. - For .deb packages, dpkg-deb must be installed. -EOF -} - -create_tarball() { - local RID=$1 - local ARCH=$2 - - local SOURCE_DIR="$PUBLISH_DIR/$RID" - - if [ ! -d "$SOURCE_DIR" ]; then - echo "Warning: Source directory not found: $SOURCE_DIR" - echo "Run publish-all.sh -l first" - return - fi - - local TAR_NAME="Logbert-$VERSION-linux-$ARCH.tar.gz" - local TAR_PATH="$PACKAGE_DIR/$TAR_NAME" - - echo "Creating $TAR_NAME..." - - # Create temporary directory - local TEMP_DIR=$(mktemp -d) - local APP_DIR="$TEMP_DIR/logbert-$VERSION" - mkdir -p "$APP_DIR" - - # Copy files - cp -r "$SOURCE_DIR"/* "$APP_DIR/" - - # Make executable - chmod +x "$APP_DIR/Logbert" - - # Add README - cat > "$APP_DIR/README.txt" << EOREADME -Logbert $VERSION for Linux $ARCH - -INSTALLATION -============ -1. Extract this archive to a folder of your choice: - tar -xzf $TAR_NAME - -2. Run the application: - ./Logbert - -OPTIONAL: Create a desktop shortcut -==================================== -Copy logbert.desktop to ~/.local/share/applications/ -Update the Exec and Icon paths in the file. - -REQUIREMENTS -============ -No additional requirements - this is a self-contained application. - -DOCUMENTATION -============= -https://github.com/logbert/logbert/wiki - -LICENSE -======= -MIT License - See LICENSE.txt for details -EOREADME - - # Add desktop file - cat > "$APP_DIR/logbert.desktop" << EODESKTOP -[Desktop Entry] -Version=1.0 -Type=Application -Name=Logbert -Comment=Cross-platform log file viewer -Exec=/opt/logbert/Logbert -Icon=/opt/logbert/logbert.png -Terminal=false -Categories=Development;Utility; -EODESKTOP - - # Create tarball - tar -czf "$TAR_PATH" -C "$TEMP_DIR" "logbert-$VERSION" - - # Cleanup - rm -rf "$TEMP_DIR" - - echo "Created: $TAR_PATH" - echo "Size: $(du -h "$TAR_PATH" | cut -f1)" -} - -create_deb() { - local RID=$1 - local ARCH=$2 - local DEB_ARCH=$3 - - local SOURCE_DIR="$PUBLISH_DIR/$RID" - - if [ ! -d "$SOURCE_DIR" ]; then - echo "Warning: Source directory not found: $SOURCE_DIR" - echo "Run publish-all.sh -l first" - return - fi - - if ! command -v dpkg-deb &> /dev/null; then - echo "Warning: dpkg-deb not found, skipping .deb package for $ARCH" - return - fi - - local DEB_NAME="logbert_${VERSION}_${DEB_ARCH}.deb" - local DEB_PATH="$PACKAGE_DIR/$DEB_NAME" - - echo "Creating $DEB_NAME..." - - # Create temporary directory structure - local TEMP_DIR=$(mktemp -d) - local DEB_ROOT="$TEMP_DIR/logbert" - - mkdir -p "$DEB_ROOT/DEBIAN" - mkdir -p "$DEB_ROOT/opt/logbert" - mkdir -p "$DEB_ROOT/usr/share/applications" - mkdir -p "$DEB_ROOT/usr/share/icons/hicolor/256x256/apps" - - # Copy application files - cp -r "$SOURCE_DIR"/* "$DEB_ROOT/opt/logbert/" - chmod +x "$DEB_ROOT/opt/logbert/Logbert" - - # Create control file - cat > "$DEB_ROOT/DEBIAN/control" << EOCONTROL -Package: logbert -Version: $VERSION -Section: utils -Priority: optional -Architecture: $DEB_ARCH -Maintainer: Logbert Contributors -Description: Cross-platform log file viewer - Logbert is a powerful log file viewer supporting multiple formats - including Log4Net, NLog, Syslog, and Windows Event Logs. - Features include real-time monitoring, advanced filtering, - regex search, Lua scripting, and more. -Homepage: https://github.com/logbert/logbert -EOCONTROL - - # Create desktop file - cat > "$DEB_ROOT/usr/share/applications/logbert.desktop" << EODESKTOP -[Desktop Entry] -Version=1.0 -Type=Application -Name=Logbert -Comment=Cross-platform log file viewer -Exec=/opt/logbert/Logbert -Icon=logbert -Terminal=false -Categories=Development;Utility; -EODESKTOP - - # Create postinst script - cat > "$DEB_ROOT/DEBIAN/postinst" << 'EOPOSTINST' -#!/bin/bash -# Create symlink for easy command-line access -ln -sf /opt/logbert/Logbert /usr/local/bin/logbert -EOPOSTINST - chmod 755 "$DEB_ROOT/DEBIAN/postinst" - - # Create postrm script - cat > "$DEB_ROOT/DEBIAN/postrm" << 'EOPOSTRM' -#!/bin/bash -# Remove symlink -rm -f /usr/local/bin/logbert -EOPOSTRM - chmod 755 "$DEB_ROOT/DEBIAN/postrm" - - # Build .deb package - dpkg-deb --build "$DEB_ROOT" "$DEB_PATH" - - # Cleanup - rm -rf "$TEMP_DIR" - - echo "Created: $DEB_PATH" - echo "Size: $(du -h "$DEB_PATH" | cut -f1)" -} - -# Parse arguments -CREATE_TAR=false -CREATE_DEB=false -CREATE_ALL=false - -while [[ $# -gt 0 ]]; do - case $1 in - --version) - VERSION="$2" - shift 2 - ;; - --publish-dir) - PUBLISH_DIR="$2" - shift 2 - ;; - --tar) - CREATE_TAR=true - shift - ;; - --deb) - CREATE_DEB=true - shift - ;; - --all) - CREATE_ALL=true - shift - ;; - --help|-h) - show_help - exit 0 - ;; - *) - echo "Unknown option: $1" - show_help - exit 1 - ;; - esac -done - -# Default to all if nothing specified -if [ "$CREATE_TAR" = false ] && [ "$CREATE_DEB" = false ]; then - CREATE_ALL=true -fi - -if [ "$CREATE_ALL" = true ]; then - CREATE_TAR=true - CREATE_DEB=true -fi - -echo "==========================================" -echo "Logbert Linux Packaging Script" -echo "==========================================" -echo "" - -# Create packages directory -mkdir -p "$PACKAGE_DIR" - -# Create packages for each architecture -if [ "$CREATE_TAR" = true ]; then - echo "Creating tar.gz packages..." - create_tarball "linux-x64" "x64" - create_tarball "linux-arm64" "arm64" -fi - -if [ "$CREATE_DEB" = true ]; then - echo "" - echo "Creating .deb packages..." - create_deb "linux-x64" "x64" "amd64" - create_deb "linux-arm64" "arm64" "arm64" -fi - -echo "" -echo "==========================================" -echo "Packaging Complete!" -echo "==========================================" -echo "" -echo "Packages created in: $PACKAGE_DIR" -ls -la "$PACKAGE_DIR" | grep -E "\.(tar\.gz|deb)$" | grep linux || true diff --git a/deploy/macos/package-macos.sh b/deploy/macos/package-macos.sh deleted file mode 100644 index 6bfd0ec..0000000 --- a/deploy/macos/package-macos.sh +++ /dev/null @@ -1,295 +0,0 @@ -#!/bin/bash -# Logbert macOS Packaging Script -# Creates .app bundle and .dmg installer for macOS ARM64 - -set -e - -SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" -ROOT_DIR="$(cd "$SCRIPT_DIR/../.." && pwd)" -PUBLISH_DIR="${PUBLISH_DIR:-$ROOT_DIR/publish}" -PACKAGE_DIR="$ROOT_DIR/packages" -VERSION="${VERSION:-2.0.0}" -APP_NAME="Logbert" -BUNDLE_ID="com.logbert.Logbert" - -show_help() { - cat << EOF -Logbert macOS Packaging Script - -Usage: $0 [options] - -Options: - --version VERSION Version number for the package (default: 2.0.0) - --publish-dir DIR Path to the publish directory (default: ../../publish) - --app Create .app bundle only - --dmg Create .dmg installer only - --all Create both (default) - --sign IDENTITY Code signing identity (optional) - --help Show this help message - -Prerequisites: - Run publish-all.sh first to build the executables. - For .dmg creation, hdiutil must be available (macOS only). - -Note: This script should be run on macOS for full functionality. -EOF -} - -create_app_bundle() { - local SOURCE_DIR="$PUBLISH_DIR/osx-arm64" - - if [ ! -d "$SOURCE_DIR" ]; then - echo "Warning: Source directory not found: $SOURCE_DIR" - echo "Run publish-all.sh -m first" - return 1 - fi - - echo "Creating $APP_NAME.app bundle..." - - # Create .app bundle structure - local APP_BUNDLE="$PACKAGE_DIR/$APP_NAME.app" - rm -rf "$APP_BUNDLE" - - mkdir -p "$APP_BUNDLE/Contents/MacOS" - mkdir -p "$APP_BUNDLE/Contents/Resources" - - # Copy application files - cp -r "$SOURCE_DIR"/* "$APP_BUNDLE/Contents/MacOS/" - chmod +x "$APP_BUNDLE/Contents/MacOS/Logbert" - - # Create Info.plist - cat > "$APP_BUNDLE/Contents/Info.plist" << EOPLIST - - - - - CFBundleDevelopmentRegion - en - CFBundleExecutable - Logbert - CFBundleIconFile - Logbert.icns - CFBundleIdentifier - $BUNDLE_ID - CFBundleInfoDictionaryVersion - 6.0 - CFBundleName - $APP_NAME - CFBundlePackageType - APPL - CFBundleShortVersionString - $VERSION - CFBundleVersion - $VERSION - LSMinimumSystemVersion - 11.0 - NSHighResolutionCapable - - NSHumanReadableCopyright - Copyright © 2024 Logbert Contributors. MIT License. - CFBundleDocumentTypes - - - CFBundleTypeName - Log File - CFBundleTypeRole - Viewer - LSHandlerRank - Alternate - CFBundleTypeExtensions - - log - txt - xml - - - - LSApplicationCategoryType - public.app-category.developer-tools - - -EOPLIST - - # Create PkgInfo - echo "APPL????" > "$APP_BUNDLE/Contents/PkgInfo" - - # Code sign if identity provided - if [ -n "$SIGN_IDENTITY" ]; then - echo "Code signing with identity: $SIGN_IDENTITY" - codesign --force --deep --sign "$SIGN_IDENTITY" "$APP_BUNDLE" - fi - - echo "Created: $APP_BUNDLE" - return 0 -} - -create_dmg() { - local APP_BUNDLE="$PACKAGE_DIR/$APP_NAME.app" - - if [ ! -d "$APP_BUNDLE" ]; then - echo "App bundle not found. Creating it first..." - create_app_bundle || return 1 - fi - - if ! command -v hdiutil &> /dev/null; then - echo "Warning: hdiutil not found. DMG creation requires macOS." - echo "Creating tar.gz archive instead..." - create_tarball - return - fi - - local DMG_NAME="Logbert-$VERSION-macos-arm64.dmg" - local DMG_PATH="$PACKAGE_DIR/$DMG_NAME" - local DMG_TEMP="$PACKAGE_DIR/dmg_temp" - - echo "Creating $DMG_NAME..." - - # Create temporary DMG directory - rm -rf "$DMG_TEMP" - mkdir -p "$DMG_TEMP" - - # Copy .app bundle - cp -r "$APP_BUNDLE" "$DMG_TEMP/" - - # Create Applications symlink - ln -s /Applications "$DMG_TEMP/Applications" - - # Create README - cat > "$DMG_TEMP/README.txt" << EOREADME -Logbert $VERSION for macOS (Apple Silicon) - -INSTALLATION -============ -Drag Logbert.app to the Applications folder. - -FIRST RUN -========= -On first run, you may need to: -1. Right-click the app and select "Open" -2. Click "Open" in the security dialog - -This is required because the app is not notarized. - -DOCUMENTATION -============= -https://github.com/logbert/logbert/wiki - -LICENSE -======= -MIT License -EOREADME - - # Remove any existing DMG - rm -f "$DMG_PATH" - - # Create DMG - hdiutil create -volname "$APP_NAME $VERSION" \ - -srcfolder "$DMG_TEMP" \ - -ov -format UDZO \ - "$DMG_PATH" - - # Cleanup - rm -rf "$DMG_TEMP" - - echo "Created: $DMG_PATH" - echo "Size: $(du -h "$DMG_PATH" | cut -f1)" -} - -create_tarball() { - local APP_BUNDLE="$PACKAGE_DIR/$APP_NAME.app" - - if [ ! -d "$APP_BUNDLE" ]; then - echo "App bundle not found. Creating it first..." - create_app_bundle || return 1 - fi - - local TAR_NAME="Logbert-$VERSION-macos-arm64.tar.gz" - local TAR_PATH="$PACKAGE_DIR/$TAR_NAME" - - echo "Creating $TAR_NAME..." - - # Create tarball of the .app bundle - tar -czf "$TAR_PATH" -C "$PACKAGE_DIR" "$APP_NAME.app" - - echo "Created: $TAR_PATH" - echo "Size: $(du -h "$TAR_PATH" | cut -f1)" -} - -# Parse arguments -CREATE_APP=false -CREATE_DMG=false -CREATE_ALL=false -SIGN_IDENTITY="" - -while [[ $# -gt 0 ]]; do - case $1 in - --version) - VERSION="$2" - shift 2 - ;; - --publish-dir) - PUBLISH_DIR="$2" - shift 2 - ;; - --app) - CREATE_APP=true - shift - ;; - --dmg) - CREATE_DMG=true - shift - ;; - --all) - CREATE_ALL=true - shift - ;; - --sign) - SIGN_IDENTITY="$2" - shift 2 - ;; - --help|-h) - show_help - exit 0 - ;; - *) - echo "Unknown option: $1" - show_help - exit 1 - ;; - esac -done - -# Default to all if nothing specified -if [ "$CREATE_APP" = false ] && [ "$CREATE_DMG" = false ]; then - CREATE_ALL=true -fi - -if [ "$CREATE_ALL" = true ]; then - CREATE_APP=true - CREATE_DMG=true -fi - -echo "==========================================" -echo "Logbert macOS Packaging Script" -echo "==========================================" -echo "" - -# Create packages directory -mkdir -p "$PACKAGE_DIR" - -# Create packages -if [ "$CREATE_APP" = true ]; then - create_app_bundle -fi - -if [ "$CREATE_DMG" = true ]; then - create_dmg -fi - -echo "" -echo "==========================================" -echo "Packaging Complete!" -echo "==========================================" -echo "" -echo "Packages created in: $PACKAGE_DIR" -ls -la "$PACKAGE_DIR" | grep -E "\.(app|dmg|tar\.gz)$" | grep -i macos || ls -la "$PACKAGE_DIR" | grep -E "\.app$" || true diff --git a/deploy/scripts/publish-all.ps1 b/deploy/scripts/publish-all.ps1 deleted file mode 100644 index 8303710..0000000 --- a/deploy/scripts/publish-all.ps1 +++ /dev/null @@ -1,240 +0,0 @@ -# Logbert Cross-Platform Build Script (PowerShell) -# Builds self-contained executables for all supported platforms and creates versioned ZIP files - -param( - [switch]$Windows, - [switch]$Linux, - [switch]$MacOS, - [switch]$All, - [string]$Version, - [switch]$Help -) - -$ErrorActionPreference = "Stop" - -$ScriptDir = Split-Path -Parent $MyInvocation.MyCommand.Path -$RootDir = (Get-Item "$ScriptDir/../..").FullName -$ProjectPath = Join-Path $RootDir "src/Logbert/Logbert.csproj" -$OutputDir = Join-Path $RootDir "publish" -$TempDir = Join-Path $OutputDir "temp" - -# Extract version from .csproj if not provided -if (-not $Version) { - [xml]$csproj = Get-Content $ProjectPath - $Version = $csproj.Project.PropertyGroup.Version | Where-Object { $_ } | Select-Object -First 1 - if (-not $Version) { - $Version = "1.0.0" - Write-Host "Warning: Could not extract version from csproj, using default: $Version" -ForegroundColor Yellow - } -} - -function Show-Help { - Write-Host @" -Logbert Cross-Platform Build Script - -Usage: .\publish-all.ps1 [options] - -Options: - -Windows Build for Windows (x64 and ARM64) - -Linux Build for Linux (x64 and ARM64) - -MacOS Build for macOS (ARM64) - -All Build for all platforms (default if no platform specified) - -Version Override the version number (default: read from .csproj) - -Help Show this help message - -Examples: - .\publish-all.ps1 -All - .\publish-all.ps1 -Windows -Linux - .\publish-all.ps1 -Windows -Version "2.1.0" - -Output: - Creates ZIP files in the publish directory with the format: - Logbert--.zip -"@ -} - -function Publish-Runtime { - param( - [string]$RID, - [string]$FriendlyName - ) - - Write-Host "" - Write-Host "Building for $FriendlyName ($RID)..." -ForegroundColor Cyan - Write-Host "----------------------------------------" - - $TargetDir = Join-Path $TempDir $RID - - & dotnet publish $ProjectPath ` - -c Release ` - -r $RID ` - --self-contained true ` - -p:PublishSingleFile=true ` - -p:PublishTrimmed=false ` - -p:Version=$Version ` - -p:IncludeNativeLibrariesForSelfExtract=true ` - -o $TargetDir - - if ($LASTEXITCODE -ne 0) { - Write-Host "Build failed for $RID" -ForegroundColor Red - exit 1 - } - - # Create ZIP file with version number - $ZipFileName = "Logbert-$Version-$RID.zip" - $ZipPath = Join-Path $OutputDir $ZipFileName - - Write-Host "Creating $ZipFileName..." -ForegroundColor Yellow - - if (Test-Path $ZipPath) { - Remove-Item $ZipPath -Force - } - - # For macOS, create .app bundle structure - if ($RID -like "osx-*") { - $AppBundleDir = Join-Path $TempDir "Logbert.app" - New-MacOSBundle -SourceDir $TargetDir -AppBundleDir $AppBundleDir - Compress-Archive -Path $AppBundleDir -DestinationPath $ZipPath -CompressionLevel Optimal - } else { - Compress-Archive -Path "$TargetDir\*" -DestinationPath $ZipPath -CompressionLevel Optimal - } - - Write-Host "Created: $ZipPath" -ForegroundColor Green -} - -function New-MacOSBundle { - param( - [string]$SourceDir, - [string]$AppBundleDir - ) - - Write-Host "Creating macOS .app bundle structure..." -ForegroundColor Yellow - - # Clean up any existing bundle - if (Test-Path $AppBundleDir) { - Remove-Item -Recurse -Force $AppBundleDir - } - - # Create bundle directory structure - $ContentsDir = Join-Path $AppBundleDir "Contents" - $MacOSDir = Join-Path $ContentsDir "MacOS" - $ResourcesDir = Join-Path $ContentsDir "Resources" - - New-Item -ItemType Directory -Path $MacOSDir -Force | Out-Null - New-Item -ItemType Directory -Path $ResourcesDir -Force | Out-Null - - # Copy all binaries to MacOS folder - Copy-Item -Path "$SourceDir\*" -Destination $MacOSDir -Recurse -Force - - # Copy icon if available - $IconPath = Join-Path $RootDir "src/Logbert/Resources/AppIcon.png" - if (Test-Path $IconPath) { - Write-Host "Copying app icon..." -ForegroundColor Yellow - Copy-Item -Path $IconPath -Destination (Join-Path $ResourcesDir "AppIcon.png") - } - - # Create Info.plist - $InfoPlistContent = @" - - - - - CFBundleInfoDictionaryVersion - 6.0 - CFBundleDevelopmentRegion - en - CFBundlePackageType - APPL - CFBundleIdentifier - com.couchcoding.logbert - CFBundleExecutable - Logbert - CFBundleIconFile - AppIcon - CFBundleDisplayName - Logbert - CFBundleName - Logbert - CFBundleVersion - $Version - CFBundleShortVersionString - $Version - NSHumanReadableCopyright - Copyright 2024 Couchcoding - CFBundleSignature - ???? - LSMinimumSystemVersion - 10.15 - NSHighResolutionCapable - - NSSupportsAutomaticGraphicsSwitching - - - -"@ - - $InfoPlistPath = Join-Path $ContentsDir "Info.plist" - Set-Content -Path $InfoPlistPath -Value $InfoPlistContent -Encoding UTF8 - - Write-Host "macOS .app bundle created successfully" -ForegroundColor Green -} - -# Main script -if ($Help) { - Show-Help - exit 0 -} - -Write-Host "==========================================" -ForegroundColor Yellow -Write-Host "Logbert Build Script v$Version" -ForegroundColor Yellow -Write-Host "==========================================" -ForegroundColor Yellow -Write-Host "" - -# If no platform specified, build all -if (-not ($Windows -or $Linux -or $MacOS -or $All)) { - $All = $true -} - -if ($All) { - $Windows = $true - $Linux = $true - $MacOS = $true -} - -# Clean previous builds -Write-Host "Cleaning previous builds..." -if (Test-Path $OutputDir) { - Remove-Item -Recurse -Force $OutputDir -} -New-Item -ItemType Directory -Path $OutputDir -Force | Out-Null -New-Item -ItemType Directory -Path $TempDir -Force | Out-Null - -# Build for selected platforms -if ($Windows) { - Publish-Runtime -RID "win-x64" -FriendlyName "Windows x64" - Publish-Runtime -RID "win-arm64" -FriendlyName "Windows ARM64" -} - -if ($Linux) { - Publish-Runtime -RID "linux-x64" -FriendlyName "Linux x64" - Publish-Runtime -RID "linux-arm64" -FriendlyName "Linux ARM64" -} - -if ($MacOS) { - Publish-Runtime -RID "osx-arm64" -FriendlyName "macOS ARM64 (Apple Silicon)" -} - -# Clean up temp directory -Write-Host "" -Write-Host "Cleaning up temporary files..." -Remove-Item -Recurse -Force $TempDir - -Write-Host "" -Write-Host "==========================================" -ForegroundColor Green -Write-Host "Build Complete!" -ForegroundColor Green -Write-Host "==========================================" -ForegroundColor Green -Write-Host "" -Write-Host "Output directory: $OutputDir" -Write-Host "" -Write-Host "Release files:" -ForegroundColor Cyan -Get-ChildItem $OutputDir -Filter "*.zip" | Format-Table Name, @{Label="Size (MB)"; Expression={[math]::Round($_.Length / 1MB, 2)}}, LastWriteTime diff --git a/deploy/scripts/publish-all.sh b/deploy/scripts/publish-all.sh deleted file mode 100644 index 031d00f..0000000 --- a/deploy/scripts/publish-all.sh +++ /dev/null @@ -1,167 +0,0 @@ -#!/bin/bash -# Logbert Cross-Platform Build Script -# Builds self-contained executables for all supported platforms and creates versioned ZIP files - -set -e - -SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" -ROOT_DIR="$(cd "$SCRIPT_DIR/../.." && pwd)" -PROJECT_PATH="$ROOT_DIR/src/Logbert/Logbert.csproj" -OUTPUT_DIR="$ROOT_DIR/publish" -TEMP_DIR="$OUTPUT_DIR/temp" - -# Extract version from .csproj if not provided via environment variable -if [ -z "$VERSION" ]; then - VERSION=$(grep -oP '(?<=)[^<]+' "$PROJECT_PATH" | head -1) - if [ -z "$VERSION" ]; then - VERSION="1.0.0" - echo "Warning: Could not extract version from csproj, using default: $VERSION" - fi -fi - -echo "==========================================" -echo "Logbert Build Script v$VERSION" -echo "==========================================" -echo "" - -# Clean previous builds -echo "Cleaning previous builds..." -rm -rf "$OUTPUT_DIR" -mkdir -p "$OUTPUT_DIR" -mkdir -p "$TEMP_DIR" - -# Build configuration -CONFIG="Release" -SELF_CONTAINED="true" -PUBLISH_SINGLE_FILE="true" -PUBLISH_TRIMMED="false" # Trimming can cause issues with reflection - -# Function to publish for a specific runtime -publish_runtime() { - local RID=$1 - local FRIENDLY_NAME=$2 - - echo "" - echo "Building for $FRIENDLY_NAME ($RID)..." - echo "----------------------------------------" - - local TARGET_DIR="$TEMP_DIR/$RID" - - dotnet publish "$PROJECT_PATH" \ - -c "$CONFIG" \ - -r "$RID" \ - --self-contained "$SELF_CONTAINED" \ - -p:PublishSingleFile="$PUBLISH_SINGLE_FILE" \ - -p:PublishTrimmed="$PUBLISH_TRIMMED" \ - -p:Version="$VERSION" \ - -p:IncludeNativeLibrariesForSelfExtract=true \ - -o "$TARGET_DIR" - - # Create ZIP file with version number - local ZIP_FILENAME="Logbert-$VERSION-$RID.zip" - local ZIP_PATH="$OUTPUT_DIR/$ZIP_FILENAME" - - echo "Creating $ZIP_FILENAME..." - - if [ -f "$ZIP_PATH" ]; then - rm "$ZIP_PATH" - fi - - (cd "$TARGET_DIR" && zip -r "$ZIP_PATH" .) - - echo "Created: $ZIP_PATH" -} - -# Parse command line arguments -BUILD_WINDOWS=false -BUILD_LINUX=false -BUILD_MACOS=false -BUILD_ALL=false - -if [ $# -eq 0 ]; then - BUILD_ALL=true -fi - -while [[ $# -gt 0 ]]; do - case $1 in - --windows|-w) - BUILD_WINDOWS=true - shift - ;; - --linux|-l) - BUILD_LINUX=true - shift - ;; - --macos|-m) - BUILD_MACOS=true - shift - ;; - --all|-a) - BUILD_ALL=true - shift - ;; - --version|-v) - VERSION="$2" - shift 2 - ;; - --help|-h) - echo "Usage: $0 [options]" - echo "" - echo "Options:" - echo " --windows, -w Build for Windows (x64 and ARM64)" - echo " --linux, -l Build for Linux (x64 and ARM64)" - echo " --macos, -m Build for macOS (ARM64)" - echo " --all, -a Build for all platforms (default)" - echo " --version, -v Override the version number (default: read from .csproj)" - echo " --help, -h Show this help message" - echo "" - echo "Environment variables:" - echo " VERSION Override the version number (default: read from .csproj)" - echo "" - echo "Output:" - echo " Creates ZIP files in the publish directory with the format:" - echo " Logbert--.zip" - exit 0 - ;; - *) - echo "Unknown option: $1" - exit 1 - ;; - esac -done - -if [ "$BUILD_ALL" = true ]; then - BUILD_WINDOWS=true - BUILD_LINUX=true - BUILD_MACOS=true -fi - -# Build for selected platforms -if [ "$BUILD_WINDOWS" = true ]; then - publish_runtime "win-x64" "Windows x64" - publish_runtime "win-arm64" "Windows ARM64" -fi - -if [ "$BUILD_LINUX" = true ]; then - publish_runtime "linux-x64" "Linux x64" - publish_runtime "linux-arm64" "Linux ARM64" -fi - -if [ "$BUILD_MACOS" = true ]; then - publish_runtime "osx-arm64" "macOS ARM64 (Apple Silicon)" -fi - -# Clean up temp directory -echo "" -echo "Cleaning up temporary files..." -rm -rf "$TEMP_DIR" - -echo "" -echo "==========================================" -echo "Build Complete!" -echo "==========================================" -echo "" -echo "Output directory: $OUTPUT_DIR" -echo "" -echo "Release files:" -ls -lh "$OUTPUT_DIR"/*.zip 2>/dev/null || echo "No ZIP files found" diff --git a/deploy/windows/package-windows.ps1 b/deploy/windows/package-windows.ps1 deleted file mode 100644 index db8fa36..0000000 --- a/deploy/windows/package-windows.ps1 +++ /dev/null @@ -1,134 +0,0 @@ -# Logbert Windows Packaging Script -# Creates ZIP packages for Windows x64 and ARM64 - -param( - [string]$Version = "2.0.0", - [string]$PublishDir = "", - [switch]$Help -) - -$ErrorActionPreference = "Stop" - -$ScriptDir = Split-Path -Parent $MyInvocation.MyCommand.Path -$RootDir = (Get-Item "$ScriptDir/../..").FullName - -if ([string]::IsNullOrEmpty($PublishDir)) { - $PublishDir = Join-Path $RootDir "publish" -} - -$PackageDir = Join-Path $RootDir "packages" - -function Show-Help { - Write-Host @" -Logbert Windows Packaging Script - -Usage: .\package-windows.ps1 [options] - -Options: - -Version Version number for the package (default: 2.0.0) - -PublishDir Path to the publish directory (default: ../../publish) - -Help Show this help message - -Prerequisites: - Run publish-all.ps1 first to build the executables. -"@ -} - -function Create-ZipPackage { - param( - [string]$RID, - [string]$Architecture - ) - - $SourceDir = Join-Path $PublishDir $RID - - if (-not (Test-Path $SourceDir)) { - Write-Host "Source directory not found: $SourceDir" -ForegroundColor Yellow - Write-Host "Run publish-all.ps1 -Windows first" -ForegroundColor Yellow - return - } - - $ZipName = "Logbert-$Version-windows-$Architecture.zip" - $ZipPath = Join-Path $PackageDir $ZipName - - Write-Host "Creating $ZipName..." -ForegroundColor Cyan - - # Create a temporary directory with proper structure - $TempDir = Join-Path $env:TEMP "logbert-package-$RID" - if (Test-Path $TempDir) { - Remove-Item -Recurse -Force $TempDir - } - - $AppDir = Join-Path $TempDir "Logbert" - New-Item -ItemType Directory -Path $AppDir -Force | Out-Null - - # Copy files - Copy-Item -Path "$SourceDir\*" -Destination $AppDir -Recurse - - # Add README - $ReadmeContent = @" -Logbert $Version for Windows $Architecture - -INSTALLATION -============ -1. Extract this ZIP to a folder of your choice -2. Run Logbert.exe - -REQUIREMENTS -============ -No additional requirements - this is a self-contained application. - -DOCUMENTATION -============= -https://github.com/logbert/logbert/wiki - -LICENSE -======= -MIT License - See LICENSE.txt for details -"@ - $ReadmeContent | Out-File -FilePath (Join-Path $AppDir "README.txt") -Encoding UTF8 - - # Create ZIP - if (Test-Path $ZipPath) { - Remove-Item $ZipPath - } - - Compress-Archive -Path "$TempDir\*" -DestinationPath $ZipPath -CompressionLevel Optimal - - # Cleanup - Remove-Item -Recurse -Force $TempDir - - Write-Host "Created: $ZipPath" -ForegroundColor Green - - # Show file size - $FileSize = (Get-Item $ZipPath).Length / 1MB - Write-Host "Size: $([math]::Round($FileSize, 2)) MB" -ForegroundColor Gray -} - -# Main script -if ($Help) { - Show-Help - exit 0 -} - -Write-Host "==========================================" -ForegroundColor Yellow -Write-Host "Logbert Windows Packaging Script" -ForegroundColor Yellow -Write-Host "==========================================" -ForegroundColor Yellow -Write-Host "" - -# Create packages directory -if (-not (Test-Path $PackageDir)) { - New-Item -ItemType Directory -Path $PackageDir -Force | Out-Null -} - -# Create packages for each architecture -Create-ZipPackage -RID "win-x64" -Architecture "x64" -Create-ZipPackage -RID "win-arm64" -Architecture "arm64" - -Write-Host "" -Write-Host "==========================================" -ForegroundColor Green -Write-Host "Packaging Complete!" -ForegroundColor Green -Write-Host "==========================================" -ForegroundColor Green -Write-Host "" -Write-Host "Packages created in: $PackageDir" -Get-ChildItem $PackageDir -Filter "*.zip" | Where-Object { $_.Name -like "*windows*" } | Format-Table Name, Length diff --git a/docs/AVALONIA_MIGRATION_STATUS.md b/docs/AVALONIA_MIGRATION_STATUS.md index b907350..c822b4a 100644 --- a/docs/AVALONIA_MIGRATION_STATUS.md +++ b/docs/AVALONIA_MIGRATION_STATUS.md @@ -325,36 +325,30 @@ Created centralized notification service with error dialogs and validation feedb ### 8. Deployment Preparation -**Current State:** ALL PLATFORMS COMPLETE +**Current State:** GitHub Actions pipeline active; legacy local deployment scripts retired. | Platform | Package Type | Tool | Status | |----------|-------------|------|--------| -| Windows x64 | ZIP | dotnet publish + PowerShell | ✅ Complete | -| Windows ARM64 | ZIP | dotnet publish + PowerShell | ✅ Complete | -| Windows | MSIX | dotnet publish | ⏳ Not Started | -| macOS ARM64 | .app bundle ZIP | publish-all.ps1 | ✅ Complete | -| macOS | .dmg | create-dmg | ⏳ Not Started | -| Linux x64 | ZIP | publish-all.ps1 | ✅ Complete | -| Linux ARM64 | ZIP | publish-all.ps1 | ✅ Complete | -| Linux | AppImage | appimage-builder | ⏳ Not Started | -| Linux | .deb | dpkg-deb | ⏳ Not Started | -| Linux | .rpm | rpmbuild | ⏳ Not Started | - -**Publish Commands:** +| Windows x64 | ZIP | GitHub Actions release workflow | ✅ Complete | +| Windows ARM64 | ZIP | GitHub Actions release workflow | ✅ Complete | +| Windows | MSIX | Future pipeline phase | ⏳ Not Started | +| macOS ARM64 | .app bundle ZIP | GitHub Actions release workflow | ✅ Complete | +| macOS | .dmg | Future pipeline phase | ⏳ Not Started | +| Linux x64 | ZIP | GitHub Actions release workflow | ✅ Complete | +| Linux ARM64 | ZIP | GitHub Actions release workflow | ✅ Complete | +| Linux | AppImage | Future pipeline phase | ⏳ Not Started | +| Linux | .deb | Future pipeline phase | ⏳ Not Started | +| Linux | .rpm | Future pipeline phase | ⏳ Not Started | + +**Release Command:** ```bash -# Windows -dotnet publish -c Release -r win-x64 --self-contained -o publish/win-x64 -dotnet publish -c Release -r win-arm64 --self-contained -o publish/win-arm64 - -# macOS -dotnet publish -c Release -r osx-x64 --self-contained -o publish/osx-x64 -dotnet publish -c Release -r osx-arm64 --self-contained -o publish/osx-arm64 - -# Linux -dotnet publish -c Release -r linux-x64 --self-contained -o publish/linux-x64 -dotnet publish -c Release -r linux-arm64 --self-contained -o publish/linux-arm64 +# Tag version must match in src/Logbert/Logbert.csproj +git tag 2.1.2 +git push origin 2.1.2 ``` +See [Release Pipeline](RELEASE_PIPELINE.md) for the current CI/CD process. + --- ## Phase 6 Summary Checklist @@ -1014,19 +1008,13 @@ Legacy WinForms files are excluded from compilation but retained for reference: **Date:** December 12, 2025 -Successfully created Windows deployment packages using automated build and packaging scripts: +Historical note: Windows deployment packages were previously created using local build and packaging scripts. Those scripts have since been retired in favor of the GitHub Actions release workflow. **Packages Created:** - `Logbert-2.0.0-windows-x64.zip` (48.2 MB) - Windows x64 self-contained executable - `Logbert-2.0.0-windows-arm64.zip` (46.1 MB) - Windows ARM64 self-contained executable -**Build Process:** -1. Executed `deploy/scripts/publish-all.ps1 -Windows` to build self-contained executables -2. Executed `deploy/windows/package-windows.ps1 -Version "2.0.0"` to create ZIP packages -3. Packages include README.txt with installation instructions -4. No dependencies required - fully self-contained applications - -**Package Location:** `X:\Logbert\packages\` +**Current Build Process:** Push a matching version tag to run `.github/workflows/release.yml`, which publishes Windows, Linux, and macOS ZIP assets to GitHub Releases. ### Logger Tree Filtering Implementation diff --git a/docs/RELEASE_PIPELINE.md b/docs/RELEASE_PIPELINE.md new file mode 100644 index 0000000..1bf9bf4 --- /dev/null +++ b/docs/RELEASE_PIPELINE.md @@ -0,0 +1,62 @@ +# Release Pipeline + +Logbert binaries are generated by GitHub Actions. The old local deployment +scripts were removed so release packaging has a single source of truth. + +## CI + +Pull requests and pushes to `master` run `.github/workflows/ci.yml`. + +The CI workflow: + +- installs the .NET SDK from `global.json` +- restores `tests/Logbert.Tests/Logbert.Tests.csproj` +- builds `src/Logbert/Logbert.csproj` in Release mode +- runs the xUnit test project +- uploads TRX test results +- reports known NuGet vulnerabilities + +## Releases + +Pushing a version tag runs `.github/workflows/release.yml`: + +```bash +git tag 2.1.2 +git push origin 2.1.2 +``` + +The tag may also use a `v` prefix, for example `v2.1.2`. The tag version must +match `` in `src/Logbert/Logbert.csproj`. + +The release workflow creates these unsigned, self-contained ZIP assets: + +- `Logbert--win-x64.zip` +- `Logbert--win-arm64.zip` +- `Logbert--linux-x64.zip` +- `Logbert--linux-arm64.zip` +- `Logbert--osx-arm64.zip` +- `SHA256SUMS.txt` + +The workflow can also be run manually with `create_release=false` to generate +workflow artifacts without publishing a GitHub Release. + +## Packaging Details + +All runtime builds use: + +```text +--configuration Release +--self-contained true +-p:PublishSingleFile=true +-p:PublishTrimmed=false +-p:IncludeNativeLibrariesForSelfExtract=true +``` + +The macOS release job runs on a macOS runner and wraps the published output in a +`Logbert.app` bundle before creating the ZIP. + +## Current Limitations + +Release assets are unsigned. Windows code signing, macOS signing/notarization, +MSIX, DMG, DEB, RPM, AppImage, and `osx-x64` are not part of the current +pipeline. diff --git a/scripts/Installer/Info.plist.template b/scripts/Installer/Info.plist.template deleted file mode 100644 index 347e120..0000000 --- a/scripts/Installer/Info.plist.template +++ /dev/null @@ -1,36 +0,0 @@ - - - - - CFBundleInfoDictionaryVersion - 6.0 - CFBundleDevelopmentRegion - en - CFBundlePackageType - APPL - CFBundleIdentifier - com.couchcoding.logbert - CFBundleExecutable - Logbert - CFBundleIconFile - AppIcon - CFBundleDisplayName - Logbert - CFBundleName - Logbert - CFBundleVersion - __VERSION__ - CFBundleShortVersionString - __VERSION__ - NSHumanReadableCopyright - Copyright 2024 Couchcoding - CFBundleSignature - ???? - LSMinimumSystemVersion - 10.15 - NSHighResolutionCapable - - NSSupportsAutomaticGraphicsSwitching - - - diff --git a/scripts/Installer/build-macos-from-windows.bat b/scripts/Installer/build-macos-from-windows.bat deleted file mode 100644 index 9e4c3e0..0000000 --- a/scripts/Installer/build-macos-from-windows.bat +++ /dev/null @@ -1,177 +0,0 @@ -@echo off -setlocal enabledelayedexpansion -REM Build macOS binaries from Windows -REM This script allows building macOS packages from a Windows machine - -echo ************************************* -echo * Building Logbert macOS binaries * -echo ************************************* - -:: platform -set dotnetVersion=net10.0 -set platformX64=osx-x64 -set platformARM=osx-arm64 - -:: temporary paths to store the build artifacts -set temp_dir_x64=setup-macos-x64 -set temp_dir_arm=setup-macos-arm64 - -:: Path to the project files -set projectFile=../../src/Logbert/Logbert.csproj - -:: Get full git describe output -for /f "tokens=*" %%a in ('git describe --tags --long 2^>nul') do set "FULL_VERSION=%%a" - -:: If git describe fails, use a default version -if "!FULL_VERSION!"=="" ( - echo [WARN] Could not get version from git, using default - set "GIT_VERSION=1.0.0" -) else ( - :: Extract version components (e.g., 2.0.1-0-g65f8de7 -> 2.0.1.0) - for /f "tokens=1,2 delims=-" %%a in ("!FULL_VERSION!") do ( - set "BASE_VERSION=%%a" - set "COMMIT_COUNT=%%b" - ) - set "GIT_VERSION=!BASE_VERSION!.!COMMIT_COUNT!" -) - -echo [INFO] Version: !GIT_VERSION! -echo [INFO] .Net Version: %dotnetVersion% -echo [INFO] Build Platforms: %platformX64% (Intel) and %platformARM% (Apple Silicon) -echo [INFO] Building macOS binaries from Windows - -:: check if project files exists -if not exist %projectFile% ( - echo [ERROR] Logbert project file not found at %projectFile% - echo [ERROR] Terminating... - exit 2 -) - -:: cleanup from previous build attempts -if exist %temp_dir_x64% ( - echo [INFO] Intel temp folder found from previous run, cleaning up. - rd /s/q %temp_dir_x64% -) -if exist %temp_dir_arm% ( - echo [INFO] ARM temp folder found from previous run, cleaning up. - rd /s/q %temp_dir_arm% -) - -:: Build for Intel Macs (x64) -echo [INFO] Building for Intel Macs (x64)... -dotnet publish %projectFile% -c Release -r %platformX64% --self-contained true --output %temp_dir_x64%\ /p:PublishSingleFile=false -v q --nologo -if %errorlevel% neq 0 ( - echo [ERROR] An error occured while compiling for %platformX64% - echo [ERROR] Terminating... - exit 1 -) - -:: Build for Apple Silicon (ARM64) -echo [INFO] Building for Apple Silicon Macs (ARM64)... -dotnet publish %projectFile% -c Release -r %platformARM% --self-contained true --output %temp_dir_arm%\ /p:PublishSingleFile=false -v q --nologo -if %errorlevel% neq 0 ( - echo [ERROR] An error occured while compiling for %platformARM% - echo [ERROR] Terminating... - exit 1 -) - -:: Create .app bundle structure for x64 -echo [INFO] Creating x64 .app bundle structure... -set app_x64=Logbert.x64.app -if exist %app_x64% rd /s/q %app_x64% -mkdir %app_x64%\Contents\MacOS -mkdir %app_x64%\Contents\Resources - -:: Copy files to x64 .app bundle -xcopy /E /I /Q %temp_dir_x64%\* %app_x64%\Contents\MacOS\ - -:: Copy icon if available -if exist ..\..\src\Logbert\Resources\AppIcon.png ( - echo [INFO] Copying app icon for x64... - copy ..\..\src\Logbert\Resources\AppIcon.png %app_x64%\Contents\Resources\AppIcon.png > nul -) else ( - if exist ..\..\src\Logbert\Logbert.ico ( - echo [INFO] Copying app icon for x64 - ico fallback... - copy ..\..\src\Logbert\Logbert.ico %app_x64%\Contents\Resources\AppIcon.icns > nul - ) -) - -:: Create Info.plist for x64 - copy template and replace version placeholder -echo [INFO] Creating Info.plist for x64... -powershell -Command "(Get-Content 'Info.plist.template') -replace '__VERSION__', '!GIT_VERSION!' | Set-Content '%app_x64%\Contents\Info.plist' -Encoding UTF8" - -:: Create .app bundle structure for ARM64 -echo [INFO] Creating ARM64 .app bundle structure... -set app_arm=Logbert.arm64.app -if exist %app_arm% rd /s/q %app_arm% -mkdir %app_arm%\Contents\MacOS -mkdir %app_arm%\Contents\Resources - -:: Copy files to ARM64 .app bundle -xcopy /E /I /Q %temp_dir_arm%\* %app_arm%\Contents\MacOS\ - -:: Copy icon if available -if exist ..\..\src\Logbert\Resources\AppIcon.png ( - echo [INFO] Copying app icon for ARM64... - copy ..\..\src\Logbert\Resources\AppIcon.png %app_arm%\Contents\Resources\AppIcon.png > nul -) else ( - if exist ..\..\src\Logbert\Logbert.ico ( - echo [INFO] Copying app icon for ARM64 - ico fallback... - copy ..\..\src\Logbert\Logbert.ico %app_arm%\Contents\Resources\AppIcon.icns > nul - ) -) - -:: Copy Info.plist for ARM64 (same as x64) -echo [INFO] Copying Info.plist for ARM64... -copy %app_x64%\Contents\Info.plist %app_arm%\Contents\Info.plist > nul - -echo [INFO] Creating distribution archives... -:: Create zip files with .app bundles -powershell -command "Compress-Archive -Path '%app_x64%' -DestinationPath 'logbert.%GIT_VERSION%.macos-x64.zip' -Force" -powershell -command "Compress-Archive -Path '%app_arm%' -DestinationPath 'logbert.%GIT_VERSION%.macos-arm64.zip' -Force" - -echo [INFO] Note: Universal binary creation is not available when building from Windows. -echo [INFO] Note: Users will need to run 'chmod +x' on the executable after extraction. - -:: Create Output directory if it doesn't exist -echo [INFO] Preparing output directories... -if not exist Output ( - echo [INFO] Creating Output directory... - mkdir Output -) - -:: Move to output folder -move /Y logbert.%GIT_VERSION%.macos-x64.zip "./Output" > nul -move /Y logbert.%GIT_VERSION%.macos-arm64.zip "./Output" > nul - -:: Create helper script for Mac users to set permissions -echo [INFO] Creating permission helper script... -( -echo #!/bin/bash -echo # Helper script to set executable permissions after extracting on macOS -echo echo "Setting executable permissions for Logbert..." -echo chmod +x "./Logbert.x64.app/Contents/MacOS/Logbert" 2^>/dev/null ^|^| true -echo chmod +x "./Logbert.arm64.app/Contents/MacOS/Logbert" 2^>/dev/null ^|^| true -echo echo "Permissions set. You can now double-click the .app to launch." -) > fix-permissions.sh -move /Y fix-permissions.sh "./Output" > nul - -:: cleanup -echo [INFO] Cleaning up temporary files... -rd /s/q "%temp_dir_x64%" -rd /s/q "%temp_dir_arm%" -rd /s/q "%app_x64%" -rd /s/q "%app_arm%" - -echo [INFO] macOS build (from Windows) completed successfully! -echo [INFO] Created packages: -echo - logbert.!GIT_VERSION!.macos-x64.zip (Intel Macs) -echo - logbert.!GIT_VERSION!.macos-arm64.zip (Apple Silicon) -echo. -echo [INFO] IMPORTANT: Mac users must run these commands after extraction: -echo 1. Unzip the archive -echo 2. Run: chmod +x Logbert.*.app/Contents/MacOS/Logbert -echo 3. Double-click the .app to launch -echo. -echo [INFO] Or use the included fix-permissions.sh script -echo [INFO] To create a proper .icns icon file, run create-icns.sh on macOS diff --git a/scripts/Installer/build-macos.sh b/scripts/Installer/build-macos.sh deleted file mode 100644 index 6901724..0000000 --- a/scripts/Installer/build-macos.sh +++ /dev/null @@ -1,200 +0,0 @@ -#!/bin/bash - -# Build macOS binaries natively on macOS -# This script creates .app bundles with proper icons - -echo "*************************************" -echo "* Building Logbert macOS binaries *" -echo "*************************************" - -# Platform settings -DOTNET_VERSION="net10.0" -PLATFORM_X64="osx-x64" -PLATFORM_ARM="osx-arm64" - -# Temporary paths -TEMP_DIR_X64="setup-macos-x64" -TEMP_DIR_ARM="setup-macos-arm64" - -# Project path -PROJECT_FILE="../../src/Logbert/Logbert.csproj" - -# Get version from git -FULL_VERSION=$(git describe --tags --long 2>/dev/null) -if [ -z "$FULL_VERSION" ]; then - echo "[WARN] Could not get version from git, using default" - GIT_VERSION="1.0.0" -else - BASE_VERSION=$(echo "$FULL_VERSION" | cut -d'-' -f1) - COMMIT_COUNT=$(echo "$FULL_VERSION" | cut -d'-' -f2) - GIT_VERSION="${BASE_VERSION}.${COMMIT_COUNT}" -fi - -echo "[INFO] Version: $GIT_VERSION" -echo "[INFO] .Net Version: $DOTNET_VERSION" -echo "[INFO] Build Platforms: $PLATFORM_X64 (Intel) and $PLATFORM_ARM (Apple Silicon)" - -# Check if project file exists -if [ ! -f "$PROJECT_FILE" ]; then - echo "[ERROR] Logbert project file not found at $PROJECT_FILE" - exit 2 -fi - -# Cleanup previous builds -rm -rf "$TEMP_DIR_X64" "$TEMP_DIR_ARM" - -# Build for Intel Macs (x64) -echo "[INFO] Building for Intel Macs (x64)..." -dotnet publish "$PROJECT_FILE" -c Release -r "$PLATFORM_X64" --self-contained true --output "$TEMP_DIR_X64/" -p:PublishSingleFile=false -v q --nologo -if [ $? -ne 0 ]; then - echo "[ERROR] Build failed for $PLATFORM_X64" - exit 1 -fi - -# Build for Apple Silicon (ARM64) -echo "[INFO] Building for Apple Silicon Macs (ARM64)..." -dotnet publish "$PROJECT_FILE" -c Release -r "$PLATFORM_ARM" --self-contained true --output "$TEMP_DIR_ARM/" -p:PublishSingleFile=false -v q --nologo -if [ $? -ne 0 ]; then - echo "[ERROR] Build failed for $PLATFORM_ARM" - exit 1 -fi - -# Create .icns icon if not exists -if [ ! -f "AppIcon.icns" ]; then - echo "[INFO] Creating application icon..." - if [ -f "./create-icns.sh" ]; then - chmod +x ./create-icns.sh - ./create-icns.sh "../../src/Logbert/Resources/Logbert Logo Background.png" "AppIcon.icns" - fi -fi - -# Function to create app bundle -create_app_bundle() { - local SOURCE_DIR=$1 - local APP_NAME=$2 - local ARCH_SUFFIX=$3 - - local APP_BUNDLE="Logbert.${ARCH_SUFFIX}.app" - - echo "[INFO] Creating $APP_BUNDLE..." - - # Remove existing bundle - rm -rf "$APP_BUNDLE" - - # Create bundle structure - mkdir -p "$APP_BUNDLE/Contents/MacOS" - mkdir -p "$APP_BUNDLE/Contents/Resources" - - # Copy application files - cp -R "$SOURCE_DIR"/* "$APP_BUNDLE/Contents/MacOS/" - - # Copy icon - if [ -f "AppIcon.icns" ]; then - cp "AppIcon.icns" "$APP_BUNDLE/Contents/Resources/" - elif [ -f "../../src/Logbert/Logbert.ico" ]; then - # Fallback - copy ico (user should convert on Mac) - cp "../../src/Logbert/Logbert.ico" "$APP_BUNDLE/Contents/Resources/AppIcon.icns" - fi - - # Set executable permissions - chmod +x "$APP_BUNDLE/Contents/MacOS/Logbert" - - # Create launcher script - cat > "$APP_BUNDLE/Contents/MacOS/Logbert_launcher" << 'LAUNCHER_EOF' -#!/bin/bash -# Launcher script to ensure correct working directory for .NET app -DIR="$(cd "$(dirname "$0")" && pwd)" -cd "$DIR" -exec "./Logbert" "$@" -LAUNCHER_EOF - chmod +x "$APP_BUNDLE/Contents/MacOS/Logbert_launcher" - - # Create Info.plist - cat > "$APP_BUNDLE/Contents/Info.plist" << EOF - - - - - CFBundleInfoDictionaryVersion - 6.0 - CFBundleDevelopmentRegion - en - CFBundlePackageType - APPL - CFBundleIdentifier - com.couchcoding.logbert - CFBundleExecutable - Logbert_launcher - CFBundleIconFile - AppIcon.icns - CFBundleDisplayName - Logbert - CFBundleName - Logbert - CFBundleVersion - $GIT_VERSION - CFBundleShortVersionString - $GIT_VERSION - NSHumanReadableCopyright - Copyright 2024 Couchcoding - CFBundleSignature - ???? - LSMinimumSystemVersion - 10.15 - NSHighResolutionCapable - - NSSupportsAutomaticGraphicsSwitching - - - -EOF - - echo "[INFO] Created $APP_BUNDLE" -} - -# Create app bundles -create_app_bundle "$TEMP_DIR_X64" "Logbert" "x64" -create_app_bundle "$TEMP_DIR_ARM" "Logbert" "arm64" - -# Create output directory -mkdir -p Output - -# Create distribution archives -echo "[INFO] Creating distribution archives..." -zip -r -q "Output/logbert.${GIT_VERSION}.macos-x64.zip" "Logbert.x64.app" -zip -r -q "Output/logbert.${GIT_VERSION}.macos-arm64.zip" "Logbert.arm64.app" - -# Optionally create universal binary -echo "[INFO] Checking if universal binary can be created..." -if command -v lipo &> /dev/null; then - echo "[INFO] Creating universal binary..." - - # Create universal app bundle - UNIVERSAL_APP="Logbert.universal.app" - rm -rf "$UNIVERSAL_APP" - cp -R "Logbert.arm64.app" "$UNIVERSAL_APP" - - # Create universal binary using lipo - lipo -create \ - "Logbert.x64.app/Contents/MacOS/Logbert" \ - "Logbert.arm64.app/Contents/MacOS/Logbert" \ - -output "$UNIVERSAL_APP/Contents/MacOS/Logbert" - - # Create universal zip - zip -r -q "Output/logbert.${GIT_VERSION}.macos-universal.zip" "$UNIVERSAL_APP" - - rm -rf "$UNIVERSAL_APP" - echo "[INFO] Universal binary created" -fi - -# Cleanup -echo "[INFO] Cleaning up..." -rm -rf "$TEMP_DIR_X64" "$TEMP_DIR_ARM" -rm -rf "Logbert.x64.app" "Logbert.arm64.app" - -echo "" -echo "[INFO] macOS build completed successfully!" -echo "[INFO] Created packages in Output/:" -ls -la Output/*.zip -echo "" -echo "[INFO] Users can drag the .app to Applications folder after extraction" diff --git a/scripts/Installer/create-icns.sh b/scripts/Installer/create-icns.sh deleted file mode 100644 index eb66513..0000000 --- a/scripts/Installer/create-icns.sh +++ /dev/null @@ -1,109 +0,0 @@ -#!/bin/bash - -# Script to create macOS .icns file from PNG or ICO -# Usage: ./create-icns.sh [input_file] [output.icns] -# Run this on macOS to create proper .icns icon file - -INPUT_FILE=${1:-"../../src/Logbert/Resources/AppIcon.png"} -OUTPUT_ICNS=${2:-"AppIcon.icns"} -TEMP_DIR="icon.iconset" - -# Check for input file -if [ ! -f "$INPUT_FILE" ]; then - # Try alternative locations - if [ -f "../../src/Logbert/Logbert.ico" ]; then - INPUT_FILE="../../src/Logbert/Logbert.ico" - echo "Using ICO file: $INPUT_FILE" - else - echo "Error: Input file '$INPUT_FILE' not found" - echo "Usage: $0 [input_file] [output.icns]" - exit 1 - fi -fi - -echo "Creating .icns file from $INPUT_FILE..." - -# Create temporary iconset directory -rm -rf "$TEMP_DIR" -mkdir "$TEMP_DIR" - -# Determine file type and convert if necessary -FILE_EXT="${INPUT_FILE##*.}" -TEMP_PNG="temp_source.png" - -if [ "$FILE_EXT" = "ico" ]; then - echo "Converting ICO to PNG first..." - if command -v convert &> /dev/null; then - # ImageMagick - extract largest image from ICO - convert "$INPUT_FILE[0]" -resize 1024x1024 "$TEMP_PNG" - elif command -v sips &> /dev/null; then - # sips can handle some ICO files - sips -s format png "$INPUT_FILE" --out "$TEMP_PNG" 2>/dev/null || { - echo "Error: Could not convert ICO file. Please provide a PNG file instead." - exit 1 - } - else - echo "Error: Need ImageMagick or sips to convert ICO files" - exit 1 - fi - INPUT_FILE="$TEMP_PNG" -fi - -# Generate different sizes required for .icns -if command -v sips &> /dev/null; then - echo "Using sips to generate icon sizes..." - sips -z 16 16 "$INPUT_FILE" --out "$TEMP_DIR/icon_16x16.png" > /dev/null 2>&1 - sips -z 32 32 "$INPUT_FILE" --out "$TEMP_DIR/icon_16x16@2x.png" > /dev/null 2>&1 - sips -z 32 32 "$INPUT_FILE" --out "$TEMP_DIR/icon_32x32.png" > /dev/null 2>&1 - sips -z 64 64 "$INPUT_FILE" --out "$TEMP_DIR/icon_32x32@2x.png" > /dev/null 2>&1 - sips -z 128 128 "$INPUT_FILE" --out "$TEMP_DIR/icon_128x128.png" > /dev/null 2>&1 - sips -z 256 256 "$INPUT_FILE" --out "$TEMP_DIR/icon_128x128@2x.png" > /dev/null 2>&1 - sips -z 256 256 "$INPUT_FILE" --out "$TEMP_DIR/icon_256x256.png" > /dev/null 2>&1 - sips -z 512 512 "$INPUT_FILE" --out "$TEMP_DIR/icon_256x256@2x.png" > /dev/null 2>&1 - sips -z 512 512 "$INPUT_FILE" --out "$TEMP_DIR/icon_512x512.png" > /dev/null 2>&1 - sips -z 1024 1024 "$INPUT_FILE" --out "$TEMP_DIR/icon_512x512@2x.png" > /dev/null 2>&1 -elif command -v convert &> /dev/null; then - echo "Using ImageMagick to generate icon sizes..." - convert "$INPUT_FILE" -resize 16x16 "$TEMP_DIR/icon_16x16.png" - convert "$INPUT_FILE" -resize 32x32 "$TEMP_DIR/icon_16x16@2x.png" - convert "$INPUT_FILE" -resize 32x32 "$TEMP_DIR/icon_32x32.png" - convert "$INPUT_FILE" -resize 64x64 "$TEMP_DIR/icon_32x32@2x.png" - convert "$INPUT_FILE" -resize 128x128 "$TEMP_DIR/icon_128x128.png" - convert "$INPUT_FILE" -resize 256x256 "$TEMP_DIR/icon_128x128@2x.png" - convert "$INPUT_FILE" -resize 256x256 "$TEMP_DIR/icon_256x256.png" - convert "$INPUT_FILE" -resize 512x512 "$TEMP_DIR/icon_256x256@2x.png" - convert "$INPUT_FILE" -resize 512x512 "$TEMP_DIR/icon_512x512.png" - convert "$INPUT_FILE" -resize 1024x1024 "$TEMP_DIR/icon_512x512@2x.png" -else - echo "Warning: Neither sips nor ImageMagick found." - echo "On macOS: sips should be available" - echo "On Linux: install ImageMagick (apt-get install imagemagick)" - exit 1 -fi - -# Create .icns file -if command -v iconutil &> /dev/null; then - echo "Creating .icns file using iconutil..." - iconutil -c icns "$TEMP_DIR" -o "$OUTPUT_ICNS" -elif command -v png2icns &> /dev/null; then - echo "Creating .icns file using png2icns..." - png2icns "$OUTPUT_ICNS" "$TEMP_DIR"/*.png -else - echo "Warning: No .icns creation tool found (iconutil or png2icns)" - echo "On macOS: iconutil should be available" - echo "On Linux: install icnsutils (apt-get install icnsutils)" - echo "Copying PNG as fallback..." - cp "$INPUT_FILE" "$OUTPUT_ICNS" -fi - -# Cleanup -rm -rf "$TEMP_DIR" -rm -f "$TEMP_PNG" - -if [ -f "$OUTPUT_ICNS" ]; then - echo "Icon created: $OUTPUT_ICNS" - echo "Copy this file to your .app bundle's Contents/Resources/ folder" -else - echo "Failed to create icon file" - exit 1 -fi