Skip to content

Generate Update JSON #18

Generate Update JSON

Generate Update JSON #18

Workflow file for this run

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
}
});