mirror of
https://github.com/cryptoadvance/specter-desktop.git
synced 2026-08-13 12:33:29 +02:00
729 lines
26 KiB
YAML
729 lines
26 KiB
YAML
name: Release
|
|
|
|
on:
|
|
push:
|
|
tags:
|
|
- 'v[0-9]+.[0-9]+.[0-9]+'
|
|
- 'v[0-9]+.[0-9]+.[0-9]+-*'
|
|
|
|
permissions:
|
|
contents: write
|
|
id-token: write # needed for PyPI trusted publishing
|
|
|
|
env:
|
|
PYTHON_VERSION: '3.10'
|
|
|
|
jobs:
|
|
# ─── 1. Build pip package ──────────────────────────────────────────
|
|
release-pip:
|
|
name: Build & publish pip package
|
|
runs-on: ubuntu-latest
|
|
environment: release # for trusted PyPI publishing
|
|
steps:
|
|
- uses: actions/checkout@v4
|
|
with:
|
|
fetch-depth: 0 # setuptools_scm needs full history
|
|
|
|
- uses: actions/setup-python@v5
|
|
with:
|
|
python-version: ${{ env.PYTHON_VERSION }}
|
|
|
|
- name: Install build tools
|
|
run: pip install build==0.10.0
|
|
|
|
- name: Build package
|
|
run: |
|
|
# Derive PEP 440 version from git tag (pre→rc mapping)
|
|
# Avoids setuptools_scm picking wrong tag when multiple tags share a commit
|
|
VERSION=${GITHUB_REF#refs/tags/v}
|
|
PEP_VERSION=$(echo "$VERSION" | sed 's/-pre/rc/')
|
|
echo "Building version: $PEP_VERSION"
|
|
SETUPTOOLS_SCM_PRETEND_VERSION=$PEP_VERSION python3 -m build
|
|
|
|
- name: Upload pip artifacts
|
|
uses: actions/upload-artifact@v4
|
|
with:
|
|
name: pip-package
|
|
path: dist/*
|
|
|
|
- name: Publish to PyPI
|
|
if: github.repository == 'cryptoadvance/specter-desktop'
|
|
uses: pypa/gh-action-pypi-publish@release/v1
|
|
# Uses trusted publishing — no token needed if configured on PyPI
|
|
# Fallback: set TWINE_PASSWORD secret and use username __token__
|
|
|
|
# ─── 2. Build specterd binaries ────────────────────────────────────
|
|
build-specterd-linux:
|
|
name: Build specterd (Linux)
|
|
runs-on: ubuntu-latest
|
|
steps:
|
|
- uses: actions/checkout@v4
|
|
with:
|
|
fetch-depth: 0
|
|
|
|
- uses: actions/setup-python@v5
|
|
with:
|
|
python-version: ${{ env.PYTHON_VERSION }}
|
|
|
|
- name: Install system dependencies
|
|
run: sudo apt-get update && sudo apt-get install -y libusb-1.0-0-dev libudev-dev
|
|
|
|
- name: Create virtualenv and install
|
|
run: |
|
|
pip install virtualenv
|
|
virtualenv --python=python${{ env.PYTHON_VERSION }} .buildenv
|
|
source .buildenv/bin/activate
|
|
pip install -r requirements.txt --require-hashes
|
|
pip install -e ".[test]"
|
|
pip install build==0.10.0
|
|
python3 -m build
|
|
pip install ./dist/cryptoadvance_specter-*.whl
|
|
|
|
- name: Install PyInstaller requirements
|
|
run: |
|
|
source .buildenv/bin/activate
|
|
pip install -r pyinstaller/requirements.txt
|
|
|
|
- name: Build specterd
|
|
run: |
|
|
source .buildenv/bin/activate
|
|
VERSION=${GITHUB_REF#refs/tags/}
|
|
echo "$VERSION" > pyinstaller/version.txt
|
|
cd pyinstaller
|
|
pyinstaller specterd.spec
|
|
cd ..
|
|
|
|
- name: Package release
|
|
run: |
|
|
VERSION=${GITHUB_REF#refs/tags/}
|
|
mkdir -p release
|
|
cd pyinstaller/dist
|
|
cp -r ../../udev ./udev
|
|
echo "Don't forget to set up udev rules! Check out udev folder for instructions." > README.md
|
|
zip -r ../../release/specterd-${VERSION}-x86_64-linux-gnu.zip specterd udev README.md
|
|
cd ../..
|
|
|
|
- name: Upload artifact
|
|
uses: actions/upload-artifact@v4
|
|
with:
|
|
name: specterd-linux
|
|
path: release/specterd-*-linux-gnu.zip
|
|
|
|
build-specterd-windows:
|
|
name: Build specterd (Windows)
|
|
runs-on: windows-latest
|
|
steps:
|
|
- uses: actions/checkout@v4
|
|
with:
|
|
fetch-depth: 0
|
|
|
|
- uses: actions/setup-python@v5
|
|
with:
|
|
python-version: ${{ env.PYTHON_VERSION }}
|
|
|
|
- name: Install and build
|
|
shell: bash
|
|
run: |
|
|
pip install virtualenv
|
|
virtualenv --python=python${{ env.PYTHON_VERSION }} .buildenv
|
|
source .buildenv/Scripts/activate
|
|
pip install colorama # Windows-only transitive dep of click, not in requirements.txt
|
|
pip install -r requirements.txt --require-hashes
|
|
pip install -e ".[test]"
|
|
pip install build==0.10.0
|
|
python -m build
|
|
pip install ./dist/cryptoadvance_specter-*.whl
|
|
|
|
- name: Install PyInstaller requirements
|
|
shell: bash
|
|
run: |
|
|
source .buildenv/Scripts/activate
|
|
cd pyinstaller
|
|
pip install -r requirements.txt
|
|
|
|
- name: Build specterd
|
|
shell: bash
|
|
run: |
|
|
source .buildenv/Scripts/activate
|
|
VERSION=${GITHUB_REF#refs/tags/}
|
|
echo "$VERSION" > pyinstaller/version.txt
|
|
cd pyinstaller
|
|
pyinstaller specterd.spec
|
|
cd ..
|
|
|
|
- name: Package release
|
|
shell: bash
|
|
run: |
|
|
VERSION=${GITHUB_REF#refs/tags/}
|
|
mkdir -p release
|
|
cd pyinstaller/dist
|
|
7z a ../../release/specterd-${VERSION}-win64.zip specterd.exe
|
|
cd ../..
|
|
|
|
- name: Upload artifact
|
|
uses: actions/upload-artifact@v4
|
|
with:
|
|
name: specterd-windows
|
|
path: release/specterd-*-win64.zip
|
|
|
|
build-specterd-macos:
|
|
name: Build specterd (macOS ${{ matrix.arch }})
|
|
runs-on: ${{ matrix.runner }}
|
|
strategy:
|
|
matrix:
|
|
include:
|
|
# x64 builds require a paid macOS runner (macos-13 retired, macos-15-large is paid)
|
|
# Uncomment when org has paid plan:
|
|
# - runner: macos-15-large
|
|
# arch: x64
|
|
# arch_label: osx_x64
|
|
- runner: macos-14 # Apple Silicon (free tier)
|
|
arch: arm64
|
|
arch_label: osx_arm64
|
|
steps:
|
|
- uses: actions/checkout@v4
|
|
with:
|
|
fetch-depth: 0
|
|
|
|
- uses: actions/setup-python@v5
|
|
with:
|
|
python-version: ${{ env.PYTHON_VERSION }}
|
|
|
|
- name: Install system dependencies
|
|
run: brew install libusb
|
|
|
|
- name: Install and build
|
|
run: |
|
|
pip install virtualenv
|
|
virtualenv --python=python${{ env.PYTHON_VERSION }} .buildenv
|
|
source .buildenv/bin/activate
|
|
pip install -r requirements.txt --require-hashes
|
|
pip install -e ".[test]"
|
|
pip install build==0.10.0
|
|
python3 -m build
|
|
pip install ./dist/cryptoadvance_specter-*.whl
|
|
|
|
- name: Install PyInstaller requirements
|
|
run: |
|
|
source .buildenv/bin/activate
|
|
pip install -r pyinstaller/requirements.txt
|
|
|
|
- name: Build specterd
|
|
run: |
|
|
source .buildenv/bin/activate
|
|
VERSION=${GITHUB_REF#refs/tags/}
|
|
echo "$VERSION" > pyinstaller/version.txt
|
|
cd pyinstaller
|
|
pyinstaller specterd.spec
|
|
cd ..
|
|
|
|
- name: Package release
|
|
run: |
|
|
VERSION=${GITHUB_REF#refs/tags/}
|
|
mkdir -p release
|
|
cd pyinstaller/dist
|
|
zip -r ../../release/specterd-${VERSION}-${{ matrix.arch_label }}.zip specterd
|
|
cd ../..
|
|
|
|
- name: Upload artifact
|
|
uses: actions/upload-artifact@v4
|
|
with:
|
|
name: specterd-macos-${{ matrix.arch }}
|
|
path: release/specterd-*-osx*.zip
|
|
|
|
# ─── 3. Build Electron desktop apps ───────────────────────────────
|
|
build-electron-linux:
|
|
name: Build Electron (Linux)
|
|
needs: build-specterd-linux
|
|
runs-on: ubuntu-latest
|
|
steps:
|
|
- uses: actions/checkout@v4
|
|
with:
|
|
fetch-depth: 0
|
|
|
|
- uses: actions/setup-python@v5
|
|
with:
|
|
python-version: ${{ env.PYTHON_VERSION }}
|
|
|
|
- uses: actions/setup-node@v4
|
|
with:
|
|
node-version: '18'
|
|
|
|
- name: Install system dependencies
|
|
run: sudo apt-get update && sudo apt-get install -y libusb-1.0-0-dev libudev-dev
|
|
|
|
- name: Install Python packages
|
|
run: |
|
|
pip install virtualenv
|
|
virtualenv --python=python${{ env.PYTHON_VERSION }} .buildenv
|
|
source .buildenv/bin/activate
|
|
pip install -r requirements.txt --require-hashes
|
|
pip install -e ".[test]"
|
|
pip install -e .
|
|
|
|
- name: Download specterd artifact
|
|
uses: actions/download-artifact@v4
|
|
with:
|
|
name: specterd-linux
|
|
path: ./release-artifacts
|
|
|
|
- name: Cache Electron binaries
|
|
uses: actions/cache@v4
|
|
with:
|
|
path: |
|
|
~/.cache/electron
|
|
~/.cache/electron-builder
|
|
key: electron-linux-${{ hashFiles('pyinstaller/electron/package-lock.json') }}
|
|
restore-keys: electron-linux-
|
|
|
|
- name: Prepare Electron build
|
|
run: |
|
|
VERSION=${GITHUB_REF#refs/tags/}
|
|
source .buildenv/bin/activate
|
|
mkdir -p pyinstaller/dist
|
|
cd release-artifacts
|
|
unzip specterd-${VERSION}-x86_64-linux-gnu.zip -d ../pyinstaller/dist/
|
|
cd ..
|
|
cd pyinstaller/electron
|
|
npm ci
|
|
node ./set-version $VERSION ../dist/specterd
|
|
cd ../..
|
|
|
|
- name: Build Electron app
|
|
run: |
|
|
cd pyinstaller/electron
|
|
cp -R ../../src/cryptoadvance/specter/static/fonts \
|
|
../../src/cryptoadvance/specter/static/output.css \
|
|
../../src/cryptoadvance/specter/static/typography.css .
|
|
# Retry: electron-builder downloads from github.com occasionally 502
|
|
# (see release run 24636274855).
|
|
attempt=0
|
|
until npm run dist -- --linux; do
|
|
attempt=$((attempt + 1))
|
|
if [ $attempt -ge 3 ]; then
|
|
echo "electron-builder failed after $attempt attempts"; exit 1
|
|
fi
|
|
echo "Attempt $attempt failed; retrying in $((attempt * 15))s..."
|
|
sleep $((attempt * 15))
|
|
done
|
|
cd ../..
|
|
|
|
- name: Package release
|
|
run: |
|
|
VERSION=${GITHUB_REF#refs/tags/}
|
|
mkdir -p release
|
|
cd pyinstaller/electron/dist
|
|
cp -r ../../../udev ./udev
|
|
echo "Don't forget to set up udev rules! Check out udev folder for instructions." > README.md
|
|
tar -czvf ../../../release/specter_desktop-${VERSION}-x86_64-linux-gnu.tar.gz Specter-* udev README.md
|
|
cd ../../..
|
|
|
|
- name: Upload artifact
|
|
uses: actions/upload-artifact@v4
|
|
with:
|
|
name: electron-linux
|
|
path: release/specter_desktop-*-linux-gnu.tar.gz
|
|
|
|
build-electron-windows:
|
|
name: Build Electron (Windows)
|
|
needs: build-specterd-windows
|
|
runs-on: ubuntu-latest
|
|
container:
|
|
image: electronuserland/builder:wine
|
|
env:
|
|
# Shared HOME so `npm ci` (electron postinstall) and electron-builder
|
|
# write to the same ~/.cache/electron path — kept cacheable across runs.
|
|
HOME: /tmp/electron-home
|
|
steps:
|
|
- uses: actions/checkout@v4
|
|
with:
|
|
fetch-depth: 0
|
|
|
|
- name: Install system dependencies
|
|
run: |
|
|
apt-get update && apt-get install -y unzip
|
|
mkdir -p $HOME
|
|
|
|
- name: Download specterd Windows artifact
|
|
uses: actions/download-artifact@v4
|
|
with:
|
|
name: specterd-windows
|
|
path: ./release-artifacts
|
|
|
|
- name: Cache Electron binaries
|
|
uses: actions/cache@v4
|
|
with:
|
|
path: |
|
|
/tmp/electron-home/.cache/electron
|
|
/tmp/electron-home/.cache/electron-builder
|
|
key: electron-win-${{ hashFiles('pyinstaller/electron/package-lock.json') }}
|
|
restore-keys: electron-win-
|
|
|
|
- name: Prepare Electron build
|
|
run: |
|
|
VERSION=${GITHUB_REF#refs/tags/}
|
|
mkdir -p pyinstaller/dist
|
|
cd release-artifacts
|
|
unzip specterd-${VERSION}-win64.zip -d ../pyinstaller/dist/
|
|
cd ..
|
|
cd pyinstaller/electron
|
|
npm ci
|
|
node ./set-version.js $VERSION ../dist/specterd.exe
|
|
cd ../..
|
|
|
|
- name: Build Electron app
|
|
run: |
|
|
cd pyinstaller/electron
|
|
cp -R ../../src/cryptoadvance/specter/static/fonts \
|
|
../../src/cryptoadvance/specter/static/output.css \
|
|
../../src/cryptoadvance/specter/static/typography.css .
|
|
# Retry: electron-builder downloads from github.com occasionally 502
|
|
# (see release run 24636274855).
|
|
attempt=0
|
|
until npm run dist -- --win; do
|
|
attempt=$((attempt + 1))
|
|
if [ $attempt -ge 3 ]; then
|
|
echo "electron-builder failed after $attempt attempts"; exit 1
|
|
fi
|
|
echo "Attempt $attempt failed; retrying in $((attempt * 15))s..."
|
|
sleep $((attempt * 15))
|
|
done
|
|
cd ../..
|
|
|
|
- name: Package release
|
|
run: |
|
|
VERSION=${GITHUB_REF#refs/tags/}
|
|
mkdir -p release
|
|
cp pyinstaller/electron/dist/Specter\ Setup\ *.exe release/Specter-Setup-${VERSION}.exe 2>/dev/null || \
|
|
cp pyinstaller/electron/dist/*.exe release/Specter-Setup-${VERSION}.exe
|
|
|
|
- name: Upload artifact
|
|
uses: actions/upload-artifact@v4
|
|
with:
|
|
name: electron-windows
|
|
path: release/Specter-Setup-*.exe
|
|
|
|
build-electron-macos:
|
|
name: Build Electron (macOS)
|
|
needs:
|
|
- build-specterd-macos
|
|
runs-on: macos-14 # Apple Silicon for universal builds
|
|
env:
|
|
HAVE_APPLE_CERT: ${{ secrets.APPLE_CERTIFICATE_BASE64 != '' }}
|
|
steps:
|
|
- uses: actions/checkout@v4
|
|
with:
|
|
fetch-depth: 0
|
|
|
|
- uses: actions/setup-python@v5
|
|
with:
|
|
python-version: ${{ env.PYTHON_VERSION }}
|
|
|
|
- uses: actions/setup-node@v4
|
|
with:
|
|
node-version: '18'
|
|
|
|
- name: Install system dependencies
|
|
run: brew install libusb
|
|
|
|
- name: Install Python packages
|
|
run: |
|
|
pip install virtualenv
|
|
virtualenv --python=python${{ env.PYTHON_VERSION }} .buildenv
|
|
source .buildenv/bin/activate
|
|
pip install -r requirements.txt --require-hashes
|
|
pip install -e ".[test]"
|
|
pip install -e .
|
|
|
|
- name: Download specterd macOS ARM64 artifact
|
|
uses: actions/download-artifact@v4
|
|
with:
|
|
name: specterd-macos-arm64
|
|
path: ./release-artifacts
|
|
|
|
- name: Cache Electron binaries
|
|
uses: actions/cache@v4
|
|
with:
|
|
path: |
|
|
~/Library/Caches/electron
|
|
~/Library/Caches/electron-builder
|
|
key: electron-mac-${{ hashFiles('pyinstaller/electron/package-lock.json') }}
|
|
restore-keys: electron-mac-
|
|
|
|
- name: Import code signing certificate
|
|
if: env.HAVE_APPLE_CERT == 'true'
|
|
env:
|
|
APPLE_CERTIFICATE: ${{ secrets.APPLE_CERTIFICATE_BASE64 }}
|
|
APPLE_CERTIFICATE_PASSWORD: ${{ secrets.APPLE_CERTIFICATE_PASSWORD }}
|
|
run: |
|
|
# Create temporary keychain
|
|
KEYCHAIN_PATH=$RUNNER_TEMP/app-signing.keychain-db
|
|
KEYCHAIN_PASSWORD=$(openssl rand -base64 32)
|
|
security create-keychain -p "$KEYCHAIN_PASSWORD" "$KEYCHAIN_PATH"
|
|
security set-keychain-settings -lut 21600 "$KEYCHAIN_PATH"
|
|
security unlock-keychain -p "$KEYCHAIN_PASSWORD" "$KEYCHAIN_PATH"
|
|
|
|
# Import certificate
|
|
echo "$APPLE_CERTIFICATE" | base64 --decode > $RUNNER_TEMP/certificate.p12
|
|
security import $RUNNER_TEMP/certificate.p12 \
|
|
-P "$APPLE_CERTIFICATE_PASSWORD" \
|
|
-A -t cert -f pkcs12 \
|
|
-k "$KEYCHAIN_PATH"
|
|
security list-keychain -d user -s "$KEYCHAIN_PATH"
|
|
|
|
# Import provisioning profile if available
|
|
if [ -n "${{ secrets.APPLE_PROVISIONING_PROFILE_BASE64 }}" ]; then
|
|
echo "${{ secrets.APPLE_PROVISIONING_PROFILE_BASE64 }}" | base64 --decode > $RUNNER_TEMP/profile.provisionprofile
|
|
mkdir -p ~/Library/MobileDevice/Provisioning\ Profiles
|
|
cp $RUNNER_TEMP/profile.provisionprofile ~/Library/MobileDevice/Provisioning\ Profiles/
|
|
fi
|
|
|
|
- name: Prepare Electron build
|
|
run: |
|
|
VERSION=${GITHUB_REF#refs/tags/}
|
|
source .buildenv/bin/activate
|
|
mkdir -p pyinstaller/dist
|
|
cd release-artifacts
|
|
unzip specterd-${VERSION}-osx_arm64.zip -d ../pyinstaller/dist/
|
|
cd ..
|
|
cd pyinstaller/electron
|
|
npm ci
|
|
node ./set-version $VERSION ../dist/specterd
|
|
cd ../..
|
|
|
|
- name: Patch electron-builder config for CI
|
|
run: |
|
|
cd pyinstaller/electron
|
|
# Update package.json mac config for CI:
|
|
# - Remove hardcoded provisioning profile path
|
|
# - If no signing cert, remove identity to build unsigned
|
|
node -e "
|
|
const pkg = require('./package.json');
|
|
delete pkg.build.mac.provisioningProfile;
|
|
if (!process.env.APPLE_CERTIFICATE) {
|
|
pkg.build.mac.identity = null; // build unsigned
|
|
}
|
|
require('fs').writeFileSync('package.json', JSON.stringify(pkg, null, 2));
|
|
"
|
|
cd ../..
|
|
env:
|
|
APPLE_CERTIFICATE: ${{ secrets.APPLE_CERTIFICATE_BASE64 }}
|
|
|
|
- name: Build Electron app
|
|
run: |
|
|
cd pyinstaller/electron
|
|
cp -R ../../src/cryptoadvance/specter/static/fonts \
|
|
../../src/cryptoadvance/specter/static/output.css \
|
|
../../src/cryptoadvance/specter/static/typography.css .
|
|
# Retry: electron-builder downloads from github.com occasionally 502
|
|
# (see release run 24636274855).
|
|
attempt=0
|
|
until npm run dist -- --mac; do
|
|
attempt=$((attempt + 1))
|
|
if [ $attempt -ge 3 ]; then
|
|
echo "electron-builder failed after $attempt attempts"; exit 1
|
|
fi
|
|
echo "Attempt $attempt failed; retrying in $((attempt * 15))s..."
|
|
sleep $((attempt * 15))
|
|
done
|
|
cd ../..
|
|
env:
|
|
# electron-builder reads these for notarization
|
|
APPLE_ID: ${{ secrets.APPLE_ID }}
|
|
APPLE_APP_SPECIFIC_PASSWORD: ${{ secrets.APPLE_APP_SPECIFIC_PASSWORD }}
|
|
APPLE_TEAM_ID: ${{ secrets.APPLE_TEAM_ID }}
|
|
|
|
- name: Package release
|
|
run: |
|
|
VERSION=${GITHUB_REF#refs/tags/}
|
|
mkdir -p release
|
|
cp pyinstaller/electron/dist/Specter-*.dmg release/Specter-${VERSION}.dmg 2>/dev/null || true
|
|
# Fallback: if no DMG, package the .app
|
|
if [ ! -f release/Specter-${VERSION}.dmg ]; then
|
|
cd pyinstaller/electron/dist/mac-universal
|
|
zip -r ../../../../release/Specter-${VERSION}-macos.zip Specter.app
|
|
cd ../../../..
|
|
fi
|
|
|
|
- name: Upload artifact
|
|
uses: actions/upload-artifact@v4
|
|
with:
|
|
name: electron-macos
|
|
path: release/Specter-*
|
|
|
|
# ─── 4. Create GitHub Release with all artifacts ───────────────────
|
|
create-release:
|
|
name: Create GitHub Release
|
|
needs:
|
|
- release-pip
|
|
- build-specterd-linux
|
|
- build-specterd-windows
|
|
- build-specterd-macos
|
|
- build-electron-linux
|
|
- build-electron-windows
|
|
- build-electron-macos
|
|
runs-on: ubuntu-latest
|
|
env:
|
|
HAVE_GPG_KEY: ${{ secrets.GPG_PRIVATE_KEY != '' }}
|
|
steps:
|
|
- uses: actions/checkout@v4
|
|
|
|
- name: Download all artifacts
|
|
uses: actions/download-artifact@v4
|
|
with:
|
|
path: ./artifacts
|
|
|
|
- name: Collect release files and generate checksums
|
|
run: |
|
|
VERSION=${GITHUB_REF#refs/tags/}
|
|
mkdir -p release-files
|
|
|
|
# Collect all release artifacts
|
|
find artifacts -type f \( \
|
|
-name "*.zip" -o -name "*.tar.gz" -o -name "*.exe" -o -name "*.dmg" \
|
|
\) -exec cp {} release-files/ \;
|
|
|
|
# Also include pip source distribution
|
|
find artifacts/pip-package -type f -name "cryptoadvance_specter-*.tar.gz" \
|
|
-exec cp {} release-files/ \; 2>/dev/null || true
|
|
|
|
# Generate SHA256SUMS
|
|
cd release-files
|
|
sha256sum * > SHA256SUMS
|
|
echo "=== SHA256SUMS ==="
|
|
cat SHA256SUMS
|
|
cd ..
|
|
|
|
- name: GPG sign checksums
|
|
if: env.HAVE_GPG_KEY == 'true'
|
|
env:
|
|
GPG_PRIVATE_KEY: ${{ secrets.GPG_PRIVATE_KEY }}
|
|
GPG_PASSPHRASE: ${{ secrets.GPG_PASSPHRASE }}
|
|
run: |
|
|
echo "$GPG_PRIVATE_KEY" | gpg --batch --import
|
|
# Set ultimate trust so GPG will use the key on a fresh runner
|
|
FPR=$(gpg --list-secret-keys --with-colons --with-fingerprint 2>/dev/null | awk -F: '/^fpr/{print $10; exit}')
|
|
echo "Fingerprint: $FPR"
|
|
echo "${FPR}:6:" | gpg --import-ownertrust
|
|
KEY_ID=$(gpg --list-secret-keys --keyid-format long --with-colons 2>/dev/null | awk -F: '/^sec/{print $5; exit}')
|
|
echo "Signing with key: $KEY_ID"
|
|
cd release-files
|
|
if [ -n "$GPG_PASSPHRASE" ]; then
|
|
echo "$GPG_PASSPHRASE" | gpg --batch --yes --passphrase-fd 0 \
|
|
--pinentry-mode loopback --default-key "$KEY_ID" --detach-sign --armor SHA256SUMS
|
|
else
|
|
gpg --batch --yes --pinentry-mode loopback --default-key "$KEY_ID" --detach-sign --armor SHA256SUMS
|
|
fi
|
|
cd ..
|
|
|
|
- name: Generate release body
|
|
run: |
|
|
VERSION=${GITHUB_REF#refs/tags/}
|
|
DL="https://github.com/cryptoadvance/specter-desktop/releases/download/${VERSION}"
|
|
|
|
cat > release-body.md << EOF
|
|
*Please create a full backup* before migrating or any major internal changes like switching to an electrum based installation. You can easily create a backup in Settings --> Backup Specter (zip file).
|
|
|
|
## Artifacts
|
|
|
|
Specter is available in several forms: as a GUI application, as a binary that can be executed like a web app, as a PyPI package, and as a Docker image.
|
|
|
|
Signed hashsum files are available for all binaries.
|
|
|
|
## GUI Application
|
|
|
|
This is a GUI application with a windowed interface, which includes the Specter server.
|
|
Supported platforms: [Windows](${DL}/Specter-Setup-${VERSION}.exe), [MacOS](${DL}/Specter-${VERSION}.dmg), [Linux (x86_64)](${DL}/specter_desktop-${VERSION}-x86_64-linux-gnu.tar.gz)
|
|
|
|
**Note on Linux**: you need to set up udev rules (included in the archive). Check out the [readme](https://github.com/cryptoadvance/specter-desktop/blob/master/udev/README.md#usage).
|
|
|
|
**Note on macOS**: The macOS application is currently **not code-signed or notarized** by Apple. After downloading the DMG and installing, macOS Gatekeeper will block the app. To fix this, run in Terminal:
|
|
\`\`\`
|
|
cd /Applications
|
|
xattr -cr "Specter.app"
|
|
\`\`\`
|
|
The current build supports macOS Catalina (10.15) or higher. If you'd like to run Specter on an older macOS version, you can [install Specter from Pip](https://github.com/cryptoadvance/specter-desktop#installing-specter-from-pip). See [#2530](https://github.com/cryptoadvance/specter-desktop/issues/2530) for details.
|
|
|
|
## specterd
|
|
|
|
Specterd is a command-line program that runs only the Specter server, behaving like a traditional web application.
|
|
Supported platforms: [Windows](${DL}/specterd-${VERSION}-win64.zip), [MacOS](${DL}/specterd-${VERSION}-osx_arm64.zip), [Linux (x86_64)](${DL}/specterd-${VERSION}-x86_64-linux-gnu.zip)
|
|
|
|
## PyPi Packages
|
|
|
|
If you're experienced Python user and/or developer, you might appreciate the [pypi-packages](https://pypi.org/project/cryptoadvance-specter/) which are also available on our github-release-page.
|
|
|
|
## Docker
|
|
|
|
Official Docker images are published to GitHub Container Registry:
|
|
|
|
\`\`\`
|
|
docker pull ghcr.io/cryptoadvance/specter-desktop:${VERSION}
|
|
\`\`\`
|
|
|
|
See all available tags at [ghcr.io/cryptoadvance/specter-desktop](https://github.com/cryptoadvance/specter-desktop/pkgs/container/specter-desktop).
|
|
|
|
For releases prior to v2.1.2, Docker images were provided by the [Chiang Mai LN devs](https://github.com/lncm/docker-specter-desktop).
|
|
|
|
## Signatures and hashes
|
|
|
|
[SHA256SUMS](${DL}/SHA256SUMS) file contains sha256 hashes of all binary files and signed with "Specter Signer 2026" GPG key.
|
|
You can get the public key from [here](http://keyserver.ubuntu.com/pks/lookup?op=get&search=0x9dc33ca830589de3b3225c26eef5756b2ea42349).
|
|
Fingerprint of the key is \`9DC3 3CA8 3058 9DE3 B322 5C26 EEF5 756B 2EA4 2349\`
|
|
This key has been signed by @k9ert's key. For more information about Verifying signatures, see, e.g. [this video](https://www.youtube.com/watch?v=lYYsVkOplYc).
|
|
|
|
# Release notes
|
|
|
|
EOF
|
|
|
|
# Strip leading whitespace from heredoc
|
|
sed -i 's/^ //' release-body.md
|
|
|
|
- name: Generate release notes
|
|
env:
|
|
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
run: |
|
|
VERSION=${GITHUB_REF#refs/tags/}
|
|
|
|
# Use GitHub API to auto-generate "What's Changed" from merged PRs
|
|
NOTES=$(gh api repos/${{ github.repository }}/releases/generate-notes \
|
|
-f tag_name="${VERSION}" \
|
|
--jq '.body') || true
|
|
|
|
if [ -n "$NOTES" ]; then
|
|
echo "$NOTES" >> release-body.md
|
|
fi
|
|
|
|
- name: Create GitHub Release
|
|
uses: softprops/action-gh-release@v2
|
|
with:
|
|
files: release-files/*
|
|
body_path: release-body.md
|
|
draft: true # Draft first, review before publishing
|
|
env:
|
|
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
|
|
trigger-docker:
|
|
name: Trigger lncm Docker build
|
|
needs: create-release
|
|
runs-on: ubuntu-latest
|
|
if: ${{ !cancelled() && needs.create-release.result == 'success' }}
|
|
steps:
|
|
- name: Trigger lncm/docker-specter-desktop
|
|
env:
|
|
AARON_TOKEN: ${{ secrets.AARON_TRIGGER }}
|
|
run: |
|
|
VERSION=${GITHUB_REF#refs/tags/}
|
|
|
|
if [ -z "$AARON_TOKEN" ]; then
|
|
echo "AARON_TRIGGER secret not set, skipping Docker trigger"
|
|
exit 0
|
|
fi
|
|
|
|
curl -X POST \
|
|
-H "Accept: application/vnd.github.v3+json" \
|
|
-H "Authorization: token ${AARON_TOKEN}" \
|
|
https://api.github.com/repos/lncm/docker-specter-desktop/actions/workflows/dispatch.yml/dispatches \
|
|
-d "{\"ref\":\"master\", \"inputs\": {\"tag\": \"${VERSION}\"}}"
|
|
|
|
echo "Triggered lncm/docker-specter-desktop build for ${VERSION}"
|