ci: assemble complete latest.json across all platforms #201
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 Beta | |
| on: | |
| push: | |
| branches: | |
| - main | |
| issue_comment: | |
| types: [created] | |
| workflow_dispatch: | |
| concurrency: | |
| group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }} | |
| cancel-in-progress: true | |
| jobs: | |
| update_beta_ref: | |
| runs-on: ubuntu-latest | |
| if: ${{ github.event_name != 'issue_comment' || (github.event.issue.number == 69 && contains(github.event.comment.body, '/release-beta')) }} | |
| steps: | |
| - name: Create or update ref | |
| id: create-or-update-ref | |
| uses: ovsds/create-or-update-ref-action@v1 | |
| env: | |
| GITHUB_TOKEN: ${{ secrets.MY_TOKEN }} | |
| with: | |
| ref: refs/tags/beta | |
| sha: ${{ github.sha }} | |
| release_beta: | |
| needs: update_beta_ref | |
| 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: --bundles nsis,updater | |
| - 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') }} | |
| 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" | |
| - name: Install app dependencies and build web | |
| run: pnpm i | |
| - name: Replace version | |
| run: | | |
| npx tsx ./scripts/beta_version.ts | |
| cat src-tauri/tauri.conf.json | |
| env: | |
| AD_VERSION: ${{ github.ref_name }} | |
| TARGET_TRIPLE: ${{ matrix.target }} | |
| - 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: beta | |
| RCLONE_VERSION: ${{ steps.get-rclone-version.outputs.tag_name }} | |
| - name: Clean conflicting macOS app tarballs | |
| if: ${{ contains(matrix.target, 'apple-darwin') }} | |
| uses: actions/github-script@v7 | |
| with: | |
| github-token: ${{ secrets.MY_TOKEN }} | |
| script: | | |
| const [owner, repo] = process.env.GITHUB_REPOSITORY.split("/"); | |
| const tag = "beta"; | |
| const target = "${{ matrix.target }}"; | |
| const patterns = | |
| target === "x86_64-apple-darwin" | |
| ? [/^alist-desktop_x64\.app\.tar\.gz$/, /^alist-desktop_x64\.app\.tar\.gz\.sig$/] | |
| : target === "aarch64-apple-darwin" | |
| ? [/^alist-desktop_aarch64\.app\.tar\.gz$/, /^alist-desktop_aarch64\.app\.tar\.gz\.sig$/] | |
| : []; | |
| if (patterns.length === 0) return; | |
| 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 }); | |
| for (const a of assets) { | |
| if (patterns.some(rx => rx.test(a.name))) { | |
| await github.rest.repos.deleteReleaseAsset({ owner, repo, asset_id: a.id }); | |
| } | |
| } | |
| - 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: | |
| releaseName: "AList Desktop v__VERSION__" | |
| releaseBody: "See the assets to download and install this version." | |
| args: "--target ${{ matrix.target }} ${{ matrix.args }}" | |
| prerelease: true | |
| tagName: beta | |
| - 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: | |
| releaseName: "AList Desktop v__VERSION__" | |
| releaseBody: "See the assets to download and install this version." | |
| args: "--target ${{ matrix.target }} ${{ matrix.args }}" | |
| prerelease: true | |
| tagName: beta | |
| includeUpdaterJson: false | |
| build_updater: | |
| name: "Build updater beta" | |
| needs: release_beta | |
| environment: ${{ github.event.inputs.environment || 'Beta' }} | |
| runs-on: ubuntu-latest | |
| steps: | |
| - name: Checkout repository | |
| uses: actions/checkout@v4 | |
| with: | |
| ref: main | |
| - 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/*" | |
| - name: Generate proxy.json | |
| run: | | |
| npx tsx ./proxy.ts | |
| - name: Upload proxy.json | |
| uses: softprops/action-gh-release@v2 | |
| with: | |
| token: ${{ secrets.MY_TOKEN }} | |
| tag_name: beta | |
| prerelease: true | |
| make_latest: false | |
| allow_updates: true | |
| fail_on_unmatched_files: true | |
| files: | | |
| *.proxy.json | |
| compose_latest_json: | |
| name: "Compose complete latest.json beta" | |
| needs: release_beta | |
| 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 = "beta"; | |
| 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(", ")}`); |