Build and Release #247
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
| # Copyright 2024, MCSL Team, mailto:services@mcsl.com.cn | |
| # | |
| # Part of "MCSL2", a simple and multifunctional Minecraft server launcher. | |
| # | |
| # Licensed under the GNU General Public License, Version 3.0, with our | |
| # additional agreements. (the "License"); | |
| # you may not use this file except in compliance with the License. | |
| # You may obtain a copy of the License at | |
| # | |
| # https://github.com/MCSLTeam/MCSL2/raw/master/LICENSE | |
| # | |
| ################################################################################ | |
| name: Build and Release | |
| on: | |
| workflow_dispatch: | |
| inputs: | |
| build_target: | |
| description: Build target | |
| required: true | |
| default: all | |
| type: choice | |
| options: | |
| - windows | |
| - macos | |
| - linux | |
| - all | |
| debug_build: | |
| description: Build artifacts only, without creating a release | |
| required: true | |
| default: true | |
| type: boolean | |
| package_macos_dmg: | |
| description: Package macOS builds as DMG artifacts | |
| required: true | |
| default: true | |
| type: boolean | |
| release: | |
| types: [published] | |
| permissions: | |
| contents: write | |
| env: | |
| PYTHON_VERSION: "3.8" | |
| jobs: | |
| Windows: | |
| if: ${{ github.event_name == 'release' || github.event.inputs.build_target == 'windows' || github.event.inputs.build_target == 'all' }} | |
| strategy: | |
| fail-fast: false | |
| matrix: | |
| include: | |
| - architecture: x64 | |
| runner: windows-2022 | |
| experimental: false | |
| skip_arm64_missing_wheels: false | |
| use_upx: true | |
| - architecture: arm64 | |
| runner: windows-11-arm | |
| experimental: true | |
| skip_arm64_missing_wheels: true | |
| use_upx: false | |
| runs-on: ${{ matrix.runner }} | |
| continue-on-error: ${{ matrix.experimental }} | |
| steps: | |
| - name: Checkout repo | |
| uses: actions/checkout@v6.0.3 | |
| - name: Setup uv | |
| uses: astral-sh/setup-uv@v8.2.0 | |
| with: | |
| enable-cache: true | |
| cache-dependency-glob: | | |
| pyproject.toml | |
| uv.lock | |
| - name: Install Python | |
| run: uv python install ${{ env.PYTHON_VERSION }} | |
| - name: Sync dependencies | |
| shell: pwsh | |
| run: uv sync --no-dev --locked ${{ matrix.skip_arm64_missing_wheels && '--no-install-package pyqt5-qt5 --no-install-package pywin32' || '' }} | |
| - name: Build with Nuitka | |
| shell: pwsh | |
| run: uv run deploy.py --windows-console-mode=disable | |
| - name: Optimize package | |
| shell: pwsh | |
| run: | | |
| $dist = "build/MCSL2.dist" | |
| $removePaths = @( | |
| "zstandard", | |
| "_asyncio.pyd", | |
| "pyexpat.pyd", | |
| "qt5qml.dll", | |
| "qt5qmlmodels.dll", | |
| "qt5quick.dll" | |
| ) | |
| foreach ($path in $removePaths) { | |
| Remove-Item -Force -Recurse "$dist/$path" -ErrorAction SilentlyContinue | |
| } | |
| $upxTargets = @( | |
| "_ctypes.pyd", | |
| "_decimal.pyd", | |
| "_elementtree.pyd", | |
| "_lzma.pyd", | |
| "_overlapped.pyd", | |
| "_socket.pyd", | |
| "_ssl.pyd", | |
| "_win32sysloader.pyd", | |
| "libffi-7.dll", | |
| "libcrypto-1_1.dll", | |
| "libssl-1_1.dll", | |
| "MCSL2.exe", | |
| "python38.dll", | |
| "pythoncom38.dll", | |
| "pywintypes38.dll", | |
| "qt5core.dll", | |
| "qt5dbus.dll", | |
| "qt5gui.dll", | |
| "qt5multimedia.dll", | |
| "qt5network.dll", | |
| "qt5printsupport.dll", | |
| "qt5svg.dll", | |
| "qt5websockets.dll", | |
| "qt5widgets.dll", | |
| "qt5xml.dll", | |
| "select.pyd", | |
| "unicodedata.pyd", | |
| "win32api.pyd", | |
| "win32gui.pyd", | |
| "win32print.pyd" | |
| ) | ForEach-Object { "$dist/$_" } | Where-Object { Test-Path $_ } | |
| if ("${{ matrix.use_upx }}" -eq "true" -and $upxTargets.Count -gt 0) { | |
| .\upx.exe -9 $upxTargets | |
| } | |
| - name: Upload artifact | |
| uses: actions/upload-artifact@v7.0.1 | |
| with: | |
| name: MCSL2-Windows-${{ matrix.architecture }} | |
| path: build/MCSL2.dist/**/* | |
| Linux: | |
| if: ${{ github.event_name == 'release' || github.event.inputs.build_target == 'linux' || github.event.inputs.build_target == 'all' }} | |
| strategy: | |
| fail-fast: false | |
| matrix: | |
| include: | |
| - architecture: x64 | |
| runner: ubuntu-22.04 | |
| use_upx: true | |
| runs-on: ${{ matrix.runner }} | |
| steps: | |
| - name: Install tools | |
| run: | | |
| sudo apt-get update | |
| sudo apt-get install -y libfuse2 p7zip-full | |
| - name: Checkout repo | |
| uses: actions/checkout@v6.0.3 | |
| - name: Setup uv | |
| uses: astral-sh/setup-uv@v8.2.0 | |
| with: | |
| enable-cache: true | |
| cache-dependency-glob: | | |
| pyproject.toml | |
| uv.lock | |
| - name: Install Python | |
| run: uv python install ${{ env.PYTHON_VERSION }} | |
| - name: Sync dependencies | |
| run: uv sync --no-dev --locked | |
| - name: Build with Nuitka | |
| run: uv run deploy.py | |
| - name: Optimize package | |
| run: | | |
| dist="build/MCSL2.dist" | |
| rm -rf \ | |
| "$dist/zstandard" \ | |
| "$dist/_asyncio"* \ | |
| "$dist/pyexpat"* \ | |
| "$dist/libQt5Quick.so.5" \ | |
| "$dist/libQt5Qml.so.5" \ | |
| "$dist/libQt5QmlModels.so.5" | |
| if [ "${{ matrix.use_upx }}" = "true" ] && [ -f "$dist/MCSL2.bin" ]; then | |
| chmod +x ./upx | |
| ./upx -9 "$dist/MCSL2.bin" | |
| fi | |
| - name: Upload artifact | |
| uses: actions/upload-artifact@v7.0.1 | |
| with: | |
| name: MCSL2-Linux-${{ matrix.architecture }} | |
| path: build/MCSL2.dist/**/* | |
| macOS: | |
| if: ${{ github.event_name == 'release' || github.event.inputs.build_target == 'macos' || github.event.inputs.build_target == 'all' }} | |
| env: | |
| MACOS_CERTIFICATE_BASE64: ${{ secrets.MACOS_CERTIFICATE_BASE64 }} | |
| MACOS_CERTIFICATE_PASSWORD: ${{ secrets.MACOS_CERTIFICATE_PASSWORD }} | |
| MACOS_CODESIGN_IDENTITY: ${{ secrets.MACOS_CODESIGN_IDENTITY }} | |
| MACOS_KEYCHAIN_PASSWORD: ${{ secrets.MACOS_KEYCHAIN_PASSWORD }} | |
| APPLE_ID: ${{ secrets.APPLE_ID }} | |
| APPLE_TEAM_ID: ${{ secrets.APPLE_TEAM_ID }} | |
| APPLE_APP_SPECIFIC_PASSWORD: ${{ secrets.APPLE_APP_SPECIFIC_PASSWORD }} | |
| PACKAGE_MACOS_DMG: ${{ github.event_name == 'release' || inputs.package_macos_dmg }} | |
| strategy: | |
| matrix: | |
| include: | |
| - architecture: arm64 | |
| runner: macos-14 | |
| - architecture: x64 | |
| runner: macos-15-intel | |
| runs-on: ${{ matrix.runner }} | |
| steps: | |
| - name: Checkout repo | |
| uses: actions/checkout@v6.0.3 | |
| - name: Setup uv | |
| uses: astral-sh/setup-uv@v8.2.0 | |
| with: | |
| enable-cache: true | |
| cache-dependency-glob: | | |
| pyproject.toml | |
| uv.lock | |
| - name: Install Python | |
| run: uv python install ${{ env.PYTHON_VERSION }} | |
| - name: Sync dependencies | |
| run: uv sync --no-dev --locked | |
| - name: Build with Nuitka | |
| run: uv run deploy.py | |
| - name: Prepare app bundle | |
| run: | | |
| app="build/MCSL2.app" | |
| exe="$app/Contents/MacOS/MCSL2" | |
| chmod +x "$exe" | |
| rm -rf "build/MCSL2.build" "build/MCSL2.dist" | |
| find "$app" -name "__pycache__" -type d -prune -exec rm -rf {} + | |
| find "$app" -name "*.pyc" -delete | |
| find "$app" -name ".DS_Store" -delete | |
| - name: Import Apple signing certificate | |
| if: >- | |
| ${{ | |
| env.MACOS_CERTIFICATE_BASE64 != '' | |
| && env.MACOS_CERTIFICATE_PASSWORD != '' | |
| && env.MACOS_CODESIGN_IDENTITY != '' | |
| && env.MACOS_KEYCHAIN_PASSWORD != '' | |
| }} | |
| run: | | |
| certificate_path="$RUNNER_TEMP/mcsl2-signing-certificate.p12" | |
| keychain_path="$RUNNER_TEMP/mcsl2-signing.keychain-db" | |
| echo "$MACOS_CERTIFICATE_BASE64" | base64 --decode > "$certificate_path" | |
| security create-keychain -p "$MACOS_KEYCHAIN_PASSWORD" "$keychain_path" | |
| security set-keychain-settings -lut 21600 "$keychain_path" | |
| security unlock-keychain -p "$MACOS_KEYCHAIN_PASSWORD" "$keychain_path" | |
| security import "$certificate_path" -P "$MACOS_CERTIFICATE_PASSWORD" -A -t cert -f pkcs12 -k "$keychain_path" | |
| security list-keychains -d user -s "$keychain_path" | |
| security set-key-partition-list -S apple-tool:,apple:,codesign: -s -k "$MACOS_KEYCHAIN_PASSWORD" "$keychain_path" | |
| - name: Sign app bundle | |
| if: >- | |
| ${{ | |
| env.MACOS_CERTIFICATE_BASE64 != '' | |
| && env.MACOS_CERTIFICATE_PASSWORD != '' | |
| && env.MACOS_CODESIGN_IDENTITY != '' | |
| && env.MACOS_KEYCHAIN_PASSWORD != '' | |
| }} | |
| run: | | |
| app="build/MCSL2.app" | |
| codesign --force --deep --timestamp --options runtime --sign "$MACOS_CODESIGN_IDENTITY" "$app" | |
| codesign --verify --deep --strict --verbose=2 "$app" | |
| - name: Notarize app bundle | |
| if: >- | |
| ${{ | |
| env.MACOS_CERTIFICATE_BASE64 != '' | |
| && env.MACOS_CERTIFICATE_PASSWORD != '' | |
| && env.MACOS_CODESIGN_IDENTITY != '' | |
| && env.MACOS_KEYCHAIN_PASSWORD != '' | |
| && env.APPLE_ID != '' | |
| && env.APPLE_TEAM_ID != '' | |
| && env.APPLE_APP_SPECIFIC_PASSWORD != '' | |
| }} | |
| run: | | |
| app="build/MCSL2.app" | |
| notarize_zip="$RUNNER_TEMP/MCSL2-${{ matrix.architecture }}-notarize.zip" | |
| ditto -c -k --keepParent "$app" "$notarize_zip" | |
| xcrun notarytool submit "$notarize_zip" \ | |
| --apple-id "$APPLE_ID" \ | |
| --team-id "$APPLE_TEAM_ID" \ | |
| --password "$APPLE_APP_SPECIFIC_PASSWORD" \ | |
| --wait | |
| xcrun stapler staple "$app" | |
| spctl --assess --type execute --verbose "$app" | |
| - name: Install DMG packaging tool | |
| if: ${{ env.PACKAGE_MACOS_DMG == 'true' }} | |
| run: npm install --global appdmg create-dmg | |
| - name: Create DMG | |
| if: ${{ env.PACKAGE_MACOS_DMG == 'true' }} | |
| run: | | |
| app_path="$PWD/build/MCSL2.app" | |
| dmg_path="build/MCSL2-macOS-${{ matrix.architecture }}.dmg" | |
| background_path="$PWD/macos-volume-bg.png" | |
| volume_icon_path="$PWD/macos-volume-icon.icns" | |
| if [ -f "$background_path" ]; then | |
| cat > "$RUNNER_TEMP/mcsl2-dmg.json" <<JSON | |
| { | |
| "title": "MCSL2", | |
| "icon": "$volume_icon_path", | |
| "background": "$background_path", | |
| "window": { | |
| "size": { | |
| "width": 480, | |
| "height": 540 | |
| } | |
| }, | |
| "contents": [ | |
| { | |
| "x": 240, | |
| "y": 145, | |
| "type": "file", | |
| "path": "$app_path" | |
| }, | |
| { | |
| "x": 240, | |
| "y": 405, | |
| "type": "link", | |
| "path": "/Applications" | |
| } | |
| ] | |
| } | |
| JSON | |
| appdmg "$RUNNER_TEMP/mcsl2-dmg.json" "$dmg_path" | |
| else | |
| create-dmg "$app_path" build --overwrite --no-code-sign | |
| generated_dmg="$(find build -maxdepth 1 -name '*.dmg' | head -n 1)" | |
| test -n "$generated_dmg" | |
| mv "$generated_dmg" "$dmg_path" | |
| fi | |
| - name: Notarize DMG | |
| if: >- | |
| ${{ | |
| env.PACKAGE_MACOS_DMG == 'true' | |
| && env.MACOS_CERTIFICATE_BASE64 != '' | |
| && env.MACOS_CERTIFICATE_PASSWORD != '' | |
| && env.MACOS_CODESIGN_IDENTITY != '' | |
| && env.MACOS_KEYCHAIN_PASSWORD != '' | |
| && env.APPLE_ID != '' | |
| && env.APPLE_TEAM_ID != '' | |
| && env.APPLE_APP_SPECIFIC_PASSWORD != '' | |
| }} | |
| run: | | |
| dmg_path="build/MCSL2-macOS-${{ matrix.architecture }}.dmg" | |
| xcrun notarytool submit "$dmg_path" \ | |
| --apple-id "$APPLE_ID" \ | |
| --team-id "$APPLE_TEAM_ID" \ | |
| --password "$APPLE_APP_SPECIFIC_PASSWORD" \ | |
| --wait | |
| xcrun stapler staple "$dmg_path" | |
| spctl --assess --type open --context context:primary-signature --verbose "$dmg_path" | |
| - name: Upload artifact | |
| uses: actions/upload-artifact@v7.0.1 | |
| with: | |
| name: MCSL2-macOS-${{ matrix.architecture }} | |
| path: | | |
| build/MCSL2.app | |
| build/MCSL2-macOS-${{ matrix.architecture }}.dmg | |
| if-no-files-found: error | |
| Release: | |
| runs-on: ubuntu-22.04 | |
| needs: | |
| - Windows | |
| - Linux | |
| - macOS | |
| if: >- | |
| ${{ | |
| always() | |
| && (github.event_name == 'release' || !inputs.debug_build) | |
| && !contains(needs.*.result, 'failure') | |
| && !contains(needs.*.result, 'cancelled') | |
| && contains(needs.*.result, 'success') | |
| }} | |
| steps: | |
| - name: Install tools | |
| run: | | |
| sudo apt-get update | |
| sudo apt-get install -y p7zip-full | |
| - name: Download artifacts | |
| uses: actions/download-artifact@v8.0.1 | |
| - name: Checkout repo | |
| uses: actions/checkout@v6.0.3 | |
| with: | |
| path: repo | |
| - name: Set Environment Variable | |
| run: | | |
| cd repo | |
| mcsl2_version=$(python3 -c "from MCSL2Lib import MCSL2VERSION; print(MCSL2VERSION)") | |
| echo "MCSL2_VERSION=$mcsl2_version" >> "$GITHUB_ENV" | |
| cd .. | |
| - name: Compress release artifacts | |
| run: | | |
| shopt -s nullglob | |
| for dir in MCSL2-Windows-x64 MCSL2-Windows-arm64 MCSL2-Linux-x64; do | |
| if [ -d "$dir" ]; then | |
| 7z a -tzip -mx=9 "MCSL2-${MCSL2_VERSION}-${dir#MCSL2-}.zip" "./$dir/*" | |
| fi | |
| done | |
| for dir in MCSL2-macOS-arm64 MCSL2-macOS-x64; do | |
| if compgen -G "$dir/*.dmg" > /dev/null; then | |
| cp "$dir"/*.dmg . | |
| elif [ -d "$dir" ]; then | |
| 7z a -tzip -mx=9 "MCSL2-${MCSL2_VERSION}-${dir#MCSL2-}.zip" "./$dir/*" | |
| fi | |
| done | |
| - name: Create update package | |
| run: | | |
| mkdir -p Update/Windows-x64 Update/Windows-arm64 Update/Linux-x64 Update/macOS-arm64 Update/macOS-x64 | |
| if [ -f MCSL2-Windows-x64/MCSL2.exe ]; then | |
| cp MCSL2-Windows-x64/MCSL2.exe Update/Windows-x64/ | |
| fi | |
| if [ -f MCSL2-Windows-arm64/MCSL2.exe ]; then | |
| cp MCSL2-Windows-arm64/MCSL2.exe Update/Windows-arm64/ | |
| fi | |
| if [ -f MCSL2-Linux-x64/MCSL2.bin ]; then | |
| cp MCSL2-Linux-x64/MCSL2.bin Update/Linux-x64/ | |
| fi | |
| if [ -d MCSL2-macOS-arm64/MCSL2.app ]; then | |
| cp -R MCSL2-macOS-arm64/MCSL2.app Update/macOS-arm64/ | |
| fi | |
| if [ -d MCSL2-macOS-x64/MCSL2.app ]; then | |
| cp -R MCSL2-macOS-x64/MCSL2.app Update/macOS-x64/ | |
| fi | |
| for platform in Windows-x64 Windows-arm64 Linux-x64 macOS-arm64 macOS-x64; do | |
| mkdir -p "Update/$platform/MCSL2Lib" | |
| done | |
| [ -f MCSL2-Windows-x64/MCSL2Lib/verification.pyd ] \ | |
| && cp MCSL2-Windows-x64/MCSL2Lib/verification.pyd Update/Windows-x64/MCSL2Lib/ | |
| [ -f MCSL2-Windows-arm64/MCSL2Lib/verification.pyd ] \ | |
| && cp MCSL2-Windows-arm64/MCSL2Lib/verification.pyd Update/Windows-arm64/MCSL2Lib/ | |
| [ -f MCSL2-Linux-x64/MCSL2Lib/verification.so ] \ | |
| && cp MCSL2-Linux-x64/MCSL2Lib/verification.so Update/Linux-x64/MCSL2Lib/ | |
| find Update -type d -empty -delete | |
| 7z a -tzip -mx=9 "Update-${MCSL2_VERSION}.zip" "./Update/*" | |
| - name: Release | |
| uses: softprops/action-gh-release@v3.0.0 | |
| with: | |
| body_path: ./repo/ChangeLog.md | |
| prerelease: true | |
| draft: false | |
| tag_name: v${{ env.MCSL2_VERSION }} | |
| files: | | |
| *.zip | |
| env: | |
| GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} |