name: Build — Windows, Linux & macOS # Trigger on every push to main, on version tags, or manually on: push: branches: [main] tags: ['v*'] paths-ignore: - '**.md' - 'docs/**' - 'tests/**' - 'pytest.ini' - 'run_tests.sh' - 'build_gdpr.sh' - 'start_gdpr.sh' - 'install_macos.sh' - 'install_windows.ps1' - '.github/ISSUE_TEMPLATE/**' workflow_dispatch: # Only run one build at a time per branch to avoid race conditions concurrency: group: build-${{ github.ref }} cancel-in-progress: true jobs: # ── GDPRScanner ────────────────────────────────────────────────────────── build-m365-scanner: strategy: fail-fast: false matrix: include: - os: windows-latest name: windows - os: ubuntu-22.04 name: linux - os: macos-15 name: macos runs-on: ${{ matrix.os }} name: GDPRScanner / ${{ matrix.name }} steps: - name: Checkout uses: actions/checkout@v4 - name: Set up Python 3.12 uses: actions/setup-python@v5 with: python-version: "3.12" cache: pip - name: Install Linux system dependencies if: runner.os == 'Linux' run: | sudo apt-get update -qq sudo apt-get install -y --no-install-recommends \ tesseract-ocr tesseract-ocr-dan tesseract-ocr-deu \ poppler-utils \ libgtk-3-dev libwebkit2gtk-4.0-dev \ libglib2.0-dev libcairo2-dev pkg-config \ python3-dev \ xvfb - name: Start virtual display (Linux) if: runner.os == 'Linux' run: | Xvfb :99 -screen 0 1024x768x24 & echo "DISPLAY=:99" >> $GITHUB_ENV - name: Install macOS system dependencies if: runner.os == 'macOS' run: | brew install tesseract tesseract-lang poppler - name: Install Python dependencies run: | python -m pip install --upgrade pip pip install -r requirements.txt # Download the Danish spaCy model used for NER/anonymisation - name: Download spaCy model run: python -m spacy download da_core_news_sm - name: Build GDPRScanner env: PYTHONUTF8: "1" run: python build_gdpr.py - name: Package Linux binary if: runner.os == 'Linux' run: | cd dist zip -r "GDPRScanner_linux_x86_64.zip" "GDPRScanner" - name: Package Windows binary if: runner.os == 'Windows' shell: pwsh run: | Compress-Archive -Path dist\GDPRScanner -DestinationPath dist\GDPRScanner_windows_x64.zip - name: Package macOS binary if: runner.os == 'macOS' run: | cd dist zip -r "GDPRScanner_macos_arm64.zip" "GDPRScanner.app" - name: Upload artifact uses: actions/upload-artifact@v4 with: name: M365Scanner-${{ matrix.name }} retention-days: 30 path: | dist/GDPRScanner_linux_x86_64.zip dist/GDPRScanner_windows_x64.zip dist/GDPRScanner_macos_arm64.zip # ── Release ─────────────────────────────────────────────────────────────── # • version tag (v*) → proper versioned release with generated notes # • main push → rolling 'latest' pre-release (replaces previous) release: name: Create GitHub Release needs: [build-m365-scanner] if: startsWith(github.ref, 'refs/tags/v') || github.ref == 'refs/heads/main' runs-on: ubuntu-latest permissions: contents: write steps: - name: Checkout uses: actions/checkout@v4 - name: Download all artifacts uses: actions/download-artifact@v4 with: path: artifacts merge-multiple: true - name: Move 'latest' tag to current commit if: github.ref == 'refs/heads/main' run: | git tag -f latest git push origin latest --force - name: Create versioned release if: startsWith(github.ref, 'refs/tags/v') uses: softprops/action-gh-release@v2 with: name: ${{ github.ref_name }} draft: false prerelease: ${{ contains(github.ref_name, '-beta') || contains(github.ref_name, '-rc') }} generate_release_notes: true files: artifacts/** - name: Update rolling 'latest' release if: github.ref == 'refs/heads/main' uses: softprops/action-gh-release@v2 with: tag_name: latest name: "Latest build (main)" body: "Automated build from the latest commit on `main`. Not a stable release." draft: false prerelease: true files: artifacts/**