Stabilize loss estimates and add CONTROL autonomy #8
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: Cross-platform automatic release | |
| on: | |
| push: | |
| branches: [main] | |
| paths: | |
| - 'cross_platform/**' | |
| - '.github/scripts/prepare_cross_platform_release.py' | |
| - '.github/workflows/cross-platform-release.yml' | |
| workflow_dispatch: | |
| permissions: | |
| contents: write | |
| actions: write | |
| concurrency: | |
| group: pace-controller-cross-platform-release | |
| cancel-in-progress: false | |
| jobs: | |
| screenshot: | |
| name: Render real PySide6 screenshot | |
| runs-on: ubuntu-22.04 | |
| steps: | |
| - uses: actions/checkout@v6 | |
| with: | |
| ref: main | |
| fetch-depth: 0 | |
| - uses: actions/setup-python@v6 | |
| with: | |
| python-version: '3.12' | |
| cache: pip | |
| cache-dependency-path: cross_platform/requirements.txt | |
| - name: Install Qt runtime libraries | |
| run: | | |
| sudo apt-get update | |
| sudo apt-get install -y libegl1 libgl1 libxkbcommon0 libxkbcommon-x11-0 libdbus-1-3 libfontconfig1 libxcb-cursor0 libxcb-xkb1 libxcb-image0 libxcb-icccm4 libxcb-render-util0 libxcb-keysyms1 libxcb-shape0 libxcb-randr0 libxcb-xfixes0 | |
| - name: Render and validate the current real interface | |
| working-directory: cross_platform | |
| env: | |
| QT_QPA_PLATFORM: offscreen | |
| PACE_CONTROLLER_DATA_DIR: ${{ runner.temp }}/pace-controller-data | |
| run: | | |
| python -m pip install . | |
| python -m pace_controller --language en --screenshot docs/pace_controller_gui.png | |
| python -c "from PySide6.QtGui import QImage; i=QImage('docs/pace_controller_gui.png'); assert not i.isNull() and i.width() >= 1000 and i.height() >= 700, (i.width(), i.height())" | |
| - name: Commit the real screenshot | |
| shell: bash | |
| run: | | |
| set -euo pipefail | |
| git config user.name 'github-actions[bot]' | |
| git config user.email '41898282+github-actions[bot]@users.noreply.github.com' | |
| git add cross_platform/docs/pace_controller_gui.png | |
| if ! git diff --cached --quiet; then | |
| git commit -m 'Update real cross-platform interface screenshot [skip ci]' | |
| git fetch origin main | |
| git rebase origin/main | |
| git push origin HEAD:main | |
| fi | |
| prepare: | |
| if: github.actor != 'github-actions[bot]' || github.event_name == 'workflow_dispatch' | |
| needs: screenshot | |
| runs-on: ubuntu-24.04 | |
| outputs: | |
| version: ${{ steps.prepare.outputs.version }} | |
| commit_sha: ${{ steps.commit.outputs.commit_sha }} | |
| steps: | |
| - uses: actions/checkout@v6 | |
| with: | |
| ref: main | |
| fetch-depth: 0 | |
| - uses: actions/setup-python@v6 | |
| with: | |
| python-version: '3.12' | |
| cache: pip | |
| cache-dependency-path: cross_platform/requirements-dev.txt | |
| - name: Install test and manual dependencies | |
| run: | | |
| sudo apt-get update | |
| sudo apt-get install -y pandoc texlive-xetex texlive-latex-extra texlive-fonts-recommended libegl1 libgl1 libxkbcommon0 libxkbcommon-x11-0 libdbus-1-3 libfontconfig1 libxcb-cursor0 libxcb-xkb1 libxcb-image0 libxcb-icccm4 libxcb-render-util0 libxcb-keysyms1 libxcb-shape0 libxcb-randr0 libxcb-xfixes0 | |
| python -m pip install -r cross_platform/requirements-dev.txt | |
| - name: Validate source before release | |
| env: | |
| QT_QPA_PLATFORM: offscreen | |
| PACE_CONTROLLER_DATA_DIR: ${{ runner.temp }}/pace-controller-data | |
| run: | | |
| python tests/test_project.py | |
| python -m pytest -q cross_platform/tests | |
| python -m compileall -q cross_platform/src | |
| python -c "from pathlib import Path; import hashlib; data=Path('PACE_Controller.ps1').read_bytes().replace(b'\r\n', b'\n'); assert hashlib.sha256(data).hexdigest() == 'aa6ffe5431dfab7d2ea998f9b59e8ac5163b0e3478e84a3c15e2e826fb356b8e'" | |
| - name: Prepare semantic version and metadata | |
| id: prepare | |
| run: | | |
| VERSION="$(python3 .github/scripts/prepare_cross_platform_release.py)" | |
| echo "version=$VERSION" >> "$GITHUB_OUTPUT" | |
| echo "Preparing PACE Controller v$VERSION" | |
| - name: Build versioned PDF manual | |
| run: | | |
| pandoc cross_platform/docs/PACE_Controller_Manual.md \ | |
| --from markdown \ | |
| --resource-path=.:cross_platform:cross_platform/docs \ | |
| --pdf-engine=xelatex \ | |
| --output cross_platform/docs/PACE_Controller_Manual.pdf | |
| test -s cross_platform/docs/PACE_Controller_Manual.pdf | |
| - name: Validate prepared release | |
| run: | | |
| VERSION="${{ steps.prepare.outputs.version }}" | |
| python tests/test_project.py | |
| python -m pytest -q cross_platform/tests | |
| python - <<'PY' | |
| from pathlib import Path | |
| import re | |
| version = "${{ steps.prepare.outputs.version }}" | |
| init = Path("cross_platform/src/pace_controller/__init__.py").read_text(encoding="utf-8") | |
| pyproject = Path("cross_platform/pyproject.toml").read_text(encoding="utf-8") | |
| assert f'__version__ = "{version}"' in init | |
| assert f'version = "{version}"' in pyproject | |
| for path in ["README.md", "cross_platform/README.md", "cross_platform/docs/PACE_Controller_Manual.md", "CITATION.cff"]: | |
| assert version in Path(path).read_text(encoding="utf-8"), path | |
| assert Path("cross_platform/docs/PACE_Controller_Manual.pdf").stat().st_size > 10_000 | |
| PY | |
| - name: Commit prepared release | |
| id: commit | |
| run: | | |
| set -euo pipefail | |
| VERSION="${{ steps.prepare.outputs.version }}" | |
| git config user.name 'github-actions[bot]' | |
| git config user.email '41898282+github-actions[bot]@users.noreply.github.com' | |
| git add README.md CITATION.cff CHANGELOG.md cross_platform | |
| if ! git diff --cached --quiet; then | |
| git commit -m "Prepare cross-platform v${VERSION} release" | |
| git fetch origin main | |
| git rebase origin/main | |
| git push origin HEAD:main | |
| fi | |
| echo "commit_sha=$(git rev-parse HEAD)" >> "$GITHUB_OUTPUT" | |
| - name: Create immutable release tag | |
| env: | |
| VERSION: ${{ steps.prepare.outputs.version }} | |
| run: | | |
| set -euo pipefail | |
| if git ls-remote --exit-code --tags origin "refs/tags/v${VERSION}" >/dev/null 2>&1; then | |
| echo "Tag v${VERSION} already exists; refusing to overwrite it." | |
| exit 1 | |
| fi | |
| git tag "v${VERSION}" "${{ steps.commit.outputs.commit_sha }}" | |
| git push origin "v${VERSION}" | |
| windows-exe: | |
| name: Windows executable (x86_64) | |
| needs: prepare | |
| runs-on: windows-2022 | |
| steps: | |
| - uses: actions/checkout@v6 | |
| with: | |
| ref: v${{ needs.prepare.outputs.version }} | |
| - uses: actions/setup-python@v6 | |
| with: | |
| python-version: '3.12' | |
| cache: pip | |
| cache-dependency-path: cross_platform/requirements-dev.txt | |
| - name: Build standalone executable | |
| shell: powershell | |
| run: cross_platform/scripts/build_windows.ps1 -Version '${{ needs.prepare.outputs.version }}' | |
| - name: Validate Windows PE file | |
| shell: powershell | |
| run: | | |
| $path = 'cross_platform/dist/PACE-Controller-v${{ needs.prepare.outputs.version }}-Windows-x86_64.exe' | |
| $bytes = [System.IO.File]::ReadAllBytes((Resolve-Path $path)) | |
| if ($bytes.Length -lt 2 -or $bytes[0] -ne 0x4D -or $bytes[1] -ne 0x5A) { throw 'Invalid Windows PE header.' } | |
| Get-Item $path | Format-List Name,Length | |
| - uses: actions/upload-artifact@v7 | |
| with: | |
| name: pace-controller-windows | |
| path: cross_platform/dist/PACE-Controller-v${{ needs.prepare.outputs.version }}-Windows-x86_64.exe | |
| if-no-files-found: error | |
| linux-exe: | |
| name: Linux executable (x86_64) | |
| needs: prepare | |
| runs-on: ubuntu-22.04 | |
| steps: | |
| - uses: actions/checkout@v6 | |
| with: | |
| ref: v${{ needs.prepare.outputs.version }} | |
| - uses: actions/setup-python@v6 | |
| with: | |
| python-version: '3.12' | |
| cache: pip | |
| cache-dependency-path: cross_platform/requirements-dev.txt | |
| - name: Install Linux build libraries | |
| run: | | |
| sudo apt-get update | |
| sudo apt-get install -y libegl1 libgl1 libxkbcommon0 libxkbcommon-x11-0 libdbus-1-3 libfontconfig1 libxcb-cursor0 libxcb-xkb1 libxcb-image0 libxcb-icccm4 libxcb-render-util0 libxcb-keysyms1 libxcb-shape0 libxcb-randr0 libxcb-xfixes0 | |
| - name: Build standalone archive | |
| run: bash cross_platform/scripts/build_linux.sh '${{ needs.prepare.outputs.version }}' | |
| - name: Smoke-test packaged Linux GUI | |
| env: | |
| QT_QPA_PLATFORM: offscreen | |
| PACE_CONTROLLER_DATA_DIR: ${{ runner.temp }}/pace-controller-data | |
| run: | | |
| cross_platform/dist/PACE-Controller-v${{ needs.prepare.outputs.version }}-Linux-x86_64 --language en --screenshot "${{ runner.temp }}/packaged-ui.png" | |
| python -c "from PySide6.QtGui import QImage; import sys; i=QImage(sys.argv[1]); assert not i.isNull() and i.width() >= 1000 and i.height() >= 700" "${{ runner.temp }}/packaged-ui.png" | |
| - uses: actions/upload-artifact@v7 | |
| with: | |
| name: pace-controller-linux | |
| path: cross_platform/dist/PACE-Controller-v${{ needs.prepare.outputs.version }}-Linux-x86_64.tar.gz | |
| if-no-files-found: error | |
| source-package: | |
| name: Source archive and manual | |
| needs: prepare | |
| runs-on: ubuntu-24.04 | |
| steps: | |
| - uses: actions/checkout@v6 | |
| with: | |
| ref: v${{ needs.prepare.outputs.version }} | |
| - name: Create complete offline source package | |
| env: | |
| VERSION: ${{ needs.prepare.outputs.version }} | |
| run: | | |
| set -euo pipefail | |
| PACKAGE="PACE-Controller-v${VERSION}-source" | |
| mkdir -p "$PACKAGE" | |
| cp -a cross_platform/. "$PACKAGE/" | |
| cp LICENSE "$PACKAGE/" | |
| find "$PACKAGE" -type d \( -name __pycache__ -o -name .pytest_cache \) -prune -exec rm -rf {} + | |
| rm -rf "$PACKAGE/build" "$PACKAGE/dist" | |
| zip -r "${PACKAGE}.zip" "$PACKAGE" | |
| test -s "${PACKAGE}.zip" | |
| cp cross_platform/docs/PACE_Controller_Manual.pdf PACE_Controller_Manual.pdf | |
| - uses: actions/upload-artifact@v7 | |
| with: | |
| name: pace-controller-source | |
| path: | | |
| PACE-Controller-v${{ needs.prepare.outputs.version }}-source.zip | |
| PACE_Controller_Manual.pdf | |
| if-no-files-found: error | |
| publish: | |
| name: Publish GitHub release | |
| needs: [prepare, windows-exe, linux-exe, source-package] | |
| runs-on: ubuntu-24.04 | |
| steps: | |
| - uses: actions/download-artifact@v7 | |
| with: | |
| pattern: pace-controller-* | |
| path: release-assets | |
| merge-multiple: true | |
| - name: Generate checksums | |
| run: | | |
| cd release-assets | |
| sha256sum PACE-Controller-* PACE_Controller_Manual.pdf > SHA256SUMS.txt | |
| cat SHA256SUMS.txt | |
| - name: Publish validated release | |
| env: | |
| GH_TOKEN: ${{ github.token }} | |
| VERSION: ${{ needs.prepare.outputs.version }} | |
| run: | | |
| cat > /tmp/release-notes.md <<EOF | |
| ## PACE Controller v${VERSION} | |
| Cross-platform release for classic Druck PACE 5000/6000: | |
| - Ethernet TCP/SCPI and RS-232 on Windows and Linux; | |
| - standalone unsigned Windows and Linux executables; | |
| - complete source archive, illustrated PDF manual, and SHA-256 checksums; | |
| - frozen legacy PowerShell/WinForms v0.3.1 retained unchanged. | |
| **Safety:** validate the software at low pressure on an unloaded setup. Software interlocks do not replace hardware pressure protections or operator supervision. | |
| **Zenodo DOI:** pending archival or repository integration. | |
| EOF | |
| gh release create "v${VERSION}" release-assets/* \ | |
| --repo "$GITHUB_REPOSITORY" \ | |
| --target "${{ needs.prepare.outputs.commit_sha }}" \ | |
| --title "PACE Controller v${VERSION}" \ | |
| --notes-file /tmp/release-notes.md \ | |
| --verify-tag | |
| - name: Dispatch Zenodo DOI sync | |
| env: | |
| GH_TOKEN: ${{ github.token }} | |
| VERSION: ${{ needs.prepare.outputs.version }} | |
| run: | | |
| gh workflow run sync-zenodo-doi.yml \ | |
| --repo "$GITHUB_REPOSITORY" \ | |
| --ref main \ | |
| -f "version=${VERSION}" |