Files

702 lines
24 KiB
YAML

name: Build and Test Arduino Firmware
on:
push:
branches: [ main, develop ]
paths:
- 'code/RocketLauncher/**'
- '.github/workflows/**'
tags:
- 'v*'
pull_request:
branches: [ main ]
paths:
- 'code/RocketLauncher/**'
release:
types: [ published, created ]
workflow_dispatch:
inputs:
version:
description: 'Semantic version (e.g., 1.0.0)'
required: true
type: string
env:
PLATFORMIO_VERSION: 6.1.7
jobs:
version:
name: Determine Version
runs-on: ubuntu-latest
outputs:
version: ${{ steps.version.outputs.version }}
is-release: ${{ steps.version.outputs.is-release }}
tag: ${{ steps.version.outputs.tag }}
steps:
- name: Checkout code
uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Determine version
id: version
run: |
if [[ "${{ github.event_name }}" == "workflow_dispatch" ]]; then
echo "version=${{ github.event.inputs.version }}" >> $GITHUB_OUTPUT
echo "is-release=true" >> $GITHUB_OUTPUT
echo "tag=v${{ github.event.inputs.version }}" >> $GITHUB_OUTPUT
elif [[ "${{ github.ref }}" == refs/tags/v* ]]; then
TAG_VERSION=${GITHUB_REF#refs/tags/}
echo "version=${TAG_VERSION#v}" >> $GITHUB_OUTPUT
echo "is-release=true" >> $GITHUB_OUTPUT
echo "tag=${TAG_VERSION}" >> $GITHUB_OUTPUT
else
# Get latest tag and increment patch version
LATEST_TAG=$(git describe --tags --abbrev=0 2>/dev/null || echo "v0.0.0")
LATEST_VERSION=${LATEST_TAG#v}
IFS='.' read -r MAJOR MINOR PATCH <<< "$LATEST_VERSION"
NEW_PATCH=$((PATCH + 1))
NEW_VERSION="$MAJOR.$MINOR.$NEW_PATCH"
echo "version=$NEW_VERSION" >> $GITHUB_OUTPUT
echo "is-release=false" >> $GITHUB_OUTPUT
echo "tag=v$NEW_VERSION" >> $GITHUB_OUTPUT
fi
echo "Version: ${{ steps.version.outputs.version }}"
echo "Is Release: ${{ steps.version.outputs.is-release }}"
echo "Tag: ${{ steps.version.outputs.tag }}"
cmake-build:
name: CMake Build and Test
runs-on: ubuntu-latest
needs: version
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Setup CMake
uses: jwlawson/actions-setup-cmake@v1.13
with:
cmake-version: '4.1.0'
- name: Setup Python
uses: actions/setup-python@v4
with:
python-version: '3.11'
- name: Install PlatformIO
run: |
python -m pip install --upgrade pip
pip install platformio==${{ env.PLATFORMIO_VERSION }}
- name: Cache PlatformIO packages
uses: actions/cache@v3
with:
path: |
~/.platformio
~/.cache/pip
key: ${{ runner.os }}-pio-${{ hashFiles('**/platformio.ini') }}
restore-keys: |
${{ runner.os }}-pio-
- name: Configure CMake
working-directory: ./code/RocketLauncher
run: |
cmake --preset default
- name: Build CMake Project
working-directory: ./code/RocketLauncher
run: |
cmake --build . --preset default
- name: Run CMake Tests
working-directory: ./code/RocketLauncher
run: |
ctest --preset default --output-on-failure
- name: Upload CMake test results
uses: actions/upload-artifact@v4
if: always()
with:
name: cmake-test-results
path: ./code/RocketLauncher/build/
retention-days: 30
test:
name: Run PlatformIO Unit Tests
runs-on: ubuntu-latest
needs: [version, cmake-build]
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Setup Python
uses: actions/setup-python@v4
with:
python-version: '3.11'
- name: Install PlatformIO
run: |
python -m pip install --upgrade pip
pip install platformio==${{ env.PLATFORMIO_VERSION }}
- name: Cache PlatformIO packages
uses: actions/cache@v3
with:
path: |
~/.platformio
~/.cache/pip
key: ${{ runner.os }}-pio-${{ hashFiles('**/platformio.ini') }}
restore-keys: |
${{ runner.os }}-pio-
- name: Run PlatformIO Unit Tests
working-directory: ./code/RocketLauncher
run: |
pio test -e native
- name: Upload PlatformIO test results
uses: actions/upload-artifact@v4
if: always()
with:
name: platformio-test-results
path: ./code/RocketLauncher/.pio/test/native/
retention-days: 30
build-simulation:
name: Build Simulation Firmware
runs-on: ubuntu-latest
needs: [version, cmake-build, test]
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Setup Python
uses: actions/setup-python@v4
with:
python-version: '3.11'
- name: Install PlatformIO
run: |
python -m pip install --upgrade pip
pip install platformio==${{ env.PLATFORMIO_VERSION }}
- name: Cache PlatformIO packages
uses: actions/cache@v3
with:
path: |
~/.platformio
~/.cache/pip
key: ${{ runner.os }}-pio-${{ hashFiles('**/platformio.ini') }}
restore-keys: |
${{ runner.os }}-pio-
- name: Build Simulation Firmware
working-directory: ./code/RocketLauncher
run: |
pio run -e simulide
- name: Create output directory
run: mkdir -p ./code/RocketLauncher/out/simulide
- name: Copy firmware files
working-directory: ./code/RocketLauncher
run: |
cp .pio/build/simulide/firmware.hex out/simulide/
cp .pio/build/simulide/firmware.elf out/simulide/
- name: Upload simulation firmware
uses: actions/upload-artifact@v4
with:
name: simulation-firmware
path: |
./code/RocketLauncher/out/simulide/firmware.hex
./code/RocketLauncher/out/simulide/firmware.elf
retention-days: 90
build-hardware:
name: Build Hardware Firmware
runs-on: ubuntu-latest
needs: [version, cmake-build, test]
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Setup Python
uses: actions/setup-python@v4
with:
python-version: '3.11'
- name: Install PlatformIO
run: |
python -m pip install --upgrade pip
pip install platformio==${{ env.PLATFORMIO_VERSION }}
- name: Cache PlatformIO packages
uses: actions/cache@v3
with:
path: |
~/.platformio
~/.cache/pip
key: ${{ runner.os }}-pio-${{ hashFiles('**/platformio.ini') }}
restore-keys: |
${{ runner.os }}-pio-
- name: Build Hardware Firmware
working-directory: ./code/RocketLauncher
run: |
pio run -e uno_hw
- name: Upload hardware firmware
uses: actions/upload-artifact@v4
with:
name: hardware-firmware
path: |
./code/RocketLauncher/.pio/build/uno_hw/firmware.hex
./code/RocketLauncher/.pio/build/uno_hw/firmware.elf
retention-days: 90
create-tag:
name: Create Git Tag
runs-on: ubuntu-latest
needs: [version, build-simulation, build-hardware]
if: ${{ needs.version.outputs.is-release == 'true' }}
outputs:
tag: ${{ needs.version.outputs.tag }}
upload_url: ${{ steps.release_info.outputs.upload_url }}
release_id: ${{ steps.release_info.outputs.release_id }}
html_url: ${{ steps.release_info.outputs.html_url }}
steps:
- name: Checkout code
uses: actions/checkout@v4
with:
fetch-depth: 0
token: ${{ secrets.GITHUB_TOKEN }}
- name: Configure Git
run: |
git config --local user.email "action@github.com"
git config --local user.name "GitHub Action"
- name: Check if tag exists
id: check-tag
run: |
if git tag -l | grep -q "^${{ needs.version.outputs.tag }}$"; then
echo "exists=true" >> $GITHUB_OUTPUT
echo "Tag ${{ needs.version.outputs.tag }} already exists, skipping creation"
else
echo "exists=false" >> $GITHUB_OUTPUT
fi
- name: Create and push tag
if: steps.check-tag.outputs.exists != 'true'
run: |
git tag ${{ needs.version.outputs.tag }}
git push origin ${{ needs.version.outputs.tag }}
- name: Tag already exists
if: steps.check-tag.outputs.exists == 'true'
run: |
echo "Tag ${{ needs.version.outputs.tag }} already exists, continuing with release process"
- name: Check if GitHub release exists
id: check_release
run: |
# Check if a GitHub release already exists for this tag
RELEASE_INFO=$(curl -s -H "Authorization: token ${{ secrets.GITHUB_TOKEN }}" \
"https://api.github.com/repos/${{ github.repository }}/releases/tags/${{ needs.version.outputs.tag }}" || echo "")
if [[ "$RELEASE_INFO" != "" && "$(echo "$RELEASE_INFO" | jq -r '.id // empty')" != "" ]]; then
echo "exists=true" >> $GITHUB_OUTPUT
echo "id=$(echo "$RELEASE_INFO" | jq -r '.id')" >> $GITHUB_OUTPUT
echo "upload_url=$(echo "$RELEASE_INFO" | jq -r '.upload_url')" >> $GITHUB_OUTPUT
echo "html_url=$(echo "$RELEASE_INFO" | jq -r '.html_url')" >> $GITHUB_OUTPUT
echo "GitHub release for tag ${{ needs.version.outputs.tag }} already exists, will skip creation"
else
echo "exists=false" >> $GITHUB_OUTPUT
echo "id=" >> $GITHUB_OUTPUT
echo "upload_url=" >> $GITHUB_OUTPUT
echo "html_url=" >> $GITHUB_OUTPUT
fi
- name: Create GitHub Release
id: create_release
if: steps.check_release.outputs.exists != 'true'
uses: actions/create-release@v1
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
tag_name: ${{ needs.version.outputs.tag }}
release_name: "Luke's Rocket Launcher v${{ needs.version.outputs.version }}"
body: |
## 🚀 Luke's Rocket Launcher v${{ needs.version.outputs.version }}
### What's New
- Automated build and testing with CMake
- Pre-compiled firmware for Arduino and SimulIDE
- Comprehensive unit test coverage
- Modern CMake build system for IDE integration
### Downloads
- **Simulation Firmware**: For SimulIDE testing
- **Hardware Firmware**: For Arduino upload
### Installation
1. Download the appropriate firmware file
2. For Arduino: Use Arduino IDE or PlatformIO to upload
3. For SimulIDE: Load the wiring file and firmware will auto-load
### Build Information
- **Version**: ${{ needs.version.outputs.version }}
- **Build Date**: ${{ github.event.head_commit.timestamp }}
- **Commit**: ${{ github.sha }}
- **Build System**: CMake + PlatformIO
draft: false
prerelease: false
- name: Get Release Info
id: release_info
run: |
if [[ "${{ steps.check_release.outputs.exists }}" == "true" ]]; then
# Use existing release info from check_release step
echo "release_id=${{ steps.check_release.outputs.id }}" >> $GITHUB_OUTPUT
echo "upload_url=${{ steps.check_release.outputs.upload_url }}" >> $GITHUB_OUTPUT
echo "html_url=${{ steps.check_release.outputs.html_url }}" >> $GITHUB_OUTPUT
echo "Using existing GitHub release for tag ${{ needs.version.outputs.tag }}"
else
# Use newly created release info from create_release step
echo "release_id=${{ steps.create_release.outputs.id }}" >> $GITHUB_OUTPUT
echo "upload_url=${{ steps.create_release.outputs.upload_url }}" >> $GITHUB_OUTPUT
echo "html_url=${{ steps.create_release.outputs.html_url }}" >> $GITHUB_OUTPUT
echo "Created new GitHub release for tag ${{ needs.version.outputs.tag }}"
fi
create-release:
name: Create Release Assets
runs-on: ubuntu-latest
needs: [version, build-simulation, build-hardware, create-tag]
if: ${{ needs.version.outputs.is-release == 'true' }}
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Download all artifacts
uses: actions/download-artifact@v4
with:
path: ./artifacts
- name: Create release package
run: |
mkdir -p release/firmware/hardware
mkdir -p release/firmware/simulide
mkdir -p release/3dprints
mkdir -p release/simulide
# Copy firmware files to proper directories
cp -r artifacts/hardware-firmware/* release/firmware/hardware/
cp -r artifacts/simulation-firmware/* release/firmware/simulide/
# Copy 3D print files (if they exist)
if [ -d "prints" ]; then
cp -r prints/* release/3dprints/ 2>/dev/null || true
fi
# Copy SimulIDE wiring files
if [ -d "wiring" ]; then
cp -r wiring/*.sim1 release/simulide/ 2>/dev/null || true
fi
# Create a comprehensive README for the release
cat > release/README.md << 'EOF'
# Luke's Rocket Launcher v${{ needs.create-tag.outputs.tag }}
## 📁 Package Structure
```
├── firmware/
│ ├── hardware/ # Arduino UNO firmware files
│ └── simulide/ # SimulIDE simulation firmware
├── 3dprints/ # 3D printable parts (SLA files)
├── simulide/ # SimulIDE wiring files (.sim1)
└── README.md # This file
```
## 🚀 Firmware Files
### Hardware (Arduino UNO)
- `firmware/hardware/firmware.hex` - Hex file for Arduino upload
- `firmware/hardware/firmware.elf` - ELF file for debugging
### Simulation (SimulIDE)
- `firmware/simulide/firmware.hex` - Hex file for SimulIDE simulation
- `firmware/simulide/firmware.elf` - ELF file for debugging
## 🖨️ 3D Prints
- `3dprints/` - Contains all 3D printable parts
- Files are optimized for SLA printing
- Includes waterproof case components
## 🔌 SimulIDE Files
- `simulide/*.sim1` - Circuit simulation files
- Load these in SimulIDE for testing
- Firmware auto-loads from hex files
## 📋 Installation
### For Hardware
1. Download the package
2. Use Arduino IDE or PlatformIO to upload `firmware/hardware/firmware.hex`
3. Or use `./scripts/build.sh upload` from the project directory
### For Simulation
1. Download the package
2. Open SimulIDE
3. Load `simulide/rocker_launcher_controls.sim1`
4. The firmware will auto-load from `firmware/simulide/firmware.hex`
## 🏗️ Build Information
- **Version**: ${{ needs.create-tag.outputs.tag }}
- **Built on**: ${{ github.event.head_commit.timestamp }}
- **Commit**: ${{ github.sha }}
- **Platform**: ${{ runner.os }}
- **Build System**: CMake + PlatformIO
## 📚 Documentation
- [Project README](https://github.com/KofTwentyTwo/Lukes-Rocket-Launcher#readme)
- [Wiring Guide](https://github.com/KofTwentyTwo/Lukes-Rocket-Launcher/tree/main/wiring)
- [3D Prints](https://github.com/KofTwentyTwo/Lukes-Rocket-Launcher/tree/main/prints)
EOF
- name: Create release zip
run: |
cd release
zip -r ../lukes-rocket-launcher-firmware-v${{ needs.version.outputs.version }}.zip .
cd ..
- name: Upload release assets
uses: actions/upload-release-asset@v1
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
upload_url: ${{ needs.create-tag.outputs.upload_url }}
asset_path: ./lukes-rocket-launcher-firmware-v${{ needs.version.outputs.version }}.zip
asset_name: lukes-rocket-launcher-firmware-v${{ needs.version.outputs.version }}.zip
asset_content_type: application/zip
build-status:
name: Build Status Report
runs-on: ubuntu-latest
needs: [cmake-build, test, build-simulation, build-hardware]
if: always()
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Generate build report
run: |
echo "## 🚀 Build Status Report" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "**Build completed at:** $(date)" >> $GITHUB_STEP_SUMMARY
echo "**Commit:** ${{ github.sha }}" >> $GITHUB_STEP_SUMMARY
echo "**Branch:** ${{ github.ref_name }}" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
if [ "${{ needs.cmake-build.result }}" == "success" ]; then
echo "✅ **CMake Build:** SUCCESS" >> $GITHUB_STEP_SUMMARY
else
echo "❌ **CMake Build:** FAILED" >> $GITHUB_STEP_SUMMARY
fi
if [ "${{ needs.test.result }}" == "success" ]; then
echo "✅ **PlatformIO Tests:** PASSED" >> $GITHUB_STEP_SUMMARY
else
echo "❌ **PlatformIO Tests:** FAILED" >> $GITHUB_STEP_SUMMARY
fi
if [ "${{ needs.build-simulation.result }}" == "success" ]; then
echo "✅ **Simulation Build:** SUCCESS" >> $GITHUB_STEP_SUMMARY
else
echo "❌ **Simulation Build:** FAILED" >> $GITHUB_STEP_SUMMARY
fi
if [ "${{ needs.build-hardware.result }}" == "success" ]; then
echo "✅ **Hardware Build:** SUCCESS" >> $GITHUB_STEP_SUMMARY
else
echo "❌ **Hardware Build:** FAILED" >> $GITHUB_STEP_SUMMARY
fi
echo "" >> $GITHUB_STEP_SUMMARY
echo "**Build System:** CMake + PlatformIO" >> $GITHUB_STEP_SUMMARY
echo "**Firmware files are available as artifacts above.**" >> $GITHUB_STEP_SUMMARY
publish-package:
name: Publish to GitHub Packages
runs-on: ubuntu-latest
needs: [version, build-simulation, build-hardware, create-tag]
if: ${{ needs.version.outputs.is-release == 'true' }}
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Download artifacts
uses: actions/download-artifact@v4
with:
path: ./artifacts
- name: Create package manifest
run: |
mkdir -p package/firmware/hardware
mkdir -p package/firmware/simulide
mkdir -p package/3dprints
mkdir -p package/simulide
# Copy firmware files to proper directories
cp -r artifacts/hardware-firmware/* package/firmware/hardware/
cp -r artifacts/simulation-firmware/* package/firmware/simulide/
# Copy 3D print files (if they exist)
if [ -d "prints" ]; then
cp -r prints/* package/3dprints/ 2>/dev/null || true
fi
# Copy SimulIDE wiring files
if [ -d "wiring" ]; then
cp -r wiring/*.sim1 package/simulide/ 2>/dev/null || true
fi
# Create package.json for npm-style packaging
cat > package/package.json << EOF
{
"name": "lukes-rocket-launcher-firmware",
"version": "${{ needs.version.outputs.version }}",
"description": "Arduino firmware for Luke's Rocket Launch Controller",
"main": "firmware/hardware/firmware.hex",
"files": [
"firmware/**/*.hex",
"firmware/**/*.elf",
"3dprints/**/*",
"simulide/**/*.sim1",
"README.md"
],
"repository": {
"type": "git",
"url": "https://github.com/KofTwentyTwo/Lukes-Rocket-Launcher.git"
},
"keywords": [
"arduino",
"rocket",
"launcher",
"firmware",
"simulide",
"3d-printing",
"cmake",
"platformio"
],
"author": "KofTwentyTwo",
"license": "MIT",
"bugs": {
"url": "https://github.com/KofTwentyTwo/Lukes-Rocket-Launcher/issues"
},
"homepage": "https://github.com/KofTwentyTwo/Lukes-Rocket-Launcher#readme"
}
EOF
# Create comprehensive README
cat > package/README.md << EOF
# Luke's Rocket Launcher v${{ needs.version.outputs.version }}
## 📁 Package Structure
\`\`\`
├── firmware/
│ ├── hardware/ # Arduino UNO firmware files
│ └── simulide/ # SimulIDE simulation firmware
├── 3dprints/ # 3D printable parts (SLA files)
├── simulide/ # SimulIDE wiring files (.sim1)
└── README.md # This file
\`\`\`
## 🚀 Firmware Files
### Hardware (Arduino UNO)
- \`firmware/hardware/firmware.hex\` - Hex file for Arduino upload
- \`firmware/hardware/firmware.elf\` - ELF file for debugging
### Simulation (SimulIDE)
- \`firmware/simulide/firmware.hex\` - Hex file for SimulIDE simulation
- \`firmware/simulide/firmware.elf\` - ELF file for debugging
## 🖨️ 3D Prints
- \`3dprints/\` - Contains all 3D printable parts
- Files are optimized for SLA printing
- Includes waterproof case components
## 🔌 SimulIDE Files
- \`simulide/*.sim1\` - Circuit simulation files
- Load these in SimulIDE for testing
- Firmware auto-loads from hex files
## 📋 Installation
### For Hardware
1. Download the package
2. Use Arduino IDE or PlatformIO to upload \`firmware/hardware/firmware.hex\`
3. Or use \`./scripts/build.sh upload\` from the project directory
### For Simulation
1. Download the package
2. Open SimulIDE
3. Load \`simulide/rocker_launcher_controls.sim1\`
4. The firmware will auto-load from \`firmware/simulide/firmware.hex\`
## 🏗️ Build Information
- **Version**: ${{ needs.version.outputs.version }}
- **Built on**: ${{ github.event.head_commit.timestamp }}
- **Commit**: ${{ github.sha }}
- **Platform**: ${{ runner.os }}
- **Build System**: CMake + PlatformIO
## 📚 Documentation
- [Project README](https://github.com/KofTwentyTwo/Lukes-Rocket-Launcher#readme)
- [Wiring Guide](https://github.com/KofTwentyTwo/Lukes-Rocket-Launcher/tree/main/wiring)
- [3D Prints](https://github.com/KofTwentyTwo/Lukes-Rocket-Launcher/tree/main/prints)
## Changelog
See [GitHub Releases](https://github.com/KofTwentyTwo/Lukes-Rocket-Launcher/releases) for detailed changelog.
EOF
- name: Create package archive
run: |
cd package
# Create TAR archive for release upload
tar -czf ../lukes-rocket-launcher-firmware-v${{ needs.version.outputs.version }}.tar.gz .
# Create ZIP archive (available for GitHub Packages, not uploaded to release)
zip -r ../lukes-rocket-launcher-firmware-v${{ needs.version.outputs.version }}.zip .
cd ..
- name: Publish to GitHub Packages
uses: actions/upload-release-asset@v1
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
upload_url: ${{ needs.create-tag.outputs.upload_url }}
asset_path: ./lukes-rocket-launcher-firmware-v${{ needs.version.outputs.version }}.tar.gz
asset_name: lukes-rocket-launcher-firmware-v${{ needs.version.outputs.version }}.tar.gz
asset_content_type: application/gzip
# Note: ZIP file is created but not uploaded to avoid duplicate release assets
# TAR file is uploaded to the release, ZIP is available for GitHub Packages if needed