name: Desktop Release on: workflow_dispatch: jobs: release: runs-on: ubuntu-latest steps: - name: Checkout uses: https://git.daemonlord.ru/actions/checkout@v4 with: fetch-depth: 0 tags: true - name: Require master branch shell: bash run: test "$GITHUB_REF" = refs/heads/master - name: Set up Python for tests uses: https://git.daemonlord.ru/actions/setup-python@v5 with: python-version: "3.13" - name: Read release version id: version shell: bash run: | set -euo pipefail version="$(python -c 'from app_version import APP_VERSION; print(APP_VERSION)')" [[ "$version" =~ ^[0-9]+\.[0-9]+\.[0-9]+$ ]] || { echo "Invalid APP_VERSION: $version"; exit 1; } echo "value=$version" >> "$GITHUB_OUTPUT" echo "Release version: $version" - name: Check release does not exist id: check_release shell: bash env: API_TOKEN: ${{ secrets.API_TOKEN }} RELEASE_TAG: v${{ steps.version.outputs.value }} run: | set -euo pipefail test -n "$API_TOKEN" || { echo 'API_TOKEN secret is missing'; exit 1; } status="$(curl --silent --show-error --output /dev/null --write-out '%{http_code}' \ --header "Authorization: token $API_TOKEN" \ "https://git.daemonlord.ru/api/v1/repos/${{ gitea.repository }}/releases/tags/$RELEASE_TAG")" case "$status" in 200) echo "Release $RELEASE_TAG already exists; skipping."; echo 'publish=false' >> "$GITHUB_OUTPUT" ;; 404) echo 'publish=true' >> "$GITHUB_OUTPUT" ;; *) echo "Cannot check release: HTTP $status"; exit 1 ;; esac - name: Check Linux Docker runner if: steps.check_release.outputs.publish == 'true' shell: bash run: | set -euo pipefail test "$(uname -m)" = x86_64 if ! command -v docker > /dev/null; then if [ "$(id -u)" -eq 0 ]; then apt-get update && apt-get install -y docker.io else sudo apt-get update && sudo apt-get install -y docker.io fi fi docker info --format '{{.OSType}}' | grep -qx linux - name: Install Qt runtime libraries if: steps.check_release.outputs.publish == 'true' shell: bash run: | set -euo pipefail if [ "$(id -u)" -eq 0 ]; then apt-get update && apt-get install -y libgl1 libegl1 else sudo apt-get update && sudo apt-get install -y libgl1 libegl1 fi - name: Install test dependencies if: steps.check_release.outputs.publish == 'true' shell: bash run: | set -euo pipefail python -m pip install -r requirements.txt - name: Run tests if: steps.check_release.outputs.publish == 'true' shell: bash env: QT_QPA_PLATFORM: offscreen run: | set -euo pipefail python -m compileall -q app_version.py main.py build.py updater_gui.py services ui tests python -m unittest discover -s tests -p 'test_*.py' -v - name: Build Windows application with PyInstaller if: steps.check_release.outputs.publish == 'true' shell: bash run: bash scripts/docker-build-windows.sh - name: Build Windows installer with Inno Setup if: steps.check_release.outputs.publish == 'true' shell: bash env: APP_VERSION: ${{ steps.version.outputs.value }} run: | set -euo pipefail test -f 'dist/AnabasisManager/AnabasisManager.exe' test -f 'dist/AnabasisManager/AnabasisUpdater.exe' bash scripts/docker-build-installer.sh "$APP_VERSION" - name: Verify release assets if: steps.check_release.outputs.publish == 'true' shell: bash env: APP_VERSION: ${{ steps.version.outputs.value }} run: | set -euo pipefail archive="AnabasisManager-$APP_VERSION.zip" installer="AnabasisManager-setup-$APP_VERSION.exe" test -s "dist/$archive" test -s "dist/$installer" python - "$APP_VERSION" <<'PY' import sys from pathlib import Path from zipfile import ZipFile version = sys.argv[1] archive = Path('dist') / f'AnabasisManager-{version}.zip' with ZipFile(archive) as package: required = {'AnabasisManager.exe', 'AnabasisUpdater.exe', 'version.txt'} missing = required.difference(package.namelist()) if missing: raise SystemExit(f'Archive is missing: {sorted(missing)}') actual_version = package.read('version.txt').decode('utf-8').strip() if actual_version != version: raise SystemExit(f'Archive version {actual_version} != {version}') PY for name in "$archive" "$installer"; do (cd dist && sha256sum "$name" > "$name.sha256") (cd dist && sha256sum --check "$name.sha256") done - name: Create git tag if: steps.check_release.outputs.publish == 'true' shell: bash env: RELEASE_TAG: v${{ steps.version.outputs.value }} run: | set -euo pipefail if git ls-remote --exit-code --tags origin "refs/tags/$RELEASE_TAG" > /dev/null; then git fetch origin "refs/tags/$RELEASE_TAG:refs/tags/$RELEASE_TAG" test "$(git rev-parse "$RELEASE_TAG^{commit}")" = "$GITHUB_SHA" || { echo "Tag $RELEASE_TAG points to another commit"; exit 1; } else git config user.name gitea-actions git config user.email gitea-actions@daemonlord.ru git tag -a "$RELEASE_TAG" -m "Release $RELEASE_TAG" "$GITHUB_SHA" git push origin "$RELEASE_TAG" fi - name: Create Gitea Release if: steps.check_release.outputs.publish == 'true' uses: https://git.daemonlord.ru/actions/gitea-release-action@v1 with: server_url: https://git.daemonlord.ru repository: ${{ gitea.repository }} token: ${{ secrets.API_TOKEN }} tag_name: v${{ steps.version.outputs.value }} target_commitish: ${{ gitea.sha }} name: Anabasis Manager ${{ steps.version.outputs.value }} body: | Desktop release v${{ steps.version.outputs.value }} files: | dist/AnabasisManager-${{ steps.version.outputs.value }}.zip dist/AnabasisManager-${{ steps.version.outputs.value }}.zip.sha256 dist/AnabasisManager-setup-${{ steps.version.outputs.value }}.exe dist/AnabasisManager-setup-${{ steps.version.outputs.value }}.exe.sha256