name: Build Windows EXE on: push: branches: ["main"] workflow_dispatch: jobs: build: runs-on: windows defaults: run: shell: powershell env: REPO_URL: https://git.hsdi.cc/Hsdi/Shortcut_Sync_PotPlayer.git PYTHON_DIRNAME: python-3.9.1 SOURCE_DIRNAME: Shortcut_Sync_PotPlayer-src OUTPUT_SUBDIR: gitea-builds\Shortcut_Sync_PotPlayer CI_USER: ${{ secrets.CI_USER }} CI_TOKEN: ${{ secrets.CI_TOKEN }} steps: - name: Checkout repository without Node run: | $ErrorActionPreference = "Stop" $tempRoot = if ($env:RUNNER_TEMP) { $env:RUNNER_TEMP } else { $env:TEMP } $sourceDir = Join-Path $tempRoot $env:SOURCE_DIRNAME $repoUrl = $env:REPO_URL $refName = "${{ gitea.ref_name }}" $ref = "${{ gitea.ref }}" if (-not $refName) { if ($ref -match "^refs/heads/(.+)$") { $refName = $Matches[1] } elseif ($ref -match "^refs/tags/(.+)$") { $refName = $Matches[1] } else { $refName = "main" } } if (Test-Path $sourceDir) { Remove-Item -Path $sourceDir -Recurse -Force } New-Item -ItemType Directory -Path $sourceDir | Out-Null $cloneAttempts = @() $cloneAttempts += @{ Name = "anonymous" Args = @("clone", "--depth", "1", "--branch", $refName, $repoUrl, $sourceDir) } if ($env:CI_USER -and $env:CI_TOKEN) { $basicAuth = [Convert]::ToBase64String([Text.Encoding]::ASCII.GetBytes(("{0}:{1}" -f $env:CI_USER, $env:CI_TOKEN))) $cloneAttempts += @{ Name = "basic-auth" Args = @( "-c", "http.extraHeader=Authorization: Basic $basicAuth", "clone", "--depth", "1", "--branch", $refName, $repoUrl, $sourceDir ) } } $cloned = $false foreach ($attempt in $cloneAttempts) { Write-Host "Trying clone mode: $($attempt.Name)" try { & git @($attempt.Args) if ($LASTEXITCODE -eq 0) { $cloned = $true break } } catch { Write-Warning $_ } if (Test-Path $sourceDir) { Remove-Item -Path $sourceDir -Recurse -Force } New-Item -ItemType Directory -Path $sourceDir | Out-Null } if (-not $cloned) { throw "Repository checkout failed. If this repository is private, add Actions secrets CI_USER and CI_TOKEN." } & git -C $sourceDir rev-parse HEAD - name: Install Python 3.9.1 without Node run: | $ErrorActionPreference = "Stop" $tempRoot = if ($env:RUNNER_TEMP) { $env:RUNNER_TEMP } else { $env:TEMP } $pythonRoot = Join-Path $tempRoot $env:PYTHON_DIRNAME $pythonExe = Join-Path $pythonRoot "python.exe" $installerPath = Join-Path $tempRoot "python-3.9.1-amd64.exe" $needsInstall = $true if (Test-Path $pythonExe) { $versionOutput = & $pythonExe --version 2>&1 if ($versionOutput -match "^Python 3\.9\.1$") { $needsInstall = $false } } if ($needsInstall) { if (Test-Path $pythonRoot) { Remove-Item -Path $pythonRoot -Recurse -Force } Invoke-WebRequest -Uri "https://www.python.org/ftp/python/3.9.1/python-3.9.1-amd64.exe" -OutFile $installerPath Start-Process -FilePath $installerPath -ArgumentList @( "/quiet", "InstallAllUsers=0", "PrependPath=0", "Include_test=0", "Include_pip=1", "Shortcuts=0", "AssociateFiles=0", "CompileAll=0", "TargetDir=$pythonRoot" ) -Wait -NoNewWindow } if (-not (Test-Path $pythonExe)) { throw "Python 3.9.1 install failed: python.exe not found." } $versionOutput = & $pythonExe --version 2>&1 if ($versionOutput -notmatch "^Python 3\.9\.1$") { throw "Expected Python 3.9.1, got: $versionOutput" } Write-Host $versionOutput - name: Install dependencies run: | $ErrorActionPreference = "Stop" $tempRoot = if ($env:RUNNER_TEMP) { $env:RUNNER_TEMP } else { $env:TEMP } $pythonRoot = Join-Path $tempRoot $env:PYTHON_DIRNAME $pythonExe = Join-Path $pythonRoot "python.exe" & $pythonExe -m pip install --upgrade pip & $pythonExe -m pip install pyinstaller keyboard pywin32 - name: Build EXE run: | $ErrorActionPreference = "Stop" $tempRoot = if ($env:RUNNER_TEMP) { $env:RUNNER_TEMP } else { $env:TEMP } $pythonRoot = Join-Path $tempRoot $env:PYTHON_DIRNAME $sourceDir = Join-Path $tempRoot $env:SOURCE_DIRNAME $pythonExe = Join-Path $pythonRoot "python.exe" Set-Location $sourceDir & $pythonExe -m PyInstaller --clean --noconfirm --onefile --windowed --name Shortcut_Sync_PotPlayer main.py - name: Save build output on runner run: | $ErrorActionPreference = "Stop" $tempRoot = if ($env:RUNNER_TEMP) { $env:RUNNER_TEMP } else { $env:TEMP } $sourceDir = Join-Path $tempRoot $env:SOURCE_DIRNAME $outputRoot = Join-Path $env:USERPROFILE $env:OUTPUT_SUBDIR $distExe = Join-Path $sourceDir "dist\Shortcut_Sync_PotPlayer.exe" if (-not (Test-Path $distExe)) { throw "Build output not found: $distExe" } $runId = "${{ gitea.run_number }}" if (-not $runId) { $runId = (Get-Date -Format "yyyyMMdd-HHmmss") } $outputDir = Join-Path $outputRoot ("run-" + $runId) New-Item -ItemType Directory -Path $outputDir -Force | Out-Null $exePath = Join-Path $outputDir "Shortcut_Sync_PotPlayer.exe" $zipPath = Join-Path $outputDir "Shortcut_Sync_PotPlayer.zip" Copy-Item -Path $distExe -Destination $exePath -Force Compress-Archive -Path $distExe -DestinationPath $zipPath -Force Write-Host "EXE saved to: $exePath" Write-Host "ZIP saved to: $zipPath"