Skip to content

Change github remote url #137

Change github remote url

Change github remote url #137

name: MatrixOS Build and Release
on:
push:
branches:
- main
pull_request:
branches:
- main
workflow_dispatch:
inputs:
channel:
description: Release channel to build and publish
required: true
type: choice
default: release
options:
- release
- rc
- beta
- nightly
- development
release_ver:
description: RC/Beta number in the range 1-31. Ignored for release, nightly, and development.
required: false
type: string
default: '1'
tag_name:
description: Optional GitHub release tag override
required: false
type: string
release_name:
description: Optional GitHub release title override
required: false
type: string
publish:
description: Publish GitHub Release assets
required: true
type: boolean
default: true
permissions:
contents: write
env:
ESP_IDF_VERSION: v5.3.4
jobs:
prepare:
runs-on: ubuntu-latest
outputs:
asset_suffix: ${{ steps.meta.outputs.asset_suffix }}
base_version: ${{ steps.meta.outputs.base_version }}
build_target: ${{ steps.meta.outputs.build_target }}
channel: ${{ steps.meta.outputs.channel }}
channel_label: ${{ steps.meta.outputs.channel_label }}
channel_slug: ${{ steps.meta.outputs.channel_slug }}
commit_short: ${{ steps.meta.outputs.commit_short }}
display_version: ${{ steps.meta.outputs.display_version }}
generated_at: ${{ steps.meta.outputs.generated_at }}
prerelease: ${{ steps.meta.outputs.prerelease }}
publish: ${{ steps.meta.outputs.publish }}
release_date: ${{ steps.meta.outputs.release_date }}
release_name: ${{ steps.meta.outputs.release_name }}
release_tag: ${{ steps.meta.outputs.release_tag }}
release_ver: ${{ steps.meta.outputs.release_ver }}
steps:
- name: Checkout repository
uses: actions/checkout@v4
- name: Compute release metadata
id: meta
shell: bash
env:
EVENT_NAME: ${{ github.event_name }}
INPUT_CHANNEL: ${{ github.event.inputs.channel || '' }}
INPUT_PUBLISH: ${{ github.event.inputs.publish || '' }}
INPUT_RELEASE_NAME: ${{ github.event.inputs.release_name || '' }}
INPUT_RELEASE_VER: ${{ github.event.inputs.release_ver || '' }}
INPUT_TAG_NAME: ${{ github.event.inputs.tag_name || '' }}
run: |
set -euo pipefail
append_output() {
local key="$1"
local value="$2"
local delimiter="EOF_$(date +%s%N)_$RANDOM"
{
printf '%s<<%s\n' "$key" "$delimiter"
printf '%s\n' "$value"
printf '%s\n' "$delimiter"
} >> "$GITHUB_OUTPUT"
}
validate_release_ver() {
local value="$1"
local channel_name="$2"
if [[ -z "$value" ]]; then
printf '1\n'
return
fi
if [[ ! "$value" =~ ^[0-9]+$ ]]; then
echo "workflow_dispatch.release_ver must be an integer in the range 1-31 for ${channel_name} builds" >&2
exit 1
fi
local normalized=$((10#$value))
if (( normalized < 1 || normalized > 31 )); then
echo "workflow_dispatch.release_ver must be in the range 1-31 for ${channel_name} builds" >&2
exit 1
fi
printf '%s\n' "$normalized"
}
major=$(awk '/^#define MATRIXOS_MAJOR_VER / {print $3}' OS/System/Parameters.h)
minor=$(awk '/^#define MATRIXOS_MINOR_VER / {print $3}' OS/System/Parameters.h)
patch=$(awk '/^#define MATRIXOS_PATCH_VER / {print $3}' OS/System/Parameters.h)
commit_short=$(git rev-parse --short=8 HEAD)
release_date=$(date -u +'%Y-%m-%d')
date_compact=$(date -u +'%Y%m%d')
generated_at=$(date -u +'%Y-%m-%dT%H:%M:%SZ')
display_version="${major}.${minor}"
if [[ "$patch" != "0" ]]; then
display_version="${display_version}.${patch}"
fi
base_version="v${major}.${minor}.${patch}"
if [[ "$EVENT_NAME" == "workflow_dispatch" ]]; then
channel="$INPUT_CHANNEL"
publish="$INPUT_PUBLISH"
elif [[ "$EVENT_NAME" == "push" ]]; then
channel="nightly"
publish="true"
else
channel="nightly"
publish="false"
fi
case "$channel" in
release)
build_target="build-release"
channel_label="Release"
channel_slug="release"
prerelease="false"
release_ver="0"
default_tag="$base_version"
default_name="Matrix OS ${display_version} Release"
;;
rc)
build_target="build-rc"
channel_label="Release Candidate"
channel_slug="rc"
prerelease="true"
release_ver=$(validate_release_ver "${INPUT_RELEASE_VER:-}" "rc")
default_tag="${base_version}-rc.${release_ver}"
default_name="Matrix OS ${display_version} RC ${release_ver}"
;;
beta)
build_target="build-beta"
channel_label="Beta"
channel_slug="beta"
prerelease="true"
release_ver=$(validate_release_ver "${INPUT_RELEASE_VER:-}" "beta")
default_tag="${base_version}-beta.${release_ver}"
default_name="Matrix OS ${display_version} Beta ${release_ver}"
;;
nightly)
build_target="build-nightly"
channel_label="Nightly"
channel_slug="nightly"
prerelease="true"
release_ver="0"
default_tag="nightly-${date_compact}-${commit_short}"
default_name="Matrix OS ${display_version} Nightly ${release_date} ${commit_short}"
;;
development)
build_target="build-dev"
channel_label="InDev"
channel_slug="indev"
prerelease="true"
release_ver="0"
default_tag="indev-${date_compact}-${commit_short}"
default_name="Matrix OS ${display_version} InDev ${release_date} ${commit_short}"
;;
*)
echo "Unsupported channel: $channel" >&2
exit 1
;;
esac
release_tag="${INPUT_TAG_NAME:-$default_tag}"
release_name="${INPUT_RELEASE_NAME:-$default_name}"
if ! git check-ref-format --allow-onelevel "refs/tags/$release_tag" >/dev/null 2>&1; then
echo "Invalid release tag: $release_tag" >&2
exit 1
fi
asset_suffix=$(printf '%s' "$release_tag" | tr -cs 'A-Za-z0-9._-' '-')
asset_suffix=$(printf '%s' "$asset_suffix" | sed 's/^-*//; s/-*$//')
if [[ -z "$asset_suffix" ]]; then
asset_suffix="matrixos-${channel_slug}-${commit_short}"
fi
append_output "asset_suffix" "$asset_suffix"
append_output "base_version" "$base_version"
append_output "build_target" "$build_target"
append_output "channel" "$channel"
append_output "channel_label" "$channel_label"
append_output "channel_slug" "$channel_slug"
append_output "commit_short" "$commit_short"
append_output "display_version" "$display_version"
append_output "generated_at" "$generated_at"
append_output "prerelease" "$prerelease"
append_output "publish" "$publish"
append_output "release_date" "$release_date"
append_output "release_name" "$release_name"
append_output "release_tag" "$release_tag"
append_output "release_ver" "$release_ver"
build-firmware:
needs: prepare
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
device:
- Mystrix1
- Mystrix2
steps:
- name: Checkout repository
uses: actions/checkout@v4
with:
submodules: recursive
- name: Build ${{ matrix.device }} UF2
uses: espressif/esp-idf-ci-action@v1
with:
esp_idf_version: ${{ env.ESP_IDF_VERSION }}
target: esp32s3
path: .
command: >-
make DEVICE=${{ matrix.device }} FAMILY=${{ matrix.device }}
RELEASE_VER=${{ needs.prepare.outputs.release_ver }}
fullclean ${{ needs.prepare.outputs.build_target }} uf2
- name: Package ${{ matrix.device }} release artifact
shell: bash
env:
ASSET_SUFFIX: ${{ needs.prepare.outputs.asset_suffix }}
DEVICE: ${{ matrix.device }}
run: |
set -euo pipefail
sudo chown -R "$(id -u):$(id -g)" build
mkdir -p out
source_file="build/${DEVICE}/MatrixOS-${DEVICE}.uf2"
asset_name="MatrixOS-${DEVICE}-${ASSET_SUFFIX}.uf2"
cp "$source_file" "out/$asset_name"
- name: Upload ${{ matrix.device }} artifact bundle
uses: actions/upload-artifact@v4
with:
name: release-${{ matrix.device }}
path: out/*
if-no-files-found: error
build-sil:
needs: prepare
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@v4
with:
submodules: recursive
- name: Set up Node.js
uses: actions/setup-node@v4
with:
node-version: '20'
- name: Install WebUI dependencies
working-directory: Devices/MystrixSim/WebUI
run: npm ci
- name: Install MystrixSim build dependencies
shell: bash
run: |
set -euo pipefail
if command -v sudo >/dev/null 2>&1; then
sudo apt-get update
sudo apt-get install -y cmake make zip
else
apt-get update
apt-get install -y cmake make zip
fi
- name: Install Emscripten SDK
shell: bash
run: |
set -euo pipefail
git clone https://github.com/emscripten-core/emsdk.git "$RUNNER_TEMP/emsdk"
pushd "$RUNNER_TEMP/emsdk"
./emsdk install 4.0.12
./emsdk activate 4.0.12
popd
- name: Build MystrixSim runtime
shell: bash
env:
BUILD_TARGET: ${{ needs.prepare.outputs.build_target }}
RELEASE_VER: ${{ needs.prepare.outputs.release_ver }}
run: |
set -euo pipefail
source "$RUNNER_TEMP/emsdk/emsdk_env.sh"
export CMAKE="$(command -v cmake)"
export EMCMAKE="$(command -v emcmake)"
"$CMAKE" --version
make DEVICE=MystrixSim FAMILY=MystrixSim fullclean
make DEVICE=MystrixSim FAMILY=MystrixSim RELEASE_VER="$RELEASE_VER" "$BUILD_TARGET"
- name: Package MystrixSim release bundle
shell: bash
env:
ASSET_SUFFIX: ${{ needs.prepare.outputs.asset_suffix }}
run: |
set -euo pipefail
mkdir -p out
package_asset="MatrixOS-MystrixSim-${ASSET_SUFFIX}.msfw"
zip -j -q "out/$package_asset" \
"build/MystrixSim/Devices/MystrixSim/MatrixOSHost.js" \
"build/MystrixSim/Devices/MystrixSim/MatrixOSHost.wasm"
- name: Upload MystrixSim artifact bundle
uses: actions/upload-artifact@v4
with:
name: release-MystrixSim
path: out/*
if-no-files-found: error
build-firmware-dev:
if: needs.prepare.outputs.channel == 'nightly' || (needs.prepare.outputs.publish != 'true' && needs.prepare.outputs.channel != 'development')
needs: prepare
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
device:
- Mystrix1
- Mystrix2
steps:
- name: Checkout repository
uses: actions/checkout@v4
with:
submodules: recursive
- name: Build ${{ matrix.device }} InDev UF2
uses: espressif/esp-idf-ci-action@v1
with:
esp_idf_version: ${{ env.ESP_IDF_VERSION }}
target: esp32s3
path: .
command: >-
make DEVICE=${{ matrix.device }} FAMILY=${{ matrix.device }}
fullclean build-dev uf2
- name: Package ${{ matrix.device }} InDev artifact
shell: bash
env:
COMMIT_SHORT: ${{ needs.prepare.outputs.commit_short }}
RELEASE_DATE: ${{ needs.prepare.outputs.release_date }}
DEVICE: ${{ matrix.device }}
run: |
set -euo pipefail
sudo chown -R "$(id -u):$(id -g)" build
mkdir -p out
source_file="build/${DEVICE}/MatrixOS-${DEVICE}.uf2"
asset_name="MatrixOS-${DEVICE}-indev-${RELEASE_DATE}-${COMMIT_SHORT}.uf2"
cp "$source_file" "out/$asset_name"
- name: Upload ${{ matrix.device }} InDev artifact
uses: actions/upload-artifact@v4
with:
name: indev-${{ matrix.device }}
path: out/*
if-no-files-found: error
build-sil-dev:
if: needs.prepare.outputs.channel == 'nightly' || (needs.prepare.outputs.publish != 'true' && needs.prepare.outputs.channel != 'development')
needs: prepare
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@v4
with:
submodules: recursive
- name: Set up Node.js
uses: actions/setup-node@v4
with:
node-version: '20'
- name: Install WebUI dependencies
working-directory: Devices/MystrixSim/WebUI
run: npm ci
- name: Install MystrixSim build dependencies
shell: bash
run: |
set -euo pipefail
if command -v sudo >/dev/null 2>&1; then
sudo apt-get update
sudo apt-get install -y cmake make zip
else
apt-get update
apt-get install -y cmake make zip
fi
- name: Install Emscripten SDK
shell: bash
run: |
set -euo pipefail
git clone https://github.com/emscripten-core/emsdk.git "$RUNNER_TEMP/emsdk"
pushd "$RUNNER_TEMP/emsdk"
./emsdk install 4.0.12
./emsdk activate 4.0.12
popd
- name: Build MystrixSim InDev runtime
shell: bash
run: |
set -euo pipefail
source "$RUNNER_TEMP/emsdk/emsdk_env.sh"
export CMAKE="$(command -v cmake)"
export EMCMAKE="$(command -v emcmake)"
"$CMAKE" --version
make DEVICE=MystrixSim FAMILY=MystrixSim fullclean
make DEVICE=MystrixSim FAMILY=MystrixSim build-dev
- name: Package MystrixSim InDev artifact bundle
shell: bash
env:
COMMIT_SHORT: ${{ needs.prepare.outputs.commit_short }}
RELEASE_DATE: ${{ needs.prepare.outputs.release_date }}
run: |
set -euo pipefail
mkdir -p out
package_asset="MatrixOS-MystrixSim-indev-${RELEASE_DATE}-${COMMIT_SHORT}.msfw"
zip -j -q "out/$package_asset" \
"build/MystrixSim/Devices/MystrixSim/MatrixOSHost.js" \
"build/MystrixSim/Devices/MystrixSim/MatrixOSHost.wasm"
- name: Upload MystrixSim InDev artifact bundle
uses: actions/upload-artifact@v4
with:
name: indev-MystrixSim
path: out/*
if-no-files-found: error
publish-release:
if: ${{ always() && needs.prepare.outputs.publish == 'true' && !contains(needs.*.result, 'failure') && !contains(needs.*.result, 'cancelled') }}
needs:
- prepare
- build-firmware
- build-sil
- build-firmware-dev
- build-sil-dev
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@v4
- name: Set up Node.js
uses: actions/setup-node@v4
with:
node-version: '20'
- name: Download build bundles
uses: actions/download-artifact@v4
with:
pattern: release-*
path: artifacts
- name: Download InDev bundles
if: needs.prepare.outputs.channel == 'nightly'
uses: actions/download-artifact@v4
with:
pattern: indev-*
path: artifacts
- name: Collect release files and metadata
shell: bash
run: |
set -euo pipefail
mkdir -p release-files
find artifacts -type f \( -name '*.uf2' -o -name '*.msfw' -o -name '*.mspkg' \) -exec cp {} release-files/ \;
- name: Generate release index
shell: bash
env:
BASE_VERSION: ${{ needs.prepare.outputs.base_version }}
COMMIT_SHORT: ${{ needs.prepare.outputs.commit_short }}
DISPLAY_VERSION: ${{ needs.prepare.outputs.display_version }}
GENERATED_AT: ${{ needs.prepare.outputs.generated_at }}
PRERELEASE: ${{ needs.prepare.outputs.prerelease }}
RELEASE_DATE: ${{ needs.prepare.outputs.release_date }}
RELEASE_NAME: ${{ needs.prepare.outputs.release_name }}
RELEASE_TAG: ${{ needs.prepare.outputs.release_tag }}
CHANNEL_LABEL: ${{ needs.prepare.outputs.channel_label }}
CHANNEL_SLUG: ${{ needs.prepare.outputs.channel_slug }}
ASSET_SUFFIX: ${{ needs.prepare.outputs.asset_suffix }}
run: |
set -euo pipefail
channel_prefix=$(printf '%s' "$CHANNEL_SLUG" | tr '[:lower:]' '[:upper:]')
export INDEX_OUTPUT="release-files/index.json"
export INDEX_TAG="$RELEASE_TAG"
export INDEX_NAME="$RELEASE_NAME"
export INDEX_CHANNEL="$CHANNEL_LABEL"
export INDEX_CHANNEL_SLUG="$CHANNEL_SLUG"
export INDEX_VERSION="$BASE_VERSION"
export INDEX_DISPLAY_VERSION="Matrix OS ${DISPLAY_VERSION}"
export INDEX_DATE="$RELEASE_DATE"
export INDEX_GENERATED_AT="$GENERATED_AT"
export INDEX_COMMIT="$COMMIT_SHORT"
export INDEX_PRERELEASE="$PRERELEASE"
export "INDEX_${channel_prefix}_MYSTRIX1_FILES=MatrixOS-Mystrix1-${ASSET_SUFFIX}.uf2"
export "INDEX_${channel_prefix}_MYSTRIX2_FILES=MatrixOS-Mystrix2-${ASSET_SUFFIX}.uf2"
export "INDEX_${channel_prefix}_MYSTRIXSIM_FILES=MatrixOS-MystrixSim-${ASSET_SUFFIX}.msfw"
if [[ "$CHANNEL_SLUG" == "nightly" ]]; then
export INDEX_INDEV_MYSTRIX1_FILES="MatrixOS-Mystrix1-indev-${RELEASE_DATE}-${COMMIT_SHORT}.uf2"
export INDEX_INDEV_MYSTRIX2_FILES="MatrixOS-Mystrix2-indev-${RELEASE_DATE}-${COMMIT_SHORT}.uf2"
export INDEX_INDEV_MYSTRIXSIM_FILES="MatrixOS-MystrixSim-indev-${RELEASE_DATE}-${COMMIT_SHORT}.msfw"
fi
NODE_BIN="${EMSDK_NODE:-$(command -v nodejs 2>/dev/null || command -v node 2>/dev/null)}"
if [[ -z "$NODE_BIN" ]]; then
echo "Node.js is required to generate release metadata." >&2
exit 1
fi
"$NODE_BIN" Tools/release/write-device-metadata.mjs
- name: Create or update GitHub Release
uses: softprops/action-gh-release@v2
with:
tag_name: ${{ needs.prepare.outputs.release_tag }}
name: ${{ needs.prepare.outputs.release_name }}
target_commitish: ${{ github.sha }}
prerelease: ${{ needs.prepare.outputs.prerelease == 'true' }}
fail_on_unmatched_files: true
files: |
release-files/*
body: |
Channel: ${{ needs.prepare.outputs.channel_label }}
Commit: ${{ needs.prepare.outputs.commit_short }}
Generated at: ${{ needs.prepare.outputs.generated_at }}