refactor: split server into independent nber_server package #6
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: Desktop | |
| on: | |
| pull_request: | |
| push: | |
| branches: | |
| - main | |
| - master | |
| tags: | |
| - "desktop-v*" | |
| workflow_dispatch: | |
| permissions: | |
| contents: read | |
| jobs: | |
| check: | |
| runs-on: ubuntu-latest | |
| steps: | |
| - uses: actions/checkout@v4 | |
| - uses: actions/setup-python@v5 | |
| with: | |
| python-version: "3.11" | |
| - uses: astral-sh/setup-uv@v3 | |
| - uses: actions/setup-node@v4 | |
| with: | |
| node-version: "20" | |
| cache: npm | |
| cache-dependency-path: desktop/package-lock.json | |
| - name: Install Python dependencies | |
| run: uv sync --dev | |
| - name: Run Python lint | |
| run: uv run ruff check . | |
| - name: Run Python tests | |
| run: uv run pytest | |
| - name: Install desktop dependencies | |
| working-directory: desktop | |
| run: npm ci | |
| - name: Run frontend lint | |
| working-directory: desktop | |
| run: npm run lint | |
| - name: Run frontend tests | |
| working-directory: desktop | |
| run: npm run test | |
| - name: Build frontend | |
| working-directory: desktop | |
| run: npm run build | |
| build: | |
| needs: check | |
| if: startsWith(github.ref, 'refs/tags/desktop-v') || github.event_name == 'workflow_dispatch' | |
| permissions: | |
| contents: write | |
| strategy: | |
| fail-fast: false | |
| matrix: | |
| include: | |
| - os: macos-15 | |
| target: aarch64-apple-darwin | |
| bundles: app,dmg | |
| artifact-name: nber-cli-desktop-macos-arm64 | |
| release-platform: macos | |
| - os: macos-15-intel | |
| target: x86_64-apple-darwin | |
| bundles: app,dmg | |
| artifact-name: nber-cli-desktop-macos-x64 | |
| release-platform: macos | |
| - os: windows-2022 | |
| target: x86_64-pc-windows-msvc | |
| bundles: nsis | |
| artifact-name: nber-cli-desktop-windows-x64 | |
| release-platform: windows | |
| runs-on: ${{ matrix.os }} | |
| steps: | |
| - uses: actions/checkout@v4 | |
| - uses: actions/setup-python@v5 | |
| with: | |
| python-version: "3.11" | |
| - uses: astral-sh/setup-uv@v3 | |
| - uses: actions/setup-node@v4 | |
| with: | |
| node-version: "20" | |
| cache: npm | |
| cache-dependency-path: desktop/package-lock.json | |
| - uses: dtolnay/rust-toolchain@stable | |
| with: | |
| targets: ${{ matrix.target }} | |
| - name: Install Python dependencies | |
| run: uv sync --dev | |
| - name: Install desktop dependencies | |
| working-directory: desktop | |
| run: npm ci | |
| - name: Validate macOS release signing secrets | |
| if: startsWith(github.ref, 'refs/tags/desktop-v') && runner.os == 'macOS' | |
| env: | |
| APPLE_CERTIFICATE: ${{ secrets.APPLE_CERTIFICATE }} | |
| APPLE_CERTIFICATE_PASSWORD: ${{ secrets.APPLE_CERTIFICATE_PASSWORD }} | |
| KEYCHAIN_PASSWORD: ${{ secrets.KEYCHAIN_PASSWORD }} | |
| APPLE_ID: ${{ secrets.APPLE_ID }} | |
| APPLE_PASSWORD: ${{ secrets.APPLE_PASSWORD }} | |
| APPLE_TEAM_ID: ${{ secrets.APPLE_TEAM_ID }} | |
| shell: bash | |
| run: uv run python scripts/validate-desktop-signing.py --platform macos --require-signed | |
| - name: Validate Windows release signing secrets | |
| if: startsWith(github.ref, 'refs/tags/desktop-v') && runner.os == 'Windows' | |
| env: | |
| WINDOWS_CERTIFICATE: ${{ secrets.WINDOWS_CERTIFICATE }} | |
| WINDOWS_CERTIFICATE_PASSWORD: ${{ secrets.WINDOWS_CERTIFICATE_PASSWORD }} | |
| shell: pwsh | |
| run: uv run python scripts/validate-desktop-signing.py --platform windows --require-signed | |
| - name: Build sidecar | |
| run: uv run python scripts/build-sidecar.py --clean --target-triple ${{ matrix.target }} | |
| - name: Import Apple Developer ID certificate | |
| if: runner.os == 'macOS' | |
| env: | |
| APPLE_CERTIFICATE: ${{ secrets.APPLE_CERTIFICATE }} | |
| APPLE_CERTIFICATE_PASSWORD: ${{ secrets.APPLE_CERTIFICATE_PASSWORD }} | |
| KEYCHAIN_PASSWORD: ${{ secrets.KEYCHAIN_PASSWORD }} | |
| shell: bash | |
| run: | | |
| if [ -z "$APPLE_CERTIFICATE" ]; then | |
| echo "APPLE_CERTIFICATE is not configured; building without macOS signing." | |
| exit 0 | |
| fi | |
| if [ -z "$KEYCHAIN_PASSWORD" ]; then | |
| echo "KEYCHAIN_PASSWORD is required for macOS signing." | |
| exit 1 | |
| fi | |
| echo "$APPLE_CERTIFICATE" | base64 --decode > certificate.p12 | |
| security create-keychain -p "$KEYCHAIN_PASSWORD" build.keychain | |
| security default-keychain -s build.keychain | |
| security unlock-keychain -p "$KEYCHAIN_PASSWORD" build.keychain | |
| security set-keychain-settings -t 3600 -u build.keychain | |
| security import certificate.p12 -k build.keychain -P "$APPLE_CERTIFICATE_PASSWORD" -T /usr/bin/codesign | |
| security set-key-partition-list -S apple-tool:,apple:,codesign: -s -k "$KEYCHAIN_PASSWORD" build.keychain | |
| CERT_INFO=$(security find-identity -v -p codesigning build.keychain | grep "Developer ID Application" | head -n 1 || true) | |
| if [ -z "$CERT_INFO" ]; then | |
| echo "Developer ID Application certificate not found in keychain." | |
| exit 1 | |
| fi | |
| CERT_ID=$(echo "$CERT_INFO" | awk -F'"' '{print $2}') | |
| echo "APPLE_SIGNING_IDENTITY=$CERT_ID" >> "$GITHUB_ENV" | |
| - name: Import Windows code signing certificate | |
| if: runner.os == 'Windows' | |
| env: | |
| WINDOWS_CERTIFICATE: ${{ secrets.WINDOWS_CERTIFICATE }} | |
| WINDOWS_CERTIFICATE_PASSWORD: ${{ secrets.WINDOWS_CERTIFICATE_PASSWORD }} | |
| shell: pwsh | |
| run: | | |
| if (-not $env:WINDOWS_CERTIFICATE) { | |
| Write-Host "WINDOWS_CERTIFICATE is not configured; building without Windows signing." | |
| exit 0 | |
| } | |
| $certificatePath = "$env:RUNNER_TEMP\windows-certificate.pfx" | |
| [IO.File]::WriteAllBytes($certificatePath, [Convert]::FromBase64String($env:WINDOWS_CERTIFICATE)) | |
| $securePassword = ConvertTo-SecureString $env:WINDOWS_CERTIFICATE_PASSWORD -AsPlainText -Force | |
| $certificate = Import-PfxCertificate -FilePath $certificatePath -CertStoreLocation Cert:\CurrentUser\My -Password $securePassword | |
| if (-not $certificate.Thumbprint) { | |
| throw "Imported Windows certificate did not expose a thumbprint." | |
| } | |
| "WINDOWS_CERTIFICATE_THUMBPRINT=$($certificate.Thumbprint)" | Out-File -FilePath $env:GITHUB_ENV -Append | |
| - name: Prepare Tauri signing configuration | |
| env: | |
| APPLE_SIGNING_IDENTITY: ${{ env.APPLE_SIGNING_IDENTITY }} | |
| APPLE_PROVIDER_SHORT_NAME: ${{ secrets.APPLE_PROVIDER_SHORT_NAME }} | |
| WINDOWS_CERTIFICATE_THUMBPRINT: ${{ env.WINDOWS_CERTIFICATE_THUMBPRINT }} | |
| WINDOWS_DIGEST_ALGORITHM: ${{ secrets.WINDOWS_DIGEST_ALGORITHM }} | |
| WINDOWS_TIMESTAMP_URL: ${{ secrets.WINDOWS_TIMESTAMP_URL }} | |
| run: uv run python scripts/prepare-tauri-signing.py | |
| - name: Build Tauri app | |
| working-directory: desktop | |
| env: | |
| APPLE_ID: ${{ secrets.APPLE_ID }} | |
| APPLE_PASSWORD: ${{ secrets.APPLE_PASSWORD }} | |
| APPLE_TEAM_ID: ${{ secrets.APPLE_TEAM_ID }} | |
| APPLE_API_KEY: ${{ secrets.APPLE_API_KEY }} | |
| APPLE_API_ISSUER: ${{ secrets.APPLE_API_ISSUER }} | |
| run: npm run tauri build -- --target ${{ matrix.target }} --bundles ${{ matrix.bundles }} | |
| - name: Normalize release artifact names | |
| run: uv run python scripts/normalize-desktop-artifacts.py --platform ${{ matrix.release-platform }} --target-triple ${{ matrix.target }} | |
| - name: Check release artifacts | |
| run: uv run python scripts/check-desktop-release.py --platform ${{ matrix.release-platform }} --max-mb 80 | |
| - name: Smoke test desktop app | |
| run: uv run python scripts/smoke-desktop-app.py --install-from-package | |
| - name: Check signed and notarized macOS release artifacts | |
| if: startsWith(github.ref, 'refs/tags/desktop-v') && matrix.release-platform == 'macos' | |
| run: uv run python scripts/check-desktop-release.py --platform macos --max-mb 80 --require-signed --require-notarized | |
| - name: Check signed Windows release artifacts | |
| if: startsWith(github.ref, 'refs/tags/desktop-v') && matrix.release-platform == 'windows' | |
| run: uv run python scripts/check-desktop-release.py --platform ${{ matrix.release-platform }} --max-mb 80 --require-signed | |
| - name: Upload desktop artifacts | |
| uses: actions/upload-artifact@v4 | |
| with: | |
| name: ${{ matrix.artifact-name }} | |
| path: | | |
| desktop/src-tauri/target/**/release/bundle/**/*.dmg | |
| desktop/src-tauri/target/**/release/bundle/**/*.app | |
| desktop/src-tauri/target/**/release/bundle/**/*.exe | |
| desktop/src-tauri/target/**/release/bundle/**/*.msi | |
| - name: Upload GitHub Release assets | |
| if: startsWith(github.ref, 'refs/tags/desktop-v') | |
| uses: softprops/action-gh-release@v2 | |
| with: | |
| draft: true | |
| files: | | |
| desktop/src-tauri/target/**/release/bundle/**/*.dmg | |
| desktop/src-tauri/target/**/release/bundle/**/*.exe | |
| desktop/src-tauri/target/**/release/bundle/**/*.msi |