Skip to content

more more more more more more more fixes #314

more more more more more more more fixes

more more more more more more more fixes #314

Workflow file for this run

name: Build Windows
on:
push:
tags:
- 'v*'
branches:
- main
- feature
workflow_dispatch:
jobs:
build:
runs-on: windows-latest
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Debug checkout info
run: |
Write-Host "=== DEBUG: Checkout completed ==="
Write-Host "Working directory: $(Get-Location)"
Write-Host "Git ref: ${{ github.ref }}"
Write-Host "Git SHA: ${{ github.sha }}"
Write-Host "Git ref name: ${{ github.ref_name }}"
Write-Host "Repository: ${{ github.repository }}"
Write-Host "Contents of root directory:"
Get-ChildItem -ErrorAction SilentlyContinue | Select-Object Name, Length | Format-Table
- 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: |
Write-Host "=== DEBUG: Installing dependencies ==="
python --version
python -m pip install --upgrade pip
if ("${{ github.ref }}" -like "refs/tags/v*") {
Write-Host "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 {
Write-Host "Non-release build: installing from requirements-build.txt"
pip install -r requirements-build.txt
}
Write-Host "Installing build requirements (runtime deps for GUI app)..."
Write-Host "PyInstaller version (pinned from requirements-build.txt):"
pyinstaller --version
Write-Host "Installing Playwright browsers (for testing, not bundled)..."
python -m playwright install chromium
Write-Host "Verifying installed packages match requirements.txt runtime dependencies..."
Write-Host "Core packages:"
pip list | Select-String -Pattern "PySide6|requests|aiohttp|beautifulsoup4|ddgs|rapidfuzz|dateutil|pyyaml|tqdm|requests-cache|playwright|selenium|openpyxl|pyinstaller"
Write-Host "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 | ConvertFrom-Json | ForEach-Object { $_.name.ToLower() }
$missing = @()
foreach ($pkg in $required) {
if ($installed -notcontains $pkg.ToLower()) {
$missing += $pkg
}
}
if ($missing.Count -gt 0) {
Write-Warning "Missing packages: $($missing -join ', ')"
} else {
Write-Host "[OK] All required runtime dependencies are installed"
}
- name: Generate third-party licenses file (Step 11)
run: |
Write-Host "=== Generating third-party licenses (Step 11) ==="
python scripts/generate_licenses.py --output THIRD_PARTY_LICENSES.txt
if (-not (Test-Path "THIRD_PARTY_LICENSES.txt")) {
Write-Error "License bundle generation failed - THIRD_PARTY_LICENSES.txt not created"
exit 1
}
$content = Get-Content "THIRD_PARTY_LICENSES.txt" -Raw
if (-not $content -match "Package:") {
Write-Error "License bundle appears empty or invalid"
exit 1
}
Write-Host "Licenses file created: $(Get-Item THIRD_PARTY_LICENSES.txt | Select-Object -ExpandProperty Length) bytes"
- name: Install NSIS
uses: negrutiu/nsis-install@v2
with:
distro: negrutiu
arch: x86
- name: Sync version from git tag
if: startsWith(github.ref, 'refs/tags/v')
run: |
Write-Host "=== DEBUG: Syncing version from git tag ==="
Write-Host "Git ref: ${{ github.ref }}"
Write-Host "Git ref name: ${{ github.ref_name }}"
Write-Host "Running: python scripts/sync_version.py --tag ${{ github.ref_name }}"
python scripts/sync_version.py --tag ${{ github.ref_name }}
if ($LASTEXITCODE -ne 0) {
Write-Error "Version sync failed"
exit 1
}
Write-Host "[OK] Version synced successfully"
- name: Set build info
run: |
Write-Host "=== DEBUG: Setting build info ==="
Write-Host "GITHUB_RUN_NUMBER: ${{ github.run_number }}"
Write-Host "GITHUB_RUN_ID: ${{ github.run_id }}"
Write-Host "Running: python scripts/set_build_info.py"
python scripts/set_build_info.py
Write-Host "Build info script completed"
env:
GITHUB_RUN_NUMBER: ${{ github.run_number }}
GITHUB_RUN_ID: ${{ github.run_id }}
- name: Generate version info
run: |
Write-Host "=== DEBUG: Generating version info ==="
Write-Host "Current directory: $(Get-Location)"
Write-Host "Running: python scripts/generate_version_info.py"
python scripts/generate_version_info.py
if (Test-Path "build\version_info.txt") {
Write-Host "[OK] version_info.txt created"
Write-Host "File size: $(Get-Item build\version_info.txt | Select-Object -ExpandProperty Length) bytes"
Write-Host "First 20 lines:"
Get-Content build\version_info.txt -Head 20
} else {
Write-Error "version_info.txt not found after generation"
exit 1
}
- name: Validate version
run: |
Write-Host "=== DEBUG: Validating version ==="
Write-Host "Git ref: ${{ github.ref }}"
Write-Host "Git ref name: ${{ github.ref_name }}"
Write-Host "Running: python scripts/validate_version.py"
python scripts/validate_version.py
Write-Host "Version validation completed"
- name: Generate application icons
run: |
Write-Host "=== Generating application icons (taskbar/dock) ==="
python scripts/generate_icons.py
if (Test-Path "build\icon.ico") {
Write-Host "[OK] icon.ico created for Windows"
} else {
Write-Error "icon.ico not found after generate_icons.py"
exit 1
}
- name: Verify Python DLL exists
run: |
Write-Host "=== DEBUG: Verifying Python DLL ==="
$pythonVersion = python --version
Write-Host "Python version: $pythonVersion"
$pythonExe = python -c "import sys; print(sys.executable)"
Write-Host "Python executable: $pythonExe"
$pythonDir = Split-Path -Parent $pythonExe
Write-Host "Python directory: $pythonDir"
$pythonDllName = python -c "import sys; print(f'python{sys.version_info.major}{sys.version_info.minor}.dll')"
Write-Host "Python DLL name: $pythonDllName"
$pythonDllPath = Join-Path $pythonDir $pythonDllName
Write-Host "Python DLL path: $pythonDllPath"
if (Test-Path $pythonDllPath) {
Write-Host "[OK] Python DLL found at: $pythonDllPath"
$dllInfo = Get-Item $pythonDllPath
Write-Host " Size: $($dllInfo.Length) bytes"
Write-Host " Last modified: $($dllInfo.LastWriteTime)"
} else {
Write-Error "Python DLL NOT FOUND at: $pythonDllPath"
Write-Host "Checking alternative locations..."
$altPaths = @(
(Join-Path $pythonDir "DLLs\$pythonDllName"),
(Join-Path $pythonDir "python3.dll")
)
foreach ($altPath in $altPaths) {
if (Test-Path $altPath) {
Write-Host " Found at alternative location: $altPath"
}
}
exit 1
}
- name: Build with PyInstaller
run: |
Write-Host "=== DEBUG: Building with PyInstaller ==="
Write-Host "Current directory: $(Get-Location)"
Write-Host "Python version:"
python --version
Write-Host "PyInstaller version:"
pyinstaller --version
Write-Host "Checking if build directory exists:"
if (Test-Path "build") {
Write-Host " build/ exists"
Write-Host " Contents:"
Get-ChildItem build\ -ErrorAction SilentlyContinue | Format-Table Name, Length
} else {
Write-Host " build/ does not exist (will be created)"
}
Write-Host "Checking spec file for DLL inclusion:"
$specFile = "build\pyinstaller.spec"
if (Test-Path $specFile) {
$specContent = Get-Content $specFile -Raw
if ($specContent -match "python313\.dll|python_dll_name") {
Write-Host " [OK] Spec file includes Python DLL collection code"
} else {
Write-Host " [WARNING] Spec file may not include DLL collection"
}
}
Write-Host "Running: python scripts/build_pyinstaller.py"
python scripts/build_pyinstaller.py
Write-Host "PyInstaller build completed"
Write-Host "Checking dist/ directory:"
if (Test-Path "dist") {
Write-Host " dist/ exists"
Write-Host " Contents:"
Get-ChildItem dist\ -ErrorAction SilentlyContinue | Format-Table Name, Length, LastWriteTime
} else {
Write-Error "dist/ directory not found after build"
exit 1
}
Write-Host "=== Verifying DLL inclusion in built executable ==="
$exePath = "dist\CuePoint.exe"
if (Test-Path $exePath) {
Write-Host "Checking if python313.dll is in the executable bundle..."
# Note: We can't easily check inside the exe without extracting it
# But we can verify the build logs showed DLL inclusion
Write-Host " [INFO] DLL inclusion should be verified in build logs above"
Write-Host " [INFO] Look for messages like: '[PyInstaller] Including Python DLL'"
Write-Host " [INFO] Or: '[PyInstaller] Verified: python313.dll is in binaries list'"
} else {
Write-Host " [WARNING] CuePoint.exe not found in dist/"
}
- name: Import certificate
if: startsWith(github.ref, 'refs/tags/v')
env:
WINDOWS_CERT_PFX: ${{ secrets.WINDOWS_CERT_PFX }}
WINDOWS_CERT_PASSWORD: ${{ secrets.WINDOWS_CERT_PASSWORD }}
run: |
Write-Host "=== DEBUG: Importing certificate ==="
Write-Host "Git ref: ${{ github.ref }}"
Write-Host "Checking for certificate secrets..."
$hasCert = -not [string]::IsNullOrEmpty($env:WINDOWS_CERT_PFX)
$hasPassword = -not [string]::IsNullOrEmpty($env:WINDOWS_CERT_PASSWORD)
Write-Host " WINDOWS_CERT_PFX present: $hasCert"
Write-Host " WINDOWS_CERT_PASSWORD present: $hasPassword"
if (-not $hasCert -or -not $hasPassword) {
Write-Host "[SKIP] Certificate secrets not available, skipping import"
exit 0
}
Write-Host "Certificate data length: $($env:WINDOWS_CERT_PFX.Length) characters"
Write-Host "Decoding certificate from base64..."
$certBytes = [System.Convert]::FromBase64String($env:WINDOWS_CERT_PFX)
Write-Host "Certificate binary size: $($certBytes.Length) bytes"
$certPath = "cert.pfx"
Write-Host "Writing certificate to: $certPath"
[System.IO.File]::WriteAllBytes($certPath, $certBytes)
if (Test-Path $certPath) {
Write-Host "[OK] Certificate imported successfully"
Write-Host "Certificate file size: $(Get-Item $certPath | Select-Object -ExpandProperty Length) bytes"
} else {
Write-Error "Certificate file not found after write"
exit 1
}
- name: Sign executable
if: startsWith(github.ref, 'refs/tags/v')
env:
WINDOWS_CERT_PFX: ${{ secrets.WINDOWS_CERT_PFX }}
WINDOWS_CERT_PASSWORD: ${{ secrets.WINDOWS_CERT_PASSWORD }}
run: |
Write-Host "=== DEBUG: Signing executable ==="
Write-Host "Checking for certificate secrets..."
$hasCert = -not [string]::IsNullOrEmpty($env:WINDOWS_CERT_PFX)
$hasPassword = -not [string]::IsNullOrEmpty($env:WINDOWS_CERT_PASSWORD)
Write-Host " WINDOWS_CERT_PFX present: $hasCert"
Write-Host " WINDOWS_CERT_PASSWORD present: $hasPassword"
if (-not $hasCert -or -not $hasPassword) {
Write-Host "[SKIP] Certificate secrets not available, skipping signing"
exit 0
}
$certPath = "cert.pfx"
$exePath = "dist/CuePoint.exe"
Write-Host "Certificate path: $certPath"
Write-Host "Executable path: $exePath"
if (-not (Test-Path $certPath)) {
Write-Error "Certificate file not found: $certPath"
exit 1
}
if (-not (Test-Path $exePath)) {
Write-Error "Executable not found: $exePath"
exit 1
}
Write-Host "Executable size before signing: $(Get-Item $exePath | Select-Object -ExpandProperty Length) bytes"
Write-Host "Running signtool sign..."
signtool sign /f $certPath /p "$env:WINDOWS_CERT_PASSWORD" /fd SHA256 /tr http://timestamp.digicert.com /td SHA256 $exePath
$signExitCode = $LASTEXITCODE
Write-Host "signtool sign exit code: $signExitCode"
if ($signExitCode -ne 0) {
Write-Error "signtool sign failed with exit code $signExitCode"
exit 1
}
Write-Host "Executable size after signing: $(Get-Item $exePath | Select-Object -ExpandProperty Length) bytes"
Write-Host "Running signtool verify..."
signtool verify /pa /v $exePath
$verifyExitCode = $LASTEXITCODE
Write-Host "signtool verify exit code: $verifyExitCode"
if ($verifyExitCode -ne 0) {
Write-Error "signtool verify failed with exit code $verifyExitCode"
exit 1
}
Write-Host "[OK] Executable signed and verified successfully"
- name: Build installer
if: startsWith(github.ref, 'refs/tags/v')
run: |
Write-Host "=== DEBUG: Building installer ==="
Write-Host "Git ref: ${{ github.ref }}"
Write-Host "Current directory: $(Get-Location)"
# Verify PyInstaller build completed successfully
Write-Host "Checking for PyInstaller build output..."
$exeFound = $false
if (Test-Path "dist\CuePoint.exe") {
Write-Host "[OK] Found CuePoint.exe in dist/ (onefile mode)"
$exeInfo = Get-Item "dist\CuePoint.exe"
Write-Host " Size: $($exeInfo.Length) bytes"
Write-Host " Last modified: $($exeInfo.LastWriteTime)"
$exeFound = $true
} elseif (Test-Path "dist\CuePoint\CuePoint.exe") {
Write-Host "[OK] Found CuePoint.exe in dist/CuePoint/ (onedir mode)"
$exeInfo = Get-Item "dist\CuePoint\CuePoint.exe"
Write-Host " Size: $($exeInfo.Length) bytes"
Write-Host " Last modified: $($exeInfo.LastWriteTime)"
$exeFound = $true
}
if (-not $exeFound) {
Write-Error "CuePoint.exe not found in dist/ or dist/CuePoint/"
Write-Host "Contents of dist/:"
$distContents = Get-ChildItem dist\ -ErrorAction SilentlyContinue
if ($distContents) {
$distContents | Format-Table Name, Length, LastWriteTime, Attributes
} else {
Write-Host " dist/ is empty or doesn't exist"
}
exit 1
}
Write-Host "Getting version from version.py..."
$env:PYTHONIOENCODING = "utf-8"
$env:PYTHONUTF8 = "1"
$fullVersion = python -c "import sys; sys.path.insert(0, 'src'); from cuepoint.version import __version__; sys.stdout.write(__version__)"
Write-Host "Full version: $fullVersion"
# Extract base version (X.Y.Z) for NSIS - NSIS requires format X.Y.Z (no prerelease suffixes)
# Remove prerelease suffix (everything after -) and build metadata (everything after +)
$version = $fullVersion
if ($version -match '^([^-+]+)') {
$version = $matches[1]
}
Write-Host "Base version for NSIS: $version"
# Try to find makensis in common locations or PATH
Write-Host "Searching for makensis..."
$makensis = $null
$possiblePaths = @(
"${env:ProgramFiles(x86)}\NSIS\makensis.exe",
"${env:ProgramFiles}\NSIS\makensis.exe",
"C:\Program Files (x86)\NSIS\makensis.exe",
"C:\Program Files\NSIS\makensis.exe"
)
foreach ($path in $possiblePaths) {
Write-Host " Checking: $path"
if (Test-Path $path) {
$makensis = $path
Write-Host "[OK] Found makensis at: $path"
$versionInfo = & $path /VERSION 2>&1
Write-Host " NSIS version: $versionInfo"
break
}
}
if (-not $makensis) {
Write-Host " Not found in common paths, checking PATH..."
$makensisCmd = Get-Command makensis -ErrorAction SilentlyContinue
if ($makensisCmd) {
$makensis = $makensisCmd.Path
Write-Host "[OK] Found makensis in PATH at: $makensis"
}
}
if (-not $makensis) {
Write-Error "makensis not found. Please ensure NSIS is installed."
Write-Host "Searched paths:"
foreach ($path in $possiblePaths) {
Write-Host " $path : $(if (Test-Path $path) { 'EXISTS' } else { 'NOT FOUND' })"
}
exit 1
}
# NSIS File command resolves paths relative to the .nsi file's directory (scripts/)
# The installer script uses relative paths (..\dist\) which work reliably
$currentDir = Get-Location
Write-Host "Current directory: $currentDir"
$exePath = "$currentDir\dist\CuePoint.exe"
Write-Host "Verifying executable exists: $exePath"
if (-not (Test-Path $exePath)) {
Write-Error "CuePoint.exe not found. Current dir: $currentDir"
Write-Host "Contents of dist/:"
Get-ChildItem dist\ -ErrorAction SilentlyContinue | Format-Table Name, Length, LastWriteTime
exit 1
}
Write-Host "[OK] Executable verified"
# Check if installer script exists
$installerScript = "scripts\installer.nsi"
Write-Host "Checking installer script: $installerScript"
if (-not (Test-Path $installerScript)) {
Write-Error "Installer script not found: $installerScript"
exit 1
}
Write-Host "[OK] Installer script found"
Write-Host "Script size: $(Get-Item $installerScript | Select-Object -ExpandProperty Length) bytes"
# Run makensis from project root
# The installer script uses relative paths (..\dist\) relative to scripts/ directory
Write-Host "Running makensis..."
Write-Host " Command: $makensis /DVERSION=$version $installerScript"
Write-Host " Working directory: $currentDir"
$makensisResult = & $makensis /DVERSION=$version $installerScript 2>&1
$makensisExitCode = $LASTEXITCODE
Write-Host "Makensis exit code: $makensisExitCode"
Write-Host "Makensis output:"
Write-Host $makensisResult
if ($makensisExitCode -ne 0) {
Write-Error "makensis failed with exit code $makensisExitCode"
exit 1
}
# NSIS creates installer with base version in filename
# Rename it to include full version (with prerelease suffix) if different
$baseInstallerName = "CuePoint-Setup-v$version.exe"
$installerName = "CuePoint-Setup-v$fullVersion.exe"
$baseInstallerPath = "dist\$baseInstallerName"
$installerPath = "dist\$installerName"
Write-Host "Waiting for file system to sync..."
Start-Sleep -Seconds 2
# Rename installer to include full version if different
if ($fullVersion -ne $version -and (Test-Path $baseInstallerPath)) {
Write-Host "Renaming installer to include full version..."
Write-Host " From: $baseInstallerName"
Write-Host " To: $installerName"
Rename-Item -Path $baseInstallerPath -NewName $installerName -Force
Write-Host "[OK] Installer renamed successfully"
}
# Check for installer using expected filename (full version)
$expectedInstaller = "dist\$installerName"
$absInstallerPath = Join-Path $currentDir $expectedInstaller
Write-Host "Checking for installer..."
Write-Host " Expected relative path: $expectedInstaller"
Write-Host " Expected absolute path: $absInstallerPath"
# Try multiple methods to find the file
$installerFiles = @()
# Method 1: Exact path
Write-Host "Method 1: Checking exact path..."
if (Test-Path $expectedInstaller) {
$file = Get-Item $expectedInstaller
$installerFiles += $file
Write-Host "[OK] Found installer using exact path"
Write-Host " File: $($file.FullName)"
Write-Host " Size: $($file.Length) bytes"
Write-Host " Last modified: $($file.LastWriteTime)"
} else {
Write-Host " Not found at relative path"
}
# Method 2: Pattern matching
Write-Host "Method 2: Checking pattern dist\CuePoint-Setup-v*.exe..."
$patternFiles = Get-ChildItem "dist\CuePoint-Setup-v*.exe" -ErrorAction SilentlyContinue
if ($patternFiles) {
$installerFiles += $patternFiles
Write-Host "[OK] Found $($patternFiles.Count) file(s) using pattern matching"
$patternFiles | ForEach-Object { Write-Host " - $($_.Name) ($($_.Length) bytes)" }
} else {
Write-Host " No files found with pattern"
}
# Method 3: All exe files with "Setup" in name
Write-Host "Method 3: Checking all .exe files with 'Setup' in name..."
$allSetupFiles = Get-ChildItem "dist\*.exe" -ErrorAction SilentlyContinue | Where-Object { $_.Name -like "*Setup*" }
if ($allSetupFiles) {
$installerFiles += $allSetupFiles
Write-Host "[OK] Found $($allSetupFiles.Count) file(s) using wildcard search"
$allSetupFiles | ForEach-Object { Write-Host " - $($_.Name) ($($_.Length) bytes)" }
} else {
Write-Host " No files found with 'Setup' in name"
}
# Remove duplicates
$installerFiles = $installerFiles | Select-Object -Unique
Write-Host "Total unique installer files found: $($installerFiles.Count)"
if ($installerFiles.Count -eq 0) {
Write-Error "Installer was not found. Expected: $expectedInstaller"
Write-Host "Makensis reported creating the file, but it's not accessible."
Write-Host "All files in dist directory:"
$allFiles = Get-ChildItem "dist\" -ErrorAction SilentlyContinue
if ($allFiles) {
$allFiles | Format-Table Name, Length, LastWriteTime, Attributes
} else {
Write-Host " dist/ directory is empty or doesn't exist"
}
Write-Host "Current working directory: $(Get-Location)"
Write-Host "Absolute path check:"
Write-Host " Expected: $absInstallerPath"
Write-Host " Exists: $(Test-Path $absInstallerPath)"
if (Test-Path $absInstallerPath) {
Write-Host " File info:"
Get-Item $absInstallerPath | Format-List
}
exit 1
}
Write-Host "[OK] Installer found successfully:"
$installerFiles | Format-Table Name, Length, LastWriteTime, FullName
- name: Sign installer
if: startsWith(github.ref, 'refs/tags/v')
env:
WINDOWS_CERT_PFX: ${{ secrets.WINDOWS_CERT_PFX }}
WINDOWS_CERT_PASSWORD: ${{ secrets.WINDOWS_CERT_PASSWORD }}
run: |
Write-Host "=== DEBUG: Signing installer ==="
Write-Host "Checking for certificate secrets..."
$hasCert = -not [string]::IsNullOrEmpty($env:WINDOWS_CERT_PFX)
$hasPassword = -not [string]::IsNullOrEmpty($env:WINDOWS_CERT_PASSWORD)
Write-Host " WINDOWS_CERT_PFX present: $hasCert"
Write-Host " WINDOWS_CERT_PASSWORD present: $hasPassword"
if (-not $hasCert -or -not $hasPassword) {
Write-Host "[SKIP] Certificate secrets not available, skipping installer signing"
exit 0
}
$certPath = "cert.pfx"
Write-Host "Certificate path: $certPath"
if (-not (Test-Path $certPath)) {
Write-Error "Certificate file not found: $certPath"
exit 1
}
Write-Host "[OK] Certificate file found"
Write-Host "Searching for installer files..."
Write-Host " Pattern 1: dist\CuePoint-Setup-v*-setup.exe"
$installer = Get-ChildItem dist\CuePoint-Setup-v*-setup.exe -ErrorAction SilentlyContinue | Select-Object -First 1
if (-not $installer) {
Write-Host " Pattern 1: Not found, trying pattern 2..."
Write-Host " Pattern 2: dist\CuePoint-Setup-v*.exe"
$installer = Get-ChildItem dist\CuePoint-Setup-v*.exe -ErrorAction SilentlyContinue | Select-Object -First 1
}
if (-not $installer) {
Write-Host " Pattern 2: Not found, trying pattern 3..."
Write-Host " Pattern 3: dist\*-setup.exe"
$installer = Get-ChildItem dist\*-setup.exe -ErrorAction SilentlyContinue | Select-Object -First 1
}
if (-not $installer) {
Write-Error "Installer not found with any pattern"
Write-Host "All files in dist/:"
Get-ChildItem dist\ -ErrorAction SilentlyContinue | Format-Table Name, Length, LastWriteTime
exit 1
}
Write-Host "[OK] Found installer: $($installer.FullName)"
Write-Host " Size before signing: $($installer.Length) bytes"
Write-Host " Last modified: $($installer.LastWriteTime)"
Write-Host "Running signtool sign..."
signtool sign /f $certPath /p "$env:WINDOWS_CERT_PASSWORD" /fd SHA256 /tr http://timestamp.digicert.com /td SHA256 "$($installer.FullName)"
$signExitCode = $LASTEXITCODE
Write-Host "signtool sign exit code: $signExitCode"
if ($signExitCode -ne 0) {
Write-Error "signtool sign failed with exit code $signExitCode"
exit 1
}
# Refresh file info after signing
$installer = Get-Item $installer.FullName
Write-Host " Size after signing: $($installer.Length) bytes"
Write-Host " Last modified: $($installer.LastWriteTime)"
Write-Host "Running signtool verify..."
signtool verify /pa /v "$($installer.FullName)"
$verifyExitCode = $LASTEXITCODE
Write-Host "signtool verify exit code: $verifyExitCode"
if ($verifyExitCode -ne 0) {
Write-Error "signtool verify failed with exit code $verifyExitCode"
exit 1
}
Write-Host "[OK] Installer signed and verified successfully"
- 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: 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 version embedding
run: |
Write-Host "=== DEBUG: Verifying version embedding ==="
Write-Host "Current directory: $(Get-Location)"
Write-Host "Running: python scripts/verify_version_embedding.py"
python scripts/verify_version_embedding.py
$verifyExitCode = $LASTEXITCODE
Write-Host "Version embedding verification exit code: $verifyExitCode"
if ($verifyExitCode -ne 0) {
Write-Error "Version embedding verification failed"
exit 1
}
Write-Host "[OK] Version embedding verified"
- name: Verify installer exists before upload
if: startsWith(github.ref, 'refs/tags/v')
run: |
Write-Host "=== DEBUG: Verifying installer exists before upload ==="
Write-Host "Git ref: ${{ github.ref }}"
Write-Host "Current directory: $(Get-Location)"
# Get version from environment or git tag
$version = "${{ env.VERSION }}"
Write-Host "env.VERSION: $version"
if (-not $version -or $version -eq "") {
$version = "${{ github.ref_name }}"
Write-Host "Using github.ref_name: $version"
$version = $version -replace '^v', ''
Write-Host "Version after removing 'v' prefix: $version"
}
Write-Host "Final version: $version"
Write-Host "Looking for installer with version: $version"
# Try multiple patterns to find installer
Write-Host "Searching for installer files..."
$installerFiles = @()
Write-Host "Pattern 1: dist\CuePoint-Setup-v*.exe"
$pattern1 = Get-ChildItem "dist\CuePoint-Setup-v*.exe" -ErrorAction SilentlyContinue
if ($pattern1) {
Write-Host " Found $($pattern1.Count) file(s)"
$pattern1 | ForEach-Object { Write-Host " - $($_.Name) ($($_.Length) bytes)" }
$installerFiles += $pattern1
} else {
Write-Host " No files found"
}
Write-Host "Pattern 2: dist\*-setup.exe"
$pattern2 = Get-ChildItem "dist\*-setup.exe" -ErrorAction SilentlyContinue
if ($pattern2) {
Write-Host " Found $($pattern2.Count) file(s)"
$pattern2 | ForEach-Object { Write-Host " - $($_.Name) ($($_.Length) bytes)" }
$installerFiles += $pattern2
} else {
Write-Host " No files found"
}
Write-Host "Pattern 3: dist\*.exe with 'Setup' in name"
$pattern3 = Get-ChildItem "dist\*.exe" -ErrorAction SilentlyContinue | Where-Object { $_.Name -like "*Setup*" }
if ($pattern3) {
Write-Host " Found $($pattern3.Count) file(s)"
$pattern3 | ForEach-Object { Write-Host " - $($_.Name) ($($_.Length) bytes)" }
$installerFiles += $pattern3
} else {
Write-Host " No files found"
}
# Remove duplicates
$installerFiles = $installerFiles | Select-Object -Unique
Write-Host "Total unique installer files found: $($installerFiles.Count)"
if ($installerFiles.Count -eq 0) {
Write-Error "No installer files found in dist/"
Write-Host "All files in dist directory:"
$allFiles = Get-ChildItem dist\ -ErrorAction SilentlyContinue
if ($allFiles) {
$allFiles | Format-Table Name, Length, LastWriteTime, Attributes, FullName
} else {
Write-Host " dist/ directory is empty or doesn't exist"
}
Write-Host "Checking explicit path:"
$explicitPath = "dist\CuePoint-Setup-v$version.exe"
$absExplicitPath = Join-Path (Get-Location) $explicitPath
Write-Host " Relative path: $explicitPath"
Write-Host " Absolute path: $absExplicitPath"
Write-Host " Exists (relative): $(Test-Path $explicitPath)"
Write-Host " Exists (absolute): $(Test-Path $absExplicitPath)"
if (Test-Path $explicitPath) {
Write-Host " File info:"
Get-Item $explicitPath | Format-List *
}
exit 1
}
Write-Host "[OK] Found $($installerFiles.Count) installer file(s):"
$installerFiles | Format-Table Name, Length, LastWriteTime, FullName
- name: Prepare artifact upload
if: startsWith(github.ref, 'refs/tags/v')
run: |
Write-Host "=== DEBUG: Preparing artifact upload ==="
Write-Host "Current directory: $(Get-Location)"
# Find installer using the actual pattern
Write-Host "Searching for installer files..."
$installerFiles = @()
# Try the actual pattern first: CuePoint-Setup-v*.exe
Write-Host "Pattern 1: dist\CuePoint-Setup-v*.exe"
$pattern1 = Get-ChildItem dist\CuePoint-Setup-v*.exe -ErrorAction SilentlyContinue
if ($pattern1) {
Write-Host "[OK] Found $($pattern1.Count) file(s) with pattern 1:"
$pattern1 | ForEach-Object { Write-Host " - $($_.FullName) ($($_.Length) bytes)" }
$installerFiles += $pattern1
}
# Try alternative pattern: *-setup.exe (in case naming changes)
Write-Host "Pattern 2: dist\*-setup.exe"
$pattern2 = Get-ChildItem dist\*-setup.exe -ErrorAction SilentlyContinue
if ($pattern2) {
Write-Host "[OK] Found $($pattern2.Count) file(s) with pattern 2:"
$pattern2 | ForEach-Object { Write-Host " - $($_.FullName) ($($_.Length) bytes)" }
$installerFiles += $pattern2
}
# Try any .exe with "Setup" in name
Write-Host "Pattern 3: dist\*.exe with 'Setup' in name"
$pattern3 = Get-ChildItem dist\*.exe -ErrorAction SilentlyContinue | Where-Object { $_.Name -like "*Setup*" }
if ($pattern3) {
Write-Host "[OK] Found $($pattern3.Count) file(s) with pattern 3:"
$pattern3 | ForEach-Object { Write-Host " - $($_.FullName) ($($_.Length) bytes)" }
$installerFiles += $pattern3
}
# Remove duplicates
$installerFiles = $installerFiles | Select-Object -Unique
if ($installerFiles.Count -eq 0) {
Write-Error "No installer files found for upload"
Write-Host "All files in dist/:"
Get-ChildItem dist\ -ErrorAction SilentlyContinue | Format-Table Name, Length, LastWriteTime
exit 1
}
Write-Host "[OK] Found $($installerFiles.Count) installer file(s) to upload:"
$installerFiles | Format-Table Name, Length, LastWriteTime, FullName
# Verify the pattern matches before upload
Write-Host "Verifying upload pattern will match files..."
$verifyPattern = Get-ChildItem dist\CuePoint-Setup-v*.exe -ErrorAction SilentlyContinue
if ($verifyPattern) {
Write-Host "[OK] Pattern 'dist\CuePoint-Setup-v*.exe' matches $($verifyPattern.Count) file(s)"
} else {
Write-Error "Pattern 'dist\CuePoint-Setup-v*.exe' does not match any files!"
exit 1
}
- name: Upload artifact
if: startsWith(github.ref, 'refs/tags/v')
id: upload_installer
uses: actions/upload-artifact@v4
with:
name: windows-installer
path: dist/CuePoint-Setup-v*.exe
retention-days: 30
if-no-files-found: error
- name: Verify artifact upload
if: startsWith(github.ref, 'refs/tags/v')
run: |
Write-Host "=== DEBUG: Verifying artifact upload ==="
Write-Host "Upload step outcome: ${{ steps.upload_installer.outcome }}"
Write-Host "Upload step conclusion: ${{ steps.upload_installer.conclusion }}"
if ("${{ steps.upload_installer.outcome }}" -ne "success") {
Write-Error "Artifact upload failed"
Write-Host "Upload step details:"
Write-Host " Outcome: ${{ steps.upload_installer.outcome }}"
Write-Host " Conclusion: ${{ steps.upload_installer.conclusion }}"
exit 1
}
Write-Host "[OK] Artifact uploaded successfully"