chore: import upstream snapshot with attribution
CI / lint (push) Has been cancelled
CI / js-syntax (push) Successful in 10m24s
CI / deps-audit (push) Has been cancelled
CI / test (push) Failing after 24m55s
CI / sast-bandit (push) Failing after 11m13s
CI / trivy (push) Failing after 9m32s
Docker Publish / build-and-push (push) Failing after 34m3s
CI / lint (push) Has been cancelled
CI / js-syntax (push) Successful in 10m24s
CI / deps-audit (push) Has been cancelled
CI / test (push) Failing after 24m55s
CI / sast-bandit (push) Failing after 11m13s
CI / trivy (push) Failing after 9m32s
Docker Publish / build-and-push (push) Failing after 34m3s
This commit is contained in:
@@ -0,0 +1,72 @@
|
||||
name: Bug report
|
||||
description: Something isn't working as expected.
|
||||
title: "[Bug]: "
|
||||
labels: ["bug"]
|
||||
body:
|
||||
- type: markdown
|
||||
attributes:
|
||||
value: Thanks for reporting a bug. Please fill in the details so we can reproduce it.
|
||||
- type: checkboxes
|
||||
id: preflight
|
||||
attributes:
|
||||
label: Before reporting
|
||||
options:
|
||||
- label: I'm on the latest release and the issue still happens.
|
||||
required: true
|
||||
- label: I searched existing issues and didn't find a duplicate.
|
||||
required: true
|
||||
- type: textarea
|
||||
id: what
|
||||
attributes:
|
||||
label: What happened?
|
||||
description: A clear description of the bug and what you expected instead.
|
||||
placeholder: When I ..., StemDeck ... but I expected ...
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
id: steps
|
||||
attributes:
|
||||
label: Steps to reproduce
|
||||
placeholder: |
|
||||
1. Open StemDeck
|
||||
2. Import ...
|
||||
3. Click ...
|
||||
4. See error
|
||||
validations:
|
||||
required: true
|
||||
- type: dropdown
|
||||
id: os
|
||||
attributes:
|
||||
label: Operating system
|
||||
options:
|
||||
- macOS (Apple Silicon)
|
||||
- macOS (Intel)
|
||||
- Windows
|
||||
- Linux
|
||||
- Other
|
||||
validations:
|
||||
required: true
|
||||
- type: input
|
||||
id: version
|
||||
attributes:
|
||||
label: StemDeck version
|
||||
description: Shown in the About dialog (Help icon).
|
||||
placeholder: e.g. v0.7.0-alpha.12
|
||||
validations:
|
||||
required: true
|
||||
- type: dropdown
|
||||
id: install
|
||||
attributes:
|
||||
label: How did you install it?
|
||||
options:
|
||||
- macOS DMG
|
||||
- Windows ZIP
|
||||
- From source
|
||||
- Docker / self-hosted
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
id: extra
|
||||
attributes:
|
||||
label: Logs / screenshots
|
||||
description: Drag in screenshots or a recording, and paste any error text as code.
|
||||
@@ -0,0 +1,11 @@
|
||||
blank_issues_enabled: false
|
||||
contact_links:
|
||||
- name: Questions & Discussion
|
||||
url: https://github.com/stemdeckapp/stemdeck/discussions
|
||||
about: Ask questions, share setups, or discuss ideas with the community.
|
||||
- name: Discord
|
||||
url: https://discord.gg/2MVsWqaPRe
|
||||
about: Chat with the StemDeck community in real time.
|
||||
- name: Report a security vulnerability
|
||||
url: https://github.com/stemdeckapp/stemdeck/security/advisories/new
|
||||
about: Please report security issues privately, not as a public issue.
|
||||
@@ -0,0 +1,25 @@
|
||||
name: Feature request
|
||||
description: Suggest an idea or improvement.
|
||||
title: "[Feature]: "
|
||||
labels: ["enhancement"]
|
||||
body:
|
||||
- type: markdown
|
||||
attributes:
|
||||
value: Thanks for the suggestion! Tell us what you'd like and why.
|
||||
- type: textarea
|
||||
id: problem
|
||||
attributes:
|
||||
label: What problem does this solve?
|
||||
description: What are you trying to do that's hard or impossible today?
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
id: proposal
|
||||
attributes:
|
||||
label: Proposed solution
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
id: alternatives
|
||||
attributes:
|
||||
label: Alternatives considered
|
||||
@@ -0,0 +1,6 @@
|
||||
version: 2
|
||||
updates:
|
||||
- package-ecosystem: github-actions
|
||||
directory: /
|
||||
schedule:
|
||||
interval: weekly
|
||||
@@ -0,0 +1,143 @@
|
||||
# GitHub Actions: lint + unit tests + security scans.
|
||||
# Does not build or publish artifacts. Image scanning is done via
|
||||
# trivy fs on the project tree (covers deps, secrets, and Dockerfile
|
||||
# misconfig) so CI does not need a docker-in-docker setup.
|
||||
|
||||
name: CI
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
push:
|
||||
branches: [main]
|
||||
release:
|
||||
types: [published]
|
||||
|
||||
env:
|
||||
UV_LINK_MODE: copy
|
||||
# Version is git-derived (hatch-vcs). CI's clone is shallow/tagless, which
|
||||
# makes setuptools_scm raise, so pin a placeholder for the build -- CI only
|
||||
# lints/tests and never publishes. #169
|
||||
SETUPTOOLS_SCM_PRETEND_VERSION: "0.0.0"
|
||||
|
||||
jobs:
|
||||
lint:
|
||||
runs-on: ubuntu-latest
|
||||
container:
|
||||
image: ghcr.io/astral-sh/uv:python3.12-bookworm-slim
|
||||
steps:
|
||||
- uses: actions/checkout@v7
|
||||
- run: uv sync --frozen --all-extras
|
||||
- run: uv run ruff check app/ tests/
|
||||
- run: uv run ruff format --check app/ tests/
|
||||
- run: bash -n run.sh
|
||||
|
||||
test:
|
||||
runs-on: ubuntu-latest
|
||||
container:
|
||||
image: ghcr.io/astral-sh/uv:python3.12-bookworm-slim
|
||||
steps:
|
||||
- uses: actions/checkout@v7
|
||||
- run: apt-get update && apt-get install -y --no-install-recommends ffmpeg
|
||||
- run: uv sync --frozen --all-extras
|
||||
- run: uv run pytest tests/ -q
|
||||
|
||||
js-syntax:
|
||||
runs-on: ubuntu-latest
|
||||
container:
|
||||
image: node:20-alpine
|
||||
steps:
|
||||
- uses: actions/checkout@v7
|
||||
- run: for f in static/js/*.js; do node --check "$f"; done
|
||||
|
||||
sast-bandit:
|
||||
runs-on: ubuntu-latest
|
||||
container:
|
||||
image: ghcr.io/astral-sh/uv:python3.12-bookworm-slim
|
||||
steps:
|
||||
- uses: actions/checkout@v7
|
||||
- run: uv tool install bandit
|
||||
- run: uv tool run bandit -r app/ -ll # fail on medium+ severity
|
||||
|
||||
deps-audit:
|
||||
runs-on: ubuntu-latest
|
||||
container:
|
||||
image: ghcr.io/astral-sh/uv:python3.12-bookworm-slim
|
||||
steps:
|
||||
- uses: actions/checkout@v7
|
||||
- run: uv tool install pip-audit
|
||||
- run: uv pip compile pyproject.toml -o /tmp/requirements.txt
|
||||
# Ignored CVEs (review when upgrading torch or demucs):
|
||||
#
|
||||
# torch 2.6.0 -- pinned to <2.7 because torchaudio 2.7+ removed its
|
||||
# built-in audio writer and now requires torchcodec, which has ABI
|
||||
# issues that break demucs 4.0.1's torchaudio.save() path. All torch
|
||||
# CVEs below are in ops that StemDeck does not invoke; risk on a
|
||||
# local-only, single-user app is negligible. Re-evaluate once demucs
|
||||
# supports torch 2.7+ without torchcodec.
|
||||
#
|
||||
# joblib PYSEC-2024-277 -- no fix version available as of 2026-05-21
|
||||
# (1.5.3 is latest). joblib is a transitive dep via demucs/librosa;
|
||||
# StemDeck does not directly invoke joblib serialization. Drop once
|
||||
# a patched release is available.
|
||||
- run: |
|
||||
uv tool run pip-audit -r /tmp/requirements.txt --strict \
|
||||
--ignore-vuln CVE-2025-2953 \
|
||||
--ignore-vuln CVE-2025-3730 \
|
||||
--ignore-vuln PYSEC-2025-189 \
|
||||
--ignore-vuln PYSEC-2025-190 \
|
||||
--ignore-vuln PYSEC-2025-192 \
|
||||
--ignore-vuln PYSEC-2025-193 \
|
||||
--ignore-vuln PYSEC-2025-194 \
|
||||
--ignore-vuln PYSEC-2025-195 \
|
||||
--ignore-vuln PYSEC-2025-196 \
|
||||
--ignore-vuln PYSEC-2025-197 \
|
||||
--ignore-vuln PYSEC-2025-198 \
|
||||
--ignore-vuln PYSEC-2025-199 \
|
||||
--ignore-vuln PYSEC-2025-200 \
|
||||
--ignore-vuln PYSEC-2025-201 \
|
||||
--ignore-vuln PYSEC-2025-202 \
|
||||
--ignore-vuln PYSEC-2025-203 \
|
||||
--ignore-vuln PYSEC-2025-204 \
|
||||
--ignore-vuln PYSEC-2025-205 \
|
||||
--ignore-vuln PYSEC-2025-206 \
|
||||
--ignore-vuln PYSEC-2025-207 \
|
||||
--ignore-vuln PYSEC-2025-208 \
|
||||
--ignore-vuln PYSEC-2025-209 \
|
||||
--ignore-vuln PYSEC-2025-210 \
|
||||
--ignore-vuln PYSEC-2026-139 \
|
||||
--ignore-vuln PYSEC-2024-277 \
|
||||
--ignore-vuln CVE-2025-2148 \
|
||||
--ignore-vuln CVE-2025-2149 \
|
||||
--ignore-vuln CVE-2025-2998 \
|
||||
--ignore-vuln CVE-2025-2999 \
|
||||
--ignore-vuln CVE-2025-3000 \
|
||||
--ignore-vuln CVE-2025-3001
|
||||
|
||||
trivy:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v7
|
||||
# Scans the source tree for: known CVEs in deps, leaked secrets,
|
||||
# and Dockerfile / compose misconfigurations. Skips .venv (it can
|
||||
# be left over from earlier steps in the shared workspace; trivy
|
||||
# would scan its bundled extractor files and flag false-positive
|
||||
# secrets that ship inside third-party packages like yt-dlp).
|
||||
- name: trivy fs
|
||||
uses: aquasecurity/trivy-action@master
|
||||
with:
|
||||
scan-type: fs
|
||||
scan-ref: .
|
||||
scanners: vuln,secret,misconfig
|
||||
severity: HIGH,CRITICAL
|
||||
exit-code: '1'
|
||||
ignore-unfixed: true
|
||||
trivyignores: .trivyignore
|
||||
skip-dirs: .venv,jobs
|
||||
# Dedicated Dockerfile + compose static analysis (Trivy's IaC linter).
|
||||
- name: trivy config
|
||||
uses: aquasecurity/trivy-action@master
|
||||
with:
|
||||
scan-type: config
|
||||
scan-ref: build/
|
||||
severity: HIGH,CRITICAL
|
||||
exit-code: '1'
|
||||
@@ -0,0 +1,94 @@
|
||||
name: Docker Publish
|
||||
|
||||
# Builds the server container (build/Dockerfile) and pushes it to GHCR so it can
|
||||
# be pulled by self-hosted deployments and the Unraid Community Applications app
|
||||
# (ghcr.io/stemdeckapp/stemdeck). The image keeps the default Linux x86_64 torch
|
||||
# wheel, which is the CUDA build -- so the same image runs on CPU by default and
|
||||
# uses the GPU automatically when started with `--runtime=nvidia` (see the
|
||||
# Unraid template in templates/unraid/).
|
||||
|
||||
on:
|
||||
# Every merge to main publishes a rolling :edge image. The version is derived
|
||||
# from git (hatch-vcs style); :edge never clobbers :latest.
|
||||
push:
|
||||
branches: [main]
|
||||
release:
|
||||
# prereleased: a prerelease is published -> push the version tag only.
|
||||
# released: a stable release is published, OR a prerelease is promoted to
|
||||
# a full/Latest release -> push the version tag AND :latest.
|
||||
# (Listening to these two instead of `published` avoids a double run on a
|
||||
# stable publish, which fires both `published` and `released`.)
|
||||
types: [prereleased, released]
|
||||
# Same as a main push but on demand, from any ref.
|
||||
workflow_dispatch:
|
||||
|
||||
permissions: {}
|
||||
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.ref }}
|
||||
cancel-in-progress: true
|
||||
|
||||
env:
|
||||
IMAGE: ghcr.io/${{ github.repository_owner }}/stemdeck
|
||||
|
||||
jobs:
|
||||
build-and-push:
|
||||
runs-on: ubuntu-latest
|
||||
timeout-minutes: 60
|
||||
permissions:
|
||||
contents: read
|
||||
packages: write
|
||||
steps:
|
||||
- uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
|
||||
with:
|
||||
# Full history + tags so git describe can derive a version on manual runs.
|
||||
fetch-depth: 0
|
||||
|
||||
# Derive the version fed to the Dockerfile's VERSION build-arg (consumed as
|
||||
# SETUPTOOLS_SCM_PRETEND_VERSION, so it MUST be PEP 440-valid). On a
|
||||
# release, use the tag. Otherwise derive from git: `git describe --long`
|
||||
# yields `<tag>-<N>-g<sha>`, which is NOT PEP 440 -- rewrite the trailing
|
||||
# `-N-gSHA` into a `+N.gSHA` local segment (e.g. 0.8.0-alpha.5+3.gce86e8a).
|
||||
- name: resolve version
|
||||
id: ver
|
||||
run: |
|
||||
if [ "${{ github.event_name }}" = "release" ]; then
|
||||
v="${{ github.event.release.tag_name }}"
|
||||
else
|
||||
raw="$(git describe --tags --long 2>/dev/null || echo "0.0.0-0-g$(git rev-parse --short HEAD)")"
|
||||
v="$(printf '%s' "${raw#v}" | sed -E 's/-([0-9]+)-g([0-9a-f]+)$/+\1.g\2/')"
|
||||
fi
|
||||
echo "value=${v#v}" >> "$GITHUB_OUTPUT"
|
||||
|
||||
- name: docker metadata (tags/labels)
|
||||
id: meta
|
||||
uses: docker/metadata-action@dc802804100637a589fabce1cb79ff13a1411302 # v6.2.0
|
||||
with:
|
||||
images: ${{ env.IMAGE }}
|
||||
tags: |
|
||||
type=raw,value=edge,enable=${{ github.event_name == 'push' || github.event_name == 'workflow_dispatch' }}
|
||||
type=raw,value=${{ steps.ver.outputs.value }},enable=${{ github.event_name == 'release' }}
|
||||
type=raw,value=latest,enable=${{ github.event_name == 'release' && github.event.action == 'released' }}
|
||||
|
||||
- uses: docker/setup-buildx-action@bb05f3f5519dd87d3ba754cc423b652a5edd6d2c # v4.2.0
|
||||
|
||||
- name: log in to GHCR
|
||||
uses: docker/login-action@af1e73f918a031802d376d3c8bbc3fe56130a9b0 # v4.4.0
|
||||
with:
|
||||
registry: ghcr.io
|
||||
username: ${{ github.actor }}
|
||||
password: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
- name: build and push
|
||||
uses: docker/build-push-action@53b7df96c91f9c12dcc8a07bcb9ccacbed38856a # v7.3.0
|
||||
with:
|
||||
context: .
|
||||
file: build/Dockerfile
|
||||
# Unraid is x86_64; arm64 has no CUDA torch and is not a target.
|
||||
platforms: linux/amd64
|
||||
push: true
|
||||
build-args: |
|
||||
VERSION=${{ steps.ver.outputs.value }}
|
||||
tags: ${{ steps.meta.outputs.tags }}
|
||||
labels: ${{ steps.meta.outputs.labels }}
|
||||
provenance: false
|
||||
@@ -0,0 +1,147 @@
|
||||
name: Linux Release
|
||||
|
||||
on:
|
||||
release:
|
||||
types: [published]
|
||||
# Manual test build: builds and scans both variants on the self-hosted runner
|
||||
# but does NOT upload (no release to attach to). Lets you validate the runner
|
||||
# toolchain and the CUDA build without cutting a release tag.
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
version:
|
||||
description: "Version for the test build (must be valid PEP 440, e.g. 0.0.0)"
|
||||
required: false
|
||||
default: "0.0.0"
|
||||
|
||||
permissions: {}
|
||||
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.ref }}
|
||||
cancel-in-progress: true
|
||||
|
||||
jobs:
|
||||
build-and-upload:
|
||||
# Runner must be linux/x64 with rustup, Node.js, Docker, and sudo apt access.
|
||||
runs-on: [self-hosted, linux, x64]
|
||||
timeout-minutes: 90
|
||||
permissions:
|
||||
contents: write
|
||||
defaults:
|
||||
run:
|
||||
shell: bash
|
||||
steps:
|
||||
- name: clean workspace
|
||||
run: rm -rf .build dist
|
||||
|
||||
- uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
|
||||
|
||||
- name: install build dependencies
|
||||
env:
|
||||
DEBIAN_FRONTEND: noninteractive
|
||||
run: |
|
||||
# Tauri v2 build deps + tooling. webkit2gtk-4.1 matches the tauri = "2"
|
||||
# crate; ffmpeg is a runtime dependency, not bundled.
|
||||
#
|
||||
# The self-hosted runner does NOT have passwordless sudo, so a bare
|
||||
# `sudo apt-get` hangs forever at the password prompt. These packages are
|
||||
# already installed on the persistent runner, so check first (dpkg needs
|
||||
# no sudo) and skip apt entirely when everything is present. Only if a
|
||||
# package is genuinely missing do we touch apt, via `sudo -n` (fails fast
|
||||
# instead of prompting) so a release never hangs on sudo again.
|
||||
PKGS="build-essential curl file wget libssl-dev libxdo-dev \
|
||||
libwebkit2gtk-4.1-dev libgtk-3-dev libayatana-appindicator3-dev librsvg2-dev"
|
||||
missing=""
|
||||
for p in $PKGS; do
|
||||
dpkg -s "$p" >/dev/null 2>&1 || missing="$missing $p"
|
||||
done
|
||||
if [ -z "$missing" ]; then
|
||||
echo "All build dependencies already installed; skipping apt."
|
||||
exit 0
|
||||
fi
|
||||
echo "Missing packages:$missing"
|
||||
if ! sudo -n true 2>/dev/null; then
|
||||
echo "ERROR: build deps missing and passwordless sudo is not available." >&2
|
||||
echo "Install on the runner: sudo apt-get install -y$missing" >&2
|
||||
exit 1
|
||||
fi
|
||||
sudo -n apt-get update -o DPkg::Lock::Timeout=120
|
||||
sudo -n apt-get install -y --no-install-recommends -o DPkg::Lock::Timeout=120 $missing
|
||||
|
||||
- name: install uv
|
||||
run: |
|
||||
curl -LsSf https://astral.sh/uv/install.sh | sh
|
||||
echo "$HOME/.local/bin" >> "$GITHUB_PATH"
|
||||
|
||||
- name: install rust toolchain
|
||||
run: rustup default stable
|
||||
|
||||
- name: write version files
|
||||
env:
|
||||
DISPATCH_VERSION: ${{ inputs.version }}
|
||||
# github.ref_name (evaluated by Actions) instead of $GITHUB_REF_NAME,
|
||||
# which is only injected by runner >= 2.290 — empty on older
|
||||
# self-hosted runners.
|
||||
REF_NAME: ${{ github.ref_name }}
|
||||
run: |
|
||||
if [ "${{ github.event_name }}" = "workflow_dispatch" ]; then
|
||||
VERSION="${DISPATCH_VERSION#v}"
|
||||
else
|
||||
VERSION="${REF_NAME#v}"
|
||||
fi
|
||||
if [ -z "$VERSION" ]; then
|
||||
echo "Could not determine a version" >&2
|
||||
exit 1
|
||||
fi
|
||||
printf '{ "version": "%s" }\n' "$VERSION" > static/version.json
|
||||
sed -i "s/^version = \".*\"/version = \"$VERSION\"/" desktop/src-tauri/Cargo.toml
|
||||
sed -i "s/\"version\": \"[^\"]*\"/\"version\": \"$VERSION\"/" desktop/src-tauri/tauri.conf.json
|
||||
sed -i "s/^version = \".*\"/version = \"$VERSION\"/" pyproject.toml
|
||||
sed -i "s/\"version\": \"[^\"]*\"/\"version\": \"$VERSION\"/" desktop/package.json
|
||||
echo "VERSION=$VERSION" >> "$GITHUB_ENV"
|
||||
echo "Wrote version $VERSION to all version files"
|
||||
|
||||
- name: build Linux CPU
|
||||
run: |
|
||||
PACKAGE_NAME=StemDeck-Linux-x64 \
|
||||
PACKAGE_VERSION="$VERSION" \
|
||||
bash scripts/linux/make-portable.sh
|
||||
# Drop the uncompressed stage but keep the tarball; frees disk for the
|
||||
# larger NVIDIA build. The Tauri binary under target/ is preserved.
|
||||
rm -rf dist/StemDeck-Linux-x64
|
||||
|
||||
- name: build Linux NVIDIA
|
||||
run: |
|
||||
# CPU_ONLY=0 keeps the CUDA torch wheel; SKIP_TAURI_BUILD=1 reuses the
|
||||
# binary built in the CPU step (identical for both variants).
|
||||
PACKAGE_NAME=StemDeck-Linux-x64.NVIDIA \
|
||||
PACKAGE_VERSION="$VERSION" \
|
||||
CPU_ONLY=0 \
|
||||
SKIP_TAURI_BUILD=1 \
|
||||
bash scripts/linux/make-portable.sh
|
||||
rm -rf dist/StemDeck-Linux-x64.NVIDIA
|
||||
|
||||
- name: scan artifacts
|
||||
run: |
|
||||
echo "Artifacts staged in: $PWD/dist"
|
||||
ls -lh dist
|
||||
echo "SHA256 checksums:"
|
||||
( cd dist && sha256sum *.tar.gz )
|
||||
|
||||
echo "Pulling latest ClamAV scanner image..."
|
||||
docker pull clamav/clamav:latest
|
||||
|
||||
echo "Running ClamAV scan over dist/..."
|
||||
docker run --rm -v "$PWD/dist:/scan:ro" clamav/clamav:latest \
|
||||
clamscan --recursive --infected --bell /scan
|
||||
echo "ClamAV scan completed successfully. No infected files reported."
|
||||
|
||||
- name: upload artifacts
|
||||
# Only attach to a real release; a manual test build has nothing to upload to.
|
||||
if: github.event_name == 'release'
|
||||
uses: softprops/action-gh-release@718ea10b132b3b2eba29c1007bb80653f286566b # v3.0.1
|
||||
with:
|
||||
files: |
|
||||
dist/StemDeck-Linux-x64.tar.gz
|
||||
dist/StemDeck-Linux-x64.tar.gz.sha256
|
||||
dist/StemDeck-Linux-x64.NVIDIA.tar.gz
|
||||
dist/StemDeck-Linux-x64.NVIDIA.tar.gz.sha256
|
||||
@@ -0,0 +1,128 @@
|
||||
name: macOS Release
|
||||
|
||||
on:
|
||||
release:
|
||||
types: [published]
|
||||
|
||||
permissions: {}
|
||||
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.ref }}
|
||||
cancel-in-progress: true
|
||||
|
||||
jobs:
|
||||
build-and-upload:
|
||||
# Runner must be darwin/arm64 with Rosetta 2, Xcode CLT, Homebrew, rustup, and zstd.
|
||||
runs-on: [self-hosted, macOS, ARM64]
|
||||
timeout-minutes: 120
|
||||
permissions:
|
||||
contents: write
|
||||
defaults:
|
||||
run:
|
||||
shell: bash
|
||||
steps:
|
||||
- name: clean workspace
|
||||
run: rm -rf .build dist
|
||||
|
||||
- uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
|
||||
|
||||
- name: write version files
|
||||
env:
|
||||
# github.ref_name (evaluated by Actions) instead of $GITHUB_REF_NAME,
|
||||
# which is only injected by runner >= 2.290 — empty on older
|
||||
# self-hosted runners.
|
||||
REF_NAME: ${{ github.ref_name }}
|
||||
run: |
|
||||
if [ -z "${REF_NAME:-}" ]; then
|
||||
echo "REF_NAME is not set" >&2
|
||||
exit 1
|
||||
fi
|
||||
VERSION="${REF_NAME#v}"
|
||||
printf '{ "version": "%s" }\n' "$VERSION" > static/version.json
|
||||
sed -i '' "s/^version = \".*\"/version = \"$VERSION\"/" desktop/src-tauri/Cargo.toml
|
||||
sed -i '' "s/\"version\": \"[^\"]*\"/\"version\": \"$VERSION\"/" desktop/src-tauri/tauri.conf.json
|
||||
sed -i '' "s/^version = \".*\"/version = \"$VERSION\"/" pyproject.toml
|
||||
sed -i '' "s/\"version\": \"[^\"]*\"/\"version\": \"$VERSION\"/" desktop/package.json
|
||||
echo "VERSION=$VERSION" >> "$GITHUB_ENV"
|
||||
echo "Wrote version $VERSION to all version files"
|
||||
|
||||
- name: build macOS arm64
|
||||
env:
|
||||
SSL_CERT_FILE: /etc/ssl/cert.pem
|
||||
REQUESTS_CA_BUNDLE: /etc/ssl/cert.pem
|
||||
run: |
|
||||
command -v zstd
|
||||
command -v uv >/dev/null 2>&1 || brew install uv
|
||||
uv python install cpython-3.12-macos-aarch64-none
|
||||
ARM64_PYTHON="$(uv python find cpython-3.12-macos-aarch64-none)"
|
||||
scripts/macos/make-iconset.sh
|
||||
ARCH=arm64 VERSION="$VERSION" PYTHON_BIN="$ARM64_PYTHON" scripts/macos/make-runtime-pack.sh
|
||||
ARCH=arm64 VERSION="$VERSION" scripts/macos/make-app.sh
|
||||
ARCH=arm64 VERSION="$VERSION" scripts/macos/make-dmg.sh
|
||||
|
||||
- name: build macOS x64
|
||||
env:
|
||||
SSL_CERT_FILE: /etc/ssl/cert.pem
|
||||
REQUESTS_CA_BUNDLE: /etc/ssl/cert.pem
|
||||
run: |
|
||||
command -v zstd
|
||||
if ! arch -x86_64 /usr/bin/true >/dev/null 2>&1; then
|
||||
echo "ERROR: Rosetta 2 is required to build the x64 runtime on this agent." >&2
|
||||
exit 1
|
||||
fi
|
||||
rustup default stable
|
||||
rustup target add x86_64-apple-darwin
|
||||
command -v uv >/dev/null 2>&1 || brew install uv
|
||||
uv python install cpython-3.12-macos-x86_64-none
|
||||
X64_PYTHON="$(uv python find cpython-3.12-macos-x86_64-none)"
|
||||
ARCH=x64 VERSION="$VERSION" PYTHON_BIN="$X64_PYTHON" scripts/macos/make-runtime-pack.sh
|
||||
ARCH=x64 VERSION="$VERSION" scripts/macos/make-app.sh
|
||||
ARCH=x64 VERSION="$VERSION" scripts/macos/make-dmg.sh
|
||||
|
||||
- name: inspect artifacts
|
||||
run: |
|
||||
test -f .build/macos-dist/StemDeck-macOS-arm64.dmg
|
||||
test -f .build/StemDeck-runtime-macOS-arm64.tar.zst
|
||||
test -f .build/macos-dist/SHA256SUMS-macOS-arm64.txt
|
||||
test -f .build/macos-dist/StemDeck-macOS-x64.dmg
|
||||
test -f .build/StemDeck-runtime-macOS-x64.tar.zst
|
||||
test -f .build/macos-dist/SHA256SUMS-macOS-x64.txt
|
||||
cat .build/macos-dist/SHA256SUMS-macOS-arm64.txt
|
||||
cat .build/macos-dist/SHA256SUMS-macOS-x64.txt
|
||||
du -sh .build/macos-dist/StemDeck-macOS-arm64.dmg .build/StemDeck-runtime-macOS-arm64.tar.zst
|
||||
du -sh .build/macos-dist/StemDeck-macOS-x64.dmg .build/StemDeck-runtime-macOS-x64.tar.zst
|
||||
if find desktop/src-tauri/target/aarch64-apple-darwin/release/bundle/macos/StemDeck.app \
|
||||
\( -iname '*python*' -o -iname '*torch*' -o -iname '*ffmpeg*' -o -iname '*ffprobe*' \) |
|
||||
grep -q .; then
|
||||
echo "arm64 StemDeck.app contains runtime binaries that should stay outside the DMG." >&2
|
||||
exit 1
|
||||
fi
|
||||
if find desktop/src-tauri/target/x86_64-apple-darwin/release/bundle/macos/StemDeck.app \
|
||||
\( -iname '*python*' -o -iname '*torch*' -o -iname '*ffmpeg*' -o -iname '*ffprobe*' \) |
|
||||
grep -q .; then
|
||||
echo "x64 StemDeck.app contains runtime binaries that should stay outside the DMG." >&2
|
||||
exit 1
|
||||
fi
|
||||
for arch in arm64 x64; do
|
||||
mountpoint="$(mktemp -d /tmp/stemdeck-dmg.XXXXXX)"
|
||||
hdiutil attach ".build/macos-dist/StemDeck-macOS-$arch.dmg" -readonly -nobrowse -mountpoint "$mountpoint"
|
||||
trap 'hdiutil detach "$mountpoint" >/dev/null 2>&1 || true; rmdir "$mountpoint" >/dev/null 2>&1 || true' EXIT
|
||||
test -d "$mountpoint/StemDeck.app"
|
||||
test -L "$mountpoint/Applications"
|
||||
test -f "$mountpoint/README-macOS.txt"
|
||||
test -f "$mountpoint/THIRD_PARTY_NOTICES.txt"
|
||||
hdiutil detach "$mountpoint"
|
||||
rmdir "$mountpoint"
|
||||
trap - EXIT
|
||||
done
|
||||
|
||||
- name: upload artifacts
|
||||
uses: softprops/action-gh-release@718ea10b132b3b2eba29c1007bb80653f286566b # v3.0.1
|
||||
with:
|
||||
files: |
|
||||
.build/macos-dist/StemDeck-macOS-arm64.dmg
|
||||
.build/StemDeck-runtime-macOS-arm64.tar.zst
|
||||
.build/macos-dist/SHA256SUMS-macOS-arm64.txt
|
||||
.build/macos-dist/StemDeck-macOS-x64.dmg
|
||||
.build/StemDeck-runtime-macOS-x64.tar.zst
|
||||
.build/macos-dist/SHA256SUMS-macOS-x64.txt
|
||||
@@ -0,0 +1,103 @@
|
||||
name: Windows Release
|
||||
|
||||
on:
|
||||
release:
|
||||
types: [published]
|
||||
|
||||
permissions: {}
|
||||
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.ref }}
|
||||
cancel-in-progress: true
|
||||
|
||||
jobs:
|
||||
build-and-upload:
|
||||
# Runner must be windows/x64 with PowerShell, Docker, and rustup.
|
||||
runs-on: [self-hosted, windows, x64]
|
||||
timeout-minutes: 90
|
||||
permissions:
|
||||
contents: write
|
||||
# Source the tag from the github context (evaluated by Actions) rather than
|
||||
# $env:GITHUB_REF_NAME, which is only injected by runner >= 2.290. Keeps the
|
||||
# build working on older self-hosted runners. (#212 follow-up)
|
||||
env:
|
||||
REF_NAME: ${{ github.ref_name }}
|
||||
defaults:
|
||||
run:
|
||||
shell: powershell
|
||||
steps:
|
||||
- name: clean workspace
|
||||
run: |
|
||||
Remove-Item -Recurse -Force .build, dist -ErrorAction SilentlyContinue
|
||||
|
||||
- uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
|
||||
|
||||
- name: write version files
|
||||
run: |
|
||||
$tag = $env:REF_NAME
|
||||
if (-not $tag) { throw "REF_NAME is not set" }
|
||||
$version = $tag -replace '^v', ''
|
||||
$json = "{`"version`": `"$version`"}"
|
||||
Set-Content -Path "static/version.json" -Value $json -Encoding UTF8
|
||||
(Get-Content "desktop/src-tauri/Cargo.toml") -replace '^version = ".*"', "version = `"$version`"" |
|
||||
Set-Content "desktop/src-tauri/Cargo.toml"
|
||||
(Get-Content "desktop/src-tauri/tauri.conf.json") -replace '"version": "[^"]*"', "`"version`": `"$version`"" |
|
||||
Set-Content "desktop/src-tauri/tauri.conf.json"
|
||||
(Get-Content "pyproject.toml") -replace '^version = ".*"', "version = `"$version`"" |
|
||||
Set-Content "pyproject.toml"
|
||||
(Get-Content "desktop/package.json") -replace '"version": "[^"]*"', "`"version`": `"$version`"" |
|
||||
Set-Content "desktop/package.json"
|
||||
Write-Host "Wrote version $version to all version files"
|
||||
|
||||
- name: build Windows NVIDIA
|
||||
run: |
|
||||
powershell -NoProfile -ExecutionPolicy Bypass -File scripts/windows/make-portable.ps1 `
|
||||
-PackageName StemDeck-Windows-x64.NVIDIA `
|
||||
-PackageVersion "$env:REF_NAME" `
|
||||
-StripVenv
|
||||
|
||||
- name: build Windows CPU
|
||||
run: |
|
||||
powershell -NoProfile -ExecutionPolicy Bypass -File scripts/windows/make-portable.ps1 `
|
||||
-PackageName StemDeck-Windows-x64 `
|
||||
-PackageVersion "$env:REF_NAME" `
|
||||
-CpuOnly `
|
||||
-StripVenv
|
||||
|
||||
- name: scan artifacts
|
||||
run: |
|
||||
Write-Host "Preparing ClamAV scan for Windows release artifacts..."
|
||||
Write-Host "Artifacts staged in: $PWD\dist"
|
||||
Get-ChildItem -Path "dist" -File |
|
||||
Sort-Object Name |
|
||||
Select-Object Name,
|
||||
@{Name="SizeMB"; Expression={ [math]::Round($_.Length / 1MB, 2) }} |
|
||||
Format-Table -AutoSize
|
||||
|
||||
Write-Host "SHA256 checksums:"
|
||||
Get-ChildItem -Path "dist" -Filter "*.zip" -File |
|
||||
Sort-Object Name |
|
||||
ForEach-Object {
|
||||
$hash = Get-FileHash -Algorithm SHA256 $_.FullName
|
||||
Write-Host " $($hash.Hash) $($_.Name)"
|
||||
}
|
||||
|
||||
Write-Host "Pulling latest ClamAV scanner image..."
|
||||
docker pull clamav/clamav:latest
|
||||
|
||||
Write-Host "Running ClamAV scan over dist/..."
|
||||
docker run --rm -v "${PWD}/dist:/scan:ro" clamav/clamav:latest `
|
||||
clamscan --recursive --infected --bell /scan
|
||||
if ($LASTEXITCODE -ne 0) {
|
||||
throw "ClamAV scan failed or reported infected files. Exit code: $LASTEXITCODE"
|
||||
}
|
||||
Write-Host "ClamAV scan completed successfully. No infected files reported."
|
||||
|
||||
- name: upload artifacts
|
||||
uses: softprops/action-gh-release@718ea10b132b3b2eba29c1007bb80653f286566b # v3.0.1
|
||||
with:
|
||||
files: |
|
||||
dist/StemDeck-Windows-x64.NVIDIA.zip
|
||||
dist/StemDeck-Windows-x64.NVIDIA.zip.sha256
|
||||
dist/StemDeck-Windows-x64.zip
|
||||
dist/StemDeck-Windows-x64.zip.sha256
|
||||
Reference in New Issue
Block a user