name: start-wrt
on:
workflow_call:
workflow_dispatch:
inputs:
build-image:
type: boolean
description: Also build the full OpenWrt image (slow)
default: false
deploy:
type: choice
description: Deploy (upload images to S3 + register into the beta registry; release cut locally via manage-release.sh)
options:
- NONE
- release
force-overwrite:
type: boolean
description: Replace S3 objects that already exist for this commit
default: false
push:
branches:
- master
- integration/*
paths:
- 'projects/start-wrt/**'
- 'shared-libs/crates/**'
- 'shared-libs/ts-modules/**'
- 'Cargo.toml'
- 'Cargo.lock'
- 'angular.json'
- 'package.json'
- 'package-lock.json'
- 'tsconfig.json'
- 'tsconfig.lib.json'
- 'build/**'
- '.github/workflows/start-wrt.yaml'
- '.github/actions/setup-build/**'
- '!**/*.md'
- 'projects/start-wrt/release-notes/**'
pull_request:
types: [opened, synchronize, reopened, ready_for_review]
branches:
- master
- integration/*
paths:
- 'projects/start-wrt/**'
- 'shared-libs/crates/**'
- 'shared-libs/ts-modules/**'
- 'Cargo.toml'
- 'Cargo.lock'
- 'angular.json'
- 'package.json'
- 'package-lock.json'
- 'tsconfig.json'
- 'tsconfig.lib.json'
- 'build/**'
- '.github/workflows/start-wrt.yaml'
- '.github/actions/setup-build/**'
- '!**/*.md'
concurrency:
group: start-wrt-${{ github.event_name }}-${{ github.head_ref || github.ref }}
cancel-in-progress: ${{ github.event_name == 'pull_request' }}
env:
NODEJS_VERSION: '24.17.0'
jobs:
compile:
name: Build riscv64 binary
if: github.event.pull_request.draft != true
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6
- uses: ./.github/actions/setup-build
with:
nodejs-version: ${{ env.NODEJS_VERSION }}
- name: Make start-wrt
run: make start-wrt
env:
SCCACHE_GHA_ENABLED: on
SCCACHE_GHA_VERSION: 0
- uses: actions/upload-artifact@v7
with:
name: startwrt-riscv64
path: target/riscv64gc-unknown-linux-musl/release/startwrt
retention-days: 14
image:
name: Build OpenWrt image
if: >-
${{
(github.event_name == 'workflow_dispatch' && (github.event.inputs.build-image == 'true' || github.event.inputs.deploy == 'release'))
|| (github.event_name == 'push' && github.ref == 'refs/heads/master' && vars.STARTWRT_ALPHA_REGISTRY != '')
|| (
github.event_name == 'pull_request'
&& github.event.pull_request.draft != true
&& github.base_ref == 'master'
&& startsWith(github.head_ref, 'integration/')
&& github.event.pull_request.head.repo.full_name == github.repository
)
}}
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6
- uses: ./.github/actions/setup-build
with:
nodejs-version: ${{ env.NODEJS_VERSION }}
- name: Install OpenWrt build dependencies
run: |
# The runner image's Microsoft apt sources 403 intermittently, and one failing source fails the whole update.
grep -rl 'packages\.microsoft\.com' /etc/apt/sources.list.d/ 2>/dev/null | sudo xargs -r rm -f || true
sudo apt-get update
sudo apt-get install -y \
build-essential clang flex bison g++ gawk gcc-multilib \
g++-multilib gettext git libncurses-dev libssl-dev \
python3-setuptools rsync swig unzip \
zlib1g-dev file wget device-tree-compiler
- name: Cache OpenWrt download directory
uses: actions/cache@v4
with:
path: projects/start-wrt/openwrt/dl
key: openwrt-dl-${{ hashFiles('projects/start-wrt/build/openwrt-version', 'projects/start-wrt/build/feeds.conf', 'projects/start-wrt/build/openwrt.diffconfig') }}
restore-keys: openwrt-dl-
- name: Setup OpenWrt (fetch pinned upstream, patch, feeds, config, download)
run: make start-wrt-openwrt-setup
- name: Build image
run: make start-wrt-image
- uses: actions/upload-artifact@v7
with:
name: startwrt-openwrt-image
path: results/startwrt-*
retention-days: 14
deploy:
name: Deploy
needs: [image]
if: >-
${{
!cancelled() && needs.image.result == 'success'
&& (
(github.event_name == 'workflow_dispatch' && github.event.inputs.deploy == 'release')
|| (github.event_name == 'push' && github.ref == 'refs/heads/master' && vars.STARTWRT_ALPHA_REGISTRY != '')
)
}}
runs-on: ubuntu-latest
concurrency:
group: startwrt-deploy
cancel-in-progress: false
env:
S3_BUCKET: s3://startwrt-images
S3_CDN: https://startwrt-images.nyc3.cdn.digitaloceanspaces.com
REGISTRY: ${{ github.event_name == 'push' && vars.STARTWRT_ALPHA_REGISTRY || 'https://startwrt-beta-registry.start9.com' }}
PLATFORM: spacemit,k1-x
steps:
- uses: actions/checkout@v6
with:
sparse-checkout: |
projects/start-wrt/backend/ctrl/Cargo.toml
projects/start-wrt/release-notes/*
scripts/manage-release.sh
sparse-checkout-cone-mode: false
- name: Determine version
id: version
run: |
VERSION=$(sed -n 's/^version = "\([^"]*\)".*/\1/p' \
projects/start-wrt/backend/ctrl/Cargo.toml | head -1)
echo "version=$VERSION" >> "$GITHUB_OUTPUT"
echo "Version: $VERSION"
- name: Download image artifact
uses: actions/download-artifact@v8
with:
name: startwrt-openwrt-image
path: artifacts/
- name: Install start-cli
run: |
ARCH=$(uname -m)
OS=$(uname -s | tr '[:upper:]' '[:lower:]')
ASSET_NAME="start-cli_${ARCH}-${OS}"
DOWNLOAD_URL=$(curl -fsS \
-H "Authorization: token ${{ github.token }}" \
https://api.github.com/repos/Start9Labs/start-technologies/releases \
| jq -r '[.[].assets[] | select(.name=="'"$ASSET_NAME"'")] | first | .browser_download_url')
curl -fsSL \
-H "Authorization: token ${{ github.token }}" \
-H "Accept: application/octet-stream" \
"$DOWNLOAD_URL" -o /tmp/start-cli
sudo install -m 755 /tmp/start-cli /usr/local/bin/start-cli
echo "start-cli: $(start-cli --version)"
- name: Set up developer key
run: |
mkdir -p ~/.startos
printf '%s' "${{ secrets.DEV_KEY }}" > ~/.startos/developer.key.pem
- name: Configure S3
run: |
sudo apt-get install -y -qq s3cmd > /dev/null
cat > ~/.s3cfg <<EOF
[default]
access_key = ${{ secrets.S3_ACCESS_KEY }}
secret_key = ${{ secrets.S3_SECRET_KEY }}
host_base = nyc3.digitaloceanspaces.com
host_bucket = %(bucket)s.nyc3.digitaloceanspaces.com
use_https = True
EOF
- name: Upload images to S3
env:
FORCE_OVERWRITE: ${{ github.event.inputs.force-overwrite == 'true' }}
run: |
VERSION="${{ steps.version.outputs.version }}"
cd artifacts
conflicts=0
for file in *.img *.img.gz; do
[ -f "$file" ] || continue
key="${{ env.S3_BUCKET }}/v${VERSION}/$file"
if [ "$FORCE_OVERWRITE" != true ] && [ -n "$(s3cmd ls "$key")" ]; then
echo "::error::$key already exists — this commit has been published before. Overwriting it would invalidate any beta or production commitment pointing at that URL. Re-dispatch with force-overwrite to replace it deliberately."
conflicts=$((conflicts + 1))
continue
fi
echo "Uploading $file..."
s3cmd put -P "$file" "$key"
done
[ "$conflicts" -eq 0 ] || exit 1
- name: Drop the previous alpha build of this version
if: github.event_name == 'push'
run: |
VERSION="${{ steps.version.outputs.version }}"
start-cli --registry="${{ env.REGISTRY }}" registry os version remove "$VERSION" \
|| echo "::notice::v${VERSION} was not indexed in ${{ env.REGISTRY }} yet."
- name: Register StartWRT version in the target registry
run: |
VERSION="${{ steps.version.outputs.version }}"
NOTES=$(CHANGELOG_REF="${{ github.sha }}" ./scripts/manage-release.sh notes start-wrt) \
|| { echo "::warning::No release notes for v${VERSION}; registering without them."; NOTES=""; }
start-cli --registry="${{ env.REGISTRY }}" registry os version add \
"$VERSION" "v${VERSION}" "$NOTES" ">=0.1.0-beta.1 <=${VERSION}"
- name: Index assets in the target registry
run: |
VERSION="${{ steps.version.outputs.version }}"
cd artifacts
for file in *.img *.img.gz; do
[ -f "$file" ] || continue
# start-cli infers the asset slot from the file extension and only
# accepts iso/img/squashfs. Both images ship gzipped, so present
# each under a hardlink whose extension names its slot: the sdcard
# image as .img (the fresh-install slot) and the sysupgrade image
# as .squashfs (start-os's update-asset slot). The indexed URLs
# still point at the honestly-named .img.gz files on S3 (the
# registry only requires the URL's bytes to match the signed
# blake3 commitment, which the hardlinks share).
case "$file" in
*-sdcard.img.gz) index_file="${file%.img.gz}.img" ;;
*-sysupgrade.img.gz) index_file="${file%.img.gz}.squashfs" ;;
*) index_file="$file" ;;
esac
[ "$index_file" = "$file" ] || ln -f "$file" "$index_file"
echo "Indexing $file for platform ${{ env.PLATFORM }}..."
start-cli --registry="${{ env.REGISTRY }}" registry os asset add \
--platform="${{ env.PLATFORM }}" --version="$VERSION" \
"$index_file" "${{ env.S3_CDN }}/v${VERSION}/$file"
done