diff --git a/.github/CI_CD_README.md b/.github/CI_CD_README.md new file mode 100644 index 0000000..227f4a0 --- /dev/null +++ b/.github/CI_CD_README.md @@ -0,0 +1,128 @@ +# YTSage CI/CD Workflow + +This repository uses GitHub Actions to automatically build and release YTSage for Windows when version tags are pushed. + +## How It Works + +### Trigger +The workflow is triggered when you push a git tag that starts with `v` (e.g., `v4.8.0`, `v4.9.1`). + +### Build Process +1. **Setup**: Uses Python 3.12.10 on Windows +2. **Builds**: Creates both Standard and FFmpeg versions +3. **Packages**: Generates MSI installers and ZIP portable versions +4. **Release**: Creates a draft GitHub release with all artifacts + +## Usage + +### Creating a Release + +1. **Update version** in your source code if needed +2. **Commit your changes**: + ```bash + git add . + git commit -m "Release v4.8.0" + ``` + +3. **Create and push a tag**: + ```bash + git tag v4.8.0 + git push origin v4.8.0 + ``` + +4. **Watch the action**: Go to Actions tab in GitHub to monitor progress + +5. **Review draft release**: Once complete, check the Releases section for the draft + +### Release Artifacts + +The workflow creates the following files: + +- `YTSage-v.msi` - Standard Windows installer +- `YTSage-v.zip` - Standard portable version +- `YTSage-v-ffmpeg.msi` - FFmpeg bundle installer +- `YTSage-v-ffmpeg.zip` - FFmpeg bundle portable + +### Release Notes + +Automatic release notes are generated including: +- Download links and descriptions +- Installation instructions +- System requirements +- Feature highlights + +## Workflow Features + +### Automatic Version Detection +- Extracts version from git tag (removes 'v' prefix) +- Updates setup.py files with correct version +- Names all artifacts consistently + +### Caching +- Python dependencies are cached to speed up builds +- Virtual environment is cached between runs + +### Error Handling +- Comprehensive error checking at each step +- Detailed logging for troubleshooting +- Artifact verification before upload + +### Security +- Uses official GitHub Actions +- No external dependencies +- Secure token handling + +## Manual Intervention + +### After Workflow Completion +1. **Review the draft release** in GitHub +2. **Test the artifacts** if needed +3. **Edit release notes** if desired +4. **Publish the release** when ready + +### Troubleshooting +If the workflow fails: +1. Check the Actions logs for error details +2. Ensure all required files are present +3. Verify the tag format is correct (`v*`) +4. Check that dependencies are properly listed + +## Configuration + +### Modifying the Workflow +The workflow file is located at `.github/workflows/build-windows.yml`. + +Key configuration options: +- `PYTHON_VERSION`: Python version to use +- Artifact naming patterns +- Release note templates + +### Adding New Build Types +To add new build configurations: +1. Create new setup-*.py files +2. Add build steps to the workflow +3. Update artifact collection logic + +## Notes + +- The workflow only runs on Windows +- Requires Python 3.12.10 for MSI compatibility +- All builds use cx_Freeze for packaging +- FFmpeg binaries are expected in standard locations +- Draft releases allow for review before publication + +## Example Tag Commands + +```bash +# For a new release +git tag v4.8.0 +git push origin v4.8.0 + +# For a patch release +git tag v4.8.1 +git push origin v4.8.1 + +# To delete a tag (if needed) +git tag -d v4.8.0 +git push origin :refs/tags/v4.8.0 +``` diff --git a/.github/workflows/build-windows.yml b/.github/workflows/build-windows.yml new file mode 100644 index 0000000..37c7c6b --- /dev/null +++ b/.github/workflows/build-windows.yml @@ -0,0 +1,231 @@ +name: Build Windows Release + +on: + push: + tags: + - 'v* # Update setup.py + $setupContent = Get-Content "build/windows/setup.py" -Raw + $setupContent = $setupContent -replace 'version\s*=\s*["\'][^"\']*["\']', "version='$version'" + Set-Content "build/windows/setup.py" -Value $setupContent + + # Update setup-ffmpeg.py + $setupFFmpegContent = Get-Content "build/windows/setup-ffmpeg.py" -Raw + $setupFFmpegContent = $setupFFmpegContent -replace 'version\s*=\s*["\'][^"\']*["\']', "version='$version'" + Set-Content "build/windows/setup-ffmpeg.py" -Value $setupFFmpegContent + + # Update build script + $buildScript = Get-Content "build/windows/windows-build-universal.ps1" -Raw + $buildScript = $buildScript -replace '\$SCRIPT_VERSION\s*=\s*["\'][^"\']*["\']', "`$SCRIPT_VERSION = '$version'" + Set-Content "build/windows/windows-build-universal.ps1" -Value $buildScripton version tags like v4.8.0, v4.8.1, etc. + +env: + PYTHON_VERSION: '3.12.10' + +jobs: + build-windows: + runs-on: windows-latest + + steps: + - name: Checkout code + uses: actions/checkout@v4 + with: + fetch-depth: 0 + + - name: Extract version from tag + id: get_version + shell: powershell + run: | + $tag = "${{ github.ref_name }}" + $version = $tag -replace '^v', '' + echo "VERSION=$version" >> $env:GITHUB_OUTPUT + echo "TAG=$tag" >> $env:GITHUB_OUTPUT + Write-Host "Extracted version: $version from tag: $tag" + + - name: Set up Python ${{ env.PYTHON_VERSION }} + uses: actions/setup-python@v4 + with: + python-version: ${{ env.PYTHON_VERSION }} + + - name: Cache Python dependencies + uses: actions/cache@v3 + with: + path: | + ~\AppData\Local\pip\Cache + venv + key: ${{ runner.os }}-python-${{ env.PYTHON_VERSION }}-${{ hashFiles('requirements.txt') }} + restore-keys: | + ${{ runner.os }}-python-${{ env.PYTHON_VERSION }}- + + - name: Create virtual environment and install dependencies + shell: powershell + run: | + Write-Host "Creating virtual environment..." + python -m venv venv + .\venv\Scripts\Activate.ps1 + + Write-Host "Installing dependencies..." + python -m pip install --upgrade pip + pip install -r requirements.txt + pip install cx_Freeze + + Write-Host "Verifying installation..." + python --version + pip list + + - name: Update version in source files + shell: powershell + run: | + $version = "${{ steps.get_version.outputs.VERSION }}" + Write-Host "Updating version to: $version" + + # Update setup.py + $setupContent = Get-Content "setup.py" -Raw + $setupContent = $setupContent -replace 'version\s*=\s*["\'][^"\']*["\']', "version='$version'" + Set-Content "setup.py" -Value $setupContent + + # Update setup-ffmpeg.py + $setupFFmpegContent = Get-Content "setup-ffmpeg.py" -Raw + $setupFFmpegContent = $setupFFmpegContent -replace 'version\s*=\s*["\'][^"\']*["\']', "version='$version'" + Set-Content "setup-ffmpeg.py" -Value $setupFFmpegContent + + # Update build scripts version + $buildScript = Get-Content "windows-build-universal.ps1" -Raw + $buildScript = $buildScript -replace '\$SCRIPT_VERSION\s*=\s*["\'][^"\']*["\']', "`$SCRIPT_VERSION = '$version'" + Set-Content "windows-build-universal.ps1" -Value $buildScript + + Write-Host "Version updated in all files" + + - name: Build Standard Version (MSI + ZIP) + shell: powershell + run: | + .\venv\Scripts\Activate.ps1 + Write-Host "Building Standard Version..." + .\build\windows\windows-build-universal.ps1 -Verbose + + - name: Build FFmpeg Version (MSI + ZIP) + shell: powershell + run: | + .\venv\Scripts\Activate.ps1 + Write-Host "Building FFmpeg Version..." + .\build\windows\windows-build-universal.ps1 -FFmpeg -Verbose + + - name: Prepare release artifacts + shell: powershell + run: | + $version = "${{ steps.get_version.outputs.VERSION }}" + Write-Host "Preparing artifacts for version: $version" + + # Create artifacts directory + New-Item -ItemType Directory -Force -Path "artifacts" + + # List all files in releases directory + Write-Host "Files in releases directory:" + Get-ChildItem "releases" -Recurse | ForEach-Object { Write-Host $_.FullName } + + # Copy and rename artifacts with proper versioning + $standardMsi = Get-ChildItem "releases" -Filter "*YTSage*.msi" | Where-Object { $_.Name -notlike "*ffmpeg*" } | Select-Object -First 1 + $standardZip = Get-ChildItem "releases" -Filter "*YTSage*portable*.zip" | Where-Object { $_.Name -notlike "*ffmpeg*" } | Select-Object -First 1 + $ffmpegMsi = Get-ChildItem "releases" -Filter "*ffmpeg*.msi" | Select-Object -First 1 + $ffmpegZip = Get-ChildItem "releases" -Filter "*ffmpeg*portable*.zip" | Select-Object -First 1 + + if ($standardMsi) { + Copy-Item $standardMsi.FullName "artifacts\YTSage-v$version.msi" + Write-Host "Copied: $($standardMsi.Name) -> YTSage-v$version.msi" + } + + if ($standardZip) { + Copy-Item $standardZip.FullName "artifacts\YTSage-v$version.zip" + Write-Host "Copied: $($standardZip.Name) -> YTSage-v$version.zip" + } + + if ($ffmpegMsi) { + Copy-Item $ffmpegMsi.FullName "artifacts\YTSage-v$version-ffmpeg.msi" + Write-Host "Copied: $($ffmpegMsi.Name) -> YTSage-v$version-ffmpeg.msi" + } + + if ($ffmpegZip) { + Copy-Item $ffmpegZip.FullName "artifacts\YTSage-v$version-ffmpeg.zip" + Write-Host "Copied: $($ffmpegZip.Name) -> YTSage-v$version-ffmpeg.zip" + } + + # Verify artifacts + Write-Host "Final artifacts:" + Get-ChildItem "artifacts" | ForEach-Object { + Write-Host "$($_.Name) - $([math]::Round($_.Length / 1MB, 2)) MB" + } + + - name: Create Release Notes + shell: powershell + run: | + $version = "${{ steps.get_version.outputs.VERSION }}" + $tag = "${{ steps.get_version.outputs.TAG }}" + $releaseDate = Get-Date -Format "yyyy-MM-dd" + + $releaseNotes = @" +# YTSage $version + +Released: $releaseDate + +## Downloads + +### Standard Version +- **YTSage-v$version.msi** - Windows Installer (Recommended) +- **YTSage-v$version.zip** - Portable ZIP (No installation required) + +### FFmpeg Bundle Version +- **YTSage-v$version-ffmpeg.msi** - Windows Installer with FFmpeg included +- **YTSage-v$version-ffmpeg.zip** - Portable ZIP with FFmpeg included + +## Installation + +### MSI Installer (Recommended) +1. Download the `.msi` file +2. Double-click to install +3. Follow the installation wizard + +### Portable ZIP +1. Download the `.zip` file +2. Extract to your preferred location +3. Run `YTSage.exe` + +## System Requirements + +- Windows 10/11 (64-bit) +- .NET Framework (usually pre-installed) +- Internet connection for yt-dlp updates + +## Notes + +- Standard version: Downloads FFmpeg automatically when needed +- FFmpeg bundle: Includes FFmpeg binaries for offline use + +--- + +**Full Changelog**: https://github.com/${{ github.repository }}/compare/v${{ steps.get_version.outputs.VERSION }}...HEAD +"@ + + Set-Content "artifacts\RELEASE_NOTES.md" -Value $releaseNotes + Write-Host "Release notes created" + + - name: Upload artifacts + uses: actions/upload-artifact@v3 + with: + name: windows-release-${{ steps.get_version.outputs.VERSION }} + path: artifacts/ + retention-days: 30 + + - name: Create Draft Release + uses: softprops/action-gh-release@v1 + with: + tag_name: ${{ steps.get_version.outputs.TAG }} + name: YTSage ${{ steps.get_version.outputs.VERSION }} + body_path: artifacts/RELEASE_NOTES.md + draft: true + prerelease: false + files: | + artifacts/YTSage-v${{ steps.get_version.outputs.VERSION }}.msi + artifacts/YTSage-v${{ steps.get_version.outputs.VERSION }}.zip + artifacts/YTSage-v${{ steps.get_version.outputs.VERSION }}-ffmpeg.msi + artifacts/YTSage-v${{ steps.get_version.outputs.VERSION }}-ffmpeg.zip + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}