mirror of
https://github.com/Dispatcharr/Dispatcharr.git
synced 2026-01-23 02:35:14 +00:00
Add FreeBSD release workflow and build script
New files: .github/workflows/freebsd-release.yml: - Triggers on version tags (v*) and manual dispatch - Builds frontend with npm - Validates Python syntax - Runs compatibility tests - Creates release tarball with checksums - Tests package in FreeBSD VM (vmactions/freebsd-vm) - Uploads to GitHub Releases with release notes scripts/build-freebsd.sh: - Standalone build script for local builds - Works on FreeBSD, Linux, or macOS - Options: --version, --output, --skip-frontend, --skip-tests, --clean - Generates tarball with SHA256 and MD5 checksums - Self-contained with dependency checking BUILD.md: - Complete documentation for building FreeBSD packages - Quick start guide for automated and local builds - Package contents and installation instructions - Troubleshooting section - Development workflow guide The release package includes: - Pre-built React frontend - Django application code - FreeBSD installation script - Compatibility test suite - Build metadata
This commit is contained in:
parent
bc0310c0fc
commit
5089b16d36
3 changed files with 1134 additions and 0 deletions
343
.github/workflows/freebsd-release.yml
vendored
Normal file
343
.github/workflows/freebsd-release.yml
vendored
Normal file
|
|
@ -0,0 +1,343 @@
|
|||
# FreeBSD Release Build
|
||||
#
|
||||
# Builds a FreeBSD release package containing:
|
||||
# - Pre-built frontend assets
|
||||
# - Python application code
|
||||
# - FreeBSD installation scripts
|
||||
# - RC.d service scripts
|
||||
# - Configuration templates
|
||||
#
|
||||
# The package can be installed on FreeBSD using the included install script.
|
||||
#
|
||||
name: FreeBSD Release
|
||||
|
||||
on:
|
||||
push:
|
||||
tags:
|
||||
- 'v*'
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
version:
|
||||
description: 'Version to build (e.g., 0.16.0)'
|
||||
required: false
|
||||
default: ''
|
||||
create_release:
|
||||
description: 'Create GitHub Release'
|
||||
type: boolean
|
||||
default: true
|
||||
|
||||
env:
|
||||
PROJECT_NAME: dispatcharr
|
||||
|
||||
jobs:
|
||||
# Job 1: Build the FreeBSD release package
|
||||
build:
|
||||
name: Build FreeBSD Package
|
||||
runs-on: ubuntu-latest
|
||||
outputs:
|
||||
version: ${{ steps.version.outputs.version }}
|
||||
package_name: ${{ steps.package.outputs.name }}
|
||||
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Determine version
|
||||
id: version
|
||||
run: |
|
||||
if [ -n "${{ github.event.inputs.version }}" ]; then
|
||||
VERSION="${{ github.event.inputs.version }}"
|
||||
elif [[ "${{ github.ref }}" == refs/tags/v* ]]; then
|
||||
VERSION="${GITHUB_REF#refs/tags/v}"
|
||||
else
|
||||
# Extract from version.py
|
||||
VERSION=$(grep -oP "(?<=version = ['\"])[^'\"]*" version.py 2>/dev/null || echo "0.0.0")
|
||||
VERSION="${VERSION}-dev.$(date +%Y%m%d)"
|
||||
fi
|
||||
echo "version=$VERSION" >> $GITHUB_OUTPUT
|
||||
echo "Building version: $VERSION"
|
||||
|
||||
- name: Set up Node.js
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: '20'
|
||||
cache: 'npm'
|
||||
cache-dependency-path: frontend/package-lock.json
|
||||
|
||||
- name: Build frontend
|
||||
run: |
|
||||
cd frontend
|
||||
npm ci --legacy-peer-deps
|
||||
npm run build
|
||||
echo "Frontend build complete"
|
||||
ls -la dist/
|
||||
|
||||
- name: Set up Python
|
||||
uses: actions/setup-python@v5
|
||||
with:
|
||||
python-version: '3.11'
|
||||
|
||||
- name: Validate Python syntax
|
||||
run: |
|
||||
python -m py_compile manage.py
|
||||
find apps core dispatcharr -name "*.py" -exec python -m py_compile {} \;
|
||||
echo "Python syntax validation passed"
|
||||
|
||||
- name: Run FreeBSD compatibility tests
|
||||
run: |
|
||||
chmod +x scripts/ci_test.sh
|
||||
./scripts/ci_test.sh
|
||||
|
||||
- name: Create release package
|
||||
id: package
|
||||
run: |
|
||||
VERSION="${{ steps.version.outputs.version }}"
|
||||
PACKAGE_NAME="${{ env.PROJECT_NAME }}-${VERSION}-freebsd"
|
||||
BUILD_DIR="build/${PACKAGE_NAME}"
|
||||
|
||||
echo "Creating package: ${PACKAGE_NAME}"
|
||||
mkdir -p "${BUILD_DIR}"
|
||||
|
||||
# Copy application code
|
||||
cp -r apps core dispatcharr "${BUILD_DIR}/"
|
||||
cp manage.py requirements.txt version.py "${BUILD_DIR}/"
|
||||
|
||||
# Copy pre-built frontend
|
||||
mkdir -p "${BUILD_DIR}/frontend"
|
||||
cp -r frontend/dist "${BUILD_DIR}/frontend/"
|
||||
cp frontend/package.json "${BUILD_DIR}/frontend/"
|
||||
|
||||
# Copy FreeBSD-specific files
|
||||
cp freebsd_start.sh "${BUILD_DIR}/"
|
||||
cp -r scripts "${BUILD_DIR}/"
|
||||
mkdir -p "${BUILD_DIR}/tests/freebsd"
|
||||
cp -r tests/freebsd/* "${BUILD_DIR}/tests/freebsd/"
|
||||
|
||||
# Copy documentation
|
||||
cp README.md LICENSE "${BUILD_DIR}/" 2>/dev/null || true
|
||||
[ -f CHANGELOG.md ] && cp CHANGELOG.md "${BUILD_DIR}/"
|
||||
|
||||
# Create version info file
|
||||
cat > "${BUILD_DIR}/BUILD_INFO" << EOF
|
||||
Package: ${PACKAGE_NAME}
|
||||
Version: ${VERSION}
|
||||
Build Date: $(date -u +"%Y-%m-%d %H:%M:%S UTC")
|
||||
Git Commit: ${GITHUB_SHA:-unknown}
|
||||
Git Ref: ${GITHUB_REF:-unknown}
|
||||
Target: FreeBSD 14.x/15.x (amd64)
|
||||
EOF
|
||||
|
||||
# Create installation wrapper
|
||||
cat > "${BUILD_DIR}/install.sh" << 'INSTALL_EOF'
|
||||
#!/bin/sh
|
||||
# Dispatcharr FreeBSD Installation Wrapper
|
||||
#
|
||||
# This script wraps freebsd_start.sh for release package installation.
|
||||
#
|
||||
set -e
|
||||
|
||||
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
|
||||
|
||||
echo "=========================================="
|
||||
echo "Dispatcharr FreeBSD Installation"
|
||||
echo "=========================================="
|
||||
cat "${SCRIPT_DIR}/BUILD_INFO"
|
||||
echo "=========================================="
|
||||
echo ""
|
||||
|
||||
# Check if running as root
|
||||
if [ "$(id -u)" -ne 0 ]; then
|
||||
echo "Error: This script must be run as root"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Check if on FreeBSD
|
||||
if [ "$(uname -s)" != "FreeBSD" ]; then
|
||||
echo "Error: This package is for FreeBSD only"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Run the main installation script
|
||||
exec "${SCRIPT_DIR}/freebsd_start.sh" "$@"
|
||||
INSTALL_EOF
|
||||
chmod +x "${BUILD_DIR}/install.sh"
|
||||
|
||||
# Create the tarball
|
||||
cd build
|
||||
tar -czvf "${PACKAGE_NAME}.tar.gz" "${PACKAGE_NAME}"
|
||||
|
||||
# Generate checksums
|
||||
sha256sum "${PACKAGE_NAME}.tar.gz" > "${PACKAGE_NAME}.tar.gz.sha256"
|
||||
md5sum "${PACKAGE_NAME}.tar.gz" > "${PACKAGE_NAME}.tar.gz.md5"
|
||||
|
||||
echo "name=${PACKAGE_NAME}" >> $GITHUB_OUTPUT
|
||||
echo "Package created: ${PACKAGE_NAME}.tar.gz"
|
||||
ls -lh "${PACKAGE_NAME}.tar.gz"
|
||||
|
||||
- name: Upload build artifacts
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: freebsd-package
|
||||
path: |
|
||||
build/${{ steps.package.outputs.name }}.tar.gz
|
||||
build/${{ steps.package.outputs.name }}.tar.gz.sha256
|
||||
build/${{ steps.package.outputs.name }}.tar.gz.md5
|
||||
retention-days: 30
|
||||
|
||||
# Job 2: Test in FreeBSD VM (optional but recommended)
|
||||
test:
|
||||
name: Test in FreeBSD VM
|
||||
needs: build
|
||||
runs-on: ubuntu-latest
|
||||
# Only run on tag pushes or when explicitly requested
|
||||
if: startsWith(github.ref, 'refs/tags/') || github.event_name == 'workflow_dispatch'
|
||||
|
||||
steps:
|
||||
- name: Download package
|
||||
uses: actions/download-artifact@v4
|
||||
with:
|
||||
name: freebsd-package
|
||||
path: ./package
|
||||
|
||||
- name: Test package in FreeBSD VM
|
||||
uses: vmactions/freebsd-vm@v1
|
||||
with:
|
||||
release: "14.0"
|
||||
usesh: true
|
||||
prepare: |
|
||||
pkg update -f
|
||||
pkg install -y bash git
|
||||
|
||||
run: |
|
||||
set -e
|
||||
echo "=== FreeBSD Package Test ==="
|
||||
freebsd-version
|
||||
|
||||
# Extract package
|
||||
cd /root
|
||||
tar -xzf /home/runner/work/*/*/package/*.tar.gz
|
||||
|
||||
# Verify package contents
|
||||
PACKAGE_DIR=$(ls -d dispatcharr-* | head -1)
|
||||
echo "Package directory: ${PACKAGE_DIR}"
|
||||
|
||||
cd "${PACKAGE_DIR}"
|
||||
|
||||
# Verify key files exist
|
||||
echo "Checking package contents..."
|
||||
test -f freebsd_start.sh && echo "✓ freebsd_start.sh"
|
||||
test -f install.sh && echo "✓ install.sh"
|
||||
test -f manage.py && echo "✓ manage.py"
|
||||
test -f requirements.txt && echo "✓ requirements.txt"
|
||||
test -d frontend/dist && echo "✓ frontend/dist/"
|
||||
test -d apps && echo "✓ apps/"
|
||||
test -d core && echo "✓ core/"
|
||||
|
||||
# Run compatibility tests
|
||||
echo ""
|
||||
echo "Running compatibility tests..."
|
||||
if [ -f tests/freebsd/test_freebsd_compat.sh ]; then
|
||||
chmod +x tests/freebsd/test_freebsd_compat.sh
|
||||
bash tests/freebsd/test_freebsd_compat.sh
|
||||
fi
|
||||
|
||||
echo ""
|
||||
echo "=== Package test completed successfully ==="
|
||||
|
||||
# Job 3: Create GitHub Release
|
||||
release:
|
||||
name: Create GitHub Release
|
||||
needs: [build, test]
|
||||
runs-on: ubuntu-latest
|
||||
if: |
|
||||
always() &&
|
||||
needs.build.result == 'success' &&
|
||||
(needs.test.result == 'success' || needs.test.result == 'skipped') &&
|
||||
(startsWith(github.ref, 'refs/tags/') || (github.event_name == 'workflow_dispatch' && github.event.inputs.create_release == 'true'))
|
||||
permissions:
|
||||
contents: write
|
||||
|
||||
steps:
|
||||
- name: Download package
|
||||
uses: actions/download-artifact@v4
|
||||
with:
|
||||
name: freebsd-package
|
||||
path: ./release
|
||||
|
||||
- name: Prepare release notes
|
||||
id: notes
|
||||
run: |
|
||||
VERSION="${{ needs.build.outputs.version }}"
|
||||
PACKAGE="${{ needs.build.outputs.package_name }}"
|
||||
|
||||
cat > release_notes.md << EOF
|
||||
## FreeBSD Release Package
|
||||
|
||||
This release includes a pre-built package for FreeBSD 14.x/15.x (amd64).
|
||||
|
||||
### Installation
|
||||
|
||||
\`\`\`bash
|
||||
# Download and extract
|
||||
fetch https://github.com/${{ github.repository }}/releases/download/v${VERSION}/${PACKAGE}.tar.gz
|
||||
tar -xzf ${PACKAGE}.tar.gz
|
||||
cd ${PACKAGE}
|
||||
|
||||
# Verify checksum (optional)
|
||||
fetch https://github.com/${{ github.repository }}/releases/download/v${VERSION}/${PACKAGE}.tar.gz.sha256
|
||||
sha256 -c ${PACKAGE}.tar.gz.sha256
|
||||
|
||||
# Install (as root)
|
||||
sudo ./install.sh
|
||||
\`\`\`
|
||||
|
||||
### Package Contents
|
||||
|
||||
- Pre-built React frontend
|
||||
- Django application code
|
||||
- FreeBSD installation script
|
||||
- RC.d service scripts (auto-generated during install)
|
||||
- Compatibility test suite
|
||||
|
||||
### Requirements
|
||||
|
||||
- FreeBSD 14.x or 15.x (amd64)
|
||||
- PostgreSQL 15+
|
||||
- Redis
|
||||
- Python 3.11+
|
||||
- Node.js (only if rebuilding frontend)
|
||||
|
||||
### Checksums
|
||||
|
||||
See \`.sha256\` and \`.md5\` files for verification.
|
||||
|
||||
---
|
||||
*Built from commit: ${{ github.sha }}*
|
||||
EOF
|
||||
|
||||
- name: Create Release
|
||||
uses: softprops/action-gh-release@v2
|
||||
with:
|
||||
name: "v${{ needs.build.outputs.version }}"
|
||||
tag_name: "v${{ needs.build.outputs.version }}"
|
||||
body_path: release_notes.md
|
||||
draft: ${{ github.event_name == 'workflow_dispatch' }}
|
||||
prerelease: ${{ contains(needs.build.outputs.version, 'dev') || contains(needs.build.outputs.version, 'alpha') || contains(needs.build.outputs.version, 'beta') }}
|
||||
files: |
|
||||
release/${{ needs.build.outputs.package_name }}.tar.gz
|
||||
release/${{ needs.build.outputs.package_name }}.tar.gz.sha256
|
||||
release/${{ needs.build.outputs.package_name }}.tar.gz.md5
|
||||
fail_on_unmatched_files: true
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
- name: Summary
|
||||
run: |
|
||||
echo "## FreeBSD Release Published" >> $GITHUB_STEP_SUMMARY
|
||||
echo "" >> $GITHUB_STEP_SUMMARY
|
||||
echo "**Version:** ${{ needs.build.outputs.version }}" >> $GITHUB_STEP_SUMMARY
|
||||
echo "**Package:** ${{ needs.build.outputs.package_name }}.tar.gz" >> $GITHUB_STEP_SUMMARY
|
||||
echo "" >> $GITHUB_STEP_SUMMARY
|
||||
echo "[View Release](https://github.com/${{ github.repository }}/releases/tag/v${{ needs.build.outputs.version }})" >> $GITHUB_STEP_SUMMARY
|
||||
260
BUILD.md
Normal file
260
BUILD.md
Normal file
|
|
@ -0,0 +1,260 @@
|
|||
# Building Dispatcharr for FreeBSD
|
||||
|
||||
This document describes how to build a FreeBSD release package for Dispatcharr.
|
||||
|
||||
## Overview
|
||||
|
||||
Dispatcharr is a Python/Django application with a React frontend. The FreeBSD "build" creates a distributable package containing:
|
||||
|
||||
- Pre-built React frontend (compiled with Vite)
|
||||
- Django application code
|
||||
- FreeBSD installation script (`freebsd_start.sh`)
|
||||
- RC.d service templates
|
||||
- Compatibility tests
|
||||
|
||||
## Quick Start
|
||||
|
||||
### Automated Build (GitHub Actions)
|
||||
|
||||
The easiest way to build is using GitHub Actions:
|
||||
|
||||
1. **Tag a release:**
|
||||
```bash
|
||||
git tag v1.0.0
|
||||
git push origin v1.0.0
|
||||
```
|
||||
This triggers the `freebsd-release.yml` workflow automatically.
|
||||
|
||||
2. **Manual trigger:**
|
||||
- Go to **Actions** → **FreeBSD Release**
|
||||
- Click **Run workflow**
|
||||
- Optionally specify a version
|
||||
- Click **Run workflow**
|
||||
|
||||
The workflow will:
|
||||
- Build the frontend
|
||||
- Run compatibility tests
|
||||
- Create a release package
|
||||
- (Optionally) Test in a FreeBSD VM
|
||||
- Upload to GitHub Releases
|
||||
|
||||
### Local Build
|
||||
|
||||
Build locally using the standalone script:
|
||||
|
||||
```bash
|
||||
# Standard build
|
||||
./scripts/build-freebsd.sh
|
||||
|
||||
# Build with specific version
|
||||
./scripts/build-freebsd.sh --version 1.0.0
|
||||
|
||||
# Quick rebuild (skip frontend if unchanged)
|
||||
./scripts/build-freebsd.sh --skip-frontend
|
||||
|
||||
# Clean build to custom location
|
||||
./scripts/build-freebsd.sh --clean --output /tmp/build
|
||||
```
|
||||
|
||||
## Build Requirements
|
||||
|
||||
### For Local Builds
|
||||
|
||||
| Tool | Version | Purpose |
|
||||
|------|---------|---------|
|
||||
| Node.js | 18+ | Frontend build |
|
||||
| npm | 9+ | Package management |
|
||||
| Python | 3.9+ | Syntax validation |
|
||||
| bash | 4+ | Build script |
|
||||
| tar | any | Packaging |
|
||||
| sha256sum | any | Checksums |
|
||||
|
||||
### For FreeBSD Installation
|
||||
|
||||
| Package | Purpose |
|
||||
|---------|---------|
|
||||
| python3 | Runtime |
|
||||
| py311-pip | Package installation |
|
||||
| postgresql17-server | Database |
|
||||
| redis | Cache/queue |
|
||||
| nginx | Web server |
|
||||
| node, npm | Frontend (if rebuilding) |
|
||||
| git | Updates |
|
||||
|
||||
## Build Script Options
|
||||
|
||||
```
|
||||
./scripts/build-freebsd.sh [OPTIONS]
|
||||
|
||||
OPTIONS:
|
||||
--version <ver> Version string (default: from version.py)
|
||||
--output <path> Output directory (default: ./build)
|
||||
--skip-frontend Skip frontend build, use existing dist/
|
||||
--skip-tests Skip compatibility tests
|
||||
--clean Clean build directory first
|
||||
--help Show help
|
||||
```
|
||||
|
||||
## Package Contents
|
||||
|
||||
The generated package (`dispatcharr-VERSION-freebsd.tar.gz`) contains:
|
||||
|
||||
```
|
||||
dispatcharr-VERSION-freebsd/
|
||||
├── apps/ # Django applications
|
||||
├── core/ # Core Django app
|
||||
├── dispatcharr/ # Django settings
|
||||
├── frontend/
|
||||
│ └── dist/ # Pre-built React frontend
|
||||
├── scripts/ # Utility scripts
|
||||
├── tests/
|
||||
│ └── freebsd/ # Compatibility tests
|
||||
├── freebsd_start.sh # Main installation script
|
||||
├── install.sh # Installation wrapper
|
||||
├── manage.py # Django management
|
||||
├── requirements.txt # Python dependencies
|
||||
├── BUILD_INFO # Build metadata
|
||||
├── README.md
|
||||
└── LICENSE
|
||||
```
|
||||
|
||||
## Installation on FreeBSD
|
||||
|
||||
```bash
|
||||
# Download the release
|
||||
fetch https://github.com/USER/REPO/releases/download/vX.X.X/dispatcharr-X.X.X-freebsd.tar.gz
|
||||
|
||||
# Verify checksum (optional but recommended)
|
||||
fetch https://github.com/USER/REPO/releases/download/vX.X.X/dispatcharr-X.X.X-freebsd.tar.gz.sha256
|
||||
sha256 -c dispatcharr-X.X.X-freebsd.tar.gz.sha256
|
||||
|
||||
# Extract
|
||||
tar -xzf dispatcharr-X.X.X-freebsd.tar.gz
|
||||
cd dispatcharr-X.X.X-freebsd
|
||||
|
||||
# Install (as root)
|
||||
sudo ./install.sh
|
||||
```
|
||||
|
||||
The installation script will:
|
||||
1. Install required packages via `pkg`
|
||||
2. Create the `dispatcharr` user
|
||||
3. Set up PostgreSQL database
|
||||
4. Install Python dependencies
|
||||
5. Run Django migrations
|
||||
6. Configure Nginx
|
||||
7. Create and start RC.d services
|
||||
|
||||
## GitHub Actions Workflow
|
||||
|
||||
### Triggers
|
||||
|
||||
| Event | Condition | Action |
|
||||
|-------|-----------|--------|
|
||||
| Push tag | `v*` | Build and release |
|
||||
| Manual | workflow_dispatch | Build (optional release) |
|
||||
|
||||
### Jobs
|
||||
|
||||
1. **build**: Creates the package on Ubuntu
|
||||
2. **test**: Tests package in FreeBSD VM (tags only)
|
||||
3. **release**: Uploads to GitHub Releases
|
||||
|
||||
### Secrets Required
|
||||
|
||||
None - uses `GITHUB_TOKEN` automatically provided.
|
||||
|
||||
### Customization
|
||||
|
||||
Edit `.github/workflows/freebsd-release.yml` to:
|
||||
- Change FreeBSD version (default: 14.0)
|
||||
- Add additional build steps
|
||||
- Modify release notes template
|
||||
- Adjust artifact retention
|
||||
|
||||
## Testing
|
||||
|
||||
### Compatibility Tests
|
||||
|
||||
Run tests before building:
|
||||
|
||||
```bash
|
||||
# Quick CI tests
|
||||
./scripts/ci_test.sh
|
||||
|
||||
# Detailed tests
|
||||
./tests/freebsd/test_freebsd_compat.sh --verbose
|
||||
|
||||
# Python tests
|
||||
python3 tests/freebsd/test_freebsd_script.py
|
||||
```
|
||||
|
||||
### Test in FreeBSD Jail
|
||||
|
||||
On a FreeBSD host:
|
||||
|
||||
```bash
|
||||
sudo ./scripts/test_in_jail.sh --branch main --verbose
|
||||
```
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### Frontend Build Fails
|
||||
|
||||
```bash
|
||||
# Clear npm cache
|
||||
cd frontend
|
||||
rm -rf node_modules package-lock.json
|
||||
npm cache clean --force
|
||||
npm install --legacy-peer-deps
|
||||
```
|
||||
|
||||
### Python Syntax Errors
|
||||
|
||||
```bash
|
||||
# Find problematic files
|
||||
find apps core dispatcharr -name "*.py" -exec python3 -m py_compile {} \;
|
||||
```
|
||||
|
||||
### Package Too Large
|
||||
|
||||
The frontend `dist/` includes source maps by default. To reduce size:
|
||||
|
||||
```bash
|
||||
# Edit frontend/vite.config.js
|
||||
build: {
|
||||
sourcemap: false,
|
||||
...
|
||||
}
|
||||
```
|
||||
|
||||
### Checksum Mismatch
|
||||
|
||||
Ensure you're downloading both files from the same release:
|
||||
|
||||
```bash
|
||||
# Re-download and verify
|
||||
rm -f dispatcharr-*.tar.gz*
|
||||
fetch URL/dispatcharr-X.X.X-freebsd.tar.gz
|
||||
fetch URL/dispatcharr-X.X.X-freebsd.tar.gz.sha256
|
||||
sha256 -c dispatcharr-X.X.X-freebsd.tar.gz.sha256
|
||||
```
|
||||
|
||||
## Development Workflow
|
||||
|
||||
1. Make changes to the codebase
|
||||
2. Run compatibility tests: `./scripts/ci_test.sh`
|
||||
3. Test locally: `./scripts/build-freebsd.sh --skip-tests`
|
||||
4. Test in jail: `sudo ./scripts/test_in_jail.sh`
|
||||
5. Commit and push
|
||||
6. Tag for release: `git tag vX.X.X && git push origin vX.X.X`
|
||||
|
||||
## Related Files
|
||||
|
||||
- `.github/workflows/freebsd-release.yml` - GitHub Actions workflow
|
||||
- `.github/workflows/freebsd-compat.yml` - Compatibility testing
|
||||
- `scripts/build-freebsd.sh` - Standalone build script
|
||||
- `scripts/ci_test.sh` - CI test runner
|
||||
- `scripts/test_in_jail.sh` - Jail-based testing
|
||||
- `freebsd_start.sh` - Installation script
|
||||
- `tests/freebsd/` - Compatibility test suite
|
||||
531
scripts/build-freebsd.sh
Executable file
531
scripts/build-freebsd.sh
Executable file
|
|
@ -0,0 +1,531 @@
|
|||
#!/usr/bin/env bash
|
||||
#
|
||||
# Dispatcharr FreeBSD Build Script
|
||||
#
|
||||
# Creates a release package for FreeBSD containing:
|
||||
# - Pre-built frontend assets
|
||||
# - Python application code
|
||||
# - Installation scripts
|
||||
# - RC.d service templates
|
||||
#
|
||||
# Usage:
|
||||
# ./build-freebsd.sh [OPTIONS]
|
||||
#
|
||||
# Options:
|
||||
# --version <ver> Version string (default: from version.py or 0.0.0-dev)
|
||||
# --output <path> Output directory (default: ./build)
|
||||
# --skip-frontend Skip frontend build (use existing dist/)
|
||||
# --skip-tests Skip compatibility tests
|
||||
# --clean Clean build directory before building
|
||||
# --help Show this help message
|
||||
#
|
||||
# Requirements:
|
||||
# - Node.js and npm (for frontend build)
|
||||
# - Python 3.x (for syntax validation)
|
||||
# - tar, gzip (for packaging)
|
||||
#
|
||||
# This script can run on FreeBSD, Linux, or macOS.
|
||||
#
|
||||
|
||||
set -e
|
||||
set -o pipefail
|
||||
|
||||
# Script directory and project root
|
||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
PROJECT_ROOT="$(cd "${SCRIPT_DIR}/.." && pwd)"
|
||||
|
||||
# Default configuration
|
||||
VERSION=""
|
||||
OUTPUT_DIR="${PROJECT_ROOT}/build"
|
||||
SKIP_FRONTEND=0
|
||||
SKIP_TESTS=0
|
||||
CLEAN_BUILD=0
|
||||
PROJECT_NAME="dispatcharr"
|
||||
|
||||
# Colors (disabled if not a terminal)
|
||||
if [ -t 1 ]; then
|
||||
RED='\033[0;31m'
|
||||
GREEN='\033[0;32m'
|
||||
YELLOW='\033[1;33m'
|
||||
BLUE='\033[0;34m'
|
||||
BOLD='\033[1m'
|
||||
NC='\033[0m'
|
||||
else
|
||||
RED=''
|
||||
GREEN=''
|
||||
YELLOW=''
|
||||
BLUE=''
|
||||
BOLD=''
|
||||
NC=''
|
||||
fi
|
||||
|
||||
# Logging functions
|
||||
log_info() {
|
||||
echo -e "${BLUE}[INFO]${NC} $1"
|
||||
}
|
||||
|
||||
log_success() {
|
||||
echo -e "${GREEN}[OK]${NC} $1"
|
||||
}
|
||||
|
||||
log_warn() {
|
||||
echo -e "${YELLOW}[WARN]${NC} $1"
|
||||
}
|
||||
|
||||
log_error() {
|
||||
echo -e "${RED}[ERROR]${NC} $1" >&2
|
||||
}
|
||||
|
||||
log_step() {
|
||||
echo ""
|
||||
echo -e "${BOLD}━━━ $1 ━━━${NC}"
|
||||
}
|
||||
|
||||
show_help() {
|
||||
cat << 'EOF'
|
||||
Dispatcharr FreeBSD Build Script
|
||||
|
||||
USAGE:
|
||||
./build-freebsd.sh [OPTIONS]
|
||||
|
||||
OPTIONS:
|
||||
--version <ver> Version string to embed in package
|
||||
Default: extracted from version.py or "0.0.0-dev"
|
||||
|
||||
--output <path> Output directory for build artifacts
|
||||
Default: ./build
|
||||
|
||||
--skip-frontend Skip frontend build, use existing frontend/dist/
|
||||
Useful for faster rebuilds when frontend hasn't changed
|
||||
|
||||
--skip-tests Skip FreeBSD compatibility tests
|
||||
Not recommended for release builds
|
||||
|
||||
--clean Remove existing build directory before building
|
||||
|
||||
--help Show this help message
|
||||
|
||||
EXAMPLES:
|
||||
# Standard build
|
||||
./build-freebsd.sh
|
||||
|
||||
# Build specific version
|
||||
./build-freebsd.sh --version 1.0.0
|
||||
|
||||
# Quick rebuild (skip frontend)
|
||||
./build-freebsd.sh --skip-frontend
|
||||
|
||||
# Clean build to custom directory
|
||||
./build-freebsd.sh --clean --output /tmp/dispatcharr-build
|
||||
|
||||
OUTPUT:
|
||||
Creates a tarball: dispatcharr-<version>-freebsd.tar.gz
|
||||
With checksums: dispatcharr-<version>-freebsd.tar.gz.sha256
|
||||
dispatcharr-<version>-freebsd.tar.gz.md5
|
||||
|
||||
REQUIREMENTS:
|
||||
- Node.js 18+ and npm (for frontend build)
|
||||
- Python 3.9+ (for syntax validation)
|
||||
- bash, tar, gzip, sha256sum/shasum
|
||||
|
||||
EOF
|
||||
}
|
||||
|
||||
# Parse command line arguments
|
||||
parse_args() {
|
||||
while [[ $# -gt 0 ]]; do
|
||||
case $1 in
|
||||
--version)
|
||||
VERSION="$2"
|
||||
shift 2
|
||||
;;
|
||||
--output)
|
||||
OUTPUT_DIR="$2"
|
||||
shift 2
|
||||
;;
|
||||
--skip-frontend)
|
||||
SKIP_FRONTEND=1
|
||||
shift
|
||||
;;
|
||||
--skip-tests)
|
||||
SKIP_TESTS=1
|
||||
shift
|
||||
;;
|
||||
--clean)
|
||||
CLEAN_BUILD=1
|
||||
shift
|
||||
;;
|
||||
--help|-h)
|
||||
show_help
|
||||
exit 0
|
||||
;;
|
||||
*)
|
||||
log_error "Unknown option: $1"
|
||||
echo "Use --help for usage information"
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
done
|
||||
}
|
||||
|
||||
# Check for required tools
|
||||
check_dependencies() {
|
||||
log_step "Checking Dependencies"
|
||||
|
||||
local missing=()
|
||||
|
||||
# Check Node.js (only if building frontend)
|
||||
if [ $SKIP_FRONTEND -eq 0 ]; then
|
||||
if command -v node >/dev/null 2>&1; then
|
||||
log_success "Node.js $(node --version)"
|
||||
else
|
||||
missing+=("node")
|
||||
fi
|
||||
|
||||
if command -v npm >/dev/null 2>&1; then
|
||||
log_success "npm $(npm --version)"
|
||||
else
|
||||
missing+=("npm")
|
||||
fi
|
||||
fi
|
||||
|
||||
# Check Python
|
||||
if command -v python3 >/dev/null 2>&1; then
|
||||
log_success "Python $(python3 --version 2>&1 | cut -d' ' -f2)"
|
||||
else
|
||||
missing+=("python3")
|
||||
fi
|
||||
|
||||
# Check tar
|
||||
if command -v tar >/dev/null 2>&1; then
|
||||
log_success "tar available"
|
||||
else
|
||||
missing+=("tar")
|
||||
fi
|
||||
|
||||
# Check checksum tools
|
||||
if command -v sha256sum >/dev/null 2>&1; then
|
||||
SHA256_CMD="sha256sum"
|
||||
log_success "sha256sum available"
|
||||
elif command -v shasum >/dev/null 2>&1; then
|
||||
SHA256_CMD="shasum -a 256"
|
||||
log_success "shasum available"
|
||||
else
|
||||
missing+=("sha256sum or shasum")
|
||||
fi
|
||||
|
||||
if command -v md5sum >/dev/null 2>&1; then
|
||||
MD5_CMD="md5sum"
|
||||
elif command -v md5 >/dev/null 2>&1; then
|
||||
MD5_CMD="md5 -r"
|
||||
else
|
||||
MD5_CMD=""
|
||||
log_warn "md5sum not available, skipping MD5 checksum"
|
||||
fi
|
||||
|
||||
if [ ${#missing[@]} -gt 0 ]; then
|
||||
log_error "Missing required tools: ${missing[*]}"
|
||||
echo ""
|
||||
echo "Please install the missing tools and try again."
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
|
||||
# Determine version
|
||||
determine_version() {
|
||||
log_step "Determining Version"
|
||||
|
||||
if [ -n "$VERSION" ]; then
|
||||
log_info "Using specified version: $VERSION"
|
||||
return
|
||||
fi
|
||||
|
||||
# Try to extract from version.py
|
||||
if [ -f "${PROJECT_ROOT}/version.py" ]; then
|
||||
VERSION=$(grep -oP "(?<=version = ['\"])[^'\"]*" "${PROJECT_ROOT}/version.py" 2>/dev/null || true)
|
||||
if [ -n "$VERSION" ]; then
|
||||
log_info "Extracted version from version.py: $VERSION"
|
||||
return
|
||||
fi
|
||||
fi
|
||||
|
||||
# Try git tag
|
||||
if command -v git >/dev/null 2>&1 && [ -d "${PROJECT_ROOT}/.git" ]; then
|
||||
VERSION=$(git -C "${PROJECT_ROOT}" describe --tags --abbrev=0 2>/dev/null | sed 's/^v//' || true)
|
||||
if [ -n "$VERSION" ]; then
|
||||
log_info "Extracted version from git tag: $VERSION"
|
||||
return
|
||||
fi
|
||||
fi
|
||||
|
||||
# Default version
|
||||
VERSION="0.0.0-dev"
|
||||
log_warn "Could not determine version, using: $VERSION"
|
||||
}
|
||||
|
||||
# Build frontend
|
||||
build_frontend() {
|
||||
log_step "Building Frontend"
|
||||
|
||||
if [ $SKIP_FRONTEND -eq 1 ]; then
|
||||
if [ -d "${PROJECT_ROOT}/frontend/dist" ]; then
|
||||
log_info "Skipping frontend build (--skip-frontend)"
|
||||
log_success "Using existing frontend/dist/"
|
||||
return
|
||||
else
|
||||
log_error "frontend/dist/ does not exist. Cannot skip frontend build."
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
|
||||
cd "${PROJECT_ROOT}/frontend"
|
||||
|
||||
log_info "Installing npm dependencies..."
|
||||
npm ci --legacy-peer-deps 2>&1 | tail -5
|
||||
|
||||
log_info "Building frontend..."
|
||||
npm run build 2>&1 | tail -10
|
||||
|
||||
if [ -d "dist" ]; then
|
||||
log_success "Frontend built successfully"
|
||||
log_info "Output size: $(du -sh dist | cut -f1)"
|
||||
else
|
||||
log_error "Frontend build failed - dist/ not created"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
cd "${PROJECT_ROOT}"
|
||||
}
|
||||
|
||||
# Validate Python code
|
||||
validate_python() {
|
||||
log_step "Validating Python Code"
|
||||
|
||||
cd "${PROJECT_ROOT}"
|
||||
|
||||
log_info "Checking Python syntax..."
|
||||
local errors=0
|
||||
|
||||
# Check manage.py
|
||||
if python3 -m py_compile manage.py 2>/dev/null; then
|
||||
log_success "manage.py"
|
||||
else
|
||||
log_error "manage.py has syntax errors"
|
||||
((errors++))
|
||||
fi
|
||||
|
||||
# Check apps, core, dispatcharr directories
|
||||
for dir in apps core dispatcharr; do
|
||||
if [ -d "$dir" ]; then
|
||||
local count=$(find "$dir" -name "*.py" | wc -l | tr -d ' ')
|
||||
local failed=0
|
||||
while IFS= read -r -d '' file; do
|
||||
if ! python3 -m py_compile "$file" 2>/dev/null; then
|
||||
log_error "Syntax error: $file"
|
||||
((failed++))
|
||||
fi
|
||||
done < <(find "$dir" -name "*.py" -print0)
|
||||
|
||||
if [ $failed -eq 0 ]; then
|
||||
log_success "${dir}/ (${count} files)"
|
||||
else
|
||||
((errors += failed))
|
||||
fi
|
||||
fi
|
||||
done
|
||||
|
||||
if [ $errors -gt 0 ]; then
|
||||
log_error "Python validation failed with $errors errors"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
log_success "All Python files validated"
|
||||
}
|
||||
|
||||
# Run compatibility tests
|
||||
run_tests() {
|
||||
log_step "Running FreeBSD Compatibility Tests"
|
||||
|
||||
if [ $SKIP_TESTS -eq 1 ]; then
|
||||
log_warn "Skipping tests (--skip-tests)"
|
||||
return
|
||||
fi
|
||||
|
||||
cd "${PROJECT_ROOT}"
|
||||
|
||||
if [ -x "scripts/ci_test.sh" ]; then
|
||||
if ./scripts/ci_test.sh; then
|
||||
log_success "All compatibility tests passed"
|
||||
else
|
||||
log_error "Compatibility tests failed"
|
||||
exit 1
|
||||
fi
|
||||
elif [ -x "tests/freebsd/test_freebsd_compat.sh" ]; then
|
||||
if bash tests/freebsd/test_freebsd_compat.sh; then
|
||||
log_success "All compatibility tests passed"
|
||||
else
|
||||
log_error "Compatibility tests failed"
|
||||
exit 1
|
||||
fi
|
||||
else
|
||||
log_warn "No test scripts found, skipping tests"
|
||||
fi
|
||||
}
|
||||
|
||||
# Create the release package
|
||||
create_package() {
|
||||
log_step "Creating Release Package"
|
||||
|
||||
PACKAGE_NAME="${PROJECT_NAME}-${VERSION}-freebsd"
|
||||
BUILD_DIR="${OUTPUT_DIR}/${PACKAGE_NAME}"
|
||||
|
||||
# Clean if requested
|
||||
if [ $CLEAN_BUILD -eq 1 ] && [ -d "${OUTPUT_DIR}" ]; then
|
||||
log_info "Cleaning build directory..."
|
||||
rm -rf "${OUTPUT_DIR}"
|
||||
fi
|
||||
|
||||
# Create build directory
|
||||
mkdir -p "${BUILD_DIR}"
|
||||
|
||||
log_info "Copying application code..."
|
||||
|
||||
# Copy Python application
|
||||
cp -r "${PROJECT_ROOT}/apps" "${BUILD_DIR}/"
|
||||
cp -r "${PROJECT_ROOT}/core" "${BUILD_DIR}/"
|
||||
cp -r "${PROJECT_ROOT}/dispatcharr" "${BUILD_DIR}/"
|
||||
cp "${PROJECT_ROOT}/manage.py" "${BUILD_DIR}/"
|
||||
cp "${PROJECT_ROOT}/requirements.txt" "${BUILD_DIR}/"
|
||||
[ -f "${PROJECT_ROOT}/version.py" ] && cp "${PROJECT_ROOT}/version.py" "${BUILD_DIR}/"
|
||||
|
||||
# Copy pre-built frontend
|
||||
log_info "Copying frontend assets..."
|
||||
mkdir -p "${BUILD_DIR}/frontend"
|
||||
cp -r "${PROJECT_ROOT}/frontend/dist" "${BUILD_DIR}/frontend/"
|
||||
cp "${PROJECT_ROOT}/frontend/package.json" "${BUILD_DIR}/frontend/"
|
||||
|
||||
# Copy FreeBSD-specific files
|
||||
log_info "Copying FreeBSD files..."
|
||||
cp "${PROJECT_ROOT}/freebsd_start.sh" "${BUILD_DIR}/"
|
||||
cp -r "${PROJECT_ROOT}/scripts" "${BUILD_DIR}/"
|
||||
|
||||
# Copy tests
|
||||
mkdir -p "${BUILD_DIR}/tests/freebsd"
|
||||
cp -r "${PROJECT_ROOT}/tests/freebsd/"* "${BUILD_DIR}/tests/freebsd/" 2>/dev/null || true
|
||||
|
||||
# Copy documentation
|
||||
log_info "Copying documentation..."
|
||||
[ -f "${PROJECT_ROOT}/README.md" ] && cp "${PROJECT_ROOT}/README.md" "${BUILD_DIR}/"
|
||||
[ -f "${PROJECT_ROOT}/LICENSE" ] && cp "${PROJECT_ROOT}/LICENSE" "${BUILD_DIR}/"
|
||||
[ -f "${PROJECT_ROOT}/CHANGELOG.md" ] && cp "${PROJECT_ROOT}/CHANGELOG.md" "${BUILD_DIR}/"
|
||||
[ -f "${PROJECT_ROOT}/BUILD.md" ] && cp "${PROJECT_ROOT}/BUILD.md" "${BUILD_DIR}/"
|
||||
|
||||
# Create BUILD_INFO
|
||||
log_info "Creating build info..."
|
||||
cat > "${BUILD_DIR}/BUILD_INFO" << EOF
|
||||
Package: ${PACKAGE_NAME}
|
||||
Version: ${VERSION}
|
||||
Build Date: $(date -u +"%Y-%m-%d %H:%M:%S UTC")
|
||||
Build Host: $(hostname)
|
||||
Build OS: $(uname -s) $(uname -r)
|
||||
Target: FreeBSD 14.x/15.x (amd64)
|
||||
EOF
|
||||
|
||||
# Add git info if available
|
||||
if command -v git >/dev/null 2>&1 && [ -d "${PROJECT_ROOT}/.git" ]; then
|
||||
echo "Git Commit: $(git -C "${PROJECT_ROOT}" rev-parse HEAD 2>/dev/null || echo 'unknown')" >> "${BUILD_DIR}/BUILD_INFO"
|
||||
echo "Git Branch: $(git -C "${PROJECT_ROOT}" rev-parse --abbrev-ref HEAD 2>/dev/null || echo 'unknown')" >> "${BUILD_DIR}/BUILD_INFO"
|
||||
fi
|
||||
|
||||
# Create installation wrapper
|
||||
log_info "Creating install wrapper..."
|
||||
cat > "${BUILD_DIR}/install.sh" << 'EOF'
|
||||
#!/bin/sh
|
||||
# Dispatcharr FreeBSD Installation Wrapper
|
||||
set -e
|
||||
|
||||
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
|
||||
|
||||
echo "=========================================="
|
||||
echo "Dispatcharr FreeBSD Installation"
|
||||
echo "=========================================="
|
||||
cat "${SCRIPT_DIR}/BUILD_INFO"
|
||||
echo "=========================================="
|
||||
echo ""
|
||||
|
||||
if [ "$(id -u)" -ne 0 ]; then
|
||||
echo "Error: This script must be run as root"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [ "$(uname -s)" != "FreeBSD" ]; then
|
||||
echo "Error: This package is for FreeBSD only"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
exec "${SCRIPT_DIR}/freebsd_start.sh" "$@"
|
||||
EOF
|
||||
chmod +x "${BUILD_DIR}/install.sh"
|
||||
chmod +x "${BUILD_DIR}/freebsd_start.sh"
|
||||
|
||||
# Create tarball
|
||||
log_info "Creating tarball..."
|
||||
cd "${OUTPUT_DIR}"
|
||||
tar -czvf "${PACKAGE_NAME}.tar.gz" "${PACKAGE_NAME}" 2>&1 | tail -3
|
||||
|
||||
# Generate checksums
|
||||
log_info "Generating checksums..."
|
||||
${SHA256_CMD} "${PACKAGE_NAME}.tar.gz" > "${PACKAGE_NAME}.tar.gz.sha256"
|
||||
if [ -n "$MD5_CMD" ]; then
|
||||
${MD5_CMD} "${PACKAGE_NAME}.tar.gz" > "${PACKAGE_NAME}.tar.gz.md5"
|
||||
fi
|
||||
|
||||
log_success "Package created successfully"
|
||||
}
|
||||
|
||||
# Print summary
|
||||
print_summary() {
|
||||
echo ""
|
||||
echo -e "${BOLD}══════════════════════════════════════════════════════════════${NC}"
|
||||
echo -e "${BOLD} BUILD COMPLETE ${NC}"
|
||||
echo -e "${BOLD}══════════════════════════════════════════════════════════════${NC}"
|
||||
echo ""
|
||||
echo " Package: ${PACKAGE_NAME}.tar.gz"
|
||||
echo " Version: ${VERSION}"
|
||||
echo " Location: ${OUTPUT_DIR}/"
|
||||
echo ""
|
||||
echo " Files created:"
|
||||
ls -lh "${OUTPUT_DIR}/${PACKAGE_NAME}.tar.gz"*
|
||||
echo ""
|
||||
echo " Package size: $(du -sh "${OUTPUT_DIR}/${PACKAGE_NAME}.tar.gz" | cut -f1)"
|
||||
echo ""
|
||||
echo -e "${BOLD}══════════════════════════════════════════════════════════════${NC}"
|
||||
echo ""
|
||||
echo "To install on FreeBSD:"
|
||||
echo ""
|
||||
echo " tar -xzf ${PACKAGE_NAME}.tar.gz"
|
||||
echo " cd ${PACKAGE_NAME}"
|
||||
echo " sudo ./install.sh"
|
||||
echo ""
|
||||
}
|
||||
|
||||
# Main execution
|
||||
main() {
|
||||
echo ""
|
||||
echo -e "${BOLD}Dispatcharr FreeBSD Build Script${NC}"
|
||||
echo ""
|
||||
|
||||
parse_args "$@"
|
||||
|
||||
cd "${PROJECT_ROOT}"
|
||||
|
||||
check_dependencies
|
||||
determine_version
|
||||
build_frontend
|
||||
validate_python
|
||||
run_tests
|
||||
create_package
|
||||
print_summary
|
||||
}
|
||||
|
||||
main "$@"
|
||||
Loading…
Add table
Add a link
Reference in a new issue