mirror of
https://github.com/lone-cloud/gerbil
synced 2026-06-03 09:33:10 -07:00
343 lines
14 KiB
YAML
343 lines
14 KiB
YAML
name: AUR Release
|
|
|
|
permissions:
|
|
contents: read
|
|
actions: read
|
|
|
|
on:
|
|
workflow_dispatch:
|
|
inputs:
|
|
tag:
|
|
description: 'Tag version to release to AUR (e.g., v0.5.1)'
|
|
required: true
|
|
type: string
|
|
pkgrel:
|
|
description: 'Package release number (default: 1)'
|
|
required: false
|
|
type: string
|
|
default: '1'
|
|
workflow_call:
|
|
inputs:
|
|
tag:
|
|
description: 'Tag version to release to AUR'
|
|
required: true
|
|
type: string
|
|
pkgrel:
|
|
description: 'Package release number (default: 1)'
|
|
required: false
|
|
type: string
|
|
default: '1'
|
|
|
|
jobs:
|
|
aur-release:
|
|
runs-on: ubuntu-latest
|
|
|
|
steps:
|
|
- name: Checkout repository
|
|
uses: actions/checkout@v4
|
|
with:
|
|
ref: ${{ inputs.tag }}
|
|
fetch-depth: 0
|
|
|
|
- name: Verify tag exists
|
|
run: |
|
|
if ! git rev-parse --verify "${{ inputs.tag }}" >/dev/null 2>&1; then
|
|
echo "❌ Tag '${{ inputs.tag }}' does not exist"
|
|
echo "Available tags:"
|
|
git tag -l | tail -10
|
|
exit 1
|
|
fi
|
|
echo "✅ Tag '${{ inputs.tag }}' exists"
|
|
|
|
- name: Get release information
|
|
id: release_info
|
|
uses: actions/github-script@v7
|
|
with:
|
|
script: |
|
|
const fs = require('fs');
|
|
const packageJson = JSON.parse(fs.readFileSync('./package.json', 'utf8'));
|
|
|
|
const tag = "${{ inputs.tag }}";
|
|
const version = tag.replace(/^v/, '');
|
|
const authorName = packageJson.author.name;
|
|
const authorEmail = packageJson.author.email;
|
|
const appImageUrl = `https://github.com/lone-cloud/gerbil/releases/download/${tag}/Gerbil-${version}.AppImage`;
|
|
|
|
core.setOutput('version', version);
|
|
core.setOutput('tag', tag);
|
|
core.setOutput('author_name', authorName);
|
|
core.setOutput('author_email', authorEmail);
|
|
core.setOutput('appimage_url', appImageUrl);
|
|
|
|
console.log(`Release info:`);
|
|
console.log(`Version: ${version}`);
|
|
console.log(`Tag: ${tag}`);
|
|
console.log(`Author: ${authorName} <${authorEmail}>`);
|
|
console.log(`AppImage URL: ${appImageUrl}`);
|
|
|
|
- name: Verify AppImage availability
|
|
run: |
|
|
echo "Verifying AppImage is accessible..."
|
|
APPIMAGE_URL="${{ steps.release_info.outputs.appimage_url }}"
|
|
max_attempts=10
|
|
attempt=1
|
|
|
|
while [ $attempt -le $max_attempts ]; do
|
|
echo "Attempt $attempt: Checking if AppImage is available..."
|
|
if curl -I -f "$APPIMAGE_URL" > /dev/null 2>&1; then
|
|
echo "✅ AppImage is accessible"
|
|
break
|
|
else
|
|
echo "❌ AppImage not yet accessible, waiting 30 seconds..."
|
|
sleep 30
|
|
attempt=$((attempt + 1))
|
|
fi
|
|
done
|
|
|
|
if [ $attempt -gt $max_attempts ]; then
|
|
echo "❌ AppImage not accessible after $max_attempts attempts"
|
|
exit 1
|
|
fi
|
|
|
|
- name: Download artifacts and calculate SHA256s
|
|
id: sha_calc
|
|
run: |
|
|
# Download AppImage and desktop file with retry logic, then calculate SHA256s
|
|
max_attempts=3
|
|
|
|
# Download AppImage with retry
|
|
for attempt in $(seq 1 $max_attempts); do
|
|
echo "Attempt $attempt: Downloading AppImage..."
|
|
if curl -L -o "gerbil-${{ steps.release_info.outputs.version }}.AppImage" "${{ steps.release_info.outputs.appimage_url }}"; then
|
|
echo "✅ AppImage downloaded successfully"
|
|
break
|
|
else
|
|
echo "❌ AppImage download failed, waiting 10 seconds..."
|
|
sleep 10
|
|
if [ $attempt -eq $max_attempts ]; then
|
|
echo "❌ Failed to download AppImage after $max_attempts attempts"
|
|
exit 1
|
|
fi
|
|
fi
|
|
done
|
|
|
|
# Use local files from the repository (already checked out)
|
|
echo "✅ Using local desktop file from assets/"
|
|
echo "✅ Using local LICENSE file from repository root"
|
|
|
|
# Verify file sizes
|
|
appimage_size=$(stat -c%s "gerbil-${{ steps.release_info.outputs.version }}.AppImage")
|
|
echo "AppImage size: $appimage_size bytes"
|
|
if [ $appimage_size -lt 50000000 ]; then # Less than 50MB is suspicious
|
|
echo "❌ AppImage seems too small ($appimage_size bytes), possible download issue"
|
|
exit 1
|
|
fi
|
|
|
|
SHA256_APPIMAGE=$(sha256sum "gerbil-${{ steps.release_info.outputs.version }}.AppImage" | cut -d' ' -f1)
|
|
SHA256_DESKTOP=$(sha256sum "assets/gerbil.desktop" | cut -d' ' -f1)
|
|
SHA256_METAINFO=$(sha256sum "assets/gerbil.metainfo.xml" | cut -d' ' -f1)
|
|
SHA256_LICENSE=$(sha256sum "LICENSE" | cut -d' ' -f1)
|
|
|
|
echo "sha256_appimage=$SHA256_APPIMAGE" >> $GITHUB_OUTPUT
|
|
echo "sha256_desktop=$SHA256_DESKTOP" >> $GITHUB_OUTPUT
|
|
echo "sha256_metainfo=$SHA256_METAINFO" >> $GITHUB_OUTPUT
|
|
echo "sha256_license=$SHA256_LICENSE" >> $GITHUB_OUTPUT
|
|
|
|
echo "AppImage SHA256: $SHA256_APPIMAGE"
|
|
echo "Desktop SHA256: $SHA256_DESKTOP"
|
|
echo "Metainfo SHA256: $SHA256_METAINFO"
|
|
echo "License SHA256: $SHA256_LICENSE"
|
|
|
|
- name: Generate PKGBUILD
|
|
run: |
|
|
cat > PKGBUILD << 'EOF'
|
|
# Maintainer: ${{ steps.release_info.outputs.author_name }} <${{ steps.release_info.outputs.author_email }}>
|
|
pkgname=gerbil
|
|
pkgver=${{ steps.release_info.outputs.version }}
|
|
pkgrel=${{ inputs.pkgrel || '1' }}
|
|
pkgdesc="Run Large Language Models locally"
|
|
arch=('x86_64')
|
|
url="https://github.com/lone-cloud/gerbil"
|
|
license=('AGPL-3.0-or-later')
|
|
depends=('gtk3' 'nss')
|
|
optdepends=('nodejs: Required for SillyTavern integration'
|
|
'uv: Required for OpenWebUI and ComfyUI integrations')
|
|
provides=('gerbil')
|
|
conflicts=('gerbil-git')
|
|
source=("gerbil-${pkgver}.AppImage::${{ steps.release_info.outputs.appimage_url }}"
|
|
"gerbil.desktop::https://raw.githubusercontent.com/lone-cloud/gerbil/${{ inputs.tag }}/assets/gerbil.desktop"
|
|
"gerbil.metainfo.xml::https://raw.githubusercontent.com/lone-cloud/gerbil/${{ inputs.tag }}/assets/gerbil.metainfo.xml"
|
|
"LICENSE::https://raw.githubusercontent.com/lone-cloud/gerbil/${{ inputs.tag }}/LICENSE")
|
|
sha256sums=('${{ steps.sha_calc.outputs.sha256_appimage }}'
|
|
'${{ steps.sha_calc.outputs.sha256_desktop }}'
|
|
'${{ steps.sha_calc.outputs.sha256_metainfo }}'
|
|
'${{ steps.sha_calc.outputs.sha256_license }}')
|
|
|
|
prepare() {
|
|
chmod +x "gerbil-${pkgver}.AppImage"
|
|
"./gerbil-${pkgver}.AppImage" --appimage-extract
|
|
}
|
|
|
|
package() {
|
|
# Install the application
|
|
install -dm755 "${pkgdir}/opt/gerbil"
|
|
cp -r squashfs-root/* "${pkgdir}/opt/gerbil/"
|
|
|
|
# Fix permissions on extracted files
|
|
chmod -R 755 "${pkgdir}/opt/gerbil/"
|
|
|
|
# Rename the main executable to lowercase
|
|
mv "${pkgdir}/opt/gerbil/Gerbil" "${pkgdir}/opt/gerbil/gerbil"
|
|
|
|
# Create executable wrapper
|
|
install -dm755 "${pkgdir}/usr/bin"
|
|
cat > "${pkgdir}/usr/bin/gerbil" << 'WRAPPER'
|
|
#!/bin/bash
|
|
exec "/opt/gerbil/gerbil" "$@"
|
|
WRAPPER
|
|
chmod +x "${pkgdir}/usr/bin/gerbil"
|
|
|
|
# Install desktop file, AppStream metadata, and license
|
|
install -dm755 "${pkgdir}/usr/share/applications"
|
|
install -dm755 "${pkgdir}/usr/share/metainfo"
|
|
install -dm755 "${pkgdir}/usr/share/licenses/gerbil"
|
|
install -m644 "${srcdir}/gerbil.desktop" "${pkgdir}/usr/share/applications/"
|
|
install -m644 "${srcdir}/gerbil.metainfo.xml" "${pkgdir}/usr/share/metainfo/"
|
|
install -m644 "${srcdir}/LICENSE" "${pkgdir}/usr/share/licenses/gerbil/"
|
|
|
|
# Install icon to hicolor theme directory and pixmaps as fallback
|
|
install -dm755 "${pkgdir}/usr/share/icons/hicolor/512x512/apps"
|
|
install -dm755 "${pkgdir}/usr/share/pixmaps"
|
|
|
|
if [ -f "${pkgdir}/opt/gerbil/usr/share/icons/hicolor/512x512/apps/Gerbil.png" ]; then
|
|
cp "${pkgdir}/opt/gerbil/usr/share/icons/hicolor/512x512/apps/Gerbil.png" "${pkgdir}/usr/share/icons/hicolor/512x512/apps/gerbil.png"
|
|
cp "${pkgdir}/opt/gerbil/usr/share/icons/hicolor/512x512/apps/Gerbil.png" "${pkgdir}/usr/share/pixmaps/gerbil.png"
|
|
else
|
|
echo "Warning: Could not find Gerbil.png in expected locations"
|
|
find "${pkgdir}/opt/gerbil" -name "*erbil*.png" -type f | head -1 | while read icon_file; do
|
|
if [ -n "$icon_file" ]; then
|
|
echo "Found icon at: $icon_file"
|
|
cp "$icon_file" "${pkgdir}/usr/share/icons/hicolor/512x512/apps/gerbil.png"
|
|
cp "$icon_file" "${pkgdir}/usr/share/pixmaps/gerbil.png"
|
|
fi
|
|
done
|
|
fi
|
|
|
|
# Install shell completions
|
|
install -dm755 "${pkgdir}/usr/share/bash-completion/completions"
|
|
install -dm755 "${pkgdir}/usr/share/zsh/site-functions"
|
|
|
|
# Bash completion
|
|
cat > "${pkgdir}/usr/share/bash-completion/completions/gerbil" << 'BASH_COMP'
|
|
_gerbil() {
|
|
local cur prev opts
|
|
COMPREPLY=()
|
|
cur="${COMP_WORDS[COMP_CWORD]}"
|
|
prev="${COMP_WORDS[COMP_CWORD-1]}"
|
|
opts="--version --cli"
|
|
|
|
case "${prev}" in
|
|
--cli)
|
|
# Don't complete after --cli, let user type kobold args
|
|
return 0
|
|
;;
|
|
*)
|
|
COMPREPLY=( $(compgen -W "${opts}" -- ${cur}) )
|
|
return 0
|
|
;;
|
|
esac
|
|
}
|
|
complete -F _gerbil gerbil
|
|
BASH_COMP
|
|
|
|
# Zsh completion
|
|
cat > "${pkgdir}/usr/share/zsh/site-functions/_gerbil" << 'ZSH_COMP'
|
|
#compdef gerbil
|
|
|
|
_gerbil() {
|
|
local context state line
|
|
|
|
_arguments -C \
|
|
'1: :->command' \
|
|
'*: :->args' && return 0
|
|
|
|
case $state in
|
|
command)
|
|
local commands=(
|
|
'--version:Show version information'
|
|
'--cli:Run in CLI mode (pass remaining args to kobold binary)'
|
|
)
|
|
_describe 'commands' commands
|
|
;;
|
|
args)
|
|
case ${words[2]} in
|
|
--cli)
|
|
# Don't complete after --cli, let user type kobold args
|
|
;;
|
|
esac
|
|
;;
|
|
esac
|
|
}
|
|
|
|
_gerbil "$@"
|
|
ZSH_COMP
|
|
}
|
|
EOF
|
|
|
|
- name: Create .SRCINFO
|
|
run: |
|
|
# Create .SRCINFO file (required for AUR)
|
|
cat > .SRCINFO << 'EOF'
|
|
pkgbase = gerbil
|
|
pkgdesc = Run Large Language Models locally
|
|
pkgver = ${{ steps.release_info.outputs.version }}
|
|
pkgrel = ${{ inputs.pkgrel || '1' }}
|
|
url = https://github.com/lone-cloud/gerbil
|
|
arch = x86_64
|
|
license = AGPL-3.0-or-later
|
|
depends = gtk3
|
|
depends = nss
|
|
optdepends = nodejs: Required for SillyTavern integration
|
|
optdepends = uv: Required for OpenWebUI and ComfyUI integrations
|
|
provides = gerbil
|
|
conflicts = gerbil-git
|
|
source = gerbil-${{ steps.release_info.outputs.version }}.AppImage::${{ steps.release_info.outputs.appimage_url }}
|
|
source = gerbil.desktop::https://raw.githubusercontent.com/lone-cloud/gerbil/${{ inputs.tag }}/assets/gerbil.desktop
|
|
source = gerbil.metainfo.xml::https://raw.githubusercontent.com/lone-cloud/gerbil/${{ inputs.tag }}/assets/gerbil.metainfo.xml
|
|
source = LICENSE::https://raw.githubusercontent.com/lone-cloud/gerbil/${{ inputs.tag }}/LICENSE
|
|
sha256sums = ${{ steps.sha_calc.outputs.sha256_appimage }}
|
|
sha256sums = ${{ steps.sha_calc.outputs.sha256_desktop }}
|
|
sha256sums = ${{ steps.sha_calc.outputs.sha256_metainfo }}
|
|
sha256sums = ${{ steps.sha_calc.outputs.sha256_license }}
|
|
|
|
pkgname = gerbil
|
|
EOF
|
|
|
|
- name: Publish to AUR
|
|
uses: KSXGitHub/github-actions-deploy-aur@v2.7.2
|
|
with:
|
|
pkgname: gerbil
|
|
pkgbuild: ./PKGBUILD
|
|
commit_username: ${{ steps.release_info.outputs.author_name }}
|
|
commit_email: ${{ steps.release_info.outputs.author_email }}
|
|
ssh_private_key: ${{ secrets.AUR_SSH_PRIVATE_KEY }}
|
|
commit_message: "Update to ${{ steps.release_info.outputs.version }}-${{ inputs.pkgrel || '1' }}"
|
|
ssh_keyscan_types: rsa,ecdsa,ed25519
|
|
|
|
- name: Create AUR release summary
|
|
run: |
|
|
echo "## AUR Release Summary" >> $GITHUB_STEP_SUMMARY
|
|
echo "" >> $GITHUB_STEP_SUMMARY
|
|
echo "📦 **Package**: gerbil" >> $GITHUB_STEP_SUMMARY
|
|
echo "🔖 **Version**: ${{ steps.release_info.outputs.version }}" >> $GITHUB_STEP_SUMMARY
|
|
echo "🔗 **AUR Page**: https://aur.archlinux.org/packages/gerbil" >> $GITHUB_STEP_SUMMARY
|
|
echo "✅ **Status**: Successfully published to AUR" >> $GITHUB_STEP_SUMMARY
|
|
echo "" >> $GITHUB_STEP_SUMMARY
|
|
echo "### Installation" >> $GITHUB_STEP_SUMMARY
|
|
echo '```bash' >> $GITHUB_STEP_SUMMARY
|
|
echo "# Using yay" >> $GITHUB_STEP_SUMMARY
|
|
echo "yay -S gerbil" >> $GITHUB_STEP_SUMMARY
|
|
echo "" >> $GITHUB_STEP_SUMMARY
|
|
echo "# Using paru" >> $GITHUB_STEP_SUMMARY
|
|
echo "paru -S gerbil" >> $GITHUB_STEP_SUMMARY
|
|
echo '```' >> $GITHUB_STEP_SUMMARY
|