ci: assemble complete latest.json across all platforms #111
Workflow file for this run
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| name: Release | |
| on: | |
| push: | |
| tags: | |
| - "v*" | |
| workflow_dispatch: | |
| jobs: | |
| release: | |
| strategy: | |
| fail-fast: false | |
| matrix: | |
| include: | |
| - os: macos-latest | |
| target: x86_64-apple-darwin | |
| args: | |
| - os: ubuntu-22.04 | |
| target: x86_64-unknown-linux-gnu | |
| args: | |
| - os: windows-latest | |
| target: x86_64-pc-windows-msvc | |
| args: | |
| - os: macos-latest | |
| target: aarch64-apple-darwin | |
| args: | |
| - os: windows-latest | |
| target: aarch64-pc-windows-msvc | |
| args: --bundles nsis,updater | |
| - os: ubuntu-22.04-arm | |
| target: aarch64-unknown-linux-gnu | |
| args: | |
| runs-on: ${{ matrix.os }} | |
| steps: | |
| - name: Checkout repository | |
| uses: actions/checkout@v4 | |
| with: | |
| repository: AlistGo/desktop | |
| token: ${{ secrets.MY_TOKEN }} | |
| - name: Install dependencies (ubuntu only) | |
| if: contains(matrix.target, 'unknown-linux-gnu') | |
| # You can remove libayatana-appindicator3-dev if you don't use the system tray feature. | |
| run: | | |
| sudo apt-get update | |
| sudo apt-get install -y libgtk-3-dev libwebkit2gtk-4.0-dev libayatana-appindicator3-dev librsvg2-dev | |
| - name: Rust setup | |
| uses: dtolnay/rust-toolchain@stable | |
| with: | |
| targets: ${{ matrix.target }} | |
| - name: Rust cache | |
| uses: swatinem/rust-cache@v2 | |
| with: | |
| workspaces: "./src-tauri -> target" | |
| - uses: pnpm/action-setup@v2 | |
| with: | |
| version: 9 | |
| run_install: false | |
| - name: Sync node version and setup cache | |
| uses: actions/setup-node@v4 | |
| with: | |
| node-version: "lts/*" | |
| cache: "pnpm" # Set this to npm, yarn or pnpm. | |
| - name: Install app dependencies and build web | |
| run: pnpm i | |
| - name: Replace version | |
| run: | | |
| npx tsx ./scripts/version.ts | |
| cat src-tauri/tauri.conf.json | |
| env: | |
| AD_VERSION: ${{ github.ref_name }} | |
| - name: Get AList version | |
| id: get-alist-version | |
| uses: fangqiuming/latest-release-version@v1.2.0-beta | |
| with: | |
| repository: AlistGo/alist | |
| token: ${{ secrets.GITHUB_TOKEN }} | |
| - name: Get Rclone version | |
| id: get-rclone-version | |
| uses: fangqiuming/latest-release-version@v1.2.0-beta | |
| with: | |
| repository: rclone/rclone | |
| token: ${{ secrets.GITHUB_TOKEN }} | |
| - name: Download sidecar | |
| run: npx tsx ./scripts/bin.ts | |
| env: | |
| TARGET_TRIPLE: ${{ matrix.target }} | |
| ALIST_VERSION: ${{ steps.get-alist-version.outputs.tag_name }} # v3.19.0 | |
| RCLONE_VERSION: ${{ steps.get-rclone-version.outputs.tag_name }} # v1.63.0 | |
| - name: Build & publish (coordinator uploads latest.json) | |
| if: ${{ matrix.os == 'macos-latest' && matrix.target == 'x86_64-apple-darwin' }} | |
| uses: tauri-apps/tauri-action@v0 | |
| env: | |
| GITHUB_TOKEN: ${{ secrets.MY_TOKEN }} | |
| TAURI_PRIVATE_KEY: ${{ secrets.TAURI_PRIVATE_KEY }} | |
| with: | |
| tagName: ${{ github.ref_name }} # This only works if your workflow triggers on new tags. | |
| releaseName: "AList Desktop v__VERSION__" # tauri-action replaces \_\_VERSION\_\_ with the app version. | |
| releaseBody: "See the assets to download and install this version." | |
| args: "--target ${{ matrix.target }} ${{ matrix.args }}" | |
| - name: Build & publish (no updater json) | |
| if: ${{ !(matrix.os == 'macos-latest' && matrix.target == 'x86_64-apple-darwin') }} | |
| uses: tauri-apps/tauri-action@v0 | |
| env: | |
| GITHUB_TOKEN: ${{ secrets.MY_TOKEN }} | |
| TAURI_PRIVATE_KEY: ${{ secrets.TAURI_PRIVATE_KEY }} | |
| with: | |
| tagName: ${{ github.ref_name }} # This only works if your workflow triggers on new tags. | |
| releaseName: "AList Desktop v__VERSION__" # tauri-action replaces \_\_VERSION\_\_ with the app version. | |
| releaseBody: "See the assets to download and install this version." | |
| args: "--target ${{ matrix.target }} ${{ matrix.args }}" | |
| includeUpdaterJson: false | |
| build_updater: | |
| name: "Build updater" | |
| needs: release | |
| environment: ${{ github.event.inputs.environment || 'Beta' }} | |
| runs-on: ubuntu-latest | |
| steps: | |
| - name: Checkout repository | |
| uses: actions/checkout@v4 | |
| - uses: pnpm/action-setup@v2 | |
| with: | |
| version: 9 | |
| run_install: false | |
| - name: Sync node version and setup cache | |
| uses: actions/setup-node@v4 | |
| with: | |
| node-version: "lts/*" | |
| # cache: "pnpm" # Set this to npm, yarn or pnpm. | |
| - name: Generate proxy.json | |
| run: | | |
| npx tsx ./proxy.ts | |
| - name: Upload proxy.json | |
| uses: softprops/action-gh-release@v1 | |
| with: | |
| fail_on_unmatched_files: true | |
| token: ${{ secrets.MY_TOKEN }} | |
| files: | | |
| *.proxy.json | |
| compose_latest_json: | |
| name: "Compose complete latest.json" | |
| needs: release | |
| runs-on: ubuntu-latest | |
| steps: | |
| - name: Assemble latest.json from every platform's updater assets | |
| uses: actions/github-script@v7 | |
| with: | |
| github-token: ${{ secrets.MY_TOKEN }} | |
| script: | | |
| const [owner, repo] = process.env.GITHUB_REPOSITORY.split("/"); | |
| const tag = "${{ github.ref_name }}"; | |
| const rel = await github.rest.repos.getReleaseByTag({ owner, repo, tag }); | |
| const assets = await github.paginate(github.rest.repos.listReleaseAssets, { | |
| owner, repo, release_id: rel.data.id, per_page: 100, | |
| }); | |
| const byName = new Map(assets.map((a) => [a.name, a])); | |
| const downloadUrl = (name) => | |
| `https://github.com/${owner}/${repo}/releases/download/${tag}/${encodeURIComponent(name)}`; | |
| async function readSig(name) { | |
| const a = byName.get(name + ".sig"); | |
| if (!a) return null; | |
| const res = await github.request( | |
| "GET /repos/{owner}/{repo}/releases/assets/{asset_id}", | |
| { owner, repo, asset_id: a.id, headers: { accept: "application/octet-stream" } } | |
| ); | |
| return Buffer.from(res.data).toString("utf8").trim(); | |
| } | |
| // First non-.sig asset whose name matches the regex. | |
| const pick = (re) => | |
| (assets.find((a) => re.test(a.name) && !a.name.endsWith(".sig")) || {}).name; | |
| const macX = pick(/^alist-desktop_x64\.app\.tar\.gz$/); | |
| const macA = pick(/^alist-desktop_aarch64\.app\.tar\.gz$/); | |
| const winXmsi = pick(/_x64_en-US\.msi\.zip$/); | |
| const winXnsis = pick(/_x64-setup\.nsis\.zip$/); | |
| const winA = pick(/_arm64-setup\.nsis\.zip$/); | |
| const linX = pick(/_amd64\.AppImage\.tar\.gz$/); | |
| const linA = pick(/_aarch64\.AppImage\.tar\.gz$/); | |
| const platforms = {}; | |
| async function add(key, name) { | |
| if (!name) return; | |
| const signature = await readSig(name); | |
| if (signature == null) { | |
| core.warning(`no .sig for ${name}, skipping ${key}`); | |
| return; | |
| } | |
| platforms[key] = { signature, url: downloadUrl(name) }; | |
| } | |
| await add("darwin-x86_64", macX); | |
| await add("darwin-x86_64-app", macX); | |
| await add("darwin-aarch64", macA); | |
| await add("darwin-aarch64-app", macA); | |
| await add("windows-x86_64", winXmsi || winXnsis); | |
| if (winXmsi) await add("windows-x86_64-msi", winXmsi); | |
| if (winXnsis) await add("windows-x86_64-nsis", winXnsis); | |
| await add("windows-aarch64", winA); | |
| await add("windows-aarch64-nsis", winA); | |
| await add("linux-x86_64", linX); | |
| await add("linux-aarch64", linA); | |
| if (Object.keys(platforms).length === 0) { | |
| core.setFailed("No updater artifacts found; latest.json not composed"); | |
| return; | |
| } | |
| let version = tag.replace(/^v/, ""); | |
| const versioned = winXnsis || winXmsi || winA || linX || linA || ""; | |
| const vm = versioned.match(/alist-desktop_([0-9][^_]*)_/); | |
| if (vm) version = vm[1]; | |
| const latest = { | |
| version, | |
| notes: "See the assets to download and install this version.", | |
| pub_date: new Date().toISOString(), | |
| platforms, | |
| }; | |
| const body = JSON.stringify(latest, null, 2); | |
| core.info("Composed latest.json:\n" + body); | |
| const existing = byName.get("latest.json"); | |
| if (existing) { | |
| await github.rest.repos.deleteReleaseAsset({ owner, repo, asset_id: existing.id }); | |
| } | |
| await github.rest.repos.uploadReleaseAsset({ | |
| owner, repo, release_id: rel.data.id, | |
| name: "latest.json", | |
| data: body, | |
| headers: { | |
| "content-type": "application/json", | |
| "content-length": Buffer.byteLength(body), | |
| }, | |
| }); | |
| core.info(`Uploaded latest.json with platforms: ${Object.keys(platforms).join(", ")}`); |