mirror of
https://github.com/t8y2/dbx.git
synced 2026-10-20 08:18:52 +00:00
199 lines
7.4 KiB
YAML
199 lines
7.4 KiB
YAML
name: UI preview
|
|
|
|
# A pull request that changes the UI gets screenshots — and a screen
|
|
# recording, the mouse drawn in, when the change needs clicking to see — of
|
|
# the real app built from it, in a fixed block at the foot of its
|
|
# description. See .github/ui-preview/.
|
|
#
|
|
# Pull requests come from forks, so this runs on pull_request_target with
|
|
# the scripts from main. The PR's code is only built and run in the record
|
|
# job, which holds the planner's API key (environment ui-preview, no approval
|
|
# asked: any PR's code can read it, so the key there is one with a low
|
|
# limit) and nothing that can write to the repo. The publish job, which can
|
|
# write, never runs the PR's code.
|
|
#
|
|
# The backend the recording runs against comes in two lanes: a diff that
|
|
# only touches the frontend (the usual case) runs against the released
|
|
# dbx-web static binary — no Rust is built; a diff that reaches crates/,
|
|
# plugins/ or src-tauri/ builds dbx-web from the PR itself. Either way the
|
|
# PR's own frontend build is what's on screen (DBX_STATIC_DIR).
|
|
|
|
on:
|
|
# Temporarily disabled (2026-10-10) while jobs queue without a runner;
|
|
# manual dispatch below still works. Uncomment to re-enable.
|
|
# pull_request_target:
|
|
# types: [opened, synchronize, reopened, labeled]
|
|
workflow_dispatch:
|
|
inputs:
|
|
pr:
|
|
description: Pull request number
|
|
required: true
|
|
|
|
concurrency:
|
|
group: ui-preview-${{ github.event.pull_request.number || inputs.pr }}
|
|
cancel-in-progress: true
|
|
|
|
permissions: {}
|
|
|
|
jobs:
|
|
detect:
|
|
if: github.event.action != 'labeled' || github.event.label.name == 'ui-preview'
|
|
runs-on: ubuntu-latest
|
|
permissions:
|
|
contents: read
|
|
pull-requests: write
|
|
outputs:
|
|
ui: ${{ steps.detect.outputs.ui }}
|
|
lane: ${{ steps.detect.outputs.lane }}
|
|
sha: ${{ steps.detect.outputs.sha }}
|
|
number: ${{ steps.detect.outputs.number }}
|
|
steps:
|
|
- uses: actions/checkout@v4
|
|
with:
|
|
ref: ${{ github.event.repository.default_branch }}
|
|
sparse-checkout: .github/ui-preview
|
|
persist-credentials: false
|
|
- uses: actions/setup-node@v4
|
|
with:
|
|
node-version: 22
|
|
- id: detect
|
|
env:
|
|
GITHUB_TOKEN: ${{ github.token }}
|
|
PR: ${{ github.event.pull_request.number || inputs.pr }}
|
|
RUN_URL: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}
|
|
run: node .github/ui-preview/publish.mjs detect
|
|
# what the recorder reads of the PR, handed over so its job needs no token
|
|
- if: steps.detect.outputs.ui == 'true'
|
|
env:
|
|
GH_TOKEN: ${{ github.token }}
|
|
PR: ${{ steps.detect.outputs.number }}
|
|
run: |
|
|
mkdir pr-info
|
|
gh api "repos/$GITHUB_REPOSITORY/pulls/$PR" -H "Accept: application/vnd.github.diff" > pr-info/pr.diff
|
|
gh api "repos/$GITHUB_REPOSITORY/pulls/$PR" --jq .title > pr-info/title.txt
|
|
gh api "repos/$GITHUB_REPOSITORY/pulls/$PR" --jq '.body // ""' > pr-info/body.txt
|
|
- if: steps.detect.outputs.ui == 'true'
|
|
uses: actions/upload-artifact@v4
|
|
with:
|
|
name: pr-info
|
|
path: pr-info
|
|
retention-days: 3
|
|
|
|
record:
|
|
needs: detect
|
|
if: needs.detect.outputs.ui == 'true'
|
|
runs-on: ubuntu-latest
|
|
timeout-minutes: ${{ needs.detect.outputs.lane == 'rust' && 60 || 30 }}
|
|
environment: ui-preview
|
|
permissions:
|
|
contents: read
|
|
env:
|
|
PLAYWRIGHT_BROWSERS_PATH: ${{ github.workspace }}/.pw
|
|
steps:
|
|
- uses: actions/checkout@v4
|
|
with:
|
|
ref: ${{ github.event.repository.default_branch }}
|
|
path: ci
|
|
sparse-checkout: .github/ui-preview
|
|
persist-credentials: false
|
|
# the fork's code, on purpose: this job is the one meant to run it,
|
|
# with a read-only token and no credentials left in the checkout
|
|
- uses: actions/checkout@v4
|
|
with:
|
|
ref: ${{ needs.detect.outputs.sha }}
|
|
path: pr
|
|
persist-credentials: false
|
|
allow-unsafe-pr-checkout: true
|
|
- uses: actions/download-artifact@v4
|
|
with:
|
|
name: pr-info
|
|
path: pr-info
|
|
|
|
# the frontend, from the PR, for both lanes
|
|
- uses: pnpm/action-setup@v6
|
|
with:
|
|
package_json_file: pr/package.json
|
|
- uses: actions/setup-node@v4
|
|
with:
|
|
node-version: 22
|
|
cache: pnpm
|
|
cache-dependency-path: pr/pnpm-lock.yaml
|
|
- name: Build the PR's frontend
|
|
working-directory: pr
|
|
run: |
|
|
pnpm install --frozen-lockfile || pnpm install
|
|
pnpm build
|
|
|
|
# the backend: released static binary, or built from the PR
|
|
- name: The released dbx-web (frontend-only diff)
|
|
if: needs.detect.outputs.lane != 'rust'
|
|
working-directory: ${{ github.workspace }}
|
|
env:
|
|
GH_TOKEN: ${{ github.token }}
|
|
run: |
|
|
mkdir -p backend
|
|
gh release download --repo "$GITHUB_REPOSITORY" --pattern '*x64-browser-static.tar.gz' --dir backend --clobber
|
|
tar xzf backend/*x64-browser-static.tar.gz -C backend
|
|
echo "DBX_WEB_BIN=$(echo backend/*/dbx-web)" >> "$GITHUB_ENV"
|
|
- name: dbx-web built from the PR (backend diff)
|
|
if: needs.detect.outputs.lane == 'rust'
|
|
working-directory: pr
|
|
run: |
|
|
cargo build --release -p dbx-web --no-default-features --features dbx-core/sqlite-bundled
|
|
echo "DBX_WEB_BIN=pr/target/release/dbx-web" >> "$GITHUB_ENV"
|
|
|
|
- name: Chromium, ffmpeg and fonts
|
|
working-directory: ci/.github/ui-preview
|
|
run: |
|
|
sudo apt-get update
|
|
sudo apt-get install -y ffmpeg fonts-noto-cjk fonts-noto-color-emoji
|
|
npm install --no-audit --no-fund
|
|
npx playwright install --with-deps chromium
|
|
- name: Record
|
|
env:
|
|
PLAN_API_URL: https://api.atlascloud.ai/v1/chat/completions
|
|
PLAN_API_KEY: ${{ secrets.PLAN_API_KEY }}
|
|
PLAN_MODEL: ${{ vars.UI_PREVIEW_PLAN_MODEL || 'openai/gpt-5.4-mini' }}
|
|
DIFF_FILE: ${{ github.workspace }}/pr-info/pr.diff
|
|
PR_BODY_FILE: ${{ github.workspace }}/pr-info/body.txt
|
|
DIST_DIR: ${{ github.workspace }}/pr/dist
|
|
SRC_DIR: ${{ github.workspace }}/pr
|
|
run: PR_TITLE="$(cat pr-info/title.txt)" ci/.github/ui-preview/run.sh out
|
|
- if: always()
|
|
uses: actions/upload-artifact@v4
|
|
with:
|
|
name: ui-preview
|
|
path: out
|
|
retention-days: 7
|
|
if-no-files-found: ignore
|
|
|
|
publish:
|
|
needs: [detect, record]
|
|
if: always() && needs.detect.outputs.ui == 'true'
|
|
runs-on: ubuntu-latest
|
|
permissions:
|
|
contents: write
|
|
pull-requests: write
|
|
steps:
|
|
- uses: actions/checkout@v4
|
|
with:
|
|
ref: ${{ github.event.repository.default_branch }}
|
|
sparse-checkout: .github/ui-preview
|
|
persist-credentials: false
|
|
- uses: actions/setup-node@v4
|
|
with:
|
|
node-version: 22
|
|
- uses: actions/download-artifact@v4
|
|
continue-on-error: true
|
|
with:
|
|
name: ui-preview
|
|
path: out
|
|
- env:
|
|
GITHUB_TOKEN: ${{ github.token }}
|
|
PR: ${{ needs.detect.outputs.number }}
|
|
SHA: ${{ needs.detect.outputs.sha }}
|
|
OUT_DIR: out
|
|
RECORD_RESULT: ${{ needs.record.result }}
|
|
RUN_URL: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}
|
|
run: node .github/ui-preview/publish.mjs publish
|