Merge pull request #18 from johndoe6345789/copilot/fix-release-image-issues

Add UEFI-bootable disk image builder with automated GitHub releases
This commit is contained in:
2025-12-29 18:01:51 +00:00
committed by GitHub
8 changed files with 1158 additions and 9 deletions

343
.github/workflows/build-image.yml vendored Normal file
View File

@@ -0,0 +1,343 @@
name: Build and Release Disk Image
on:
push:
branches:
- main
- develop
tags:
- 'v*'
pull_request:
branches:
- main
- develop
workflow_dispatch:
jobs:
build-image:
runs-on: ubuntu-latest
permissions:
contents: write
steps:
- name: Checkout repository
uses: actions/checkout@v4
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
- name: Build disk image using Docker
run: |
echo "Building SparkOS disk image..."
# Build the image builder container
docker buildx build \
--file Dockerfile.image \
--target image-builder \
--tag sparkos:image-builder \
--load \
.
# Create a container and extract the image
echo "Extracting disk image..."
CONTAINER_ID=$(docker create sparkos:image-builder)
docker cp "$CONTAINER_ID:/output/sparkos.img.gz" ./sparkos.img.gz
docker rm "$CONTAINER_ID"
echo "Disk image created successfully!"
ls -lh sparkos.img.gz
- name: Verify disk image
run: |
echo "Verifying UEFI-bootable disk image..."
if [ ! -f sparkos.img.gz ]; then
echo "ERROR: Disk image not found!"
exit 1
fi
# Show file info
ls -lh sparkos.img.gz
file sparkos.img.gz
# Decompress and check
echo "Decompressing to verify..."
gunzip -c sparkos.img.gz > sparkos.img
ls -lh sparkos.img
file sparkos.img
# Show partition table (should be GPT)
echo ""
echo "=== Partition Table (GPT) ==="
sudo fdisk -l sparkos.img || true
sudo parted sparkos.img print || true
# Try to mount and inspect partitions
echo ""
echo "=== Inspecting Partitions ==="
mkdir -p /tmp/sparkos_esp /tmp/sparkos_root
# Set up loop device
LOOP_DEV=$(sudo losetup -fP --show sparkos.img)
echo "Loop device: $LOOP_DEV"
ls -la ${LOOP_DEV}*
# Mount and check ESP
if sudo mount -o ro ${LOOP_DEV}p1 /tmp/sparkos_esp 2>/dev/null; then
echo "✓ EFI System Partition mounted"
echo "ESP contents:"
ls -laR /tmp/sparkos_esp/
if [ -f /tmp/sparkos_esp/EFI/BOOT/BOOTX64.EFI ]; then
echo "✓ UEFI bootloader (GRUB) found"
fi
if [ -f /tmp/sparkos_esp/boot/vmlinuz ]; then
echo "✓ Kernel found"
fi
sudo umount /tmp/sparkos_esp
fi
# Mount and check root partition
if sudo mount -o ro ${LOOP_DEV}p2 /tmp/sparkos_root 2>/dev/null; then
echo "✓ Root partition mounted"
echo "Root contents:"
ls -la /tmp/sparkos_root/
if [ -f /tmp/sparkos_root/sbin/init ]; then
echo "✓ Init binary found"
ls -lh /tmp/sparkos_root/sbin/init
fi
if [ -f /tmp/sparkos_root/bin/busybox ]; then
echo "✓ Busybox found"
fi
sudo umount /tmp/sparkos_root
fi
# Cleanup
sudo losetup -d $LOOP_DEV
echo ""
echo "=== Verification Complete ==="
echo "✓ UEFI-bootable image with GPT partition table"
echo "✓ EFI System Partition with GRUB"
echo "✓ Root partition with init system and busybox"
- name: Create release package
run: |
echo "Creating release package..."
mkdir -p release
# Move the compressed image
mv sparkos.img.gz release/
# Create a README for the release
cat > release/README.txt << 'EOF'
SparkOS UEFI-Bootable Disk Image
==================================
This package contains a UEFI-bootable disk image with SparkOS.
Files:
- sparkos.img.gz - Compressed UEFI-bootable disk image (~1GB)
What's Included:
---------------
✓ GPT partition table
✓ EFI System Partition (ESP) with FAT32 filesystem
✓ GRUB UEFI bootloader
✓ Linux kernel
✓ SparkOS init system
✓ Busybox utilities
✓ Basic FHS-compliant filesystem structure
Boot Support:
------------
✓ UEFI boot (x86_64 systems)
✓ Automatic boot after 3 seconds
✓ Console on tty1
Quick Start:
-----------
1. Decompress the image:
gunzip sparkos.img.gz
2. Write to USB drive (Linux - BE CAREFUL!):
sudo dd if=sparkos.img of=/dev/sdX bs=4M status=progress oflag=sync
WARNING: Replace /dev/sdX with your actual USB drive device.
This will DESTROY all data on the target drive!
3. Boot from USB:
- Insert the USB drive into a UEFI-capable system
- Enter BIOS/UEFI settings (usually F2, F12, DEL, or ESC at boot)
- Select the USB drive as boot device
- SparkOS should boot automatically
Advanced - Inspect Partitions:
------------------------------
To mount and inspect the partitions:
# Set up loop device
sudo losetup -fP --show sparkos.img
# Note the loop device name (e.g., /dev/loop0)
# Mount ESP (EFI System Partition)
sudo mount /dev/loop0p1 /mnt
ls -la /mnt/EFI
sudo umount /mnt
# Mount root partition
sudo mount /dev/loop0p2 /mnt
ls -la /mnt
sudo umount /mnt
# Cleanup
sudo losetup -d /dev/loop0
Documentation:
-------------
See the full documentation at:
https://github.com/johndoe6345789/SparkOS
Support:
-------
For issues and questions, visit:
https://github.com/johndoe6345789/SparkOS/issues
EOF
# Create a ZIP with the image and README
cd release || exit 1
zip sparkos-image.zip sparkos.img.gz README.txt
cd .. || exit 1
echo "Release package created!"
ls -lh release/
- name: Upload image artifact
uses: actions/upload-artifact@v4
with:
name: sparkos-image-${{ github.sha }}
path: |
release/sparkos-image.zip
release/sparkos.img.gz
retention-days: 90
- name: Create GitHub Release
if: startsWith(github.ref, 'refs/tags/')
uses: softprops/action-gh-release@v1
with:
files: |
release/sparkos-image.zip
release/sparkos.img.gz
body: |
# SparkOS UEFI-Bootable Disk Image Release ${{ github.ref_name }}
This release includes a **UEFI-bootable** disk image with SparkOS.
## What's Included
- **sparkos-image.zip**: Complete package with image and README
- **sparkos.img.gz**: Compressed UEFI-bootable disk image (~1GB)
## Features
✅ **UEFI Boot Support** - Boot on modern UEFI systems
✅ **GPT Partition Table** - Modern partitioning scheme
✅ **GRUB Bootloader** - Reliable UEFI bootloader
✅ **Linux Kernel** - Full kernel included
✅ **SparkOS Init System** - Custom init with busybox
✅ **Ready to Boot** - Write to USB and boot immediately
## Quick Start
### Write to USB and Boot
```bash
# Download and decompress
wget https://github.com/johndoe6345789/SparkOS/releases/download/${{ github.ref_name }}/sparkos.img.gz
gunzip sparkos.img.gz
# Write to USB drive (Linux - BE CAREFUL!)
sudo dd if=sparkos.img of=/dev/sdX bs=4M status=progress oflag=sync
```
**⚠️ WARNING**: Replace `/dev/sdX` with your actual USB device (e.g., `/dev/sdb`). This will **ERASE ALL DATA** on the target drive!
### Boot Instructions
1. Insert the USB drive into a UEFI-capable system
2. Enter BIOS/UEFI settings (usually F2, F12, DEL, or ESC at boot)
3. Select the USB drive as boot device
4. SparkOS will boot automatically after 3 seconds
### Inspect Partitions (Advanced)
```bash
# Set up loop device
LOOP_DEV=$(sudo losetup -fP --show sparkos.img)
# Mount ESP (EFI System Partition)
sudo mount ${LOOP_DEV}p1 /mnt
ls -la /mnt/EFI # View bootloader and kernel
sudo umount /mnt
# Mount root partition
sudo mount ${LOOP_DEV}p2 /mnt
ls -la /mnt # View SparkOS filesystem
sudo umount /mnt
# Cleanup
sudo losetup -d $LOOP_DEV
```
## Technical Details
- **Size**: ~1GB (compressed)
- **Partition Table**: GPT
- **ESP**: 200MB FAT32 (EFI System Partition)
- **Root**: ~800MB ext4
- **Bootloader**: GRUB (UEFI)
- **Kernel**: Linux kernel (from Ubuntu)
- **Init**: SparkOS custom init system
- **Shell**: Busybox
## Docker Image
A Docker image is also available:
```bash
docker pull ghcr.io/johndoe6345789/sparkos:${{ github.ref_name }}
```
## Documentation
See [README.md](https://github.com/johndoe6345789/SparkOS/blob/main/README.md) for full documentation.
## What's Changed
See commit history for detailed changes.
draft: false
prerelease: false
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- name: Output summary
run: |
echo "### Disk Image Build Summary 💾" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "**Status:** ✅ Success" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "**Disk Image:**" >> $GITHUB_STEP_SUMMARY
echo '```' >> $GITHUB_STEP_SUMMARY
ls -lh release/sparkos.img.gz >> $GITHUB_STEP_SUMMARY
echo '```' >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "**Release Package:**" >> $GITHUB_STEP_SUMMARY
echo '```' >> $GITHUB_STEP_SUMMARY
ls -lh release/sparkos-image.zip >> $GITHUB_STEP_SUMMARY
echo '```' >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
if [[ "${{ github.ref }}" == refs/tags/* ]]; then
echo "**Release:** Created GitHub release for ${{ github.ref_name }}" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "Download from: https://github.com/${{ github.repository }}/releases/tag/${{ github.ref_name }}" >> $GITHUB_STEP_SUMMARY
else
echo "**Artifact:** Uploaded as workflow artifact (available for 90 days)" >> $GITHUB_STEP_SUMMARY
fi

179
Dockerfile.image Normal file
View File

@@ -0,0 +1,179 @@
# Dockerfile for building UEFI-bootable SparkOS image
# Creates a .img file with GPT partition table, ESP, and GRUB
FROM ubuntu:22.04 AS image-builder
# Install required tools
RUN apt-get update && \
apt-get install -y \
gcc \
make \
dosfstools \
mtools \
e2fsprogs \
parted \
gdisk \
grub-efi-amd64-bin \
grub-common \
wget \
busybox-static \
kmod \
&& rm -rf /var/lib/apt/lists/*
WORKDIR /build
# Copy source files
COPY src/ ./src/
COPY Makefile .
COPY scripts/ ./scripts/
COPY config/ ./config/
COPY rootfs/ ./rootfs/
# Build the init binary
RUN make init
# Download a minimal Linux kernel (using Ubuntu's kernel for now)
RUN mkdir -p /kernel && \
apt-get update && \
apt-get download linux-image-generic && \
dpkg -x linux-image-*.deb /kernel && \
rm -rf /var/lib/apt/lists/* linux-image-*.deb
# Create UEFI-bootable image with GPT partition table
RUN mkdir -p /output /mnt/esp /mnt/root && \
echo "=== Creating UEFI-bootable SparkOS image with GRUB ===" && \
# Create 1GB disk image (larger for kernel + bootloader)
dd if=/dev/zero of=/output/sparkos.img bs=1M count=1024 && \
\
# Create GPT partition table
echo "Creating GPT partition table..." && \
parted -s /output/sparkos.img mklabel gpt && \
\
# Create EFI System Partition (ESP) - 200MB, FAT32
echo "Creating EFI System Partition..." && \
parted -s /output/sparkos.img mkpart ESP fat32 1MiB 201MiB && \
parted -s /output/sparkos.img set 1 esp on && \
\
# Create root partition - remaining space, ext4
echo "Creating root partition..." && \
parted -s /output/sparkos.img mkpart primary ext4 201MiB 100% && \
\
# Set up loop device for the image
LOOP_DEV=$(losetup -f) && \
losetup -P $LOOP_DEV /output/sparkos.img && \
\
# Wait for partition devices
sleep 1 && \
\
# Format partitions
echo "Formatting EFI System Partition (FAT32)..." && \
mkfs.vfat -F 32 -n "SPARKOSEFI" ${LOOP_DEV}p1 && \
\
echo "Formatting root partition (ext4)..." && \
mkfs.ext4 -L "SparkOS" ${LOOP_DEV}p2 && \
\
# Mount ESP
echo "Mounting partitions..." && \
mount ${LOOP_DEV}p1 /mnt/esp && \
mount ${LOOP_DEV}p2 /mnt/root && \
\
# Install GRUB to ESP
echo "Installing GRUB bootloader..." && \
mkdir -p /mnt/esp/EFI/BOOT && \
\
# Create GRUB EFI binary using grub-mkstandalone
grub-mkstandalone \
--format=x86_64-efi \
--output=/mnt/esp/EFI/BOOT/BOOTX64.EFI \
--locales="" \
--fonts="" \
"boot/grub/grub.cfg=/dev/null" && \
\
# Find the kernel
KERNEL_PATH=$(find /kernel/boot -name "vmlinuz-*" | head -1) && \
KERNEL_VERSION=$(basename $KERNEL_PATH | sed 's/vmlinuz-//') && \
INITRD_PATH=$(find /kernel/boot -name "initrd.img-*" | head -1) && \
\
# Copy kernel and initrd to ESP
echo "Installing kernel..." && \
mkdir -p /mnt/esp/boot && \
cp $KERNEL_PATH /mnt/esp/boot/vmlinuz && \
if [ -f "$INITRD_PATH" ]; then cp $INITRD_PATH /mnt/esp/boot/initrd.img; fi && \
\
# Create GRUB configuration
mkdir -p /mnt/esp/boot/grub && \
cat > /mnt/esp/boot/grub/grub.cfg << 'GRUB_EOF' && \
set timeout=3
set default=0
menuentry "SparkOS" {
linux /boot/vmlinuz root=LABEL=SparkOS rw init=/sbin/init console=tty1 quiet
}
GRUB_EOF
\
# Set up root filesystem
echo "Setting up root filesystem..." && \
mkdir -p /mnt/root/{bin,sbin,etc,proc,sys,dev,tmp,usr/{bin,sbin,lib,lib64},var/{log,run},root,home/spark,boot} && \
\
# Install SparkOS init
cp /build/init /mnt/root/sbin/init && \
chmod 755 /mnt/root/sbin/init && \
\
# Install busybox
echo "Installing busybox..." && \
cp /bin/busybox /mnt/root/bin/busybox && \
chmod 755 /mnt/root/bin/busybox && \
\
# Create busybox symlinks for essential commands
for cmd in sh ls cat echo mount umount mkdir rm cp mv chmod chown ln ps kill; do \
ln -sf busybox /mnt/root/bin/$cmd; \
done && \
\
# Create system configuration files
echo "sparkos" > /mnt/root/etc/hostname && \
echo "127.0.0.1 localhost" > /mnt/root/etc/hosts && \
echo "127.0.1.1 sparkos" >> /mnt/root/etc/hosts && \
echo "root:x:0:0:root:/root:/bin/sh" > /mnt/root/etc/passwd && \
echo "spark:x:1000:1000:SparkOS User:/home/spark:/bin/sh" >> /mnt/root/etc/passwd && \
echo "root:x:0:" > /mnt/root/etc/group && \
echo "spark:x:1000:" >> /mnt/root/etc/group && \
\
# Create README
cat > /mnt/root/README.txt << 'README_EOF' && \
SparkOS UEFI-Bootable Image
This is a UEFI-bootable disk image with:
- GPT partition table
- EFI System Partition (ESP) with FAT32 filesystem
- GRUB UEFI bootloader
- Linux kernel
- SparkOS init system
- Busybox utilities
The image can be written to a USB drive and booted on UEFI systems:
sudo dd if=sparkos.img of=/dev/sdX bs=4M status=progress
sudo sync
Boot options:
- UEFI boot support (tested on x86_64 systems)
- Automatic boot after 3 seconds
- Console on tty1
For more information, see: https://github.com/johndoe6345789/SparkOS
README_EOF
\
# Sync and unmount
echo "Finalizing image..." && \
sync && \
umount /mnt/esp && \
umount /mnt/root && \
losetup -d $LOOP_DEV && \
\
# Compress the image
echo "Compressing image..." && \
gzip -9 /output/sparkos.img && \
echo "UEFI-bootable image created: /output/sparkos.img.gz"
# Final stage - export the image
FROM scratch AS export
COPY --from=image-builder /output/sparkos.img.gz /sparkos.img.gz

View File

@@ -7,7 +7,7 @@ DESTDIR = rootfs
IMAGE = sparkos.img
IMAGE_SIZE = 512M
.PHONY: all clean init image help install
.PHONY: all clean init image image-docker help install docker-release
all: init
@@ -15,13 +15,19 @@ help:
@echo "SparkOS Build System"
@echo "===================="
@echo "Targets:"
@echo " make init - Build the init system"
@echo " make install - Install init to rootfs"
@echo " make image - Create bootable dd-able image (requires root)"
@echo " make clean - Clean build artifacts"
@echo " make init - Build the init system"
@echo " make install - Install init to rootfs"
@echo " make image - Create bootable dd-able image (requires root)"
@echo " make image-docker - Create bootable image using Docker (no root required)"
@echo " make docker-release - Build release package using Docker (no root required)"
@echo " make clean - Clean build artifacts"
@echo ""
@echo "Note: Creating a bootable image requires root privileges"
@echo " and various tools (debootstrap, syslinux, etc.)"
@echo ""
@echo "For easier image building, use Docker:"
@echo " make image-docker"
@echo " OR: ./scripts/build-image.sh"
init: src/init.c
@echo "Building SparkOS init system..."
@@ -42,9 +48,18 @@ image: install
fi
@./scripts/create_image.sh
image-docker:
@echo "Building bootable image using Docker..."
@./scripts/build-image.sh
docker-release:
@echo "Building release package using Docker..."
@./scripts/docker-release.sh
clean:
@echo "Cleaning build artifacts..."
rm -f init
rm -f $(IMAGE)
rm -rf build/
rm -rf release/
@echo "Clean complete"

126
README.md
View File

@@ -45,9 +45,39 @@ To create bootable images (optional):
## Quick Start
### Using Pre-built Releases (Easiest)
### Using UEFI-Bootable Disk Image (Recommended - Boot from USB)
Download the latest release package from the [GitHub Releases page](https://github.com/johndoe6345789/SparkOS/releases):
Download the UEFI-bootable image from the [GitHub Releases page](https://github.com/johndoe6345789/SparkOS/releases):
```bash
# Download the disk image (replace VERSION with actual version, e.g., v1.0.0)
wget https://github.com/johndoe6345789/SparkOS/releases/download/VERSION/sparkos.img.gz
# Decompress the image
gunzip sparkos.img.gz
# Write to USB drive (Linux - BE CAREFUL!)
sudo dd if=sparkos.img of=/dev/sdX bs=4M status=progress oflag=sync
```
**⚠️ WARNING**: Replace `/dev/sdX` with your actual USB device (e.g., `/dev/sdb`). This will **DESTROY ALL DATA** on the target drive!
**Boot Instructions:**
1. Insert the USB drive into a UEFI-capable system
2. Enter BIOS/UEFI settings (usually F2, F12, DEL, or ESC at boot)
3. Select the USB drive as boot device
4. SparkOS will boot automatically
The UEFI-bootable disk image includes:
-**UEFI boot support** with GRUB bootloader
-**GPT partition table** with ESP (EFI System Partition)
-**Linux kernel** ready to boot
-**SparkOS init system** and busybox utilities
-**Ready to boot** - No additional setup required
### Using Pre-built Binary Package
Download the binary package from the [GitHub Releases page](https://github.com/johndoe6345789/SparkOS/releases):
```bash
# Download the latest release (replace VERSION with actual version, e.g., v1.0.0)
@@ -84,6 +114,9 @@ docker run --rm ghcr.io/johndoe6345789/sparkos:latest
docker build -t sparkos:local .
docker run --rm sparkos:local
# Or use Docker Compose for even simpler testing
docker-compose up
# Build for specific architecture
docker buildx build --platform linux/amd64 -t sparkos:amd64 --load .
docker buildx build --platform linux/arm64 -t sparkos:arm64 --load .
@@ -97,6 +130,18 @@ The Docker image includes:
Images are automatically built and published to [GitHub Container Registry](https://github.com/johndoe6345789/SparkOS/pkgs/container/sparkos) on every push to main branch.
**Building Releases with Docker (No Root Required):**
Create release packages easily using Docker without needing root privileges or special tools:
```bash
# Build a release package for version v1.0.0
./scripts/docker-release.sh v1.0.0
# The release ZIP will be created in release/sparkos-release.zip
# This is the same artifact that GitHub Actions creates
```
### Building the Init System
```bash
@@ -117,9 +162,32 @@ make init
make install
```
### Creating a Bootable Image (Advanced)
### Creating a UEFI-Bootable Image
⚠️ **Warning**: Creating bootable images requires root privileges and proper tools.
**Using Docker (Recommended - No Root Required):**
Build UEFI-bootable disk images easily using Docker without needing root privileges on your host:
```bash
# Build the UEFI-bootable disk image using Docker
make image-docker
# Or use the script directly
./scripts/build-image.sh
# The compressed UEFI-bootable image will be in release/sparkos.img.gz
```
This creates a complete UEFI-bootable image with:
- GPT partition table
- EFI System Partition (ESP) with FAT32
- GRUB UEFI bootloader
- Linux kernel
- SparkOS init system and busybox
**Traditional Method (Requires Root):**
⚠️ **Warning**: This method is for creating custom partitioned images and requires root privileges.
```bash
# Install required tools (Ubuntu/Debian)
@@ -243,16 +311,66 @@ docker buildx build --platform linux/amd64,linux/arm64 -t sparkos:multiarch .
# Test the image
docker run --rm sparkos:dev
# Or use Docker Compose
docker-compose up
# Inspect the init binary
docker run --rm sparkos:dev sh -c "ls -lh /sparkos/rootfs/sbin/init"
```
### Creating Releases
**Using Docker (Recommended - No Root Required):**
Build release packages locally using Docker without needing root privileges:
```bash
# Build a release package
./scripts/docker-release.sh v1.0.0
# The release ZIP will be in release/sparkos-release.zip
# This is identical to what GitHub Actions creates
```
**Creating a GitHub Release:**
1. **Commit and push your changes** to the main branch
2. **Create and push a version tag:**
```bash
git tag v1.0.0
git push origin v1.0.0
```
3. **GitHub Actions will automatically:**
- Build the init binary
- Create the release package ZIP
- Build and publish Docker images (AMD64 + ARM64)
- Create a GitHub Release with the artifacts
- Publish to GitHub Container Registry
The release will be available at:
- **GitHub Releases:** https://github.com/johndoe6345789/SparkOS/releases
- **Docker Images:** `ghcr.io/johndoe6345789/sparkos:v1.0.0`
**Manual Release Creation:**
You can also create a release manually:
1. Go to https://github.com/johndoe6345789/SparkOS/releases/new
2. Choose or create a tag (e.g., `v1.0.0`)
3. Fill in the release title and description
4. Upload the `sparkos-release.zip` (built locally with `docker-release.sh`)
5. Publish the release
For detailed instructions on creating releases, see [RELEASING.md](RELEASING.md).
### Building Components
```bash
# Build init system only
make init
# Build release package using Docker
make docker-release
# Install to rootfs
make install

233
RELEASING.md Normal file
View File

@@ -0,0 +1,233 @@
# SparkOS Release Guide
This guide explains how to create and publish releases for SparkOS.
## Release Methods
SparkOS supports two ways to create releases:
1. **Automatic (Recommended)**: Push a version tag to trigger GitHub Actions
2. **Manual**: Build locally and upload to GitHub
## Method 1: Automatic Release (Recommended)
This method uses GitHub Actions to automatically build and publish releases.
### Prerequisites
- Push access to the repository
- All changes committed and pushed to `main` branch
### Steps
1. **Ensure everything is ready**
```bash
# Make sure you're on main and up to date
git checkout main
git pull origin main
# Verify the build works
make init
```
2. **Create and push a version tag**
```bash
# Create a tag (use semantic versioning: v1.0.0, v2.1.3, etc.)
git tag v1.0.0
# Push the tag to GitHub
git push origin v1.0.0
```
3. **Wait for GitHub Actions**
- Go to https://github.com/johndoe6345789/SparkOS/actions
- Two workflows will run:
- **"Build and Release"**: Creates the release ZIP
- **"Docker Build and Publish"**: Publishes Docker images
- Both should complete successfully (green checkmarks)
4. **Verify the release**
- Go to https://github.com/johndoe6345789/SparkOS/releases
- Your new release should appear with `sparkos-release.zip` attached
- Docker images are available at `ghcr.io/johndoe6345789/sparkos:v1.0.0`
### What Gets Published
When you push a version tag, GitHub Actions automatically:
- ✅ Builds the init binary (statically linked)
- ✅ Creates a release package ZIP containing:
- Compiled init binary
- Complete source code
- Build scripts and configuration
- Root filesystem structure
- Full documentation
- ✅ Creates a GitHub Release at `/releases`
- ✅ Builds multi-architecture Docker images (AMD64 + ARM64)
- ✅ Publishes Docker images to GitHub Container Registry
- ✅ Tags Docker images with version number
## Method 2: Manual Release
Use this method if you need to build releases locally without pushing tags.
### Prerequisites
- Docker installed locally
- `zip` utility installed
### Steps
1. **Build the release package using Docker**
```bash
# Build for a specific version
./scripts/docker-release.sh v1.0.0
# Or use Make
make docker-release
# The package will be created at: release/sparkos-release.zip
```
2. **Verify the package**
```bash
# Check the file was created
ls -lh release/sparkos-release.zip
# List contents
unzip -l release/sparkos-release.zip | head -40
```
3. **Create a GitHub Release manually**
- Go to https://github.com/johndoe6345789/SparkOS/releases/new
- Fill in:
- **Tag**: Create a new tag (e.g., `v1.0.0`)
- **Title**: `SparkOS v1.0.0` (or similar)
- **Description**: List changes and features
- **Upload** the `sparkos-release.zip` file
- Click **"Publish release"**
### What's Included
The Docker-based release script creates the exact same package as GitHub Actions:
- Compiled init binary (statically linked, ready to use)
- Complete source code
- Build scripts (including `docker-release.sh`)
- Configuration files
- Root filesystem structure
- Full documentation (README, ARCHITECTURE, CONTRIBUTING)
## Testing Before Release
Always test your changes before creating a release:
### Test the Build
```bash
# Test compilation
make clean && make init
# Verify the binary
file init
ldd init # Should show "not a dynamic executable" (static)
```
### Test with Docker
```bash
# Build the Docker image
docker build -t sparkos:test .
# Run the test environment
docker run --rm sparkos:test
# Or use Docker Compose
docker-compose up
```
### Test the Release Script
```bash
# Build a test release package
./scripts/docker-release.sh test
# Verify it was created
ls -lh release/sparkos-release.zip
```
## Release Checklist
Before creating a release:
- [ ] All changes are committed and pushed to `main`
- [ ] Build succeeds: `make init` works
- [ ] Docker build succeeds: `docker build -t sparkos:test .` works
- [ ] Documentation is up to date (README, ARCHITECTURE, etc.)
- [ ] Version follows semantic versioning (vMAJOR.MINOR.PATCH)
- [ ] CHANGELOG or release notes are prepared (if applicable)
## Troubleshooting
### GitHub Actions Fails
1. Check the workflow logs at https://github.com/johndoe6345789/SparkOS/actions
2. Common issues:
- Build errors: Check if `make init` works locally
- Permission errors: Ensure `contents: write` permission in workflow
- Docker errors: Verify Dockerfile builds locally
### Release Not Created
- Ensure you pushed a tag starting with `v` (e.g., `v1.0.0`)
- Check that the workflow has `contents: write` permissions
- Verify the workflow completed successfully (green checkmark)
### Docker Images Not Published
- Check the "Docker Build and Publish" workflow logs
- Ensure the tag was pushed (not just created locally)
- Verify `packages: write` permission in workflow
## Version Numbering
Use semantic versioning for releases:
- **v1.0.0**: First stable release
- **v1.1.0**: New features, backward compatible
- **v1.1.1**: Bug fixes only
- **v2.0.0**: Breaking changes
## Release Artifacts
Each release includes:
1. **GitHub Release Page**
- Release notes
- Downloadable `sparkos-release.zip`
- Link to Docker images
2. **Docker Images** (automatically published)
- `ghcr.io/johndoe6345789/sparkos:v1.0.0` (specific version)
- `ghcr.io/johndoe6345789/sparkos:1.0` (minor version)
- `ghcr.io/johndoe6345789/sparkos:1` (major version)
- `ghcr.io/johndoe6345789/sparkos:latest` (if released from main)
3. **Multi-Architecture Support**
- Linux AMD64 (x86_64)
- Linux ARM64 (aarch64)
## Next Steps
After releasing:
1. Announce the release (if applicable)
2. Update documentation links to point to the new version
3. Test the release on different platforms
4. Monitor for issues and prepare patches if needed
## Support
For questions or issues with releases:
- Open an issue: https://github.com/johndoe6345789/SparkOS/issues
- Check workflow logs: https://github.com/johndoe6345789/SparkOS/actions

11
docker-compose.yml Normal file
View File

@@ -0,0 +1,11 @@
version: '3.8'
services:
sparkos:
build:
context: .
dockerfile: Dockerfile
image: sparkos:local
container_name: sparkos-test
# The container will run the test script and exit
# Use 'docker-compose up' to test the build

67
scripts/build-image.sh Executable file
View File

@@ -0,0 +1,67 @@
#!/bin/bash
# Build SparkOS disk image using Docker
# This script builds a .img file without requiring root on the host
set -e
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
PROJECT_ROOT="$(cd "$SCRIPT_DIR/.." && pwd)"
OUTPUT_DIR="$PROJECT_ROOT/release"
echo "SparkOS Disk Image Builder (Docker)"
echo "===================================="
echo ""
# Clean previous build
if [ -f "$OUTPUT_DIR/sparkos.img.gz" ]; then
echo "Cleaning previous image..."
rm -f "$OUTPUT_DIR/sparkos.img.gz"
fi
mkdir -p "$OUTPUT_DIR"
echo "Building disk image using Docker..."
echo "This may take a few minutes..."
echo ""
# Build the image builder container
cd "$PROJECT_ROOT"
docker buildx build \
--file Dockerfile.image \
--target image-builder \
--tag sparkos:image-builder \
--load \
.
# Extract the image
echo ""
echo "Extracting disk image..."
CONTAINER_ID=$(docker create sparkos:image-builder)
docker cp "$CONTAINER_ID:/output/sparkos.img.gz" "$OUTPUT_DIR/sparkos.img.gz"
docker rm "$CONTAINER_ID" > /dev/null
echo ""
echo "SUCCESS! Disk image created:"
echo " Location: $OUTPUT_DIR/sparkos.img.gz"
echo " Size: $(du -h "$OUTPUT_DIR/sparkos.img.gz" | cut -f1)"
echo ""
# Show decompressed size
echo "Decompressed size:"
DECOMPRESSED_SIZE=$(gunzip -l "$OUTPUT_DIR/sparkos.img.gz" | tail -1 | awk '{print $2}')
echo " $(numfmt --to=iec-i --suffix=B $DECOMPRESSED_SIZE)"
echo ""
echo "To write to a USB drive:"
echo " gunzip $OUTPUT_DIR/sparkos.img.gz"
echo " sudo dd if=$OUTPUT_DIR/sparkos.img of=/dev/sdX bs=4M status=progress"
echo ""
echo "WARNING: Replace /dev/sdX with your actual USB device!"
echo " This will DESTROY all data on the target drive!"
echo ""
echo "To inspect the image:"
echo " gunzip -c $OUTPUT_DIR/sparkos.img.gz > /tmp/sparkos.img"
echo " sudo mount -o loop /tmp/sparkos.img /mnt"
echo " ls -la /mnt"
echo " sudo umount /mnt"

183
scripts/docker-release.sh Executable file
View File

@@ -0,0 +1,183 @@
#!/bin/bash
# SparkOS Docker-based Release Builder
# Build release artifacts using Docker (no root required)
set -e
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
PROJECT_ROOT="$(cd "$SCRIPT_DIR/.." && pwd)"
RELEASE_DIR="$PROJECT_ROOT/release"
VERSION="${1:-dev}"
echo "SparkOS Docker Release Builder"
echo "=============================="
echo ""
echo "Version: $VERSION"
echo ""
# Clean previous release
if [ -d "$RELEASE_DIR" ]; then
echo "Cleaning previous release..."
rm -rf "$RELEASE_DIR"
fi
mkdir -p "$RELEASE_DIR"
# Build using Docker (multi-stage build)
echo "Building init binary using Docker..."
docker build -t sparkos:build-temp --target builder "$PROJECT_ROOT"
# Extract the built binary
echo "Extracting init binary..."
CONTAINER_ID=$(docker create sparkos:build-temp)
docker cp "$CONTAINER_ID:/build/init" "$RELEASE_DIR/init"
docker rm "$CONTAINER_ID" > /dev/null
# Verify the binary
echo ""
echo "Verifying init binary..."
if [ ! -f "$RELEASE_DIR/init" ]; then
echo "ERROR: Failed to extract init binary"
exit 1
fi
ls -lh "$RELEASE_DIR/init"
file "$RELEASE_DIR/init"
# Create release package structure
echo ""
echo "Creating release package..."
mkdir -p "$RELEASE_DIR/sparkos"
# Copy compiled binary
cp "$RELEASE_DIR/init" "$RELEASE_DIR/sparkos/"
# Copy essential files
cp "$PROJECT_ROOT/README.md" "$RELEASE_DIR/sparkos/"
cp "$PROJECT_ROOT/LICENSE" "$RELEASE_DIR/sparkos/"
cp "$PROJECT_ROOT/ARCHITECTURE.md" "$RELEASE_DIR/sparkos/"
cp "$PROJECT_ROOT/CONTRIBUTING.md" "$RELEASE_DIR/sparkos/"
cp "$PROJECT_ROOT/Makefile" "$RELEASE_DIR/sparkos/"
cp "$PROJECT_ROOT/Dockerfile" "$RELEASE_DIR/sparkos/"
# Copy source for reference
cp -r "$PROJECT_ROOT/src" "$RELEASE_DIR/sparkos/"
# Copy scripts
cp -r "$PROJECT_ROOT/scripts" "$RELEASE_DIR/sparkos/"
# Copy config
cp -r "$PROJECT_ROOT/config" "$RELEASE_DIR/sparkos/"
# Copy rootfs structure (without generated content)
mkdir -p "$RELEASE_DIR/sparkos/rootfs"
for dir in etc root home; do
if [ -d "$PROJECT_ROOT/rootfs/$dir" ]; then
cp -r "$PROJECT_ROOT/rootfs/$dir" "$RELEASE_DIR/sparkos/rootfs/"
fi
done
# Create README for the release
cat > "$RELEASE_DIR/sparkos/RELEASE_README.md" << 'EOF'
# SparkOS Release Package
This package contains the compiled SparkOS init system and all necessary files to run or build SparkOS.
## Contents
- `init` - The compiled init binary (statically linked)
- `src/` - Source code for the init system
- `scripts/` - Build and setup scripts
- `config/` - Configuration files
- `rootfs/` - Root filesystem structure
- `Dockerfile` - Docker image definition
- `Makefile` - Build system
- Documentation files (README.md, ARCHITECTURE.md, etc.)
## Quick Start
### Using the Pre-built Binary
The `init` binary is already compiled and ready to use:
```bash
# Copy to your rootfs
cp init /path/to/your/rootfs/sbin/init
chmod 755 /path/to/your/rootfs/sbin/init
```
### Using Docker
The easiest way to test SparkOS:
```bash
# Build the Docker image
docker build -t sparkos .
# Run the test environment
docker run --rm sparkos
```
### Rebuilding from Source
If you need to rebuild:
```bash
# Build the init system
make init
# Install to rootfs
make install
```
## Using Docker for Releases
Build release artifacts without needing root or special tools:
```bash
# Build release package
./scripts/docker-release.sh v1.0.0
# The release package will be in release/sparkos-release.zip
```
## System Requirements
- Linux system with kernel 3.x or later
- Busybox for shell and utilities
- For building: Docker or GCC compiler and Make
## Documentation
See README.md for complete documentation, including:
- Building instructions
- Docker usage
- Network configuration
- Development guidelines
## Support
For issues and questions, visit: https://github.com/johndoe6345789/SparkOS
EOF
# Create release archive
echo ""
echo "Creating release archive..."
cd "$RELEASE_DIR"
zip -q -r "sparkos-release.zip" sparkos/
cd "$PROJECT_ROOT"
echo ""
echo "SUCCESS! Release package created:"
echo " Location: $RELEASE_DIR/sparkos-release.zip"
echo " Size: $(du -h "$RELEASE_DIR/sparkos-release.zip" | cut -f1)"
echo ""
echo "Contents:"
ls -lh "$RELEASE_DIR/sparkos-release.zip"
echo ""
echo "To verify the contents:"
echo " unzip -l $RELEASE_DIR/sparkos-release.zip | head -40"
echo ""
echo "To test the Docker image:"
echo " docker build -t sparkos:$VERSION ."
echo " docker run --rm sparkos:$VERSION"