OpenSSF Scorecard / Scorecard analysis (push) Waiting to run
CI / Build & test (Node 20) (push) Canceled after 0s
CI / Build & test (Node 24) (push) Canceled after 0s
CI / Build & test (push) Canceled after 0s
CodeQL / Analyze (javascript-typescript) (push) Canceled after 0s
Security / Secret scan (gitleaks) (push) Canceled after 0s
Security / Dependency scan (OSV-Scanner) (push) Canceled after 0s
Security / IaC/config scan (Trivy) (push) Canceled after 0s
Security / License compliance scan (Trivy) (push) Canceled after 0s
GitHub stays the build machine — it has the Windows runners the native audio module needs — but the update feed moves to this fork's own Gitea. The GitHub repository is private, and electron-updater against a private GitHub repo needs a token inside the shipped app, which is a leaked token. Gitea serves release assets to anyone, so the installer carries no credential. The flow was verified end to end against the live instance before writing this: create release, upload asset, download anonymously. The release tag is fixed at 'latest' because electron-updater fetches latest.yml before it knows which version exists, so the URL cannot carry a version; CI replaces that release's assets each publish. electron-builder runs with --publish never since it cannot upload to Gitea, but still emits the latest.yml the updater reads. Needs a GITEA_TOKEN secret on the GitHub repository.
153 lines
5.8 KiB
YAML
153 lines
5.8 KiB
YAML
# Compila no GitHub, publica no Gitea.
|
|
#
|
|
# O GitHub entra só como máquina de build — é dele que vêm os runners Windows
|
|
# de que o módulo nativo de áudio precisa. A distribuição fica no Gitea, que
|
|
# serve os arquivos a qualquer um: assim o electron-updater não precisa de
|
|
# credencial embutida no app, o que aconteceria com um repositório privado no
|
|
# GitHub.
|
|
name: Publicar no Gitea
|
|
|
|
on:
|
|
push:
|
|
tags: ['v*']
|
|
workflow_dispatch:
|
|
inputs:
|
|
tag:
|
|
description: Tag a publicar (ex. v1.1.0)
|
|
required: true
|
|
type: string
|
|
|
|
permissions:
|
|
contents: read
|
|
|
|
jobs:
|
|
build:
|
|
strategy:
|
|
fail-fast: false
|
|
matrix:
|
|
include:
|
|
- os: windows-2022
|
|
args: --win --x64
|
|
- os: ubuntu-latest
|
|
args: --linux --x64
|
|
runs-on: ${{ matrix.os }}
|
|
|
|
steps:
|
|
- name: Checkout
|
|
uses: actions/checkout@93cb6efe18208431cddfb8368fd83d5badbf9bfd # v5.0.1
|
|
|
|
- name: Install Linux build dependencies
|
|
if: runner.os == 'Linux'
|
|
run: |
|
|
sudo apt-get update
|
|
sudo apt-get install -y \
|
|
libx11-dev libxtst-dev libxt-dev \
|
|
libxkbcommon-dev libxkbcommon-x11-dev libxkbfile-dev \
|
|
libxrandr-dev libxinerama-dev libx11-xcb-dev
|
|
|
|
- name: Setup pnpm
|
|
uses: pnpm/action-setup@fc06bc1257f339d1d5d8b3a19a8cae5388b55320 # v5.0.0
|
|
with:
|
|
version: 10.34.3
|
|
|
|
- name: Setup Node.js
|
|
uses: actions/setup-node@a0853c24544627f65ddf259abe73b1d18a591444 # v5.0.0
|
|
with:
|
|
node-version: 20
|
|
cache: pnpm
|
|
|
|
- name: Cache Electron binaries
|
|
uses: actions/cache@v4
|
|
with:
|
|
path: |
|
|
~/.cache/electron
|
|
~/.cache/electron-builder
|
|
~\AppData\Local\electron\Cache
|
|
~\AppData\Local\electron-builder\Cache
|
|
key: electron-cache-${{ runner.os }}-${{ hashFiles('**/pnpm-lock.yaml') }}
|
|
restore-keys: electron-cache-${{ runner.os }}-
|
|
|
|
- name: Install dependencies
|
|
run: pnpm install --frozen-lockfile
|
|
|
|
- name: Build shared package
|
|
run: pnpm --filter @backspace/shared build
|
|
|
|
# O postinstall termina em `|| console.warn` para quem não tem ferramentas
|
|
# de build. No CI isso esconde falha: o instalador sairia sem captura de
|
|
# áudio do sistema e ninguém saberia. Verifica-se o resultado.
|
|
- name: Verify native audio module compiled
|
|
if: runner.os == 'Windows'
|
|
shell: bash
|
|
run: |
|
|
found=$(find node_modules/.pnpm -path '*electron-native-screenshare*' -name '*.node' | head -5)
|
|
[ -n "$found" ] || { echo "::error::sem .node compilado — instalador sairia sem áudio do sistema"; exit 1; }
|
|
echo "$found"
|
|
|
|
- name: Compile desktop TypeScript
|
|
working-directory: packages/desktop
|
|
run: pnpm exec tsc
|
|
|
|
# --publish never: o electron-builder não sabe enviar para o Gitea. Ele
|
|
# gera os instaladores e o latest.yml (o índice que o app consulta), e o
|
|
# passo seguinte faz o upload.
|
|
- name: Build installers
|
|
working-directory: packages/desktop
|
|
run: pnpm exec electron-builder ${{ matrix.args }} --publish never
|
|
env:
|
|
CSC_IDENTITY_AUTO_DISCOVERY: "false"
|
|
|
|
- name: Upload to Gitea release
|
|
shell: bash
|
|
env:
|
|
GITEA_TOKEN: ${{ secrets.GITEA_TOKEN }}
|
|
GITEA_API: https://git.resenha.website/api/v1/repos/devsyncwrld/backspace
|
|
TAG: latest
|
|
run: |
|
|
set -euo pipefail
|
|
if [ -z "${GITEA_TOKEN:-}" ]; then
|
|
echo "::error::segredo GITEA_TOKEN não configurado no repositório"
|
|
exit 1
|
|
fi
|
|
|
|
# A release `latest` é recriada a cada publicação: o electron-updater
|
|
# busca latest.yml antes de saber qual versão existe, então a URL não
|
|
# pode conter número de versão.
|
|
ID=$(curl -sf -H "Authorization: token $GITEA_TOKEN" \
|
|
"$GITEA_API/releases/tags/$TAG" | python3 -c \
|
|
"import json,sys;print(json.load(sys.stdin).get('id',''))" 2>/dev/null || true)
|
|
|
|
if [ -n "$ID" ]; then
|
|
echo "release existente ($ID) — removendo anexos desta plataforma"
|
|
curl -sf -H "Authorization: token $GITEA_TOKEN" "$GITEA_API/releases/$ID/assets" \
|
|
| python3 -c "import json,sys;[print(a['id'],a['name']) for a in json.load(sys.stdin)]" \
|
|
| while read -r aid aname; do
|
|
case "$aname" in
|
|
*.exe|*.AppImage|*.deb|latest*.yml)
|
|
curl -s -o /dev/null -X DELETE -H "Authorization: token $GITEA_TOKEN" \
|
|
"$GITEA_API/releases/$ID/assets/$aid" ;;
|
|
esac
|
|
done
|
|
else
|
|
ID=$(curl -sf -X POST -H "Authorization: token $GITEA_TOKEN" \
|
|
-H 'Content-Type: application/json' \
|
|
-d "{\"tag_name\":\"$TAG\",\"name\":\"Última versão\",\"body\":\"Instaladores publicados automaticamente pelo CI.\"}" \
|
|
"$GITEA_API/releases" | python3 -c "import json,sys;print(json.load(sys.stdin)['id'])")
|
|
echo "release criada: $ID"
|
|
fi
|
|
|
|
shopt -s nullglob
|
|
sent=0
|
|
for f in packages/desktop/dist-electron/*.exe \
|
|
packages/desktop/dist-electron/*.AppImage \
|
|
packages/desktop/dist-electron/*.deb \
|
|
packages/desktop/dist-electron/latest*.yml; do
|
|
name=$(basename "$f")
|
|
echo "enviando $name"
|
|
curl -sf -X POST -H "Authorization: token $GITEA_TOKEN" \
|
|
-F "attachment=@$f" "$GITEA_API/releases/$ID/assets?name=$name" > /dev/null
|
|
sent=$((sent+1))
|
|
done
|
|
[ "$sent" -gt 0 ] || { echo "::error::nada para enviar — o build não produziu instaladores"; exit 1; }
|
|
echo "$sent arquivo(s) publicados"
|