ci: build on GitHub, publish updates from Gitea
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
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.
This commit is contained in:
@@ -0,0 +1,152 @@
|
||||
# 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"
|
||||
@@ -22,11 +22,19 @@ asarUnpack:
|
||||
npmRebuild: false
|
||||
afterPack: ./scripts/afterPack.js
|
||||
publish:
|
||||
# Fork: releases (and therefore the electron-updater feed) come from this
|
||||
# repository, not upstream's.
|
||||
- provider: github
|
||||
owner: syncwrld
|
||||
repo: resenhacord
|
||||
# Updates are served from this fork's own Gitea, not from GitHub.
|
||||
#
|
||||
# GitHub is only the build machine — it has the Windows runners the native
|
||||
# audio module needs. Its repository is private, and electron-updater against
|
||||
# a private GitHub repo would need a token shipped inside the app, which is a
|
||||
# leaked token. Gitea serves release assets to anyone, so no credential ends
|
||||
# up in the installer.
|
||||
#
|
||||
# The tag is fixed at `latest` on purpose: electron-updater fetches
|
||||
# latest.yml before it knows which version exists, so the URL cannot contain
|
||||
# a version. CI replaces that release's assets on every publish.
|
||||
- provider: generic
|
||||
url: https://git.resenha.website/devsyncwrld/backspace/releases/download/latest/
|
||||
protocols:
|
||||
- name: Backspace
|
||||
schemes:
|
||||
|
||||
Reference in New Issue
Block a user