Generate Update JSON #17
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: Generate Update JSON | |
| on: | |
| workflow_dispatch: | |
| inputs: | |
| tag: | |
| description: 'The release tag to generate update JSON for (e.g. v0.1.0)' | |
| required: true | |
| type: string | |
| jobs: | |
| create-update: | |
| permissions: | |
| contents: write | |
| runs-on: ubuntu-latest | |
| steps: | |
| - name: Checkout | |
| uses: actions/checkout@v4 | |
| - name: Install Node.js | |
| uses: actions/setup-node@v4 | |
| with: | |
| node-version: 20 | |
| - name: Install pnpm | |
| uses: pnpm/action-setup@v2 | |
| with: | |
| version: 8 | |
| run_install: false | |
| - name: Install Tauri CLI | |
| run: pnpm add -D @tauri-apps/cli | |
| - name: Install jq | |
| run: sudo apt-get install jq | |
| - name: Download release assets | |
| uses: actions/github-script@v7 | |
| with: | |
| script: | | |
| const version = '${{ inputs.tag }}'.replace(/^v/, ''); | |
| const artifacts = [ | |
| 'litepost_aarch64.app.tar.gz', | |
| 'litepost_x64.app.tar.gz', | |
| `litepost_${version}_amd64.AppImage`, | |
| `litepost_${version}_x64-setup.exe` | |
| ]; | |
| const tag = '${{ inputs.tag }}'; | |
| const owner = context.repo.owner; | |
| const repo = context.repo.repo; | |
| // Get all releases including drafts | |
| const releases = await github.rest.repos.listReleases({ | |
| owner, | |
| repo, | |
| per_page: 100 | |
| }); | |
| // Find the release by tag, including drafts | |
| const release = releases.data.find(r => r.tag_name === tag); | |
| if (!release) { | |
| throw new Error('Release not found'); | |
| } | |
| const fs = require('fs'); | |
| const path = require('path'); | |
| if (!fs.existsSync('artifacts')) { | |
| fs.mkdirSync('artifacts'); | |
| } | |
| for (const asset of release.assets) { | |
| if (artifacts.includes(asset.name)) { | |
| // Download using the GitHub API | |
| const response = await github.rest.repos.getReleaseAsset({ | |
| owner, | |
| repo, | |
| asset_id: asset.id, | |
| headers: { | |
| accept: 'application/octet-stream' | |
| } | |
| }); | |
| fs.writeFileSync( | |
| path.join('artifacts', asset.name), | |
| Buffer.from(response.data) | |
| ); | |
| } | |
| } | |
| - name: Generate signatures and updater JSON | |
| env: | |
| TAURI_SIGNING_PRIVATE_KEY: ${{ secrets.TAURI_PRIVATE_KEY }} | |
| TAURI_PRIVATE_KEY: ${{ secrets.TAURI_PRIVATE_KEY }} | |
| TAURI_SIGNING_PRIVATE_KEY_PASSWORD: ${{ secrets.TAURI_KEY_PASSWORD }} | |
| TAURI_KEY_PASSWORD: ${{ secrets.TAURI_KEY_PASSWORD }} | |
| GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} | |
| run: | | |
| # Extract version from tag (remove 'v' prefix) | |
| VERSION="${{ inputs.tag }}" | |
| VERSION=${VERSION#v} | |
| echo "Using version: $VERSION" | |
| echo "Artifact directory contents:" | |
| ls -la artifacts/ | |
| # Sign artifacts and collect signatures | |
| declare -A signatures | |
| # Function to handle signing and capture both stdout and stderr | |
| sign_artifact() { | |
| local file=$1 | |
| local platform=$2 | |
| echo "Attempting to sign $file for $platform..." | |
| echo "Current directory: $(pwd)" | |
| echo "File exists: $(test -f "$file" && echo "yes" || echo "no")" | |
| echo "File size: $(stat -f%z "$file" 2>/dev/null || stat -c%s "$file" 2>/dev/null || echo "unknown")" | |
| echo "TAURI_KEY_PASSWORD is set: $(test -n "$TAURI_KEY_PASSWORD" && echo "yes" || echo "no")" | |
| # Capture both stdout and stderr | |
| if ! output=$(pnpm tauri signer sign -p "$TAURI_KEY_PASSWORD" "$file" 2>&1); then | |
| echo "Error during signing:" | |
| echo "$output" | |
| return 1 | |
| fi | |
| # Extract signature - now handling multiline output | |
| local sig=$(echo "$output" | awk '/Public signature:/{getline; print}' || echo "") | |
| if [ -z "$sig" ]; then | |
| echo "Failed to extract signature from output:" | |
| echo "$output" | |
| return 1 | |
| fi | |
| signatures[$platform]="$sig" | |
| echo "$platform signing completed (signature ${#sig} chars)" | |
| return 0 | |
| } | |
| # Sign each artifact and extract signature from output | |
| if [ -f "artifacts/litepost_x64.app.tar.gz" ]; then | |
| sign_artifact "artifacts/litepost_x64.app.tar.gz" "darwin-x86_64" || echo "Failed to sign macOS x64 artifact" | |
| fi | |
| if [ -f "artifacts/litepost_aarch64.app.tar.gz" ]; then | |
| sign_artifact "artifacts/litepost_aarch64.app.tar.gz" "darwin-aarch64" || echo "Failed to sign macOS aarch64 artifact" | |
| fi | |
| if [ -f "artifacts/litepost_${VERSION}_amd64.AppImage" ]; then | |
| sign_artifact "artifacts/litepost_${VERSION}_amd64.AppImage" "linux-x86_64" || echo "Failed to sign Linux artifact" | |
| fi | |
| if [ -f "artifacts/litepost_${VERSION}_x64-setup.exe" ]; then | |
| sign_artifact "artifacts/litepost_${VERSION}_x64-setup.exe" "windows-x86_64" || echo "Failed to sign Windows artifact" | |
| fi | |
| echo "Collected signatures (lengths):" | |
| for key in "${!signatures[@]}"; do | |
| echo "$key: ${#signatures[$key]} characters" | |
| echo "First 50 chars of signature: ${signatures[$key]:0:50}..." | |
| done | |
| # Create latest.json with collected signatures | |
| echo '{ | |
| "version": "${{ inputs.tag }}", | |
| "notes": "See the assets to download this version and install.", | |
| "pub_date": "'$(date -u +"%Y-%m-%dT%H:%M:%SZ")'", | |
| "platforms": { | |
| "darwin-x86_64": { | |
| "signature": "'${signatures["darwin-x86_64"]}'", | |
| "url": "https://github.com/LykosAI/LitePost/releases/download/${{ inputs.tag }}/litepost_x64.app.tar.gz" | |
| }, | |
| "darwin-aarch64": { | |
| "signature": "'${signatures["darwin-aarch64"]}'", | |
| "url": "https://github.com/LykosAI/LitePost/releases/download/${{ inputs.tag }}/litepost_aarch64.app.tar.gz" | |
| }, | |
| "linux-x86_64": { | |
| "signature": "'${signatures["linux-x86_64"]}'", | |
| "url": "https://github.com/LykosAI/LitePost/releases/download/${{ inputs.tag }}/litepost_'${VERSION}'_amd64.AppImage" | |
| }, | |
| "windows-x86_64": { | |
| "signature": "'${signatures["windows-x86_64"]}'", | |
| "url": "https://github.com/LykosAI/LitePost/releases/download/${{ inputs.tag }}/litepost_'${VERSION}'_x64-setup.exe" | |
| } | |
| } | |
| }' > latest.json | |
| - name: Upload latest.json | |
| uses: actions/github-script@v7 | |
| with: | |
| script: | | |
| const fs = require('fs'); | |
| const tag = '${{ inputs.tag }}'; | |
| const owner = context.repo.owner; | |
| const repo = context.repo.repo; | |
| // Get all releases including drafts | |
| const releases = await github.rest.repos.listReleases({ | |
| owner, | |
| repo, | |
| per_page: 100 | |
| }); | |
| // Find the release by tag, including drafts | |
| const release = releases.data.find(r => r.tag_name === tag); | |
| if (!release) { | |
| throw new Error('Release not found'); | |
| } | |
| // Delete existing latest.json if it exists | |
| for (const asset of release.assets) { | |
| if (asset.name === 'latest.json') { | |
| await github.rest.repos.deleteReleaseAsset({ | |
| owner, | |
| repo, | |
| asset_id: asset.id | |
| }); | |
| break; | |
| } | |
| } | |
| // Upload new latest.json | |
| const contentType = 'application/json'; | |
| const content = await fs.promises.readFile('latest.json'); | |
| await github.rest.repos.uploadReleaseAsset({ | |
| owner, | |
| repo, | |
| release_id: release.id, | |
| name: 'latest.json', | |
| data: content, | |
| headers: { | |
| 'content-type': contentType, | |
| 'content-length': content.length | |
| } | |
| }); |