Skip to content

Generate Update JSON #11

Generate Update JSON

Generate Update JSON #11

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 artifacts = [
'litepost_aarch64.app.tar.gz',
'litepost_x64.app.tar.gz',
'litepost_0.1.0_amd64.AppImage',
'litepost_0.1.0_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=${INPUT_TAG#v}
echo "Using version: $VERSION"
echo "Artifact directory contents:"
ls -la artifacts/
# Sign artifacts and collect signatures
declare -A signatures
# Sign each artifact and extract signature from output
if [ -f "artifacts/litepost_x64.app.tar.gz" ]; then
echo "Signing macOS x64 artifact..."
{ set +x; } 2>/dev/null # Disable command echoing
output=$(pnpm tauri signer sign --password "$TAURI_KEY_PASSWORD" "artifacts/litepost_x64.app.tar.gz" 2>&1)
signatures["darwin-x86_64"]=$(echo "$output" | awk -F': ' '/Public signature/{print $2}')
set -x # Re-enable command echoing
echo "macOS x64 signing completed (signature ${#signatures["darwin-x86_64"]} chars)"
fi
if [ -f "artifacts/litepost_aarch64.app.tar.gz" ]; then
echo "Signing macOS aarch64 artifact..."
{ set +x; } 2>/dev/null
output=$(pnpm tauri signer sign --password "$TAURI_KEY_PASSWORD" "artifacts/litepost_aarch64.app.tar.gz" 2>&1)
signatures["darwin-aarch64"]=$(echo "$output" | awk -F': ' '/Public signature/{print $2}')
set -x
echo "macOS aarch64 signing completed (signature ${#signatures["darwin-aarch64"]} chars)"
fi
if [ -f "artifacts/litepost_${VERSION}_amd64.AppImage" ]; then
echo "Signing Linux artifact..."
{ set +x; } 2>/dev/null
output=$(pnpm tauri signer sign --password "$TAURI_KEY_PASSWORD" "artifacts/litepost_${VERSION}_amd64.AppImage" 2>&1)
signatures["linux-x86_64"]=$(echo "$output" | awk -F': ' '/Public signature/{print $2}')
set -x
echo "Linux signing completed (signature ${#signatures["linux-x86_64"]} chars)"
fi
if [ -f "artifacts/litepost_${VERSION}_x64-setup.exe" ]; then
echo "Signing Windows artifact..."
{ set +x; } 2>/dev/null
output=$(pnpm tauri signer sign --password "$TAURI_KEY_PASSWORD" "artifacts/litepost_${VERSION}_x64-setup.exe" 2>&1)
signatures["windows-x86_64"]=$(echo "$output" | awk -F': ' '/Public signature/{print $2}')
set -x
echo "Windows signing completed (signature ${#signatures["windows-x86_64"]} chars)"
fi
echo "Collected signatures (lengths):"
for key in "${!signatures[@]}"; do
echo "$key: ${#signatures[$key]} characters"
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
}
});