Skip to content

inCrate button disabled #302

inCrate button disabled

inCrate button disabled #302

Workflow file for this run

name: Build macOS
on:
push:
tags:
- 'v*'
branches:
- main
workflow_dispatch:
jobs:
build:
runs-on: macos-latest
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Set up Python (pinned)
uses: actions/setup-python@v5
with:
python-version: '3.13.7'
cache: 'pip'
- name: "Install dependencies (release: with hash checking per 2.8)"
run: |
echo "=== DEBUG: Installing dependencies ==="
python --version
python -m pip install --upgrade pip
if [ "${{ startsWith(github.ref, 'refs/tags/v') }}" = "true" ]; then
echo "Release build: using pip --require-hashes (2.8)"
python -m pip install "pip<26"
python -m pip install pip-tools
python scripts/generate_requirements_hashes.py
pip install -r requirements-build-hashed.txt --require-hashes
else
echo "Non-release build: installing from requirements-build.txt"
pip install -r requirements-build.txt
fi
echo "Installing build requirements (runtime deps for GUI app)..."
echo "PyInstaller version (pinned from requirements-build.txt):"
pyinstaller --version
echo "Installing Playwright browsers (for testing, not bundled)..."
python -m playwright install chromium
echo "Verifying installed packages match requirements.txt runtime dependencies..."
echo "Core packages:"
pip list | grep -E "PySide6|requests|aiohttp|beautifulsoup4|ddgs|rapidfuzz|dateutil|pyyaml|tqdm|requests-cache|playwright|selenium|openpyxl|pyinstaller"
echo "Checking for missing dependencies..."
required=("PySide6" "requests" "aiohttp" "beautifulsoup4" "ddgs" "rapidfuzz" "python-dateutil" "pyyaml" "tqdm" "requests-cache" "playwright" "selenium" "openpyxl")
installed=$(pip list --format=json | python -c "import sys, json; print('\n'.join(p['name'].lower() for p in json.load(sys.stdin)))")
missing=()
for pkg in "${required[@]}"; do
if ! printf "%s\n" "$installed" | grep -qx "${pkg,,}"; then
missing+=("$pkg")
fi
done
if [ ${#missing[@]} -gt 0 ]; then
echo "⚠️ Warning: Missing packages: ${missing[*]}"
else
echo "✅ All required runtime dependencies are installed"
fi
- name: Generate third-party licenses file (Step 11)
run: |
python scripts/generate_licenses.py --output THIRD_PARTY_LICENSES.txt
if [ ! -f THIRD_PARTY_LICENSES.txt ]; then
echo "ERROR: License bundle generation failed - THIRD_PARTY_LICENSES.txt not created"
exit 1
fi
if ! grep -q "Package:" THIRD_PARTY_LICENSES.txt; then
echo "ERROR: License bundle appears empty or invalid"
exit 1
fi
- name: Sync version from git tag
if: startsWith(github.ref, 'refs/tags/v')
run: |
echo "Syncing version.py from git tag: ${{ github.ref_name }}"
python scripts/sync_version.py --tag ${{ github.ref_name }}
continue-on-error: false
- name: Set build info
run: python scripts/set_build_info.py
env:
GITHUB_RUN_NUMBER: ${{ github.run_number }}
GITHUB_RUN_ID: ${{ github.run_id }}
- name: Process Info.plist
run: python scripts/process_info_plist.py
- name: Validate version
run: python scripts/validate_version.py
- name: Generate application icons
run: |
echo "=== Generating application icons (taskbar/dock) ==="
python scripts/generate_icons.py
if [ -f build/icon.icns ]; then
echo "[OK] icon.icns created for macOS"
elif [ -f build/icon.ico ]; then
echo "[OK] icon.ico created (ICNS may need manual conversion on macOS)"
else
echo "ERROR: No icon file found after generate_icons.py"
exit 1
fi
- name: Build with PyInstaller
run: |
python scripts/build_pyinstaller.py
- name: Import signing certificate
if: startsWith(github.ref, 'refs/tags/v')
env:
MACOS_CERT_P12: ${{ secrets.MACOS_SIGNING_CERT_P12 }}
MACOS_CERT_PASSWORD: ${{ secrets.MACOS_SIGNING_CERT_PASSWORD }}
run: |
if [ -z "$MACOS_CERT_P12" ] || [ -z "$MACOS_CERT_PASSWORD" ]; then
echo "Skipping certificate import: secrets not available"
exit 0
fi
# Create keychain
security create-keychain -p "" build.keychain
security default-keychain -s build.keychain
security unlock-keychain -p "" build.keychain
security set-keychain-settings -t 3600 -u build.keychain
# Import certificate
echo "$MACOS_CERT_P12" | base64 --decode > cert.p12
security import cert.p12 -k build.keychain -P "$MACOS_CERT_PASSWORD" -T /usr/bin/codesign
security set-key-partition-list -S apple-tool:,apple:,codesign: -s -k "" build.keychain
# Clean up certificate file
rm -f cert.p12
- name: Sign app
if: startsWith(github.ref, 'refs/tags/v')
env:
APPLE_DEVELOPER_ID: ${{ secrets.APPLE_DEVELOPER_ID }}
run: |
if [ -z "$APPLE_DEVELOPER_ID" ]; then
echo "Skipping app signing: APPLE_DEVELOPER_ID not available"
exit 0
fi
bash scripts/sign_macos.sh dist/CuePoint.app
- name: Create DMG
if: startsWith(github.ref, 'refs/tags/v')
id: create_dmg
run: |
echo "=== DEBUG: Creating DMG ==="
echo "Current directory: $(pwd)"
echo "Checking for existing DMG files..."
ls -la dist/*.dmg 2>/dev/null || echo "No existing DMG files found"
echo "Checking for mounted volumes..."
hdiutil info | grep -A 5 "CuePoint" || echo "No CuePoint volumes mounted"
echo "Cleaning up any existing mounts..."
# Unmount any existing CuePoint volumes
for vol in $(hdiutil info | grep -i "cuepoint" | awk '{print $1}' || true); do
echo "Unmounting volume: $vol"
hdiutil detach "$vol" -force 2>/dev/null || true
done
sleep 2
VERSION=$(python -c "import sys; sys.path.insert(0, 'src'); from cuepoint.version import __version__; print(__version__)")
echo "Version: $VERSION"
echo "Running: bash scripts/create_dmg.sh \"$VERSION\""
bash scripts/create_dmg.sh "$VERSION"
# Verify DMG was created
echo "Verifying DMG was created..."
DMG_FILE=$(ls dist/CuePoint-v*.dmg 2>/dev/null | head -1)
if [ -z "$DMG_FILE" ]; then
echo "Error: DMG file not found after creation"
echo "Contents of dist/:"
ls -la dist/ || true
exit 1
fi
echo "DMG created: $DMG_FILE"
echo "DMG size: $(ls -lh "$DMG_FILE" | awk '{print $5}')"
echo "dmg_file=$DMG_FILE" >> $GITHUB_OUTPUT
- name: Generate build metadata
if: startsWith(github.ref, 'refs/tags/v')
run: python scripts/generate_build_metadata.py --output dist/build_info.json
env:
GITHUB_RUN_ID: ${{ github.run_id }}
- name: Notarize DMG
if: startsWith(github.ref, 'refs/tags/v') && steps.create_dmg.outcome == 'success'
env:
APPLE_TEAM_ID: ${{ secrets.APPLE_TEAM_ID }}
APPLE_NOTARYTOOL_ISSUER_ID: ${{ secrets.APPLE_NOTARYTOOL_ISSUER_ID }}
APPLE_NOTARYTOOL_KEY_ID: ${{ secrets.APPLE_NOTARYTOOL_KEY_ID }}
APPLE_NOTARYTOOL_KEY: ${{ secrets.APPLE_NOTARYTOOL_KEY }}
run: |
if [ -z "$APPLE_NOTARYTOOL_ISSUER_ID" ] || [ -z "$APPLE_NOTARYTOOL_KEY_ID" ] || [ -z "$APPLE_NOTARYTOOL_KEY" ]; then
echo "Skipping notarization: secrets not available"
exit 0
fi
DMG_FILE=$(ls dist/CuePoint-v*.dmg | head -1)
bash scripts/notarize_macos.sh "$DMG_FILE"
- name: Verify version embedding
run: python scripts/verify_version_embedding.py
- name: Verify installer (checksums and signatures, Design 2.38)
if: startsWith(github.ref, 'refs/tags/v')
run: |
python scripts/generate_checksums.py --output dist/SHA256SUMS.txt --algorithms sha256
python scripts/verify_installer.py --dir dist/ --checksums dist/SHA256SUMS.txt
python scripts/validate_signatures.py --dir dist/
- name: Verify DMG exists before upload
if: startsWith(github.ref, 'refs/tags/v')
run: |
DMG_COUNT=$(ls dist/*.dmg 2>/dev/null | wc -l | tr -d ' ')
if [ "$DMG_COUNT" -eq 0 ]; then
echo "Error: No DMG files found in dist/"
ls -la dist/ || true
exit 1
fi
echo "Found $DMG_COUNT DMG file(s):"
ls -lh dist/*.dmg
- name: Upload artifact
if: startsWith(github.ref, 'refs/tags/v')
id: upload_dmg
uses: actions/upload-artifact@v4
with:
name: macos-dmg
path: dist/
retention-days: 30
if-no-files-found: error
- name: Verify artifact upload
if: startsWith(github.ref, 'refs/tags/v')
run: |
if [ "${{ steps.upload_dmg.outcome }}" != "success" ]; then
echo "Error: Artifact upload failed"
exit 1
fi
echo "Artifact uploaded successfully"