mirror of
https://github.com/torlando-tech/pyxis.git
synced 2026-08-14 06:39:54 +00:00
282 lines
11 KiB
YAML
282 lines
11 KiB
YAML
name: Build and Deploy Firmware
|
|
|
|
on:
|
|
push:
|
|
branches:
|
|
- main
|
|
tags:
|
|
- 'v*'
|
|
|
|
permissions:
|
|
contents: write
|
|
pages: write
|
|
id-token: write
|
|
|
|
jobs:
|
|
build-and-deploy:
|
|
runs-on: ubuntu-latest
|
|
|
|
steps:
|
|
- name: Checkout repository
|
|
uses: actions/checkout@v4
|
|
with:
|
|
submodules: recursive
|
|
fetch-depth: 0
|
|
|
|
- name: Verify release tag points at current main
|
|
if: startsWith(github.ref, 'refs/tags/v')
|
|
run: |
|
|
TAG="${GITHUB_REF#refs/tags/}"
|
|
if [[ ! "$TAG" =~ ^v[0-9]+\.[0-9]+\.[0-9]+(-[0-9A-Za-z.-]+)?$ ]]; then
|
|
echo "Invalid release tag: $TAG" >&2
|
|
exit 1
|
|
fi
|
|
git fetch origin main
|
|
test "$(git rev-parse HEAD)" = "$(git rev-parse origin/main)"
|
|
|
|
- name: Set up Python
|
|
uses: actions/setup-python@v5
|
|
with:
|
|
python-version: '3.11'
|
|
|
|
- name: Install PlatformIO
|
|
run: pip install platformio
|
|
|
|
- name: Build release-qualified T-Deck firmware
|
|
run: pio run -e tdeck-release
|
|
|
|
- name: Audit release artifact
|
|
run: python tools/audit_release_build.py
|
|
|
|
- name: Determine version string
|
|
id: version
|
|
run: |
|
|
if [[ "$GITHUB_REF" == refs/tags/v* ]]; then
|
|
echo "VERSION=${GITHUB_REF#refs/tags/}" >> "$GITHUB_OUTPUT"
|
|
else
|
|
echo "VERSION=dev-${GITHUB_SHA::7}" >> "$GITHUB_OUTPUT"
|
|
fi
|
|
|
|
- name: Copy firmware binaries
|
|
run: |
|
|
mkdir -p docs/flasher/firmware
|
|
cp .pio/build/tdeck-release/bootloader.bin docs/flasher/firmware/
|
|
cp .pio/build/tdeck-release/partitions.bin docs/flasher/firmware/
|
|
cp .pio/build/tdeck-release/firmware.bin docs/flasher/firmware/
|
|
BOOT_APP0=$(find ~/.platformio -name "boot_app0.bin" | head -1)
|
|
cp "$BOOT_APP0" docs/flasher/firmware/
|
|
|
|
# For tagged releases, also deploy to a versioned path on GitHub Pages
|
|
# so the flasher can fetch them same-origin (GitHub release downloads lack CORS)
|
|
if [[ "$GITHUB_REF" == refs/tags/v* ]]; then
|
|
TAG="${GITHUB_REF#refs/tags/}"
|
|
mkdir -p "docs/flasher/firmware/releases/${TAG}"
|
|
cp .pio/build/tdeck-release/bootloader.bin "docs/flasher/firmware/releases/${TAG}/"
|
|
cp .pio/build/tdeck-release/partitions.bin "docs/flasher/firmware/releases/${TAG}/"
|
|
cp .pio/build/tdeck-release/firmware.bin "docs/flasher/firmware/releases/${TAG}/"
|
|
cp "$BOOT_APP0" "docs/flasher/firmware/releases/${TAG}/"
|
|
fi
|
|
|
|
- name: Generate audited release metadata
|
|
if: startsWith(github.ref, 'refs/tags/v')
|
|
env:
|
|
VERSION: ${{ steps.version.outputs.VERSION }}
|
|
run: |
|
|
BL="docs/flasher/firmware/bootloader.bin"
|
|
PT="docs/flasher/firmware/partitions.bin"
|
|
BA="docs/flasher/firmware/boot_app0.bin"
|
|
FW="docs/flasher/firmware/firmware.bin"
|
|
BL_SHA="$(sha256sum "$BL" | cut -d' ' -f1)"
|
|
PT_SHA="$(sha256sum "$PT" | cut -d' ' -f1)"
|
|
BA_SHA="$(sha256sum "$BA" | cut -d' ' -f1)"
|
|
FW_SHA="$(sha256sum "$FW" | cut -d' ' -f1)"
|
|
BL_SIZE="$(stat -c '%s' "$BL")"
|
|
PT_SIZE="$(stat -c '%s' "$PT")"
|
|
BA_SIZE="$(stat -c '%s' "$BA")"
|
|
FW_SIZE="$(stat -c '%s' "$FW")"
|
|
cat > docs/flasher/firmware/pyxis-release.json << EOF
|
|
{
|
|
"schema": 1,
|
|
"version": "${VERSION}",
|
|
"source_commit": "${GITHUB_SHA}",
|
|
"environment": "tdeck-release",
|
|
"chip_family": "ESP32-S3",
|
|
"flash_size": 8388608,
|
|
"persistence_safe": true,
|
|
"images": {
|
|
"bootloader.bin": { "file": "bootloader.bin", "offset": 0, "size": ${BL_SIZE}, "sha256": "${BL_SHA}" },
|
|
"partitions.bin": { "file": "partitions.bin", "offset": 32768, "size": ${PT_SIZE}, "sha256": "${PT_SHA}" },
|
|
"boot_app0.bin": { "file": "boot_app0.bin", "offset": 57344, "size": ${BA_SIZE}, "sha256": "${BA_SHA}" },
|
|
"firmware.bin": { "file": "firmware.bin", "offset": 65536, "size": ${FW_SIZE}, "sha256": "${FW_SHA}" }
|
|
}
|
|
}
|
|
EOF
|
|
cp docs/flasher/firmware/pyxis-release.json "docs/flasher/firmware/releases/${VERSION}/"
|
|
python tools/validate_pyxis_web_release.py \
|
|
--directory "docs/flasher/firmware/releases/${VERSION}" \
|
|
--version "${VERSION}"
|
|
|
|
- name: Build Columba-compatible Pyxis package
|
|
if: startsWith(github.ref, 'refs/tags/v')
|
|
env:
|
|
VERSION: ${{ steps.version.outputs.VERSION }}
|
|
run: |
|
|
PACKAGE_VERSION="${VERSION#v}"
|
|
python tools/package_pyxis_release.py \
|
|
--firmware docs/flasher/firmware/firmware.bin \
|
|
--boot-app0 docs/flasher/firmware/boot_app0.bin \
|
|
--version "${PACKAGE_VERSION}" \
|
|
--output "docs/flasher/firmware/pyxis-${VERSION}.pyxis.zip"
|
|
|
|
- name: Download existing release assets for GitHub Pages
|
|
if: github.ref == 'refs/heads/main'
|
|
run: |
|
|
# Fetch all published releases and download their firmware assets
|
|
# so versioned firmware is available same-origin on GitHub Pages.
|
|
# With keep_files: true, each release only needs to be downloaded once.
|
|
for tag in $(gh api repos/${{ github.repository }}/releases --jq '.[] | select(.draft == false and .prerelease == false) | select(any(.assets[]; .name == "pyxis-release.json")) | .tag_name'); do
|
|
dir="docs/flasher/firmware/releases/${tag}"
|
|
# Skip if we already have this version's firmware (e.g., current tagged build)
|
|
if python tools/validate_pyxis_web_release.py --directory "${dir}" --version "${tag}"; then
|
|
echo "Skipping ${tag} — already present"
|
|
continue
|
|
fi
|
|
mkdir -p "${dir}"
|
|
echo "Downloading assets for ${tag}..."
|
|
for asset in pyxis-release.json bootloader.bin partitions.bin boot_app0.bin firmware.bin; do
|
|
url="https://github.com/${{ github.repository }}/releases/download/${tag}/${asset}"
|
|
if curl -sL -o "${dir}/${asset}" -w '%{http_code}' "${url}" | grep -qx 200; then
|
|
echo " ${asset} OK"
|
|
else
|
|
rm -f "${dir}/${asset}"
|
|
echo " ${asset} not found"
|
|
fi
|
|
done
|
|
if ! python tools/validate_pyxis_web_release.py --directory "${dir}" --version "${tag}"; then
|
|
rm -rf "${dir}"
|
|
echo "Rejected ${tag} — metadata or image verification failed"
|
|
fi
|
|
done
|
|
env:
|
|
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
|
|
- name: Generate manifest files
|
|
if: github.ref == 'refs/heads/main'
|
|
env:
|
|
VERSION: ${{ steps.version.outputs.VERSION }}
|
|
run: |
|
|
cat > docs/flasher/manifest-install.json << EOF
|
|
{
|
|
"name": "Pyxis T-Deck",
|
|
"version": "${VERSION}",
|
|
"new_install_prompt_erase": false,
|
|
"builds": [
|
|
{
|
|
"chipFamily": "ESP32-S3",
|
|
"parts": [
|
|
{ "path": "firmware/bootloader.bin", "offset": 0 },
|
|
{ "path": "firmware/partitions.bin", "offset": 32768 },
|
|
{ "path": "firmware/boot_app0.bin", "offset": 57344 },
|
|
{ "path": "firmware/firmware.bin", "offset": 65536 }
|
|
]
|
|
}
|
|
]
|
|
}
|
|
EOF
|
|
cat > docs/flasher/manifest-update.json << EOF
|
|
{
|
|
"name": "Pyxis T-Deck",
|
|
"version": "${VERSION}",
|
|
"new_install_prompt_erase": false,
|
|
"builds": [
|
|
{
|
|
"chipFamily": "ESP32-S3",
|
|
"parts": [
|
|
{ "path": "firmware/firmware.bin", "offset": 65536 }
|
|
]
|
|
}
|
|
]
|
|
}
|
|
EOF
|
|
|
|
- name: Generate root landing page from README
|
|
if: github.ref == 'refs/heads/main'
|
|
run: |
|
|
mkdir -p docs/root
|
|
pip install markdown
|
|
python3 -c "
|
|
import markdown, pathlib
|
|
md = pathlib.Path('README.md').read_text()
|
|
body = markdown.markdown(md, extensions=['fenced_code', 'tables'])
|
|
html = '''<!DOCTYPE html>
|
|
<html lang=\"en\">
|
|
<head>
|
|
<meta charset=\"UTF-8\">
|
|
<meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">
|
|
<title>Pyxis — LXMF Messenger for T-Deck</title>
|
|
<style>
|
|
body { font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
|
|
max-width: 800px; margin: 0 auto; padding: 2rem 1rem; line-height: 1.6;
|
|
background: #0f172a; color: #e2e8f0; }
|
|
a { color: #3b82f6; }
|
|
h1, h2 { color: #3b82f6; }
|
|
code { background: rgba(255,255,255,0.1); padding: 0.15em 0.4em; border-radius: 4px; font-size: 0.9em; }
|
|
.nav { text-align: center; margin: 2rem 0; }
|
|
.nav a { display: inline-block; padding: 0.75rem 1.5rem; background: #3b82f6; color: white;
|
|
text-decoration: none; border-radius: 8px; margin: 0.5rem; font-weight: 500; }
|
|
.nav a:hover { background: #2563eb; }
|
|
</style>
|
|
</head>
|
|
<body>
|
|
''' + body + '''
|
|
<div class=\"nav\">
|
|
<a href=\"flasher/\">Web Flasher</a>
|
|
<a href=\"https://github.com/torlando-tech/pyxis\">GitHub</a>
|
|
<a href=\"https://github.com/torlando-tech/pyxis/releases\">Releases</a>
|
|
</div>
|
|
</body></html>'''
|
|
pathlib.Path('docs/root/index.html').write_text(html)
|
|
"
|
|
|
|
- name: Deploy root landing page
|
|
if: github.ref == 'refs/heads/main'
|
|
uses: peaceiris/actions-gh-pages@v4
|
|
with:
|
|
github_token: ${{ secrets.GITHUB_TOKEN }}
|
|
publish_dir: ./docs/root
|
|
keep_files: true
|
|
|
|
- name: Deploy flasher to GitHub Pages
|
|
if: github.ref == 'refs/heads/main'
|
|
uses: peaceiris/actions-gh-pages@v4
|
|
with:
|
|
github_token: ${{ secrets.GITHUB_TOKEN }}
|
|
publish_dir: ./docs/flasher
|
|
destination_dir: flasher
|
|
keep_files: true
|
|
|
|
- name: Deploy versioned web-flasher assets
|
|
if: startsWith(github.ref, 'refs/tags/v')
|
|
uses: peaceiris/actions-gh-pages@v4
|
|
with:
|
|
github_token: ${{ secrets.GITHUB_TOKEN }}
|
|
publish_dir: ./docs/flasher/firmware/releases/${{ steps.version.outputs.VERSION }}
|
|
destination_dir: flasher/firmware/releases/${{ steps.version.outputs.VERSION }}
|
|
keep_files: true
|
|
|
|
- name: Create GitHub Release
|
|
if: startsWith(github.ref, 'refs/tags/v')
|
|
uses: softprops/action-gh-release@v2
|
|
with:
|
|
tag_name: ${{ steps.version.outputs.VERSION }}
|
|
name: ${{ steps.version.outputs.VERSION }}
|
|
files: |
|
|
docs/flasher/firmware/bootloader.bin
|
|
docs/flasher/firmware/partitions.bin
|
|
docs/flasher/firmware/boot_app0.bin
|
|
docs/flasher/firmware/firmware.bin
|
|
docs/flasher/firmware/pyxis-release.json
|
|
docs/flasher/firmware/*.pyxis.zip
|
|
generate_release_notes: true
|
|
draft: true
|