Release v1.0.63 #74
Workflow file for this run
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: Build Installer | |
| on: | |
| push: | |
| tags: | |
| - 'v*.*.*' | |
| - 'v*.*.*-staging' | |
| workflow_dispatch: | |
| inputs: | |
| version: | |
| description: 'Version (e.g., 1.0.0 or 1.0.0-staging)' | |
| required: false | |
| default: '' | |
| staging: | |
| description: 'Staging build (no server upload)' | |
| type: boolean | |
| default: false | |
| env: | |
| PYREVIT_VERSION: "5.3.1.25308" | |
| PYREVIT_URL: "https://github.com/pyrevitlabs/pyRevit/releases/download/v5.3.1.25308%2B1659/pyRevit_5.3.1.25308_signed.exe" | |
| permissions: | |
| contents: write | |
| jobs: | |
| build: | |
| runs-on: windows-latest | |
| steps: | |
| - name: Checkout code | |
| uses: actions/checkout@v4 | |
| with: | |
| fetch-depth: 0 | |
| - name: Get version | |
| id: version | |
| shell: pwsh | |
| run: | | |
| if ("${{ github.event.inputs.version }}" -ne "") { | |
| $version = "${{ github.event.inputs.version }}" | |
| } elseif ($env:GITHUB_REF -match "refs/tags/v(.+)") { | |
| $version = $matches[1] | |
| } else { | |
| $version = "0.0.1-dev" | |
| } | |
| echo "VERSION=$version" >> $env:GITHUB_OUTPUT | |
| # Determine if this is a staging build | |
| $isStaging = $false | |
| if ("${{ github.event.inputs.staging }}" -eq "true") { | |
| $isStaging = $true | |
| } elseif ($version -match "-staging$") { | |
| $isStaging = $true | |
| } | |
| echo "IS_STAGING=$isStaging" >> $env:GITHUB_OUTPUT | |
| Write-Host "Version: $version, Staging: $isStaging" | |
| - name: Prepare build directory | |
| shell: pwsh | |
| run: | | |
| New-Item -ItemType Directory -Path "build" -Force | |
| Copy-Item -Path "pyrevit.extension" -Destination "build\CPSK.extension" -Recurse | |
| Copy-Item -Path "installer\scripts\*" -Destination "build\" -Force | |
| # Copy requirements.txt, version.yaml and config.py to root (not extension!) | |
| Copy-Item -Path "requirements.txt" -Destination "build\" -Force | |
| Copy-Item -Path "version.yaml" -Destination "build\" -Force | |
| Copy-Item -Path "config.py" -Destination "build\" -Force | |
| - name: Remove dev tools from build | |
| shell: pwsh | |
| run: | | |
| $libDir = "build\CPSK.extension\lib" | |
| # Remove dev tools not needed in production | |
| $devTools = @("pyrevit_checker.py") | |
| foreach ($tool in $devTools) { | |
| $path = Join-Path $libDir $tool | |
| if (Test-Path $path) { | |
| Remove-Item $path -Force | |
| Write-Host "Removed: $tool (dev tool)" | |
| } | |
| } | |
| Write-Host "Files in lib:" | |
| Get-ChildItem $libDir | ForEach-Object { Write-Host " $($_.Name)" } | |
| - name: Set DEBUG=False in config.py | |
| shell: pwsh | |
| run: | | |
| $configFile = "build\config.py" | |
| $content = Get-Content $configFile -Raw -Encoding UTF8 | |
| $content = $content -replace 'DEBUG\s*=\s*True', 'DEBUG = False' | |
| [System.IO.File]::WriteAllText($configFile, $content, [System.Text.UTF8Encoding]::new($false)) | |
| Write-Host "Set DEBUG = False in config.py" | |
| - name: Setup Python | |
| uses: actions/setup-python@v5 | |
| with: | |
| python-version: '3.11' | |
| - name: Minify Python code | |
| shell: pwsh | |
| run: | | |
| Write-Host "Installing python-minifier..." | |
| pip install python-minifier | |
| $libDir = "build\CPSK.extension\lib" | |
| Write-Host "=== Minifying Python files in $libDir ===" | |
| # Encoding declaration required for IronPython with non-ASCII characters | |
| $encodingDecl = "# -*- coding: utf-8 -*-`n" | |
| # Files to minify (lib modules) | |
| Get-ChildItem "$libDir\*.py" | ForEach-Object { | |
| if ($_.Name -ne "__init__.py") { | |
| $originalSize = $_.Length | |
| Write-Host "Minifying: $($_.Name) ($originalSize bytes)" | |
| # Minify with Python 2 compatible settings (no transforms that could break IronPython) | |
| $tempFile = "$($_.FullName).min" | |
| python -m python_minifier $_.FullName --remove-literal-statements --no-remove-annotations --no-hoist-literals --no-rename-locals --no-convert-posargs-to-args -o $tempFile | |
| if (Test-Path $tempFile) { | |
| # Add encoding declaration back (minifier removes comments) | |
| $content = Get-Content $tempFile -Raw -Encoding UTF8 | |
| $content = $encodingDecl + $content | |
| [System.IO.File]::WriteAllText($_.FullName, $content, [System.Text.UTF8Encoding]::new($false)) | |
| Remove-Item $tempFile -Force | |
| $newSize = (Get-Item $_.FullName).Length | |
| $reduction = [math]::Round((1 - $newSize / $originalSize) * 100) | |
| Write-Host " [OK] $originalSize -> $newSize bytes (-$reduction%)" | |
| } else { | |
| Write-Host " [WARN] Minification failed, keeping original" | |
| } | |
| } | |
| } | |
| Write-Host "=== Minification complete ===" | |
| - name: Install Inno Setup | |
| shell: pwsh | |
| run: | | |
| choco install innosetup -y | |
| - name: Build Installer | |
| shell: pwsh | |
| run: | | |
| $version = "${{ steps.version.outputs.VERSION }}" | |
| $pyrevitVersion = "${{ env.PYREVIT_VERSION }}" | |
| $pyrevitUrl = "${{ env.PYREVIT_URL }}" | |
| & "C:\Program Files (x86)\Inno Setup 6\ISCC.exe" ` | |
| /DMyAppVersion="$version" ` | |
| /DPyRevitVersion="$pyrevitVersion" ` | |
| /DPyRevitUrl="$pyrevitUrl" ` | |
| /O"." ` | |
| "installer\setup.iss" | |
| - name: Upload artifact | |
| uses: actions/upload-artifact@v4 | |
| with: | |
| name: CPSK-Tools-Installer | |
| path: "CPSK_Tools_*.exe" | |
| retention-days: 30 | |
| - name: Generate release notes | |
| if: startsWith(github.ref, 'refs/tags/') | |
| id: release_notes | |
| shell: pwsh | |
| env: | |
| GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} | |
| run: | | |
| $version = "${{ steps.version.outputs.VERSION }}" | |
| $lastTag = git describe --tags --abbrev=0 HEAD~1 2>$null | |
| # Get authors | |
| if ($lastTag) { | |
| $authors = git log --pretty=format:"%an" "$lastTag..HEAD" --no-merges | Sort-Object -Unique | Where-Object { $_ -ne "github-actions[bot]" -and $_ -ne "" } | |
| } else { | |
| $authors = git log --pretty=format:"%an" -10 --no-merges | Sort-Object -Unique | Where-Object { $_ -ne "github-actions[bot]" -and $_ -ne "" } | |
| } | |
| # Try to get PR description (smart approach) | |
| $prBody = "" | |
| $prAuthor = "" | |
| $prNumber = "" | |
| $mergeCommit = git log --merges --pretty=format:"%s" -1 2>$null | |
| if ($mergeCommit -match "Merge pull request #(\d+)") { | |
| $prNumber = $matches[1] | |
| Write-Host "Found merged PR #$prNumber" | |
| try { | |
| # Get PR body and author | |
| $prData = gh pr view $prNumber --json body,author 2>$null | ConvertFrom-Json | |
| $prBody = $prData.body | |
| $prAuthor = $prData.author.login | |
| Write-Host "PR author: @$prAuthor" | |
| # Clean PR body - remove technical sections | |
| $opts = [System.Text.RegularExpressions.RegexOptions]::Singleline | |
| $prBody = [regex]::Replace($prBody, '## Связанные Issues.*?((?=##)|$)', '', $opts) | |
| $prBody = [regex]::Replace($prBody, '## Чеклист.*?((?=##)|$)', '', $opts) | |
| $prBody = [regex]::Replace($prBody, '## Скриншоты.*?((?=##)|$)', '', $opts) | |
| $prBody = [regex]::Replace($prBody, '## Описание\s*\r?\n\s*(Краткое описание изменений\.?)?\s*', '', $opts) | |
| $prBody = [regex]::Replace($prBody, '## Тип изменения.*?((?=##)|$)', '', $opts) | |
| $prBody = [regex]::Replace($prBody, 'Closes #\(номер issue\)', '', $opts) | |
| $prBody = [regex]::Replace($prBody, 'Если применимо.*UI\.?', '', $opts) | |
| $prBody = [regex]::Replace($prBody, '<img[^>]*>', '', $opts) | |
| $prBody = [regex]::Replace($prBody, 'Краткое описание изменений\.?', '', $opts) | |
| # Remove multiple empty lines | |
| $prBody = [regex]::Replace($prBody, '(\r?\n){3,}', "`n`n") | |
| $prBody = $prBody.Trim() | |
| Write-Host "Using PR description" | |
| } catch { | |
| Write-Host "Could not get PR body: $_" | |
| } | |
| } | |
| # Build content section | |
| if ($prBody) { | |
| $changes = $prBody | |
| } else { | |
| # Fallback to commits | |
| Write-Host "No PR found, using commits" | |
| if ($lastTag) { | |
| $commitList = git log --pretty=format:"- %s" "$lastTag..HEAD" --no-merges | Where-Object { $_ -notmatch "Release v" } | |
| } else { | |
| $commitList = git log --pretty=format:"- %s" -10 --no-merges | Where-Object { $_ -notmatch "Release v" } | |
| } | |
| $changes = "### Изменения`n" + ($commitList -join "`n") | |
| } | |
| # Build authors section | |
| $authorsSection = "" | |
| if ($prAuthor) { | |
| # PR author with GitHub link | |
| $authorsSection = "### Авторы`n- [@$prAuthor](https://github.com/$prAuthor)" | |
| # Add commit authors if different | |
| $otherAuthors = $authors | Where-Object { $_ -ne $prAuthor } | |
| if ($otherAuthors) { | |
| $authorsSection += "`n" + (($otherAuthors | ForEach-Object { "- $_" }) -join "`n") | |
| } | |
| } elseif ($authors) { | |
| $authorsSection = "### Авторы`n" + (($authors | ForEach-Object { "- $_" }) -join "`n") | |
| } | |
| # Server notes | |
| $serverNotes = "## CPSK Tools v$version`n`n$changes" | |
| if ($authorsSection) { | |
| $serverNotes += "`n`n$authorsSection" | |
| } | |
| $serverNotes += "`n`n### Требования`n- Windows 10/11`n- Autodesk Revit 2021-2025" | |
| $serverNotes | Out-File -FilePath "release_notes.txt" -Encoding UTF8 | |
| # GitHub notes (with install instructions) | |
| $githubNotes = "## CPSK Tools v$version`n`n" | |
| $githubNotes += "### Установка`n1. Скачайте ``CPSK_Tools_v$version.exe```n2. Запустите установщик`n3. Перезапустите Revit`n`n" | |
| $githubNotes += $changes | |
| if ($authorsSection) { | |
| $githubNotes += "`n`n$authorsSection" | |
| } | |
| $githubNotes += "`n`n### Требования`n- Windows 10/11`n- Autodesk Revit 2021-2025" | |
| $githubNotes | Out-File -FilePath "github_release_notes.txt" -Encoding UTF8 | |
| Write-Host "=== Release notes generated ===" | |
| - name: Create Release | |
| if: startsWith(github.ref, 'refs/tags/') | |
| uses: softprops/action-gh-release@v2 | |
| with: | |
| name: "CPSK Tools v${{ steps.version.outputs.VERSION }}" | |
| body_path: github_release_notes.txt | |
| files: "CPSK_Tools_*.exe" | |
| draft: false | |
| prerelease: ${{ steps.version.outputs.IS_STAGING == 'True' }} | |
| env: | |
| GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} | |
| - name: Upload to release server | |
| if: startsWith(github.ref, 'refs/tags/') && steps.version.outputs.IS_STAGING != 'True' | |
| shell: pwsh | |
| run: | | |
| $version = "${{ steps.version.outputs.VERSION }}" | |
| $token = "${{ secrets.RELEASE_API_TOKEN }}" | |
| if (-not $token) { | |
| Write-Host "WARNING: RELEASE_API_TOKEN secret not set, skipping upload" | |
| exit 0 | |
| } | |
| $exeFile = Get-ChildItem -Path "." -Filter "CPSK_Tools_*.exe" | Select-Object -First 1 | |
| if (-not $exeFile) { | |
| Write-Host "ERROR: No exe file found" | |
| exit 1 | |
| } | |
| # Read release notes from file | |
| $releaseNotes = Get-Content -Path "release_notes.txt" -Raw -Encoding UTF8 | |
| Write-Host "Uploading $($exeFile.Name) to release server..." | |
| $headers = @{ | |
| "Authorization" = "Bearer $token" | |
| } | |
| $form = @{ | |
| version = $version | |
| exe_file = Get-Item $exeFile.FullName | |
| release_notes = $releaseNotes | |
| git_tag = "v$version" | |
| git_commit = "${{ github.sha }}" | |
| github_release_url = "https://github.com/${{ github.repository }}/releases/tag/v$version" | |
| min_revit_version = "2021" | |
| max_revit_version = "2025" | |
| } | |
| try { | |
| $response = Invoke-RestMethod -Uri "https://rocket-tools.ru/api/rocketrevit/releases/upload/" ` | |
| -Method POST ` | |
| -Headers $headers ` | |
| -Form $form | |
| Write-Host "Upload successful!" | |
| Write-Host "Response: $($response | ConvertTo-Json)" | |
| } catch { | |
| Write-Host "ERROR: Upload failed: $_" | |
| Write-Host "Response: $($_.ErrorDetails.Message)" | |
| # Don't fail the build if upload fails - GitHub release is already created | |
| Write-Host "WARNING: Server upload failed, but GitHub release was created successfully" | |
| } |