Bump actions/checkout from 4 to 6 #364
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: CI | |
| on: | |
| push: | |
| branches: [master] | |
| tags: ["v*"] | |
| pull_request: | |
| branches: [master] | |
| jobs: | |
| changes: | |
| name: Detect CI-relevant changes | |
| runs-on: ubuntu-24.04 | |
| outputs: | |
| run_ci: ${{ steps.filter.outputs.run_ci }} | |
| steps: | |
| - uses: actions/checkout@v6 | |
| with: | |
| fetch-depth: 0 | |
| - name: Decide whether CI is required | |
| id: filter | |
| env: | |
| EVENT_NAME: ${{ github.event_name }} | |
| EVENT_BEFORE: ${{ github.event.before }} | |
| EVENT_SHA: ${{ github.sha }} | |
| PR_BASE_SHA: ${{ github.event.pull_request.base.sha }} | |
| PR_HEAD_SHA: ${{ github.event.pull_request.head.sha }} | |
| REF_TYPE: ${{ github.ref_type }} | |
| run: | | |
| set -euo pipefail | |
| if [ "${REF_TYPE}" = "tag" ]; then | |
| echo "Tag push detected; CI will run." | |
| echo "run_ci=true" >> "$GITHUB_OUTPUT" | |
| exit 0 | |
| fi | |
| if [ "${EVENT_NAME}" = "pull_request" ]; then | |
| base_sha="${PR_BASE_SHA}" | |
| head_sha="${PR_HEAD_SHA}" | |
| else | |
| base_sha="${EVENT_BEFORE}" | |
| head_sha="${EVENT_SHA}" | |
| fi | |
| if [ -z "${base_sha}" ] || [ "${base_sha}" = "0000000000000000000000000000000000000000" ]; then | |
| echo "No comparable base commit; CI will run." | |
| echo "run_ci=true" >> "$GITHUB_OUTPUT" | |
| exit 0 | |
| fi | |
| mapfile -t changed_files < <(git diff --name-only "${base_sha}" "${head_sha}") | |
| if [ "${#changed_files[@]}" -eq 0 ]; then | |
| echo "No changed files detected; CI will run." | |
| echo "run_ci=true" >> "$GITHUB_OUTPUT" | |
| exit 0 | |
| fi | |
| printf 'Changed files:\n' | |
| printf ' - %s\n' "${changed_files[@]}" | |
| for path in "${changed_files[@]}"; do | |
| case "${path}" in | |
| docs/*|website/*|images/*) | |
| ;; | |
| *) | |
| echo "CI-relevant change detected: ${path}" | |
| echo "run_ci=true" >> "$GITHUB_OUTPUT" | |
| exit 0 | |
| ;; | |
| esac | |
| done | |
| echo "Only docs/ website/ and images/ changed; skipping CI." | |
| echo "run_ci=false" >> "$GITHUB_OUTPUT" | |
| quality: | |
| name: Quality (ruff + ty) | |
| needs: [changes] | |
| if: needs.changes.outputs.run_ci == 'true' | |
| runs-on: ubuntu-24.04 | |
| steps: | |
| - uses: actions/checkout@v6 | |
| - name: Install i18n tooling | |
| run: | | |
| sudo apt-get update | |
| sudo apt-get install -y gettext | |
| - name: Cache pip downloads | |
| uses: actions/cache@v4 | |
| with: | |
| path: ~/.cache/pip | |
| key: ${{ runner.os }}-quality-pip-${{ hashFiles('pyproject.toml') }} | |
| restore-keys: | | |
| ${{ runner.os }}-quality-pip- | |
| - name: Install project | |
| run: | | |
| python3 -m venv .venv | |
| . .venv/bin/activate | |
| python -m pip install --upgrade pip | |
| python -m pip install -e ".[dev]" | |
| - name: Verify POT is up to date | |
| run: bash tools/i18n.sh --check-pot-sync | |
| - name: Validate translation catalogs | |
| run: bash tools/i18n.sh --check-catalogs --require-complete | |
| - name: Compile translations | |
| run: bash tools/i18n.sh --compile | |
| - name: Check package-data sync | |
| run: python3 tools/check_package_data_sync.py | |
| - name: Check translation packaging | |
| run: python3 tools/check_translation_packaging.py | |
| - name: Lint (ruff check) | |
| run: .venv/bin/python -m ruff check docking/ tests/ | |
| - name: Format (ruff format) | |
| run: .venv/bin/python -m ruff format --check docking/ tests/ | |
| - name: Type check (ty) | |
| run: .venv/bin/python -m ty check docking/ | |
| test-ubuntu: | |
| name: Test (Python ${{ matrix.python }}, Ubuntu ${{ matrix.ubuntu }}) | |
| needs: [changes, quality] | |
| if: needs.changes.outputs.run_ci == 'true' | |
| runs-on: ubuntu-${{ matrix.ubuntu }} | |
| strategy: | |
| matrix: | |
| include: | |
| - ubuntu: "22.04" | |
| python: "3.10" | |
| - ubuntu: "24.04" | |
| python: "3.12" | |
| - ubuntu: "24.04" | |
| python: "3.14" | |
| steps: | |
| - uses: actions/checkout@v6 | |
| - name: Set up Python | |
| if: matrix.python == '3.14' | |
| uses: actions/setup-python@v5 | |
| with: | |
| python-version: ${{ matrix.python }} | |
| - name: Cache pip downloads | |
| uses: actions/cache@v4 | |
| with: | |
| path: ~/.cache/pip | |
| key: ${{ runner.os }}-ubuntu-${{ matrix.ubuntu }}-py${{ matrix.python }}-pip-${{ hashFiles('pyproject.toml') }} | |
| restore-keys: | | |
| ${{ runner.os }}-ubuntu-${{ matrix.ubuntu }}-py${{ matrix.python }}-pip- | |
| ${{ runner.os }}-ubuntu-${{ matrix.ubuntu }}-pip- | |
| - name: Install system dependencies | |
| run: | | |
| sudo apt-get update | |
| icon_theme_pkg="adwaita-icon-theme" | |
| if apt-cache show adwaita-icon-theme-full >/dev/null 2>&1; then | |
| icon_theme_pkg="adwaita-icon-theme-full" | |
| fi | |
| sudo apt-get install -y \ | |
| python3-venv \ | |
| xvfb xauth \ | |
| gir1.2-gtk-3.0 gir1.2-gdk-3.0 \ | |
| gir1.2-gdkpixbuf-2.0 gir1.2-wnck-3.0 gir1.2-pango-1.0 \ | |
| gir1.2-nm-1.0 gir1.2-gstreamer-1.0 \ | |
| libcairo2-dev libgirepository1.0-dev libglib2.0-dev \ | |
| meson ninja-build pkg-config \ | |
| python3-cairo python3-gi python3-gi-cairo \ | |
| librsvg2-common hicolor-icon-theme "$icon_theme_pkg" | |
| if command -v gdk-pixbuf-query-loaders >/dev/null 2>&1; then | |
| gdk-pixbuf-query-loaders | grep -qi librsvg | |
| fi | |
| - name: Install project with system GI bindings | |
| if: matrix.python != '3.14' | |
| run: | | |
| python3 -m venv --system-site-packages .venv | |
| . .venv/bin/activate | |
| python -m pip install --upgrade pip | |
| python -m pip install -e ".[dev]" | |
| - name: Install project without GI bindings | |
| if: matrix.python == '3.14' | |
| run: | | |
| python -m venv .venv | |
| . .venv/bin/activate | |
| python -m pip install --upgrade pip setuptools wheel | |
| python -m pip install pycairo | |
| python -m pip install -e ".[dev]" | |
| - name: Full tests | |
| if: matrix.python != '3.14' | |
| env: | |
| GSETTINGS_BACKEND: memory | |
| GTK_THEME: Adwaita | |
| COVERAGE_MIN: "55" | |
| run: | | |
| xvfb-run -a .venv/bin/python -m pytest tests/ -v \ | |
| --cov=docking \ | |
| --cov-report=term-missing \ | |
| --cov-report=xml:coverage.xml \ | |
| --cov-report=html:htmlcov \ | |
| --cov-fail-under=${COVERAGE_MIN} | |
| - name: Python 3.14 smoke tests | |
| if: matrix.python == '3.14' | |
| run: | | |
| .venv/bin/python -m pytest -q \ | |
| tests/core/test_config.py \ | |
| tests/ui/test_about.py \ | |
| tests/ui/test_menu_integration.py \ | |
| tests/ui/test_settings.py \ | |
| tests/test_app.py | |
| - name: Upload coverage artifact | |
| if: matrix.python != '3.14' | |
| uses: actions/upload-artifact@v4 | |
| with: | |
| name: coverage-ubuntu-${{ matrix.ubuntu }}-py${{ matrix.python }} | |
| path: | | |
| coverage.xml | |
| htmlcov/ | |
| - name: Upload coverage to Codecov | |
| if: matrix.ubuntu == '24.04' && matrix.python == '3.12' && env.CODECOV_TOKEN != '' | |
| uses: codecov/codecov-action@v5 | |
| env: | |
| CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }} | |
| with: | |
| token: ${{ env.CODECOV_TOKEN }} | |
| files: coverage.xml | |
| flags: ubuntu-24.04-py3.12 | |
| fail_ci_if_error: false | |
| test-debian: | |
| name: Test (Python ${{ matrix.python }}, Debian ${{ matrix.debian }}) | |
| needs: [changes, quality] | |
| if: needs.changes.outputs.run_ci == 'true' | |
| runs-on: ubuntu-22.04 | |
| strategy: | |
| matrix: | |
| include: | |
| - debian: "11" | |
| python: "3.10" | |
| image: python:3.10-bullseye | |
| - debian: "12" | |
| python: "3.12" | |
| image: python:3.12-bookworm | |
| - debian: "12" | |
| python: "3.14" | |
| image: python:3.14-bookworm | |
| container: | |
| image: ${{ matrix.image }} | |
| steps: | |
| - uses: actions/checkout@v6 | |
| - name: Cache pip downloads | |
| uses: actions/cache@v4 | |
| with: | |
| path: /root/.cache/pip | |
| key: ${{ runner.os }}-debian-${{ matrix.debian }}-py${{ matrix.python }}-pip-${{ hashFiles('pyproject.toml') }} | |
| restore-keys: | | |
| ${{ runner.os }}-debian-${{ matrix.debian }}-py${{ matrix.python }}-pip- | |
| ${{ runner.os }}-debian-${{ matrix.debian }}-pip- | |
| - name: Install system dependencies | |
| run: | | |
| apt-get update | |
| apt-get install -y \ | |
| build-essential \ | |
| ca-certificates curl git \ | |
| xvfb xauth pkg-config gobject-introspection libcairo2-dev libgirepository1.0-dev \ | |
| gir1.2-gtk-3.0 gir1.2-gdk-3.0 gir1.2-gdkpixbuf-2.0 gir1.2-wnck-3.0 \ | |
| gir1.2-pango-1.0 gir1.2-nm-1.0 gir1.2-gstreamer-1.0 | |
| - name: Install project with GI bindings | |
| if: matrix.python != '3.14' | |
| run: | | |
| python -m pip install --upgrade pip | |
| python -m pip install pycairo "PyGObject==3.42.2" | |
| python -m pip install -e ".[dev]" | |
| - name: Install project without GI bindings | |
| if: matrix.python == '3.14' | |
| run: | | |
| python -m pip install --upgrade pip | |
| python -m pip install pycairo | |
| python -m pip install -e ".[dev]" | |
| - name: Full tests | |
| if: matrix.python != '3.14' | |
| env: | |
| GSETTINGS_BACKEND: memory | |
| GTK_THEME: Adwaita | |
| run: xvfb-run -a python -m pytest tests/ -v | |
| - name: Python 3.14 smoke tests | |
| if: matrix.python == '3.14' | |
| run: | | |
| python -m pytest -q \ | |
| tests/core/test_config.py \ | |
| tests/ui/test_about.py \ | |
| tests/ui/test_menu_integration.py \ | |
| tests/ui/test_settings.py \ | |
| tests/test_app.py | |
| test-fedora-smoke: | |
| name: Smoke (Fedora 41) | |
| needs: [changes, quality] | |
| if: needs.changes.outputs.run_ci == 'true' | |
| runs-on: ubuntu-24.04 | |
| container: | |
| image: fedora:41 | |
| steps: | |
| - uses: actions/checkout@v6 | |
| - name: Install system dependencies | |
| run: | | |
| dnf install -y \ | |
| git \ | |
| python3 python3-pip \ | |
| cairo-devel cairo-gobject-devel gobject-introspection-devel \ | |
| gtk3 gdk-pixbuf2 libwnck3 pango NetworkManager-libnm gstreamer1 \ | |
| python3-cairo python3-gobject \ | |
| xorg-x11-server-Xvfb xorg-x11-xauth \ | |
| adwaita-icon-theme hicolor-icon-theme librsvg2 | |
| - name: Install project | |
| run: | | |
| python3 -m venv --system-site-packages .venv | |
| . .venv/bin/activate | |
| python -m pip install --upgrade pip | |
| python -m pip install -e ".[dev]" | |
| - name: Smoke tests | |
| env: | |
| GSETTINGS_BACKEND: memory | |
| GTK_THEME: Adwaita | |
| run: | | |
| xvfb-run -a .venv/bin/python -m pytest -q \ | |
| tests/core/test_config.py \ | |
| tests/ui/test_about.py \ | |
| tests/ui/test_menu_integration.py \ | |
| tests/applets/test_registry.py \ | |
| tests/applets/test_trivia.py | |
| test-opensuse-smoke: | |
| name: Smoke (openSUSE Tumbleweed) | |
| needs: [changes, quality] | |
| if: needs.changes.outputs.run_ci == 'true' | |
| runs-on: ubuntu-24.04 | |
| container: | |
| image: opensuse/tumbleweed:latest | |
| steps: | |
| - uses: actions/checkout@v6 | |
| - name: Install system dependencies | |
| run: | | |
| zypper --non-interactive refresh | |
| choose_pkg() { | |
| for pkg in "$@"; do | |
| if zypper --non-interactive info "$pkg" >/dev/null 2>&1; then | |
| printf '%s\n' "$pkg" | |
| return 0 | |
| fi | |
| done | |
| return 1 | |
| } | |
| PYTHON_PKG="$(choose_pkg python313 python312 python311 python3)" | |
| PYTHON_DEV_PKG="$(choose_pkg python313-devel python312-devel python311-devel python3-devel)" | |
| PYTHON_PIP_PKG="$(choose_pkg python313-pip python312-pip python311-pip python3-pip)" | |
| PANGOCAIRO_TYPELIB_PKG="$(choose_pkg typelib-1_0-PangoCairo-1_0 || true)" | |
| zypper --non-interactive install --no-recommends \ | |
| git \ | |
| gcc \ | |
| meson \ | |
| ninja \ | |
| "$PYTHON_PKG" \ | |
| "$PYTHON_DEV_PKG" \ | |
| "$PYTHON_PIP_PKG" \ | |
| cairo-devel glib2-devel gobject-introspection-devel pkgconf \ | |
| typelib-1_0-GdkPixbuf-2_0 \ | |
| typelib-1_0-Gtk-3_0 \ | |
| typelib-1_0-Pango-1_0 \ | |
| typelib-1_0-Wnck-3_0 \ | |
| gdk-pixbuf-loader-rsvg librsvg \ | |
| xauth xorg-x11-server-Xvfb \ | |
| adwaita-icon-theme hicolor-icon-theme \ | |
| ${PANGOCAIRO_TYPELIB_PKG:+$PANGOCAIRO_TYPELIB_PKG} | |
| - name: Install project | |
| run: | | |
| PYTHON="$(command -v python3 || command -v python3.13 || command -v python3.12 || command -v python3.11)" | |
| "$PYTHON" -m venv .venv | |
| . .venv/bin/activate | |
| python -m pip install --upgrade pip setuptools wheel | |
| python -m pip install pycairo PyGObject | |
| python -m pip install -e ".[dev]" | |
| - name: Smoke tests | |
| env: | |
| GSETTINGS_BACKEND: memory | |
| GTK_THEME: Adwaita | |
| run: | | |
| Xvfb :99 -screen 0 1280x800x24 & | |
| XVFB_PID=$! | |
| trap 'kill $XVFB_PID' EXIT | |
| export DISPLAY=:99 | |
| .venv/bin/python -m pytest -q \ | |
| tests/core/test_config.py \ | |
| tests/ui/test_about.py \ | |
| tests/ui/test_menu_integration.py \ | |
| tests/applets/test_trivia.py | |
| build-deb: | |
| name: Build .deb | |
| runs-on: ubuntu-22.04 | |
| needs: [changes, test-ubuntu, test-debian, test-fedora-smoke, test-opensuse-smoke] | |
| if: needs.changes.outputs.run_ci == 'true' | |
| steps: | |
| - uses: actions/checkout@v6 | |
| - name: Install build dependencies | |
| run: | | |
| sudo apt-get update | |
| sudo apt-get install -y \ | |
| debhelper dh-python python3-setuptools python3-wheel python3-pip \ | |
| python3-gi python3-gi-cairo gir1.2-gtk-3.0 gir1.2-wnck-3.0 \ | |
| pybuild-plugin-pyproject python3-all gettext | |
| - name: Build .deb | |
| run: | | |
| bash packaging/deb/build.sh | |
| mkdir -p artifacts | |
| cp ../docking_*.deb artifacts/ | |
| ls -lh artifacts/docking_*.deb | |
| - name: Validate .deb install | |
| run: | | |
| set -euo pipefail | |
| sudo apt-get update | |
| sudo apt-get install -y ./artifacts/docking_*.deb | |
| echo "[check] dpkg status" | |
| dpkg -s docking | grep -F "Status: install ok installed" | |
| echo "[check] executable exists: /usr/bin/docking" | |
| if [ -x /usr/bin/docking ]; then | |
| ls -l /usr/bin/docking | |
| else | |
| echo "missing or non-executable: /usr/bin/docking" | |
| dpkg -L docking | sed -n '1,200p' | |
| exit 1 | |
| fi | |
| echo "[check] desktop file exists" | |
| if [ -f /usr/share/applications/org.docking.Docking.desktop ]; then | |
| ls -l /usr/share/applications/org.docking.Docking.desktop | |
| else | |
| echo "missing: /usr/share/applications/org.docking.Docking.desktop" | |
| dpkg -L docking | sed -n '1,200p' | |
| exit 1 | |
| fi | |
| echo "[check] vendored dependencies directory exists" | |
| if [ -d /usr/lib/docking/vendor ]; then | |
| ls -ld /usr/lib/docking/vendor | |
| else | |
| echo "missing: /usr/lib/docking/vendor" | |
| dpkg -L docking | sed -n '1,200p' | |
| exit 1 | |
| fi | |
| echo "[check] all install validations passed" | |
| - name: Upload .deb artifact | |
| uses: actions/upload-artifact@v4 | |
| with: | |
| name: docking-deb | |
| path: artifacts/docking_*.deb | |
| build-rpm: | |
| name: Build RPM | |
| runs-on: ubuntu-22.04 | |
| needs: [changes, test-ubuntu, test-debian, test-fedora-smoke, test-opensuse-smoke] | |
| if: needs.changes.outputs.run_ci == 'true' | |
| steps: | |
| - uses: actions/checkout@v6 | |
| - name: Install RPM tooling | |
| run: | | |
| sudo apt-get update | |
| sudo apt-get install -y rpm python3-pip gettext | |
| - name: Compile translations | |
| run: bash tools/i18n.sh --compile | |
| - name: Build RPM package | |
| run: | | |
| mkdir -p artifacts | |
| ./packaging/rpm/build.sh | |
| - name: Upload RPM artifact | |
| uses: actions/upload-artifact@v4 | |
| with: | |
| name: docking-rpm | |
| path: artifacts/*.rpm | |
| build-flatpak: | |
| name: Build Flatpak | |
| runs-on: ubuntu-22.04 | |
| needs: [changes, test-ubuntu, test-debian, test-fedora-smoke, test-opensuse-smoke] | |
| if: needs.changes.outputs.run_ci == 'true' | |
| steps: | |
| - uses: actions/checkout@v6 | |
| - name: Install Flatpak tooling | |
| run: | | |
| sudo apt-get update | |
| sudo apt-get install -y flatpak flatpak-builder gettext | |
| - name: Compile translations | |
| run: bash tools/i18n.sh --compile | |
| - name: Build Flatpak bundle | |
| run: | | |
| flatpak remote-add --user --if-not-exists flathub https://flathub.org/repo/flathub.flatpakrepo | |
| flatpak install --user -y flathub org.gnome.Platform//46 org.gnome.Sdk//46 | |
| flatpak-builder --force-clean --repo=flatpak-repo flatpak-build packaging/flatpak/org.docking.Docking.json | |
| mkdir -p artifacts | |
| flatpak build-bundle flatpak-repo artifacts/org.docking.Docking.flatpak org.docking.Docking | |
| ls -lh artifacts/org.docking.Docking.flatpak | |
| - name: Upload Flatpak artifact | |
| uses: actions/upload-artifact@v4 | |
| with: | |
| name: docking-flatpak | |
| path: artifacts/org.docking.Docking.flatpak | |
| build-snap: | |
| name: Build Snap | |
| runs-on: ubuntu-22.04 | |
| needs: [changes, test-ubuntu, test-debian, test-fedora-smoke, test-opensuse-smoke] | |
| if: needs.changes.outputs.run_ci == 'true' | |
| steps: | |
| - uses: actions/checkout@v6 | |
| - name: Install Snapcraft | |
| run: | | |
| sudo apt-get update | |
| sudo apt-get install -y snapcraft gettext | |
| - name: Compile translations | |
| run: bash tools/i18n.sh --compile | |
| - name: Build Snap package | |
| run: | | |
| mkdir -p artifacts | |
| ( | |
| cd packaging/snap | |
| sudo snapcraft pack --destructive-mode --output "$GITHUB_WORKSPACE/artifacts/docking.snap" | |
| ) | |
| sudo chown "$USER:$USER" artifacts/docking.snap | |
| ls -lh artifacts/*.snap | |
| - name: Upload Snap artifact | |
| uses: actions/upload-artifact@v4 | |
| with: | |
| name: docking-snap | |
| path: artifacts/*.snap | |
| build-appimage: | |
| name: Build AppImage | |
| runs-on: ubuntu-22.04 | |
| needs: [changes, test-ubuntu, test-debian, test-fedora-smoke, test-opensuse-smoke] | |
| if: needs.changes.outputs.run_ci == 'true' | |
| steps: | |
| - uses: actions/checkout@v6 | |
| - name: Install AppImage tooling | |
| run: | | |
| sudo apt-get update | |
| sudo apt-get install -y python3-pip libfuse2 gettext | |
| python3 -m pip install --upgrade pip | |
| python3 -m pip install appimage-builder | |
| - name: Compile translations | |
| run: bash tools/i18n.sh --compile | |
| - name: Build AppImage | |
| run: | | |
| mkdir -p artifacts | |
| ./packaging/appimage/build.sh | |
| - name: Upload AppImage artifact | |
| uses: actions/upload-artifact@v4 | |
| with: | |
| name: docking-appimage | |
| path: artifacts/*.AppImage | |
| build-arch: | |
| name: Build Arch package | |
| runs-on: ubuntu-22.04 | |
| needs: [changes, test-ubuntu, test-debian, test-fedora-smoke, test-opensuse-smoke] | |
| if: needs.changes.outputs.run_ci == 'true' | |
| container: | |
| image: archlinux:latest | |
| steps: | |
| - uses: actions/checkout@v6 | |
| - name: Install Arch build tooling | |
| run: | | |
| pacman -Sy --noconfirm archlinux-keyring | |
| pacman -Syu --noconfirm | |
| pacman -S --noconfirm --needed base-devel git python python-pip gettext | |
| - name: Compile translations | |
| run: bash tools/i18n.sh --compile | |
| - name: Build Arch package | |
| run: | | |
| useradd -m builder | |
| chown -R builder:builder "$GITHUB_WORKSPACE" | |
| su - builder -c "cd '$GITHUB_WORKSPACE' && ./packaging/arch/build.sh" | |
| ls -lh artifacts/*.pkg.tar.* | |
| - name: Upload Arch artifact | |
| uses: actions/upload-artifact@v4 | |
| with: | |
| name: docking-arch | |
| path: artifacts/*.pkg.tar.* | |
| build-nix: | |
| name: Build Nix package | |
| runs-on: ubuntu-22.04 | |
| needs: [changes, test-ubuntu, test-debian, test-fedora-smoke, test-opensuse-smoke] | |
| if: needs.changes.outputs.run_ci == 'true' | |
| steps: | |
| - uses: actions/checkout@v6 | |
| - name: Install Nix | |
| uses: cachix/install-nix-action@v30 | |
| with: | |
| nix_path: nixpkgs=channel:nixos-24.11 | |
| - name: Install i18n tooling | |
| run: | | |
| sudo apt-get update | |
| sudo apt-get install -y gettext | |
| - name: Compile translations | |
| run: bash tools/i18n.sh --compile | |
| - name: Build Nix package | |
| run: | | |
| mkdir -p artifacts | |
| ./packaging/nix/build.sh | |
| - name: Upload Nix artifact | |
| uses: actions/upload-artifact@v4 | |
| with: | |
| name: docking-nix | |
| path: | | |
| artifacts/docking-nix-output.tar.gz | |
| artifacts/docking-nix-store-path.txt | |
| release: | |
| name: Release | |
| runs-on: ubuntu-22.04 | |
| needs: [changes, build-deb, build-rpm, build-flatpak, build-snap, build-appimage, build-arch, build-nix] | |
| if: github.ref == 'refs/heads/master' && needs.changes.outputs.run_ci == 'true' | |
| permissions: | |
| contents: write | |
| steps: | |
| - uses: actions/checkout@v6 | |
| - name: Get version from pyproject.toml | |
| id: version | |
| run: | | |
| VERSION=$( | |
| awk -F ' *= *' ' | |
| $0 == "[project]" { in_project = 1; next } | |
| /^\[/ { in_project = 0 } | |
| in_project && $1 == "version" { | |
| gsub(/"/, "", $2) | |
| print $2 | |
| exit | |
| } | |
| ' pyproject.toml | |
| ) | |
| if [ -z "${VERSION}" ]; then | |
| echo "Failed to read [project].version from pyproject.toml" | |
| exit 1 | |
| fi | |
| echo "version=$VERSION" >> "$GITHUB_OUTPUT" | |
| echo "tag=v$VERSION" >> "$GITHUB_OUTPUT" | |
| - name: Decide if release is needed | |
| id: release_check | |
| env: | |
| GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} | |
| run: | | |
| set -euo pipefail | |
| current_version="${{ steps.version.outputs.version }}" | |
| api_url="https://api.github.com/repos/${GITHUB_REPOSITORY}/releases/latest" | |
| status_code=$( | |
| curl -sS -o /tmp/latest-release.json -w "%{http_code}" \ | |
| -H "Authorization: Bearer ${GH_TOKEN}" \ | |
| -H "Accept: application/vnd.github+json" \ | |
| "${api_url}" | |
| ) | |
| if [ "${status_code}" = "404" ]; then | |
| echo "latest_tag=" >> "$GITHUB_OUTPUT" | |
| echo "should_release=true" >> "$GITHUB_OUTPUT" | |
| echo "reason=no_existing_release" >> "$GITHUB_OUTPUT" | |
| exit 0 | |
| fi | |
| if [ "${status_code}" != "200" ]; then | |
| echo "GitHub API error (${status_code}) while reading latest release" | |
| cat /tmp/latest-release.json | |
| exit 1 | |
| fi | |
| latest_tag=$( | |
| python3 -c 'import json, pathlib; print(json.loads(pathlib.Path("/tmp/latest-release.json").read_text()).get("tag_name", ""))' | |
| ) | |
| latest_version="${latest_tag#v}" | |
| echo "latest_tag=${latest_tag}" >> "$GITHUB_OUTPUT" | |
| if [ -z "${latest_version}" ]; then | |
| echo "should_release=true" >> "$GITHUB_OUTPUT" | |
| echo "reason=latest_release_without_tag" >> "$GITHUB_OUTPUT" | |
| elif [ "${current_version}" = "${latest_version}" ]; then | |
| echo "should_release=false" >> "$GITHUB_OUTPUT" | |
| echo "reason=already_released" >> "$GITHUB_OUTPUT" | |
| elif [ "$(printf '%s\n%s\n' "${latest_version}" "${current_version}" | sort -V | tail -n1)" = "${current_version}" ]; then | |
| echo "should_release=true" >> "$GITHUB_OUTPUT" | |
| echo "reason=version_is_newer" >> "$GITHUB_OUTPUT" | |
| else | |
| echo "should_release=false" >> "$GITHUB_OUTPUT" | |
| echo "reason=version_not_newer" >> "$GITHUB_OUTPUT" | |
| fi | |
| - name: Create tag | |
| if: steps.release_check.outputs.should_release == 'true' | |
| run: | | |
| set -euo pipefail | |
| tag="${{ steps.version.outputs.tag }}" | |
| if git ls-remote --exit-code --tags origin "refs/tags/${tag}" >/dev/null 2>&1; then | |
| echo "Tag ${tag} already exists on origin, skipping tag creation" | |
| exit 0 | |
| fi | |
| git config user.name "github-actions[bot]" | |
| git config user.email "41898282+github-actions[bot]@users.noreply.github.com" | |
| git tag "${tag}" | |
| git push origin "${tag}" | |
| - name: Download .deb artifact | |
| uses: actions/download-artifact@v4 | |
| with: | |
| name: docking-deb | |
| path: artifacts | |
| - name: Download RPM artifact | |
| uses: actions/download-artifact@v4 | |
| with: | |
| name: docking-rpm | |
| path: artifacts | |
| - name: Download Flatpak artifact | |
| uses: actions/download-artifact@v4 | |
| with: | |
| name: docking-flatpak | |
| path: artifacts | |
| - name: Download Snap artifact | |
| uses: actions/download-artifact@v4 | |
| with: | |
| name: docking-snap | |
| path: artifacts | |
| - name: Download AppImage artifact | |
| uses: actions/download-artifact@v4 | |
| with: | |
| name: docking-appimage | |
| path: artifacts | |
| - name: Download Arch artifact | |
| uses: actions/download-artifact@v4 | |
| with: | |
| name: docking-arch | |
| path: artifacts | |
| - name: Download Nix artifact | |
| uses: actions/download-artifact@v4 | |
| with: | |
| name: docking-nix | |
| path: artifacts | |
| - name: Normalize release asset names | |
| if: steps.release_check.outputs.should_release == 'true' | |
| run: | | |
| set -euo pipefail | |
| shopt -s nullglob | |
| version="${{ steps.version.outputs.version }}" | |
| host_arch="$(uname -m)" | |
| source_dir="artifacts" | |
| release_dir="${source_dir}/release" | |
| mkdir -p "${release_dir}" | |
| echo "Downloaded artifacts:" | |
| find "${source_dir}" -maxdepth 2 -type f | sed 's#^# - #' | |
| normalize_arch() { | |
| case "$1" in | |
| amd64) | |
| echo "x86_64" | |
| ;; | |
| arm64) | |
| echo "aarch64" | |
| ;; | |
| noarch) | |
| echo "all" | |
| ;; | |
| *) | |
| echo "$1" | |
| ;; | |
| esac | |
| } | |
| pick_candidate() { | |
| local label="$1" | |
| shift | |
| if [ "$#" -eq 0 ]; then | |
| echo "Missing ${label} artifact" >&2 | |
| exit 1 | |
| fi | |
| if [ "$#" -gt 1 ]; then | |
| echo "Multiple ${label} artifacts found ($#), selecting first:" >&2 | |
| printf ' - %s\n' "$@" | |
| fi | |
| printf '%s\n' "$1" | |
| } | |
| copy_release_asset() { | |
| local src="$1" | |
| local versioned_name="$2" | |
| local latest_name="$3" | |
| cp -f "${src}" "${release_dir}/${versioned_name}" | |
| cp -f "${src}" "${release_dir}/${latest_name}" | |
| } | |
| deb_candidates=("${source_dir}"/docking_*.deb) | |
| deb_file="$(pick_candidate "deb" "${deb_candidates[@]}")" | |
| deb_arch="$(echo "${deb_file##*/}" | sed -E 's/.*_([[:alnum:]_]+)\.deb$/\1/')" | |
| deb_arch="$(normalize_arch "${deb_arch}")" | |
| copy_release_asset \ | |
| "${deb_file}" \ | |
| "docking-${version}-linux-${deb_arch}.deb" \ | |
| "docking-latest-linux-${deb_arch}.deb" | |
| rpm_candidates=("${source_dir}"/*.rpm) | |
| rpm_primary=() | |
| for f in "${rpm_candidates[@]}"; do | |
| if [[ "${f}" != *.src.rpm ]]; then | |
| rpm_primary+=("${f}") | |
| fi | |
| done | |
| rpm_file="$(pick_candidate "rpm" "${rpm_primary[@]}")" | |
| rpm_arch="$(echo "${rpm_file##*/}" | sed -E 's/.*\.([^.]+)\.rpm$/\1/')" | |
| rpm_arch="$(normalize_arch "${rpm_arch}")" | |
| copy_release_asset \ | |
| "${rpm_file}" \ | |
| "docking-${version}-linux-${rpm_arch}.rpm" \ | |
| "docking-latest-linux-${rpm_arch}.rpm" | |
| flatpak_candidates=("${source_dir}"/*.flatpak) | |
| flatpak_file="$(pick_candidate "flatpak" "${flatpak_candidates[@]}")" | |
| copy_release_asset \ | |
| "${flatpak_file}" \ | |
| "docking-${version}-linux-${host_arch}.flatpak" \ | |
| "docking-latest-linux-${host_arch}.flatpak" | |
| snap_candidates=("${source_dir}"/*.snap) | |
| snap_file="$(pick_candidate "snap" "${snap_candidates[@]}")" | |
| copy_release_asset \ | |
| "${snap_file}" \ | |
| "docking-${version}-linux-${host_arch}.snap" \ | |
| "docking-latest-linux-${host_arch}.snap" | |
| appimage_candidates=("${source_dir}"/*.AppImage) | |
| appimage_file="$(pick_candidate "appimage" "${appimage_candidates[@]}")" | |
| appimage_arch="$(echo "${appimage_file##*/}" | sed -nE 's/.*-([[:alnum:]_]+)\.AppImage$/\1/p')" | |
| if [ -z "${appimage_arch}" ]; then | |
| appimage_arch="${host_arch}" | |
| fi | |
| appimage_arch="$(normalize_arch "${appimage_arch}")" | |
| copy_release_asset \ | |
| "${appimage_file}" \ | |
| "docking-${version}-linux-${appimage_arch}.AppImage" \ | |
| "docking-latest-linux-${appimage_arch}.AppImage" | |
| arch_candidates=("${source_dir}"/*.pkg.tar.*) | |
| arch_primary=() | |
| for f in "${arch_candidates[@]}"; do | |
| if [[ "${f}" != *.sig && "${f##*/}" != docking-debug-* ]]; then | |
| arch_primary+=("${f}") | |
| fi | |
| done | |
| arch_file="$(pick_candidate "arch" "${arch_primary[@]}")" | |
| arch_arch="$(echo "${arch_file##*/}" | sed -E 's/.*-([^-]+)\.pkg\.tar\..+$/\1/')" | |
| arch_arch="$(normalize_arch "${arch_arch}")" | |
| arch_ext="${arch_file##*.pkg.tar.}" | |
| copy_release_asset \ | |
| "${arch_file}" \ | |
| "docking-${version}-linux-${arch_arch}.pkg.tar.${arch_ext}" \ | |
| "docking-latest-linux-${arch_arch}.pkg.tar.${arch_ext}" | |
| nix_output_candidates=("${source_dir}"/docking-nix-output.tar.gz) | |
| nix_output_file="$(pick_candidate "nix output tarball" "${nix_output_candidates[@]}")" | |
| copy_release_asset \ | |
| "${nix_output_file}" \ | |
| "docking-${version}-linux-${host_arch}-nix-output.tar.gz" \ | |
| "docking-latest-linux-${host_arch}-nix-output.tar.gz" | |
| nix_path_candidates=("${source_dir}"/docking-nix-store-path.txt) | |
| nix_path_file="$(pick_candidate "nix store path" "${nix_path_candidates[@]}")" | |
| copy_release_asset \ | |
| "${nix_path_file}" \ | |
| "docking-${version}-linux-${host_arch}-nix-store-path.txt" \ | |
| "docking-latest-linux-${host_arch}-nix-store-path.txt" | |
| echo "Standardized release assets:" | |
| ls -lh "${release_dir}" | |
| - name: Create GitHub Release | |
| if: steps.release_check.outputs.should_release == 'true' | |
| uses: softprops/action-gh-release@v2 | |
| with: | |
| tag_name: ${{ steps.version.outputs.tag }} | |
| name: Docking ${{ steps.version.outputs.version }} | |
| files: | | |
| artifacts/release/* | |
| generate_release_notes: true | |
| - name: Skip release summary | |
| if: steps.release_check.outputs.should_release != 'true' | |
| run: | | |
| echo "Release skipped: ${{ steps.release_check.outputs.reason }}" | |
| echo "Latest release tag: ${{ steps.release_check.outputs.latest_tag }}" | |
| echo "Current pyproject version: ${{ steps.version.outputs.version }}" |