740 lines
27 KiB
YAML
740 lines
27 KiB
YAML
name: Build and Publish Multi-Platform
|
||
|
||
on:
|
||
workflow_dispatch:
|
||
inputs:
|
||
version:
|
||
description: 'Beta release (0.1.0)'
|
||
required: true
|
||
type: string
|
||
dry_run:
|
||
description: 'Dry run mode (skip AUR publishing)'
|
||
required: false
|
||
default: false
|
||
type: boolean
|
||
|
||
permissions:
|
||
contents: read
|
||
pull-requests: write
|
||
|
||
env:
|
||
APP_NAME: android-file-handler
|
||
PYTHON_VERSION: "3.12"
|
||
|
||
jobs:
|
||
build:
|
||
strategy:
|
||
matrix:
|
||
include:
|
||
- os: ubuntu-latest
|
||
platform: linux-deb
|
||
binary_name: android-file-handler
|
||
- os: windows-latest
|
||
platform: windows
|
||
binary_name: android-file-handler.exe
|
||
- os: ubuntu-20.04
|
||
platform: linux-rpm
|
||
binary_name: android-file-handler
|
||
- os: ubuntu-latest
|
||
platform: linux-arch
|
||
binary_name: android-file-handler
|
||
container: archlinux:latest
|
||
|
||
runs-on: ${{ matrix.os }}
|
||
container: ${{ matrix.container }}
|
||
|
||
steps:
|
||
- uses: actions/checkout@v4
|
||
|
||
- name: Detect and Configure Environment
|
||
shell: bash
|
||
run: |
|
||
# Environment detection function
|
||
detect_environment() {
|
||
if [ "${ACT:-false}" = "true" ]; then
|
||
echo "ACT_ENVIRONMENT=local" >> $GITHUB_ENV
|
||
echo "PYTHON_CMD=python3" >> $GITHUB_ENV
|
||
echo "PIP_CMD=pip3" >> $GITHUB_ENV
|
||
echo "🔧 Local testing environment detected (Act)"
|
||
else
|
||
echo "ACT_ENVIRONMENT=github" >> $GITHUB_ENV
|
||
echo "PYTHON_CMD=python" >> $GITHUB_ENV
|
||
echo "PIP_CMD=pip" >> $GITHUB_ENV
|
||
echo "🚀 GitHub Actions environment detected"
|
||
fi
|
||
}
|
||
|
||
# Setup system Python for Act
|
||
setup_system_python() {
|
||
echo "Setting up system Python for local testing..."
|
||
|
||
# Update package manager and install Python
|
||
if command -v apt-get &> /dev/null; then
|
||
apt-get update -qq
|
||
apt-get install -y python3 python3-pip python3-venv curl
|
||
elif command -v pacman &> /dev/null; then
|
||
pacman -Sy --noconfirm python python-pip curl
|
||
elif command -v dnf &> /dev/null; then
|
||
dnf install -y python3 python3-pip curl
|
||
fi
|
||
|
||
# Create symbolic links for compatibility
|
||
ln -sf $(which python3) /usr/local/bin/python || echo "Python already linked"
|
||
ln -sf $(which pip3) /usr/local/bin/pip || echo "Pip already linked"
|
||
|
||
# Verify installation
|
||
python3 --version
|
||
pip3 --version
|
||
}
|
||
|
||
# Main execution
|
||
detect_environment
|
||
|
||
if [ "${ACT_ENVIRONMENT}" = "local" ]; then
|
||
setup_system_python
|
||
fi
|
||
|
||
- name: Setup Arch Linux environment
|
||
if: matrix.platform == 'linux-arch'
|
||
run: |
|
||
pacman -Sy --noconfirm
|
||
pacman -S --noconfirm python python-pip base-devel git curl
|
||
|
||
# For Act compatibility, ensure Python is available as 'python'
|
||
if [ "${ACT:-false}" = "true" ]; then
|
||
ln -sf $(which python3) /usr/local/bin/python || echo "Python already linked"
|
||
ln -sf $(which pip3) /usr/local/bin/pip || echo "Pip already linked"
|
||
fi
|
||
|
||
- name: Set up Python ${{ env.PYTHON_VERSION }} (GitHub Actions Only)
|
||
if: matrix.platform != 'linux-arch' && env.ACT != 'true'
|
||
uses: actions/setup-python@v4
|
||
with:
|
||
python-version: ${{ env.PYTHON_VERSION }}
|
||
|
||
- name: Install Poetry
|
||
shell: bash
|
||
run: |
|
||
echo "Installing Poetry for ${ACT_ENVIRONMENT:-github} environment..."
|
||
|
||
if [ "${{ matrix.platform }}" == "linux-arch" ]; then
|
||
# Arch Linux has Poetry in packages
|
||
if command -v pacman &> /dev/null; then
|
||
pacman -S --noconfirm python-poetry
|
||
else
|
||
pip install poetry
|
||
fi
|
||
# Configure poetry for system-wide installation in containers
|
||
poetry config virtualenvs.create false
|
||
poetry config virtualenvs.in-project false
|
||
else
|
||
# Install Poetry via official installer for other platforms
|
||
if [ "${ACT_ENVIRONMENT}" = "local" ]; then
|
||
# For Act, install Poetry with system Python
|
||
curl -sSL https://install.python-poetry.org | python3 -
|
||
echo "$HOME/.local/bin" >> $GITHUB_PATH
|
||
export PATH="$HOME/.local/bin:$PATH"
|
||
# Configure Poetry for Act compatibility
|
||
poetry config virtualenvs.create false
|
||
echo "🔧 Configured Poetry for system-wide installation (Act)"
|
||
else
|
||
# For GitHub Actions, use the action
|
||
curl -sSL https://install.python-poetry.org | python -
|
||
echo "$HOME/.local/bin" >> $GITHUB_PATH
|
||
fi
|
||
fi
|
||
|
||
# Verify Poetry installation
|
||
export PATH="$HOME/.local/bin:$PATH"
|
||
poetry --version
|
||
|
||
- name: Lock and install dependencies
|
||
shell: bash
|
||
run: |
|
||
echo "Installing dependencies in ${ACT_ENVIRONMENT:-github} environment..."
|
||
|
||
# Ensure Poetry is in PATH
|
||
export PATH="$HOME/.local/bin:$PATH"
|
||
|
||
# Configure Poetry based on environment
|
||
if [ "${ACT_ENVIRONMENT}" = "local" ] || [ "${{ matrix.platform }}" = "linux-arch" ]; then
|
||
# For Act and Arch containers, use system-wide installation
|
||
poetry config virtualenvs.create false
|
||
poetry config virtualenvs.in-project false
|
||
echo "🔧 Configured Poetry for system-wide installation"
|
||
else
|
||
# For GitHub Actions, use virtual environments
|
||
poetry config virtualenvs.create true
|
||
poetry config virtualenvs.in-project true
|
||
echo "🚀 Configured Poetry for virtual environment"
|
||
fi
|
||
|
||
poetry lock
|
||
poetry install
|
||
|
||
- name: Build binary with PyInstaller
|
||
shell: bash
|
||
run: |
|
||
echo "Building binary in ${ACT_ENVIRONMENT:-github} environment..."
|
||
|
||
# Ensure Poetry is in PATH
|
||
export PATH="$HOME/.local/bin:$PATH"
|
||
|
||
# Install PyInstaller
|
||
poetry run pip install pyinstaller
|
||
|
||
# Build based on platform
|
||
if [ "${{ matrix.platform }}" == "windows" ]; then
|
||
echo "Building Windows binary..."
|
||
poetry run pyinstaller --onefile \
|
||
--name "${{ matrix.binary_name }}" \
|
||
--icon=icon_media/robot_files_256.ico \
|
||
src/main.py
|
||
else
|
||
echo "Building Linux binary..."
|
||
poetry run pyinstaller --onefile \
|
||
--name "${{ matrix.binary_name }}" \
|
||
--icon=icon_media/robot_files_256.png \
|
||
src/main.py
|
||
fi
|
||
|
||
echo "✅ Binary built successfully for ${{ matrix.platform }}"
|
||
|
||
# Verify binary was created
|
||
if [ -f "dist/${{ matrix.binary_name }}" ]; then
|
||
echo "✅ Binary verified: dist/${{ matrix.binary_name }}"
|
||
ls -la "dist/${{ matrix.binary_name }}"
|
||
else
|
||
echo "❌ Binary not found: dist/${{ matrix.binary_name }}"
|
||
echo "Available files in dist/:"
|
||
ls -la dist/ || echo "No dist/ directory found"
|
||
exit 1
|
||
fi
|
||
|
||
- name: Install fpm (Ubuntu/Debian)
|
||
if: matrix.platform == 'linux-deb' || matrix.platform == 'linux-rpm'
|
||
run: |
|
||
sudo apt-get update
|
||
sudo apt-get install -y ruby ruby-dev rubygems build-essential rpm
|
||
sudo gem install --no-document fpm
|
||
|
||
- name: Install package tools (Arch)
|
||
if: matrix.platform == 'linux-arch'
|
||
run: |
|
||
pacman -S --noconfirm base-devel
|
||
|
||
- name: Create .deb package
|
||
if: matrix.platform == 'linux-deb'
|
||
run: |
|
||
mkdir -p package/usr/bin
|
||
cp "dist/${{ matrix.binary_name }}" "package/usr/bin/${{ env.APP_NAME }}"
|
||
fpm -s dir -t deb -n ${{ env.APP_NAME }} -v ${{ github.event.inputs.version }} \
|
||
--description "Android file transfer utility via ADB" \
|
||
--depends "python3.12" \
|
||
--maintainer "Jason Ross <jason.ross841@gmail.com>" \
|
||
--url "https://github.com/${{ github.repository }}" \
|
||
-C package \
|
||
usr/bin/
|
||
|
||
- name: Create .rpm package
|
||
if: matrix.platform == 'linux-rpm'
|
||
run: |
|
||
mkdir -p package/usr/bin
|
||
cp "dist/${{ matrix.binary_name }}" "package/usr/bin/${{ env.APP_NAME }}"
|
||
fpm -s dir -t rpm -n ${{ env.APP_NAME }} -v ${{ github.event.inputs.version }} \
|
||
--description "Android file transfer utility via ADB" \
|
||
--depends "python3.12" \
|
||
--maintainer "Jason Ross <jason.ross841@gmail.com>" \
|
||
--url "https://github.com/${{ github.repository }}" \
|
||
-C package \
|
||
usr/bin/
|
||
|
||
- name: Calculate SHA256 for Arch PKGBUILD
|
||
if: matrix.platform == 'linux-arch'
|
||
run: |
|
||
# Calculate checksum of the Linux binary for PKGBUILD with enhanced error context
|
||
binary_file="dist/${{ matrix.binary_name }}"
|
||
|
||
echo "=== SHA256 Calculation for Arch Package ==="
|
||
echo "Target binary: $binary_file"
|
||
|
||
if [ ! -f "$binary_file" ]; then
|
||
echo "❌ Critical Error: Binary file not found"
|
||
echo " Expected location: $binary_file"
|
||
echo " Working directory: $(pwd)"
|
||
echo " Available files in dist/:"
|
||
if [ -d "dist/" ]; then
|
||
ls -la dist/
|
||
else
|
||
echo " No dist/ directory found"
|
||
fi
|
||
echo " This indicates a PyInstaller build failure"
|
||
exit 1
|
||
fi
|
||
|
||
# Validate file size before calculating checksum
|
||
file_size=$(stat -c%s "$binary_file")
|
||
minimum_expected_size=100000 # 100KB minimum
|
||
|
||
if [ "$file_size" -lt "$minimum_expected_size" ]; then
|
||
echo "❌ Critical Error: Binary file suspiciously small"
|
||
echo " File size: $file_size bytes"
|
||
echo " Expected minimum: $minimum_expected_size bytes"
|
||
echo " This indicates a build failure or corruption"
|
||
exit 1
|
||
fi
|
||
|
||
# Calculate SHA256 checksum
|
||
sha256_sum=$(sha256sum "$binary_file" | cut -d' ' -f1)
|
||
|
||
if [ -z "$sha256_sum" ]; then
|
||
echo "❌ Critical Error: Failed to calculate SHA256 checksum"
|
||
echo " This indicates file corruption or system issues"
|
||
exit 1
|
||
fi
|
||
|
||
echo "✅ SHA256 calculated successfully: $sha256_sum"
|
||
echo " File: $binary_file"
|
||
echo " Size: $file_size bytes"
|
||
echo "SHA256SUM=$sha256_sum" >> $GITHUB_ENV
|
||
|
||
- name: Create Arch PKGBUILD
|
||
if: matrix.platform == 'linux-arch'
|
||
run: |
|
||
# Create PKGBUILD file for AUR submission with improved formatting
|
||
{
|
||
echo '# Maintainer: Jason Ross <jason.ross841@gmail.com>'
|
||
echo 'pkgname=${{ env.APP_NAME }}'
|
||
echo 'pkgver=${{ github.event.inputs.version }}'
|
||
echo 'pkgrel=1'
|
||
echo 'pkgdesc="Android file transfer utility via ADB"'
|
||
echo "arch=('x86_64')"
|
||
echo 'url="https://github.com/${{ github.repository }}"'
|
||
echo "license=('MIT')"
|
||
echo "depends=('python')"
|
||
echo 'source=("${pkgname}-${pkgver}::https://github.com/${{ github.repository }}/releases/download/v${pkgver}/${{ env.APP_NAME }}-${pkgver}-linux")'
|
||
echo 'sha256sums=(${{ env.SHA256SUM }})'
|
||
echo ''
|
||
echo 'package() {'
|
||
echo ' install -Dm755 "${srcdir}/${pkgname}-${pkgver}" "${pkgdir}/usr/bin/${pkgname}"'
|
||
echo '}'
|
||
} > PKGBUILD
|
||
|
||
# Generate .SRCINFO file with improved formatting
|
||
{
|
||
echo 'pkgbase = ${{ env.APP_NAME }}'
|
||
echo $'\tpkgdesc = Android file transfer utility via ADB'
|
||
echo $'\tpkgver = ${{ github.event.inputs.version }}'
|
||
echo $'\tpkgrel = 1'
|
||
echo $'\turl = https://github.com/${{ github.repository }}'
|
||
echo $'\tarch = x86_64'
|
||
echo $'\tlicense = MIT'
|
||
echo $'\tdepends = python'
|
||
echo $'\tsource = ${{ env.APP_NAME }}-${{ github.event.inputs.version }}::https://github.com/${{ github.repository }}/releases/download/v${{ github.event.inputs.version }}/${{ env.APP_NAME }}-${{ github.event.inputs.version }}-linux'
|
||
echo $'\tsha256sums = ${{ env.SHA256SUM }}'
|
||
echo ''
|
||
echo 'pkgname = ${{ env.APP_NAME }}'
|
||
} > .SRCINFO
|
||
|
||
- name: Verify generated files
|
||
if: matrix.platform == 'linux-arch'
|
||
run: |
|
||
echo "=== PKGBUILD Content ==="
|
||
cat PKGBUILD
|
||
echo "=== .SRCINFO Content ==="
|
||
cat .SRCINFO
|
||
echo "=== File validation ==="
|
||
if [ ! -f "PKGBUILD" ] || [ ! -f ".SRCINFO" ]; then
|
||
echo "Error: Required files not generated"
|
||
exit 1
|
||
fi
|
||
|
||
# Validate PKGBUILD syntax
|
||
if ! grep -q "^pkgname=" PKGBUILD; then
|
||
echo "Error: Invalid PKGBUILD format"
|
||
exit 1
|
||
fi
|
||
|
||
# Validate .SRCINFO syntax
|
||
if ! grep -q "^pkgbase = " .SRCINFO; then
|
||
echo "Error: Invalid .SRCINFO format"
|
||
exit 1
|
||
fi
|
||
|
||
echo "✓ All files validated successfully"
|
||
|
||
- name: Upload Artifacts
|
||
uses: actions/upload-artifact@v4
|
||
with:
|
||
name: ${{ matrix.platform }}-artifacts
|
||
path: |
|
||
dist/${{ matrix.binary_name }}
|
||
*.deb
|
||
*.rpm
|
||
PKGBUILD
|
||
.SRCINFO
|
||
|
||
release:
|
||
needs: build
|
||
runs-on: ubuntu-latest
|
||
steps:
|
||
- uses: actions/checkout@v4
|
||
|
||
- name: Download all artifacts
|
||
uses: actions/download-artifact@v4
|
||
with:
|
||
path: artifacts/
|
||
|
||
- name: Prepare release assets
|
||
shell: bash
|
||
run: |
|
||
mkdir -p release-assets
|
||
|
||
# Function: copy_and_validate
|
||
# Purpose: Safely copy files with comprehensive validation and error reporting
|
||
# Parameters:
|
||
# $1 (source_file_path): Absolute path to the source file to be copied
|
||
# $2 (destination_path): Absolute path where the file should be copied to
|
||
# $3 (minimum_size_bytes): Minimum expected file size in bytes for validation
|
||
# Returns:
|
||
# 0: Success - file copied and validated successfully
|
||
# 1: Failure - file not found, too small, or copy operation failed
|
||
# Side Effects:
|
||
# - Creates destination file if source is valid
|
||
# - Outputs detailed status messages with file information
|
||
copy_and_validate() {
|
||
local source_file_path="$1"
|
||
local destination_path="$2"
|
||
local minimum_size_bytes="$3"
|
||
|
||
echo "--- Validating: $(basename "$source_file_path") ---"
|
||
|
||
if [ ! -f "$source_file_path" ]; then
|
||
echo "❌ File not found: $source_file_path"
|
||
echo " Expected location: $source_file_path"
|
||
echo " Parent directory contents:"
|
||
ls -la "$(dirname "$source_file_path")" 2>/dev/null || echo " Directory does not exist"
|
||
return 1
|
||
fi
|
||
|
||
local actual_file_size=$(stat -c%s "$source_file_path")
|
||
echo " File size: $actual_file_size bytes"
|
||
|
||
if [ "$actual_file_size" -lt "$minimum_size_bytes" ]; then
|
||
echo "❌ File too small: $source_file_path"
|
||
echo " Actual size: $actual_file_size bytes"
|
||
echo " Required minimum: $minimum_size_bytes bytes"
|
||
echo " This indicates a build failure or incomplete binary"
|
||
return 1
|
||
fi
|
||
|
||
# Attempt to copy file
|
||
if cp "$source_file_path" "$destination_path"; then
|
||
echo "✅ Successfully copied: $(basename "$destination_path")"
|
||
echo " Size: $actual_file_size bytes"
|
||
echo " Source: $source_file_path"
|
||
echo " Destination: $destination_path"
|
||
return 0
|
||
else
|
||
echo "❌ Failed to copy file"
|
||
echo " Source: $source_file_path"
|
||
echo " Destination: $destination_path"
|
||
echo " Check disk space and permissions"
|
||
return 1
|
||
fi
|
||
}
|
||
|
||
echo "=== Release Asset Preparation ==="
|
||
echo "Working directory: $(pwd)"
|
||
echo "Available artifacts:"
|
||
find artifacts/ -type f -name "*" | head -20
|
||
|
||
# Track validation results for comprehensive reporting
|
||
linux_binary_success=false
|
||
windows_binary_success=false
|
||
|
||
# Validate and copy Linux binary (minimum 1MB for GUI application)
|
||
if copy_and_validate "artifacts/linux-deb-artifacts/dist/android-file-handler" "release-assets/${{ env.APP_NAME }}-${{ github.event.inputs.version }}-linux" 1000000; then
|
||
linux_binary_success=true
|
||
fi
|
||
|
||
# Validate and copy Windows binary (minimum 1MB for GUI application)
|
||
if copy_and_validate "artifacts/windows-artifacts/dist/android-file-handler.exe" "release-assets/${{ env.APP_NAME }}-${{ github.event.inputs.version }}-windows.exe" 1000000; then
|
||
windows_binary_success=true
|
||
fi
|
||
|
||
# Copy and count package files
|
||
echo "=== Package Collection ==="
|
||
deb_count=$(find artifacts/ -name "*.deb" -exec cp {} release-assets/ \; -print | wc -l)
|
||
rpm_count=$(find artifacts/ -name "*.rpm" -exec cp {} release-assets/ \; -print | wc -l)
|
||
|
||
echo "=== Build Quality Assessment ==="
|
||
echo "Linux binary: $([ "$linux_binary_success" = true ] && echo "✅ PASS" || echo "❌ FAIL")"
|
||
echo "Windows binary: $([ "$windows_binary_success" = true ] && echo "✅ PASS" || echo "❌ FAIL")"
|
||
echo "DEB packages: $deb_count $([ "$deb_count" -gt 0 ] && echo "✅" || echo "❌")"
|
||
echo "RPM packages: $rpm_count $([ "$rpm_count" -gt 0 ] && echo "✅" || echo "❌")"
|
||
|
||
# Comprehensive release asset validation
|
||
echo "=== Release Asset Validation ==="
|
||
|
||
# Check if any assets were created
|
||
if [ -z "$(ls -A release-assets/)" ]; then
|
||
echo "❌ Critical Error: No release assets were created"
|
||
echo " This indicates a complete build system failure"
|
||
echo " Check artifact download and binary generation steps"
|
||
exit 1
|
||
fi
|
||
|
||
# Require at least one valid binary for release
|
||
if [ "$linux_binary_success" = false ] && [ "$windows_binary_success" = false ]; then
|
||
echo "❌ Critical Error: No valid binaries were created"
|
||
echo " At least one platform binary is required for release"
|
||
echo " Linux binary status: $([ "$linux_binary_success" = true ] && echo "SUCCESS" || echo "FAILED")"
|
||
echo " Windows binary status: $([ "$windows_binary_success" = true ] && echo "SUCCESS" || echo "FAILED")"
|
||
exit 1
|
||
fi
|
||
|
||
# Count total release assets
|
||
total_assets=$(ls -1 release-assets/ | wc -l)
|
||
echo "✅ Release validation passed"
|
||
echo " Total assets: $total_assets"
|
||
echo " Binaries: $([ "$linux_binary_success" = true ] && echo -n "Linux " || true)$([ "$windows_binary_success" = true ] && echo -n "Windows" || true)"
|
||
echo " Packages: $deb_count DEB, $rpm_count RPM"
|
||
|
||
# Generate comprehensive checksums
|
||
cd release-assets
|
||
sha256sum * > SHA256SUMS
|
||
echo "=== Final Release Assets ==="
|
||
ls -la
|
||
echo "=== SHA256 Checksums ==="
|
||
cat SHA256SUMS
|
||
|
||
- name: Create Release
|
||
uses: softprops/action-gh-release@v1
|
||
with:
|
||
tag_name: v${{ github.event.inputs.version }}
|
||
name: Release v${{ github.event.inputs.version }}
|
||
draft: false
|
||
prerelease: true
|
||
files: release-assets/*
|
||
env:
|
||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||
|
||
publish-aur:
|
||
needs: release
|
||
runs-on: ubuntu-latest
|
||
if: github.event.inputs.dry_run != 'true'
|
||
steps:
|
||
- uses: actions/checkout@v4
|
||
|
||
- name: Download Arch artifacts
|
||
uses: actions/download-artifact@v4
|
||
with:
|
||
name: linux-arch-artifacts
|
||
path: aur-files/
|
||
|
||
- name: Validate AUR files
|
||
run: |
|
||
echo "=== Validating AUR files ==="
|
||
if [ ! -f "aur-files/PKGBUILD" ]; then
|
||
echo "❌ Error: PKGBUILD not found"
|
||
exit 1
|
||
fi
|
||
|
||
if [ ! -f "aur-files/.SRCINFO" ]; then
|
||
echo "❌ Error: .SRCINFO not found"
|
||
exit 1
|
||
fi
|
||
|
||
echo "=== PKGBUILD Content ==="
|
||
cat aur-files/PKGBUILD
|
||
echo "=== .SRCINFO Content ==="
|
||
cat aur-files/.SRCINFO
|
||
|
||
# Validate PKGBUILD has required fields
|
||
if ! grep -q "^pkgname=" aur-files/PKGBUILD; then
|
||
echo "❌ Error: PKGBUILD missing pkgname"
|
||
exit 1
|
||
fi
|
||
|
||
if ! grep -q "^pkgver=" aur-files/PKGBUILD; then
|
||
echo "❌ Error: PKGBUILD missing pkgver"
|
||
exit 1
|
||
fi
|
||
|
||
echo "✓ AUR files validated successfully"
|
||
|
||
# AUR Publishing (Requires Repository Secrets)
|
||
# Required secrets for AUR publishing:
|
||
# AUR_SSH_PRIVATE_KEY: SSH private key for AUR publishing
|
||
# AUR_USER_NAME: Git user name for AUR commits
|
||
# AUR_USER_EMAIL: Git user email for AUR commits
|
||
- name: Publish to AUR
|
||
env:
|
||
AUR_SSH_PRIVATE_KEY: ${{ secrets.AUR_SSH_PRIVATE_KEY }}
|
||
AUR_USER_NAME: ${{ secrets.AUR_USER_NAME }}
|
||
AUR_USER_EMAIL: ${{ secrets.AUR_USER_EMAIL }}
|
||
run: |
|
||
# Setup SSH with proper security
|
||
mkdir -p ~/.ssh
|
||
chmod 700 ~/.ssh
|
||
echo "$AUR_SSH_PRIVATE_KEY" > ~/.ssh/aur
|
||
chmod 600 ~/.ssh/aur
|
||
ssh-keyscan aur.archlinux.org >> ~/.ssh/known_hosts
|
||
|
||
# Configure git
|
||
git config --global user.name "$AUR_USER_NAME"
|
||
git config --global user.email "$AUR_USER_EMAIL"
|
||
|
||
# Clone or create AUR repo
|
||
echo "📦 Connecting to AUR..."
|
||
ssh -i ~/.ssh/aur aur@aur.archlinux.org -o StrictHostKeyChecking=no "ls -la" || echo "AUR access confirmed"
|
||
git clone ssh://aur@aur.archlinux.org/${{ env.APP_NAME }}.git aur-repo || mkdir aur-repo
|
||
cd aur-repo
|
||
|
||
# Initialize if new repo
|
||
if [ ! -d ".git" ]; then
|
||
echo "📦 Initializing new AUR repository..."
|
||
git init
|
||
git remote add origin ssh://aur@aur.archlinux.org/${{ env.APP_NAME }}.git
|
||
fi
|
||
|
||
# Copy and validate files
|
||
cp ../aur-files/PKGBUILD ./
|
||
cp ../aur-files/.SRCINFO ./
|
||
|
||
echo "📦 Files prepared for AUR submission:"
|
||
ls -la PKGBUILD .SRCINFO
|
||
|
||
# Commit and push with fallback for branch names
|
||
git add PKGBUILD .SRCINFO
|
||
if git commit -m "Update to version ${{ github.event.inputs.version }}"; then
|
||
echo "📦 Pushing to AUR..."
|
||
git push -u origin master 2>/dev/null || git push -u origin main
|
||
echo "✅ Successfully published to AUR!"
|
||
else
|
||
echo "ℹ️ No changes to commit (package may already be up to date)"
|
||
fi
|
||
|
||
dry-run-summary:
|
||
needs: release
|
||
runs-on: ubuntu-latest
|
||
if: github.event.inputs.dry_run == 'true'
|
||
steps:
|
||
- name: Dry Run Summary
|
||
run: |
|
||
echo "🔍 DRY RUN MODE - No packages were published"
|
||
echo "==============================================="
|
||
echo "✅ Binaries built successfully"
|
||
echo "✅ Packages created successfully"
|
||
echo "✅ GitHub release created"
|
||
echo "⏭️ AUR publishing skipped (dry run mode)"
|
||
echo ""
|
||
echo "To publish to AUR, re-run with dry_run=false"
|
||
|
||
|
||
|
||
|
||
inputs:
|
||
new_version:
|
||
description: "New version to release (e.g., 0.2.0)"
|
||
required: false
|
||
type: string
|
||
pr_check_timeout:
|
||
description: "Timeout in seconds for PR status checks (default: 1800)"
|
||
required: false
|
||
type: number
|
||
default: 1800
|
||
jobs:
|
||
description: "Comma-separated jobs to run (e.g., build-windows,build-debian,build-arch,build-rhel)"
|
||
required: true
|
||
default: "build-windows,build-debian,build-arch,build-rhel"
|
||
start_from_step:
|
||
description: "Start workflow from this step (all subsequent steps will run)"
|
||
required: false
|
||
type: choice
|
||
default: "bump-version"
|
||
options:
|
||
- "bump-version"
|
||
- "merge-develop-to-main"
|
||
|
||
|
||
|
||
rollback-on-build-failure:
|
||
needs: [merge-develop-to-main, wait-for-main-pr, build-windows, build-debian, build-arch, build-rhel]
|
||
if: |
|
||
${{
|
||
always() &&
|
||
(github.event.inputs.start_from_step == 'bump-version' ||
|
||
github.event.inputs.start_from_step == 'merge-develop-to-main') &&
|
||
needs.wait-for-main-pr.result == 'success' &&
|
||
(needs.build-windows.result == 'failure' ||
|
||
needs.build-debian.result == 'failure' ||
|
||
needs.build-arch.result == 'failure' ||
|
||
needs.build-rhel.result == 'failure')
|
||
}}
|
||
runs-on: ubuntu-latest
|
||
permissions:
|
||
contents: write
|
||
# Prevent multiple rollback operations from running concurrently
|
||
concurrency:
|
||
group: main-branch-rollback
|
||
cancel-in-progress: false
|
||
steps:
|
||
- name: Checkout main branch
|
||
uses: actions/checkout@v4
|
||
with:
|
||
ref: main
|
||
fetch-depth: 0
|
||
token: ${{ secrets.GITHUB_TOKEN }}
|
||
|
||
- name: Rollback merge commit on build failure
|
||
env:
|
||
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||
run: |
|
||
set -e
|
||
echo "::error::One or more build jobs failed - initiating rollback"
|
||
|
||
# Configure git
|
||
git config user.name "github-actions[bot]"
|
||
git config user.email "github-actions[bot]@users.noreply.github.com"
|
||
|
||
# Fetch latest
|
||
git fetch origin main
|
||
|
||
# Get the previous main SHA (before the merge)
|
||
PREVIOUS_MAIN_SHA="${{ needs.merge-develop-to-main.outputs.previous_main_sha }}"
|
||
echo "Resetting main to previous commit: $PREVIOUS_MAIN_SHA"
|
||
|
||
# Checkout main and reset to previous commit
|
||
git checkout main
|
||
git reset --hard "$PREVIOUS_MAIN_SHA"
|
||
|
||
# Force push the rollback
|
||
if ! git push --force origin main; then
|
||
git notes -m 'release commit could not be rolled back'
|
||
echo "::error::Failed to push rollback to main"
|
||
exit 1
|
||
fi
|
||
git notes -m 'release commit rolled back'
|
||
echo "::error::Reset main branch to commit $PREVIOUS_MAIN_SHA"
|
||
echo "::error::Build failures detected:"
|
||
|
||
# Report which builds failed
|
||
if [ "${{ needs.build-windows.result }}" = "failure" ]; then
|
||
echo "::error:: - build-windows: FAILED"
|
||
fi
|
||
if [ "${{ needs.build-debian.result }}" = "failure" ]; then
|
||
echo "::error:: - build-debian: FAILED"
|
||
fi
|
||
if [ "${{ needs.build-arch.result }}" = "failure" ]; then
|
||
echo "::error:: - build-arch: FAILED"
|
||
fi
|
||
if [ "${{ needs.build-rhel.result }}" = "failure" ]; then
|
||
echo "::error:: - build-rhel: FAILED"
|
||
fi
|
||
|
||
exit 1
|
||
|
||
|