From be8d96976b935a5cfd2e7800be87859ecd0bcfff Mon Sep 17 00:00:00 2001 From: Xarvex Date: Tue, 7 Jul 2026 17:21:08 -0500 Subject: [PATCH] feat(ci)!: rework workflows and build processes All Python setups route through one local action, and checks are much more conditional. There is more to be done, but this is a significant improvement in processing time and redundancy. As well, nightly builds are made (though not made as GitHub releases.. yet). --- .github/actions/setup-python/action.yml | 59 +++++++ .github/workflows/build.yml | 203 ++++++++++++++++++++++++ .github/workflows/build_docs.yml | 57 +++++++ .github/workflows/checks_python.yml | 171 ++++++++++++++++++++ .github/workflows/publish_docs.yaml | 51 ------ .github/workflows/pyright.yaml | 31 ---- .github/workflows/pytest.yaml | 70 -------- .github/workflows/release.yml | 156 ------------------ .github/workflows/reuse.yaml | 12 -- .github/workflows/reuse.yml | 25 +++ .github/workflows/ruff.yaml | 33 ---- nix/package/pillow-jxl-plugin.nix | 1 - nix/package/pyexiv2.nix | 1 - scripts/semver-segments.pl | 14 ++ scripts/tagstudio.spec | 22 ++- 15 files changed, 543 insertions(+), 363 deletions(-) create mode 100644 .github/actions/setup-python/action.yml create mode 100644 .github/workflows/build.yml create mode 100644 .github/workflows/build_docs.yml create mode 100644 .github/workflows/checks_python.yml delete mode 100644 .github/workflows/publish_docs.yaml delete mode 100644 .github/workflows/pyright.yaml delete mode 100644 .github/workflows/pytest.yaml delete mode 100644 .github/workflows/release.yml delete mode 100644 .github/workflows/reuse.yaml create mode 100644 .github/workflows/reuse.yml delete mode 100644 .github/workflows/ruff.yaml create mode 100755 scripts/semver-segments.pl mode change 100644 => 100755 scripts/tagstudio.spec diff --git a/.github/actions/setup-python/action.yml b/.github/actions/setup-python/action.yml new file mode 100644 index 00000000..82171987 --- /dev/null +++ b/.github/actions/setup-python/action.yml @@ -0,0 +1,59 @@ +# SPDX-FileCopyrightText: (c) TagStudio Contributors +# SPDX-License-Identifier: CC0-1.0 +--- +name: Setup Python +description: Combination of Python setup actions + +inputs: + skip-setup: + default: 'false' + description: Whether to skip setup actions and only execute installs + groups: + description: Newline-separated list of dependency groups to install + +runs: + using: composite + steps: + - name: Setup Python install + if: inputs.skip-setup != 'true' + uses: actions/setup-python@v6 + with: + python-version: '3.12' + + - name: Setup uv install + if: inputs.skip-setup != 'true' + uses: astral-sh/setup-uv@v8.2.0 + + - name: Run pip install (Windows) + if: runner.os == 'Windows' + env: + INPUT_GROUPS: ${{ inputs.groups }} + UV_PYTHON_DOWNLOADS: never + UV_SYSTEM_PYTHON: '1' + shell: pwsh + run: | + if (![string]::IsNullOrEmpty(${env:INPUT_GROUPS})) { + $groupArgs = -split ${env:INPUT_GROUPS} -replace '^', '--group=' + } + + uv pip install . ${groupArgs} + + - name: Run pip install (non-Windows) + if: runner.os != 'Windows' + env: + INPUT_GROUPS: ${{ inputs.groups }} + UV_PYTHON_DOWNLOADS: never + UV_SYSTEM_PYTHON: '1' + shell: bash + run: | + extra_args=() + + if [ -n "${INPUT_GROUPS}" ]; then + while IFS= read -r group; do + if [ -n "${group}" ]; then + extra_args+=("--group=${group}") + fi + done <<<"${INPUT_GROUPS}" + fi + + uv pip install . "${extra_args[@]}" diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml new file mode 100644 index 00000000..1be3e7d6 --- /dev/null +++ b/.github/workflows/build.yml @@ -0,0 +1,203 @@ +# SPDX-FileCopyrightText: (c) TagStudio Contributors +# SPDX-License-Identifier: CC0-1.0 + +# TODO: This will be invoked by a 'Release' workflow in the future. +--- +name: Build + +on: + push: + tags: + - v* + schedule: + # From: https://docs.github.com/en/actions/reference/workflows-and-actions/events-that-trigger-workflows#schedule + # To decrease the chance of delay, schedule your workflow to run at a different time of the hour. + - cron: 42 3 * * * + timezone: America/Los_Angeles + workflow_dispatch: + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + +defaults: + run: + shell: sh + +jobs: + meta: + name: Metadata + runs-on: ubuntu-latest + outputs: + type: ${{ steps.meta.outputs.type }} + version: ${{ steps.meta.outputs.version }} + steps: + - name: Set metadata + id: meta + run: | + type=Nightly + if [ "${GITHUB_REF_TYPE}" = tag ]; then + case ${GITHUB_REF_NAME} in + v*) + type=Release + case ${GITHUB_REF_NAME} in + *-pr*) type=Pre-${type} ;; + esac + ;; + esac + fi + + if [ ${type} = Nightly ]; then + version=dev+$(date --iso-8601 | tr -d -) + else + version=${GITHUB_REF_NAME} + fi + + cat <>"${GITHUB_OUTPUT}" + type=${type} + version=${version} + EOF + + build: + strategy: + fail-fast: ${{ needs.meta.outputs.type != 'Nightly' }} + matrix: + include: + - os: ubuntu-22.04 + os-label: Linux x86 + + - os: macos-15-intel + os-label: macOS x86 + + - os: macos-15 + os-label: macOS ARM + + - os: windows-2022 + os-label: Windows x86 + + name: Build${{ needs.meta.outputs.type && format(' {0}', needs.meta.outputs.type) }}${{ matrix.os-label && format(' ({0})', matrix.os-label) }} + needs: meta + runs-on: ${{ matrix.os }} + env: + BUILD_PREFIX: tagstudio_${{ needs.meta.outputs.version }} + steps: + - name: Prepare build (Windows) + if: runner.os == 'Windows' + shell: pwsh + run: | + $dir = "${env:RUNNER_TEMP}/upload" + New-Item -Path ${dir} -ItemType Directory -Force + + $os = ${env:RUNNER_OS}.ToLower() + $arch = uname -m + + $commonPath = "${dir}/${env:BUILD_PREFIX}_${os}_${arch}" + Add-Content -Path ${env:GITHUB_ENV} -Value @" + BUILD_ARTIFACT_DEFAULT=${commonPath}.zip + BUILD_ARTIFACT_PORTABLE=${commonPath}_portable.zip + "@ -Encoding utf8 + + - name: Prepare build (non-Windows) + if: runner.os != 'Windows' + run: | + dir=${RUNNER_TEMP}/upload + mkdir -p "${dir}" + os=$( + tr '[:upper:]' '[:lower:]' <>"${GITHUB_ENV}" + BUILD_ARTIFACT_DEFAULT=${artifact_default} + ${artifact_portable:+BUILD_ARTIFACT_PORTABLE=${artifact_portable}} + EOF + + - name: Checkout repository + uses: actions/checkout@v7 + + - name: Setup Python + uses: ./.github/actions/setup-python + with: + groups: build + + - parallel: + - name: Run PyInstaller (Linux) + if: runner.os == 'Linux' + run: | + pyinstaller --distpath dist/default --workpath build/default scripts/tagstudio.spec + tar czf "${BUILD_ARTIFACT_DEFAULT}" -C dist/default/tagstudio . + + - name: Run PyInstaller (Linux portable) + if: runner.os == 'Linux' + run: | + pyinstaller --distpath dist/portable --workpath build/portable scripts/tagstudio.spec -- --portable + tar czf "${BUILD_ARTIFACT_PORTABLE}" -C dist/portable tagstudio + + - name: Run PyInstaller (macOS) + if: runner.os == 'macOS' + run: | + scripts/tagstudio.spec + tar czf "${BUILD_ARTIFACT_DEFAULT}" -C dist TagStudio.app + + - name: Run PyInstaller (Windows) + if: runner.os == 'Windows' + shell: pwsh + run: | + PyInstaller --distpath dist/default --workpath build/default scripts/tagstudio.spec + Compress-Archive -Path dist/default/TagStudio -DestinationPath ${env:BUILD_ARTIFACT_DEFAULT} + + - name: Run PyInstaller (Windows portable) + if: runner.os == 'Windows' + shell: pwsh + run: | + PyInstaller --distpath dist/portable --workpath build/portable scripts/tagstudio.spec -- --portable + Compress-Archive -Path dist/portable/TagStudio.exe -DestinationPath ${env:BUILD_ARTIFACT_PORTABLE} + + - parallel: + - name: Upload build artifact + uses: actions/upload-artifact@v7 + with: + path: ${{ env.BUILD_ARTIFACT_DEFAULT }} + if-no-files-found: error + # Short retention for 'Pre-Release' and 'Release' because they get uploaded to a GitHub release. + retention-days: &upload-artifact-retention-days ${{ case(needs.meta.outputs.type == 'Nightly', '7', '1') }} + archive: false + + - name: Upload build artifact (portable) + if: env.BUILD_ARTIFACT_PORTABLE != '' + uses: actions/upload-artifact@v7 + with: + path: ${{ env.BUILD_ARTIFACT_PORTABLE }} + if-no-files-found: error + retention-days: *upload-artifact-retention-days + archive: false + + upload: + permissions: + contents: write + + name: Upload Builds to Release + needs: [meta, build] + if: needs.meta.outputs.type != 'Nightly' + runs-on: ubuntu-latest + steps: + - name: Download build artifacts + uses: actions/download-artifact@v8 + with: + path: ${{ runner.temp }}/download + merge-multiple: 'true' + skip-decompress: 'true' + + - name: Upload build artifacts to release + uses: softprops/action-gh-release@v3 + with: + files: ${{ runner.temp }}/download/* diff --git a/.github/workflows/build_docs.yml b/.github/workflows/build_docs.yml new file mode 100644 index 00000000..7c8665c4 --- /dev/null +++ b/.github/workflows/build_docs.yml @@ -0,0 +1,57 @@ +# SPDX-FileCopyrightText: (c) TagStudio Contributors +# SPDX-License-Identifier: CC0-1.0 + +# TODO: In the future, docs will be built (but not published) for PRs. +--- +name: Build Docs + +on: + push: + branches: + - main + paths: + - .github/actions/setup-python/action.yml + - .github/workflows/build_docs.yml + - docs/** + - CHANGELOG.md + - mkdocs.yml + workflow_dispatch: + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + +defaults: + run: + shell: sh + +jobs: + publish: + concurrency: + group: ${{ github.workflow }} + cancel-in-progress: true + permissions: + contents: write + + name: Publish Docs + runs-on: ubuntu-latest + steps: + - name: Checkout repository + uses: actions/checkout@v7 + + - name: Setup Python + uses: ./.github/actions/setup-python + with: + groups: docs + + - name: Use cache + uses: actions/cache@v6 + with: + key: mkdocs-material-${{ github.run_id }} + path: .cache + restore-keys: | + mkdocs-material- + - name: Run mkdocs + env: + DISABLE_MKDOCS_2_WARNING: 'true' + run: mkdocs gh-deploy --force diff --git a/.github/workflows/checks_python.yml b/.github/workflows/checks_python.yml new file mode 100644 index 00000000..62d0e59b --- /dev/null +++ b/.github/workflows/checks_python.yml @@ -0,0 +1,171 @@ +# SPDX-FileCopyrightText: (c) TagStudio Contributors +# SPDX-License-Identifier: CC0-1.0 +--- +name: Checks (Python) + +on: + pull_request: + paths: &on_paths + - .github/actions/setup-python/action.yml + - .github/workflows/checks_python.yml + - .editorconfig + - pyproject.toml + - pyrightconfig.json + - pytest.ini + - uv.lock + - '**.py' + push: + paths: *on_paths + workflow_dispatch: + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + +defaults: + run: + shell: sh + +jobs: + run-conditions: + name: Run Conditions + runs-on: ubuntu-latest + outputs: + pyright: ${{ steps.run-conditions.outputs.pyright }} + pytest: ${{ steps.run-conditions.outputs.pytest }} + ruff: ${{ steps.run-conditions.outputs.ruff }} + steps: + - name: Checkout repository + uses: actions/checkout@v7 + with: + fetch-depth: 0 + + - name: Check changed files + id: changed-files + uses: tj-actions/changed-files@v47.0.6 + with: + files_yaml: | + generic: + - .github/workflows/checks_python.yml + - pyproject.toml + - uv.lock + - '**.py' + pyright: + - .github/actions/setup-python/action.yml + - pyrightconfig.json + pytest: + - .github/actions/setup-python/action.yml + - pytest.ini + ruff: + - .editorconfig + + - name: Set run conditions + id: run-conditions + run: | + cat <>"${GITHUB_OUTPUT}" + pyright=${{ steps.changed-files.outputs.generic_any_changed || steps.changed-files.outputs.pyright_any_changed }} + pytest=${{ steps.changed-files.outputs.generic_any_changed || steps.changed-files.outputs.pytest_any_changed }} + ruff=${{ steps.changed-files.outputs.generic_any_changed || steps.changed-files.outputs.ruff_any_changed }} + EOF + + check-pyright: + name: Pyright + needs: run-conditions + if: needs.run-conditions.outputs.pyright == 'true' + runs-on: ubuntu-latest + steps: + - &checkout + name: Checkout repository + uses: actions/checkout@v7 + + - name: Setup Python + uses: ./.github/actions/setup-python + with: + groups: | + pyright + pytest + + - name: Execute Pyright + run: pyright + + check-pytest: + strategy: + fail-fast: false + matrix: + include: + - os: ubuntu-22.04 + os-label: Linux + + - os: macos-latest + os-label: macOS + + - os: windows-2022 + os-label: Windows + + name: pytest${{ matrix.os-label && format(' ({0})', matrix.os-label) }} + needs: run-conditions + if: needs.run-conditions.outputs.pytest == 'true' + runs-on: ${{ matrix.os }} + steps: + - *checkout + + - name: Setup Python + uses: ./.github/actions/setup-python + with: + groups: pytest + + - name: Install system dependencies (Linux) + if: runner.os == 'Linux' + run: | + sudo apt-get update + sudo apt-get install -y --no-install-recommends \ + libegl1 \ + libgl1 \ + libopengl0 \ + libpulse0 \ + libxcb-cursor0 \ + libxcb-icccm4 \ + libxcb-image0 \ + libxcb-keysyms1 \ + libxcb-randr0 \ + libxcb-render-util0 \ + libxcb-xinerama0 \ + libxkbcommon-x11-0 \ + libyaml-dev \ + ripgrep \ + x11-utils + + - name: Install system dependencies (macOS) + if: runner.os == 'macOS' + run: brew install ripgrep + + - name: Install system dependencies (Windows) + if: runner.os == 'Windows' + shell: pwsh + run: choco install ripgrep + + - name: Execute pytest (Windows) + if: runner.os == 'Windows' + shell: pwsh + run: pytest + + - name: Execute pytest (non-Windows) + if: runner.os != 'Windows' + run: pytest + + check-ruff: + name: Ruff + needs: run-conditions + if: needs.run-conditions.outputs.ruff == 'true' + runs-on: ubuntu-latest + steps: + - *checkout + + - parallel: + - name: Run Ruff linter + uses: astral-sh/ruff-action@v4.0.0 + + - name: Run Ruff formatter + uses: astral-sh/ruff-action@v4.0.0 + with: + args: format --check diff --git a/.github/workflows/publish_docs.yaml b/.github/workflows/publish_docs.yaml deleted file mode 100644 index 2482ac60..00000000 --- a/.github/workflows/publish_docs.yaml +++ /dev/null @@ -1,51 +0,0 @@ -# SPDX-FileCopyrightText: (c) TagStudio Contributors -# SPDX-License-Identifier: GPL-3.0-only ---- -name: Publish Docs - -on: - push: - branches: - - main - paths: - - .github/workflows/publish_docs.yaml - - docs/** - - mkdocs.yml - - CHANGELOG.md - -permissions: - contents: write - -concurrency: - group: publish-docs - cancel-in-progress: true - -jobs: - deploy: - runs-on: ubuntu-latest - steps: - - name: Checkout repo - uses: actions/checkout@v4 - - - name: Setup Python - uses: actions/setup-python@v5 - with: - python-version: "3.12" - cache: pip - - - name: Install Python dependencies - run: | - python -m pip install --upgrade uv - uv pip install --system . --group mkdocs - - - run: echo "cache_id=$(date --utc '+%V')" >> $GITHUB_ENV - - - uses: actions/cache@v4 - with: - key: mkdocs-material-${{ env.cache_id }} - path: .cache - restore-keys: | - mkdocs-material- - - - name: Execute mkdocs - run: mkdocs gh-deploy --force diff --git a/.github/workflows/pyright.yaml b/.github/workflows/pyright.yaml deleted file mode 100644 index 9b3ebb34..00000000 --- a/.github/workflows/pyright.yaml +++ /dev/null @@ -1,31 +0,0 @@ -# SPDX-FileCopyrightText: (c) TagStudio Contributors -# SPDX-License-Identifier: GPL-3.0-only ---- -name: Pyright - -on: [push, pull_request] - -jobs: - pyright: - name: Run Pyright - runs-on: ubuntu-latest - steps: - - name: Checkout repo - uses: actions/checkout@v4 - - - name: Setup Python - uses: actions/setup-python@v5 - with: - python-version: "3.12" - cache: pip - - - name: Install Python dependencies - run: | - python -m pip install --upgrade uv - uv pip install --system . --group pyright --group pytest - - - name: Execute Pyright - uses: jordemort/action-pyright@v1 - with: - github_token: ${{ secrets.GITHUB_TOKEN }} - reporter: ${{ github.event_name == 'pull_request' && 'github-pr-review' || 'github-check' }} diff --git a/.github/workflows/pytest.yaml b/.github/workflows/pytest.yaml deleted file mode 100644 index 29b74e0b..00000000 --- a/.github/workflows/pytest.yaml +++ /dev/null @@ -1,70 +0,0 @@ -# SPDX-FileCopyrightText: (c) TagStudio Contributors -# SPDX-License-Identifier: GPL-3.0-only ---- -name: pytest - -on: [push, pull_request] - -jobs: - pytest-linux: - name: Run pytest (Linux) - runs-on: ubuntu-24.04 - - steps: - - &checkout - name: Checkout repo - uses: actions/checkout@v4 - - - &setup-python - name: Setup Python - uses: actions/setup-python@v5 - with: - python-version: "3.12" - cache: pip - - - &install-dependencies - name: Install Python dependencies - run: | - python -m pip install --upgrade uv - uv pip install --system . --group pytest - - - name: Install system dependencies - run: | - sudo apt-get update - sudo apt-get install -y --no-install-recommends \ - libegl1 \ - libgl1 \ - libopengl0 \ - libpulse0 \ - libxcb-cursor0 \ - libxcb-icccm4 \ - libxcb-image0 \ - libxcb-keysyms1 \ - libxcb-randr0 \ - libxcb-render-util0 \ - libxcb-xinerama0 \ - libxkbcommon-x11-0 \ - libyaml-dev \ - ripgrep \ - x11-utils - - - name: Execute pytest - run: | - xvfb-run pytest --cov-report xml --cov=tagstudio - - pytest-windows: - name: Run pytest (Windows) - runs-on: windows-2025 - - steps: - - *checkout - - *setup-python - - *install-dependencies - - - name: Install system dependencies - run: | - choco install ripgrep - - - name: Execute pytest - run: | - pytest diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml deleted file mode 100644 index 681b7528..00000000 --- a/.github/workflows/release.yml +++ /dev/null @@ -1,156 +0,0 @@ -# SPDX-FileCopyrightText: (c) TagStudio Contributors -# SPDX-License-Identifier: GPL-3.0-only ---- -name: Release - -on: - push: - tags: - - v[0-9]+.[0-9]+.[0-9]+* - -jobs: - linux: - strategy: - matrix: - build-type: ["", portable] - include: - - build-type: "" - build-flag: "" - suffix: "" - - build-type: portable - build-flag: --portable - suffix: _portable - runs-on: ubuntu-22.04 - steps: - - name: Checkout repo - uses: actions/checkout@v4 - - - name: Setup Python - uses: actions/setup-python@v5 - with: - python-version: "3.12" - cache: pip - - - name: Install Python dependencies - run: | - python -m pip install --upgrade uv - uv pip install --system . --group pyinstaller - - - name: Execute PyInstaller - run: | - pyinstaller tagstudio.spec -- ${{ matrix.build-flag }} - tar czfC dist/tagstudio_linux_x86_64${{ matrix.suffix }}.tar.gz dist tagstudio - - - name: Upload artifact - uses: actions/upload-artifact@v4 - with: - name: tagstudio_linux_x86_64${{ matrix.suffix }} - path: dist/tagstudio_linux_x86_64${{ matrix.suffix }}.tar.gz - - macos: - strategy: - matrix: - os-version: ["14", "15"] - include: - - os-version: "14" - arch: x86_64 - - os-version: "15" - arch: aarch64 - - runs-on: macos-${{ matrix.os-version }} - - env: - # INFO: Even though we run on 14, target towards compatibility - MACOSX_DEPLOYMENT_TARGET: "11.0" - - steps: - - name: Checkout repo - uses: actions/checkout@v4 - - - name: Setup Python - uses: actions/setup-python@v5 - with: - python-version: "3.12" - cache: pip - - - name: Install Python dependencies - run: | - python -m pip install --upgrade uv - uv pip install --system . --group pyinstaller - - - name: Execute PyInstaller - run: | - pyinstaller tagstudio.spec - tar czfC dist/tagstudio_macos_${{ matrix.arch }}.tar.gz dist TagStudio.app - - name: Upload artifact - uses: actions/upload-artifact@v4 - with: - name: tagstudio_macos_${{ matrix.arch }} - path: dist/tagstudio_macos_${{ matrix.arch }}.tar.gz - - windows: - strategy: - matrix: - build-type: ["", portable] - include: - - build-type: "" - build-flag: "" - suffix: "" - file-end: "" - - build-type: portable - build-flag: --portable - suffix: _portable - file-end: .exe - - runs-on: windows-2022 - - steps: - - name: Checkout repo - uses: actions/checkout@v4 - - - name: Setup Python - uses: actions/setup-python@v5 - with: - python-version: "3.12" - cache: pip - - - name: Install Python dependencies - run: | - python -m pip install --upgrade uv - uv pip install --system . --group pyinstaller - - - name: Execute PyInstaller - run: | - PyInstaller tagstudio.spec -- ${{ matrix.build-flag }} - Compress-Archive -Path dist/TagStudio${{ matrix.file-end }} -DestinationPath dist/tagstudio_windows_x86_64${{ matrix.suffix }}.zip - - name: Upload artifact - uses: actions/upload-artifact@v4 - with: - name: tagstudio_windows_x86_64${{ matrix.suffix }} - path: dist/tagstudio_windows_x86_64${{ matrix.suffix }}.zip - - publish: - needs: [linux, macos, windows] - - runs-on: ubuntu-latest - - permissions: - contents: write - - steps: - - name: Checkout repo - uses: actions/checkout@v4 - - - name: Fetch artifacts - uses: actions/download-artifact@v4 - - - name: Publish release - uses: softprops/action-gh-release@v2 - with: - files: | - tagstudio_linux_x86_64/* - tagstudio_linux_x86_64_portable/* - tagstudio_macos_x86_64/* - tagstudio_macos_aarch64/* - tagstudio_windows_x86_64/* - tagstudio_windows_x86_64_portable/* diff --git a/.github/workflows/reuse.yaml b/.github/workflows/reuse.yaml deleted file mode 100644 index 4a39733f..00000000 --- a/.github/workflows/reuse.yaml +++ /dev/null @@ -1,12 +0,0 @@ -# SPDX-FileCopyrightText: 2020 Free Software Foundation Europe e.V. -# SPDX-License-Identifier: CC0-1.0 -name: REUSE compliance check -on: [push, pull_request] - -jobs: - test: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v5 - - name: REUSE Compliance Check - uses: fsfe/reuse-action@v6 diff --git a/.github/workflows/reuse.yml b/.github/workflows/reuse.yml new file mode 100644 index 00000000..af710d93 --- /dev/null +++ b/.github/workflows/reuse.yml @@ -0,0 +1,25 @@ +# SPDX-FileCopyrightText: (c) TagStudio Contributors +# SPDX-License-Identifier: CC0-1.0 +--- +name: REUSE Compliance Check + +on: [pull_request, push] + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + +defaults: + run: + shell: sh + +jobs: + check: + name: REUSE + runs-on: ubuntu-latest + steps: + - name: Checkout repository + uses: actions/checkout@v7 + + - name: Run REUSE + uses: fsfe/reuse-action@v6 diff --git a/.github/workflows/ruff.yaml b/.github/workflows/ruff.yaml deleted file mode 100644 index bb7b128e..00000000 --- a/.github/workflows/ruff.yaml +++ /dev/null @@ -1,33 +0,0 @@ -# SPDX-FileCopyrightText: (c) TagStudio Contributors -# SPDX-License-Identifier: GPL-3.0-only ---- -name: Ruff - -on: [push, pull_request] - -jobs: - ruff-format: - name: Run Ruff format - runs-on: ubuntu-latest - steps: - - name: Checkout repo - uses: actions/checkout@v4 - - - name: Execute Ruff format - uses: astral-sh/ruff-action@v3 - with: - version: 0.15.17 - args: format --check - - ruff-check: - name: Run Ruff check - runs-on: ubuntu-latest - steps: - - name: Checkout repo - uses: actions/checkout@v4 - - - name: Execute Ruff check - uses: astral-sh/ruff-action@v3 - with: - version: 0.15.17 - args: check diff --git a/nix/package/pillow-jxl-plugin.nix b/nix/package/pillow-jxl-plugin.nix index 4b8ecba5..1d4b6762 100644 --- a/nix/package/pillow-jxl-plugin.nix +++ b/nix/package/pillow-jxl-plugin.nix @@ -1,7 +1,6 @@ # SPDX-FileCopyrightText: (c) TagStudio Contributors # SPDX-License-Identifier: GPL-3.0-only - { buildPythonPackage, cmake, diff --git a/nix/package/pyexiv2.nix b/nix/package/pyexiv2.nix index a9cb9c41..bc51d756 100644 --- a/nix/package/pyexiv2.nix +++ b/nix/package/pyexiv2.nix @@ -1,7 +1,6 @@ # SPDX-FileCopyrightText: (c) TagStudio Contributors # SPDX-License-Identifier: GPL-3.0-only - { autoPatchelfHook, buildPythonPackage, diff --git a/scripts/semver-segments.pl b/scripts/semver-segments.pl new file mode 100755 index 00000000..edbe8582 --- /dev/null +++ b/scripts/semver-segments.pl @@ -0,0 +1,14 @@ +#!/usr/bin/env perl +# SPDX-FileCopyrightText: (c) TagStudio Contributors +# SPDX-License-Identifier: CC0-1.0 + +use strict; +use warnings; +use feature 'say'; + +# From: https://regex101.com/r/vkijKf/1 +if (($ARGV[0] // ) =~ /^(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)(?:-((?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*)(?:\.(?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*))*))?(?:\+([0-9a-zA-Z-]+(?:\.[0-9a-zA-Z-]+)*))?$/) { + foreach my $index (0 .. $#{^CAPTURE}) { + say ${^CAPTURE}[$index] // ""; + } +} diff --git a/scripts/tagstudio.spec b/scripts/tagstudio.spec old mode 100644 new mode 100755 index 2e1984e7..995e0195 --- a/scripts/tagstudio.spec +++ b/scripts/tagstudio.spec @@ -1,17 +1,22 @@ +#!/usr/bin/env -S python -m PyInstaller # vi: ft=python # SPDX-FileCopyrightText: (c) TagStudio Contributors # SPDX-License-Identifier: GPL-3.0-only +import argparse import platform from argparse import ArgumentParser +from pathlib import Path +from tomllib import load from PyInstaller.building.api import COLLECT, EXE, PYZ from PyInstaller.building.build_main import Analysis from PyInstaller.building.osx import BUNDLE -from tomllib import load parser = ArgumentParser() +# HACK: Without this, the script will fail if empty arguments are passed. +parser.add_argument("_", nargs="*", help=argparse.SUPPRESS) parser.add_argument("--portable", action="store_true") options = parser.parse_args() @@ -20,23 +25,24 @@ with open("pyproject.toml", "rb") as file: system = platform.system() +project_root = Path("..", "src/tagstudio") name = pyproject["name"] if system == "Windows" else "tagstudio" icon = None if system == "Windows": - icon = "src/tagstudio/resources/icon.ico" + icon = Path(project_root, "resources/icon.ico") elif system == "Darwin": - icon = "src/tagstudio/resources/icon.icns" + icon = Path(project_root, "resources/icon.icns") datafiles = [ - ("src/tagstudio/qt/*.json", "tagstudio/qt"), - ("src/tagstudio/qt/*.qrc", "tagstudio/qt"), - ("src/tagstudio/resources", "tagstudio/resources"), + (f"{project_root}/qt/*.json", "tagstudio/qt"), + (f"{project_root}/qt/*.qrc", "tagstudio/qt"), + (f"{project_root}/resources", "tagstudio/resources"), ] a = Analysis( - ["src/tagstudio/main.py"], - pathex=["src"], + [Path(project_root, "main.py")], + pathex=[], binaries=[], datas=datafiles, hiddenimports=[],