feat(ci)!: complete workflows revamp (#1437)

* chore(ci): move spec-file into scripts

* 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).

* ci: remove symlinked CHANGELONG.md from build_docs.yml paths

* docs: update location of tagstudio.spec

* ci: enforce single quotes in github yaml files

* ci(tests): remove macOS pytest runner

---------

Co-authored-by: Travis Abendshien <46939827+CyanVoxel@users.noreply.github.com>
This commit is contained in:
Xarvex
2026-07-09 00:49:57 -05:00
committed by GitHub
parent 993eeff0fc
commit 377593b190
17 changed files with 546 additions and 365 deletions
+14
View File
@@ -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] // <STDIN>) =~ /^(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] // "";
}
}
+109
View File
@@ -0,0 +1,109 @@
#!/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
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()
with open("pyproject.toml", "rb") as file:
pyproject = load(file)["project"]
system = platform.system()
project_root = Path("..", "src/tagstudio")
name = pyproject["name"] if system == "Windows" else "tagstudio"
icon = None
if system == "Windows":
icon = Path(project_root, "resources/icon.ico")
elif system == "Darwin":
icon = Path(project_root, "resources/icon.icns")
datafiles = [
(f"{project_root}/qt/*.json", "tagstudio/qt"),
(f"{project_root}/qt/*.qrc", "tagstudio/qt"),
(f"{project_root}/resources", "tagstudio/resources"),
]
a = Analysis(
[Path(project_root, "main.py")],
pathex=[],
binaries=[],
datas=datafiles,
hiddenimports=[],
hookspath=[],
hooksconfig={},
excludes=[],
runtime_hooks=[],
noarchive=False,
optimize=0,
)
pyz = PYZ(a.pure)
include = [a.scripts]
if options.portable:
include += (a.binaries, a.datas)
exe = EXE(
pyz,
*include,
[],
bootloader_ignore_signals=False,
console=False,
hide_console="hide-early",
disable_windowed_traceback=False,
debug=False,
name=name,
exclude_binaries=not options.portable,
icon=icon,
argv_emulation=False,
target_arch=None,
codesign_identity=None,
entitlements_file=None,
strip=False,
upx=True,
upx_exclude=[],
runtime_tmpdir=None,
)
coll = (
None
if options.portable
else COLLECT(
exe,
a.binaries,
a.datas,
name=name,
strip=False,
upx=True,
upx_exclude=[],
)
)
if system == "Darwin":
app = BUNDLE(
exe if coll is None else coll,
name=f"{pyproject['name']}.app",
icon=icon,
bundle_identifier="com.cyanvoxel.tagstudio",
version=pyproject["version"],
info_plist={
"NSAppleScriptEnabled": False,
"NSPrincipalClass": "NSApplication",
},
)