Skip to content

Merge pull request #106 from overwrite00/dev/release-0.2.7 #85

Merge pull request #106 from overwrite00/dev/release-0.2.7

Merge pull request #106 from overwrite00/dev/release-0.2.7 #85

Workflow file for this run

name: Build & Release
on:
push:
branches: [main, develop]
paths-ignore:
- 'docs/**'
- 'README.md'
- 'CHANGELOG.md'
- 'LICENSE'
- '*.md'
workflow_dispatch: {}
env:
FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: true
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
jobs:
# ─────────────────────────────────────────────────────────────────────────────
# TEST BUILD (develop only) — Verify code compiles and tests pass
# ─────────────────────────────────────────────────────────────────────────────
test-python:
if: github.ref == 'refs/heads/develop'
runs-on: ubuntu-latest
permissions:
contents: read
strategy:
matrix:
python-version: ['3.11', '3.12', '3.13']
steps:
- uses: actions/checkout@v6
- uses: actions/setup-python@v6
with:
python-version: ${{ matrix.python-version }}
cache: pip
cache-dependency-path: python/requirements.txt
- name: Install and run tests
run: |
cd python
pip install -r requirements.txt -q
pip install pytest pytest-asyncio httpx -q
pytest tests/ -v
test-frontend:
if: github.ref == 'refs/heads/develop'
runs-on: ubuntu-latest
permissions:
contents: read
steps:
- uses: actions/checkout@v6
- uses: actions/setup-node@v6
with:
node-version: '22'
cache: npm
cache-dependency-path: frontend/package-lock.json
- name: Install and build
run: |
cd frontend
npm ci
npm run build
test-electron:
if: github.ref == 'refs/heads/develop'
needs: test-frontend
runs-on: ubuntu-latest
permissions:
contents: read
env:
ELECTRON_CACHE: ${{ github.workspace }}/.electron-cache
steps:
- uses: actions/checkout@v6
- uses: actions/setup-python@v6
with:
python-version: '3.12'
cache: pip
cache-dependency-path: python/requirements.txt
- name: Install Python
run: |
cd python
pip install -r requirements.txt -q
pip install pyinstaller -q
- name: Build sidecar
run: |
cd python
python -m PyInstaller main.py --onefile --name metalens-sidecar --distpath dist --clean --noconfirm \
--hidden-import piexif \
--hidden-import mutagen \
--hidden-import hachoir \
--hidden-import olefile \
--hidden-import openpyxl \
--hidden-import docx \
--hidden-import pptx \
--hidden-import pypdf
- uses: actions/setup-node@v6
with:
node-version: '22'
cache: npm
cache-dependency-path: frontend/package-lock.json
- name: Build frontend
run: |
cd frontend
npm ci
npm run build
- name: Cache Electron download
uses: actions/cache@v4
with:
path: ${{ env.ELECTRON_CACHE }}
key: electron-${{ runner.os }}-${{ hashFiles('electron/package-lock.json') }}
- name: Test electron setup
run: |
cd electron
npm ci --include=dev
# ─────────────────────────────────────────────────────────────────────────────
# BETA RELEASE (develop only) — Package and publish a prerelease build
# ─────────────────────────────────────────────────────────────────────────────
get-version-beta:
if: github.ref == 'refs/heads/develop'
needs: [test-python, test-frontend, test-electron]
runs-on: ubuntu-latest
permissions:
contents: read
outputs:
base_version: ${{ steps.ver.outputs.base_version }}
beta_version: ${{ steps.ver.outputs.beta_version }}
steps:
- uses: actions/checkout@v6
- id: ver
env:
GH_TOKEN: ${{ github.token }}
run: |
BASE=$(grep -oP 'VERSION\s*=\s*"\K[^"]+' python/config.py)
# Count existing beta releases for this exact base version and increment —
# keeps beta.N scoped to the version instead of the workflow's global run number.
LAST=$(gh release list --repo "${{ github.repository }}" --limit 200 \
| grep -oP "v${BASE}-beta\.\K[0-9]+" | sort -n | tail -1)
NEXT=$(( ${LAST:-0} + 1 ))
BETA="${BASE}-beta.${NEXT}"
echo "base_version=$BASE" >> "$GITHUB_OUTPUT"
echo "beta_version=$BETA" >> "$GITHUB_OUTPUT"
echo "Building MetaLens beta v$BETA"
build-windows-beta:
if: github.ref == 'refs/heads/develop'
needs: get-version-beta
runs-on: windows-latest
permissions:
contents: read
env:
ELECTRON_CACHE: ${{ github.workspace }}/.electron-cache
steps:
- uses: actions/checkout@v6
- uses: actions/setup-python@v6
with:
python-version: '3.12'
cache: pip
cache-dependency-path: python/requirements.txt
- name: Build Python sidecar
shell: pwsh
run: |
cd python
pip install -r requirements.txt -q
pip install pyinstaller -q
python -m PyInstaller main.py --onefile --name metalens-sidecar --distpath dist --clean --noconfirm `
--hidden-import piexif `
--hidden-import mutagen `
--hidden-import hachoir `
--hidden-import olefile `
--hidden-import openpyxl `
--hidden-import docx `
--hidden-import pptx `
--hidden-import pypdf
- uses: actions/setup-node@v6
with:
node-version: '22'
cache: npm
cache-dependency-path: frontend/package-lock.json
- name: Build React frontend
run: |
cd frontend
npm ci
npm run build
- name: Copy frontend dist into electron
run: cp -r frontend/dist electron/frontend
- name: Sync electron version to beta
run: |
cd electron
npm version ${{ needs.get-version-beta.outputs.beta_version }} --no-git-tag-version --allow-same-version
- name: Cache Electron download
uses: actions/cache@v4
with:
path: ${{ env.ELECTRON_CACHE }}
key: electron-${{ runner.os }}-${{ hashFiles('electron/package-lock.json') }}
- name: Package with Electron Forge
run: |
cd electron
npm ci --include=dev
npx electron-forge make
- name: Upload Windows beta artifact
uses: actions/upload-artifact@v7
with:
name: windows-installer-beta
path: electron/out/make/**/*.exe
if-no-files-found: error
build-linux-beta:
if: github.ref == 'refs/heads/develop'
needs: get-version-beta
runs-on: ubuntu-latest
permissions:
contents: read
env:
ELECTRON_CACHE: ${{ github.workspace }}/.electron-cache
steps:
- uses: actions/checkout@v6
- name: Install system dependencies
run: sudo apt-get update -qq && sudo apt-get install -y rpm fakeroot
- uses: actions/setup-python@v6
with:
python-version: '3.12'
cache: pip
cache-dependency-path: python/requirements.txt
- name: Build Python sidecar
run: |
cd python
pip install -r requirements.txt -q
pip install pyinstaller -q
python -m PyInstaller main.py --onefile --name metalens-sidecar --distpath dist --clean --noconfirm \
--hidden-import piexif \
--hidden-import mutagen \
--hidden-import hachoir \
--hidden-import olefile \
--hidden-import openpyxl \
--hidden-import docx \
--hidden-import pptx \
--hidden-import pypdf
- uses: actions/setup-node@v6
with:
node-version: '22'
cache: npm
cache-dependency-path: frontend/package-lock.json
- name: Build React frontend
run: |
cd frontend
npm ci
npm run build
- name: Copy frontend dist into electron
run: cp -r frontend/dist electron/frontend
- name: Sync electron version to beta
run: |
cd electron
npm version ${{ needs.get-version-beta.outputs.beta_version }} --no-git-tag-version --allow-same-version
- name: Configure RPM macros
run: echo '%_build_id_links none' >> ~/.rpmmacros
- name: Cache Electron download
uses: actions/cache@v4
with:
path: ${{ env.ELECTRON_CACHE }}
key: electron-${{ runner.os }}-${{ hashFiles('electron/package-lock.json') }}
- name: Package with Electron Forge
run: |
cd electron
npm ci --include=dev
npx electron-forge make
- name: Create Linux tar.gz
run: |
VERSION=${{ needs.get-version-beta.outputs.beta_version }}
APP_DIR=$(find electron/out -maxdepth 1 -type d -name "MetaLens-linux-*" | head -1)
if [ -n "$APP_DIR" ]; then
tar -czf "electron/out/make/MetaLens-${VERSION}-Linux.tar.gz" \
-C "$(dirname "$APP_DIR")" "$(basename "$APP_DIR")"
echo "Created MetaLens-${VERSION}-Linux.tar.gz"
else
echo "Warning: no MetaLens-linux-* directory found, skipping tar.gz"
fi
- name: Upload Linux beta artifacts
uses: actions/upload-artifact@v7
with:
name: linux-packages-beta
path: |
electron/out/make/**/*.deb
electron/out/make/**/*.rpm
electron/out/make/**/*.tar.gz
if-no-files-found: error
release-beta:
if: github.ref == 'refs/heads/develop'
needs: [get-version-beta, build-windows-beta, build-linux-beta]
runs-on: ubuntu-latest
permissions:
contents: write
steps:
- uses: actions/download-artifact@v8
with:
path: artifacts
- name: List artifacts
run: find artifacts -type f
- name: Create beta GitHub Release
uses: softprops/action-gh-release@v3
with:
tag_name: v${{ needs.get-version-beta.outputs.beta_version }}
target_commitish: ${{ github.sha }}
name: MetaLens v${{ needs.get-version-beta.outputs.beta_version }} (beta)
draft: false
prerelease: true
generate_release_notes: true
make_latest: false
files: |
artifacts/windows-installer-beta/**
artifacts/linux-packages-beta/**
# ─────────────────────────────────────────────────────────────────────────────
# STABLE RELEASE (main only) — Promote the matching beta build, no rebuild
# ─────────────────────────────────────────────────────────────────────────────
get-version:
if: github.ref == 'refs/heads/main'
runs-on: ubuntu-latest
permissions:
contents: read
outputs:
version: ${{ steps.ver.outputs.version }}
steps:
- uses: actions/checkout@v6
- id: ver
run: |
VERSION=$(grep -oP 'VERSION\s*=\s*"\K[^"]+' python/config.py)
echo "version=$VERSION" >> "$GITHUB_OUTPUT"
echo "Building MetaLens v$VERSION"
find-latest-beta:
if: github.ref == 'refs/heads/main'
needs: get-version
runs-on: ubuntu-latest
permissions:
contents: read
outputs:
beta_tag: ${{ steps.find.outputs.beta_tag }}
steps:
- id: find
env:
GH_TOKEN: ${{ github.token }}
VERSION: ${{ needs.get-version.outputs.version }}
run: |
TAG=$(gh release list --repo "$GITHUB_REPOSITORY" --limit 200 --json tagName \
--jq '.[].tagName' \
| grep -E "^v${VERSION}-beta\.[0-9]+$" \
| sort -t. -k4 -n \
| tail -1)
if [ -z "$TAG" ]; then
echo "::error::Nessuna release beta trovata per v${VERSION}. Genera prima una beta da develop con la stessa VERSION in python/config.py."
exit 1
fi
echo "beta_tag=$TAG" >> "$GITHUB_OUTPUT"
echo "Promuovendo $TAG a stable v${VERSION}"
promote-stable:
if: github.ref == 'refs/heads/main'
needs: [get-version, find-latest-beta]
runs-on: ubuntu-latest
permissions:
contents: write
steps:
- name: Download beta release assets
env:
GH_TOKEN: ${{ github.token }}
run: |
mkdir -p promoted
gh release download "${{ needs.find-latest-beta.outputs.beta_tag }}" \
--repo "$GITHUB_REPOSITORY" --dir promoted
- name: Strip beta suffix from filenames
run: |
cd promoted
# Each maker encodes the beta suffix differently: "-beta.N" (exe/tar.gz),
# "beta.N" with no separator (rpm, dash stripped for Version field rules),
# ".beta.N" (deb, dot-separated per Debian version conventions).
for f in *; do
new=$(echo "$f" | sed -E 's/[-.]?beta\.?[0-9]+//')
if [ "$f" != "$new" ]; then mv -- "$f" "$new"; fi
done
ls -la
- name: Create stable GitHub Release
uses: softprops/action-gh-release@v3
with:
tag_name: v${{ needs.get-version.outputs.version }}
target_commitish: ${{ github.sha }}
name: MetaLens v${{ needs.get-version.outputs.version }}
draft: false
prerelease: false
generate_release_notes: true
make_latest: true
files: promoted/*