Sync inav to Gitea
Make sure docs are updated / settings_md (push) Canceled after 0s
Build firmware / test (push) Canceled after 0s
Build firmware / build-SITL-Windows (push) Canceled after 0s
Build firmware / build-SITL-Mac (push) Canceled after 0s
Build firmware / build-SITL-Linux (push) Canceled after 0s
Build firmware / build-SITL-Linux-arm64 (push) Canceled after 0s
Build firmware / upload-artifacts (push) Canceled after 0s
Build firmware / build-single-target (push) Canceled after 0s
Build firmware / build (9) (push) Canceled after 0s
Build firmware / build (8) (push) Canceled after 0s
Build firmware / build (7) (push) Canceled after 0s
Build firmware / build (6) (push) Canceled after 0s
Build firmware / build (5) (push) Canceled after 0s
Build firmware / build (4) (push) Canceled after 0s
Build firmware / build (3) (push) Canceled after 0s
Build firmware / build (2) (push) Canceled after 0s
Build firmware / build (14) (push) Canceled after 0s
Build firmware / build (13) (push) Canceled after 0s
Build firmware / build (12) (push) Canceled after 0s
Build firmware / build (11) (push) Canceled after 0s
Build firmware / build (10) (push) Canceled after 0s
Build firmware / build (1) (push) Canceled after 0s
Build firmware / build (0) (push) Canceled after 0s
Build firmware / detect (push) Canceled after 0s
Build pre-release / build (push) Canceled after 0s
Build pre-release / Release (push) Canceled after 0s

This commit is contained in:
2026-08-03 16:37:40 +08:00
commit dac37fd077
14095 changed files with 5603119 additions and 0 deletions
+49
View File
@@ -0,0 +1,49 @@
---
name: "\U0001F41B Bug report"
about: Report an issue to help make INAV better
title: ''
labels: ''
assignees: ''
---
**PLEASE MAKE SURE YOU READ AND UNDERSTAND THE SOCIAL MEDIA SUPPORT CHANNELS. QUESTIONS ABOUT FLASHING, CONFIGURING, PILOTING MAY BE CLOSED WITHOUT FURTHER INTERACTION.**
* [INAV Discord Server](https://discord.gg/peg2hhbYwN)
* [INAV Official on Facebook](https://www.facebook.com/groups/INAVOfficial)
* [INAV Official on Telegram](https://t.me/INAVFlight)
**Please double-check that nobody reported the issue before by using search in this bug tracker.**
**For Bug-Reports, please use the following template and provide as much information as possible. Bug-Reports that don't follow the template, might be closed unanswered. If you are not sure if you found a bug, ask for further input in the community channels or open a Github discussion.**
**PLEASE DELETE THE TEXT ABOVE AFTER READING AND UNDERSTANDING IT**
****
## Current Behavior
<!-- If applicable, add screenshots, videos and blackbox logs to help explain your problem. -->
## Steps to Reproduce
<!-- Steps to reproduce the behavior: -->
1.
2.
3.
4.
## Expected behavior
<!-- A clear and concise description of what you expected to happen. -->
## Suggested solution(s)
<!-- How could we solve this issue? What changes would need to made to INAV? -->
## Additional context
<!-- Add any other context about the problem here. -->
<!-- Go to CLI, execute `diff` command copy its output to [PasteBin](https://pastebin.com) and provide a link to a paste here -->
---
<!-- PLEASE FILL THIS OUT -->
<!-- Use CLI 'version' command to get version string -->
- FC Board name and vendor:
- INAV version string:
+24
View File
@@ -0,0 +1,24 @@
---
name: "\U0001F680Feature request"
about: Suggest a new feature for INAV
title: ''
labels: ''
assignees: ''
---
## Current Behavior
<!-- A clear and concise description of what is the current behavior / usecase. -->
## Desired Behavior
<!-- A clear and concise description of what you want to happen. -->
## Suggested Solution
<!-- Suggest a solution that the community/maintainers/you may take to enable the desired behavior -->
<!-- NOTE: Feature Requests without suggested solutions may not be addressed with the same level of urgency as those that have suggested solutions -->
## Who does this impact? Who is this for?
<!-- Who is this for? All users? Airplane users? Beginners? Advanced? Yourself? People using X, Y, Z, etc.? -->
## Additional context
<!-- Add any other context or links about the feature request here. -->
@@ -0,0 +1,38 @@
This pull requests adds support for ``$TARGET_NAME``
* [ ] Target complies with ``docs/policies/NEW_HARDWARE_POLICY.md``
The following items have been checked and confirmed working by an INAV developer on actual hardware: (feel free to remove non-relevant items)
* [ ] Samples received
* [ ] Flash firmware
* [ ] Calibrate
* [ ] Orientation matches
* [ ] Gyro working
* [ ] Accel working
* [ ] Voltage correct
* [ ] Current correct
* [ ] Baro working
* [ ] Mag I2C Bus
* [ ] Additional I2C2 Buses (Airspeed/other accessories)
* [ ] UART1
* [ ] UART2
* [ ] UART3
* [ ] UART4
* [ ] UART5
* [ ] UART6
* [ ] UART7
* [ ] UART8
* [ ] Analog Camera working
* [ ] Video Out working
* [ ] OSD working
* [ ] LEDs working
* [ ] Buzzer working
* [ ] Motor outputs
* [ ] DShot support on m1-4
* [ ] Servo outputs
* [ ] Blackbox
* [ ] PINIO1
* [ ] PINIO2
* [ ] PINIO3
* [ ] PINIO4
+4
View File
@@ -0,0 +1,4 @@
label-alias:
bug: 'BUG'
feature_request: 'Feature request'
question: 'Support'
+12
View File
@@ -0,0 +1,12 @@
# Configuration for probot-no-response - https://github.com/probot/no-response
# Number of days of inactivity before an Issue is closed for lack of response
daysUntilClose: 3
# Label requiring a response
responseRequiredLabel: Missing Information
# Comment to post when closing an Issue for lack of response. Set to `false` to disable
closeComment: >
This issue has been automatically closed because the information we asked
to be provided when opening it was not supplied by the original author.
With only the information that is currently in the issue, we don't have
enough information to take action.
+226
View File
@@ -0,0 +1,226 @@
#!/bin/bash
#
# Check if parameter group struct modifications include version increments
# This prevents settings corruption when struct layout changes without version bump
#
# Exit codes:
# 0 - No issues found
# 1 - Potential issues detected (will post comment)
# 2 - Script error
set -euo pipefail
# Output file for issues found
ISSUES_FILE=$(mktemp)
trap "rm -f $ISSUES_FILE" EXIT
# Color output for local testing
if [ -t 1 ]; then
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
NC='\033[0m' # No Color
else
RED=''
GREEN=''
YELLOW=''
NC=''
fi
echo "🔍 Checking for Parameter Group version updates..."
# Get base and head commits
BASE_REF=${GITHUB_BASE_REF:-}
HEAD_REF=${GITHUB_HEAD_REF:-}
if [ -z "$BASE_REF" ] || [ -z "$HEAD_REF" ]; then
echo "⚠️ Warning: Not running in GitHub Actions PR context"
echo "Using git diff against HEAD~1 for local testing"
BASE_COMMIT="HEAD~1"
HEAD_COMMIT="HEAD"
else
BASE_COMMIT="origin/$BASE_REF"
HEAD_COMMIT="HEAD"
fi
# Get list of changed files
CHANGED_FILES=$(git diff --name-only $BASE_COMMIT..$HEAD_COMMIT | grep -E '\.(c|h)$' || true)
if [ -z "$CHANGED_FILES" ]; then
echo "✅ No C/H files changed"
exit 0
fi
echo "📁 Changed files:"
echo "$CHANGED_FILES" | sed 's/^/ /'
# Function to extract PG info from a file
check_file_for_pg_changes() {
local file=$1
local diff_output=$(git diff $BASE_COMMIT..$HEAD_COMMIT -- "$file")
# Check if file contains PG_REGISTER in current version
if ! git show $HEAD_COMMIT:"$file" 2>/dev/null | grep -q "PG_REGISTER"; then
return 0
fi
echo " 🔎 Checking $file (contains PG_REGISTER)"
# Extract all PG_REGISTER lines from the diff (both old and new)
local pg_registers=$(echo "$diff_output" | grep -E "^[-+].*PG_REGISTER" || true)
if [ -z "$pg_registers" ]; then
# PG_REGISTER exists but wasn't changed
# Still need to check if the struct changed
pg_registers=$(git show $HEAD_COMMIT:"$file" | grep "PG_REGISTER" || true)
fi
# Process each PG registration
while IFS= read -r pg_line; do
[ -z "$pg_line" ] && continue
# Extract struct name and version
# Pattern: PG_REGISTER.*\((\w+),\s*(\w+),\s*PG_\w+,\s*(\d+)\)
if [[ $pg_line =~ PG_REGISTER[^(]*\(([^,]+),([^,]+),([^,]+),([^)]+)\) ]]; then
local struct_type="${BASH_REMATCH[1]}"
local pg_name="${BASH_REMATCH[2]}"
local pg_id="${BASH_REMATCH[3]}"
local version="${BASH_REMATCH[4]}"
# Clean up whitespace
struct_type=$(echo "$struct_type" | xargs)
version=$(echo "$version" | xargs)
echo " 📋 Found: $struct_type (version $version)"
# Check if this struct's typedef was modified in ANY changed file
local struct_pattern="typedef struct ${struct_type%_t}_s"
local struct_body_diff=""
local struct_found_in=""
# Search all changed files for this struct definition
while IFS= read -r changed_file; do
[ -z "$changed_file" ] && continue
local file_diff=$(git diff $BASE_COMMIT..$HEAD_COMMIT -- "$changed_file")
local struct_in_file=$(echo "$file_diff" | sed -n "/${struct_pattern}/,/\}.*${struct_type};/p")
if [ -n "$struct_in_file" ]; then
struct_body_diff="$struct_in_file"
struct_found_in="$changed_file"
echo " 🔍 Found struct definition in $changed_file"
break
fi
done <<< "$CHANGED_FILES"
local struct_changes=$(echo "$struct_body_diff" | grep -E "^[-+]" \
| grep -v -E "^[-+]\s*(typedef struct|}|//|\*)" \
| sed -E 's://.*$::' \
| sed -E 's:/\*.*\*/::' \
| tr -d '[:space:]')
if [ -n "$struct_changes" ]; then
echo " ⚠️ Struct definition modified in $struct_found_in"
# Check if version was incremented in PG_REGISTER
local old_version=$(echo "$diff_output" | grep "^-.*PG_REGISTER.*$struct_type" | grep -oP ',\s*\K\d+(?=\s*\))' || echo "")
local new_version=$(echo "$diff_output" | grep "^+.*PG_REGISTER.*$struct_type" | grep -oP ',\s*\K\d+(?=\s*\))' || echo "")
# Find line number of PG_REGISTER for error reporting
local line_num=$(git show $HEAD_COMMIT:"$file" | grep -n "PG_REGISTER.*$struct_type" | cut -d: -f1 | head -1)
if [ -n "$old_version" ] && [ -n "$new_version" ]; then
# PG_REGISTER was modified - check if version increased
if [ "$new_version" -le "$old_version" ]; then
echo " ❌ Version NOT incremented ($old_version$new_version)"
cat >> $ISSUES_FILE << EOF
### \`$struct_type\` ($file:$line_num)
- **Struct modified:** Field changes detected in $struct_found_in
- **Version status:** ❌ Not incremented (version $version)
- **Recommendation:** Increment version from $old_version to $(($old_version + 1))
EOF
else
echo " ✅ Version incremented ($old_version$new_version)"
fi
elif [ -z "$old_version" ] && [ -z "$new_version" ]; then
# PG_REGISTER wasn't modified but struct was - THIS IS THE BUG!
echo " ❌ PG_REGISTER not modified, version still $version"
cat >> $ISSUES_FILE << EOF
### \`$struct_type\` ($file:$line_num)
- **Struct modified:** Field changes detected in $struct_found_in
- **Version status:** ❌ Not incremented (still version $version)
- **Recommendation:** Increment version to $(($version + 1)) in $file
EOF
else
# One exists but not the other - unusual edge case
echo " ⚠️ Unusual version change pattern detected"
cat >> $ISSUES_FILE << EOF
### \`$struct_type\` ($file:$line_num)
- **Struct modified:** Field changes detected in $struct_found_in
- **Version status:** ⚠️ Unusual change pattern (old: ${old_version:-none}, new: ${new_version:-none})
- **Current version:** $version
- **Recommendation:** Manually verify version increment
EOF
fi
else
echo " ✅ Struct unchanged"
fi
fi
done <<< "$pg_registers"
}
# Build list of files to check (changed files + companions with PG_REGISTER)
echo "🔍 Building file list including companions with PG_REGISTER..."
FILES_TO_CHECK=""
ALREADY_ADDED=""
while IFS= read -r file; do
[ -z "$file" ] && continue
# Add this file to check list
if ! echo "$ALREADY_ADDED" | grep -qw "$file"; then
FILES_TO_CHECK="$FILES_TO_CHECK$file"$'\n'
ALREADY_ADDED="$ALREADY_ADDED $file"
fi
# Determine companion file (.c <-> .h)
local companion=""
if [[ "$file" == *.c ]]; then
companion="${file%.c}.h"
elif [[ "$file" == *.h ]]; then
companion="${file%.h}.c"
fi
# If companion exists and contains PG_REGISTER, add it to check list
if [ -n "$companion" ]; then
if git show $HEAD_COMMIT:"$companion" 2>/dev/null | grep -q "PG_REGISTER"; then
if ! echo "$ALREADY_ADDED" | grep -qw "$companion"; then
echo " 📎 Adding $companion (companion of $file with PG_REGISTER)"
FILES_TO_CHECK="$FILES_TO_CHECK$companion"$'\n'
ALREADY_ADDED="$ALREADY_ADDED $companion"
fi
fi
fi
done <<< "$CHANGED_FILES"
# Check each file (including companions)
while IFS= read -r file; do
[ -z "$file" ] && continue
check_file_for_pg_changes "$file"
done <<< "$FILES_TO_CHECK"
# Check if any issues were found
if [ -s $ISSUES_FILE ]; then
echo ""
echo "${YELLOW}⚠️ Potential PG version issues detected${NC}"
echo "Output saved to: $ISSUES_FILE"
cat $ISSUES_FILE
exit 1
else
echo ""
echo "${GREEN}✅ No PG version issues detected${NC}"
exit 0
fi
+58
View File
@@ -0,0 +1,58 @@
# Configuration for probot-stale - https://github.com/probot/stale
# Number of days of inactivity before an Issue or Pull Request becomes stale
daysUntilStale: 60
# Number of days of inactivity before a stale Issue or Pull Request is closed.
# Set to false to disable. If disabled, issues still need to be closed manually, but will remain marked as stale.
daysUntilClose: 14
# Issues or Pull Requests with these labels will never be considered stale. Set to `[]` to disable
exemptLabels:
- BUG
- Feature Request
- Pinned
# Set to true to ignore issues in a project (defaults to false)
exemptProjects: false
# Set to true to ignore issues in a milestone (defaults to false)
exemptMilestones: true
# Label to use when marking as stale
staleLabel: Inactive
# Comment to post when marking as stale. Set to `false` to disable
markComment: >
This issue / pull request has been automatically marked as stale because it
has not had any activity in 60 days. The resources of the INAV team are limited,
and so we are asking for your help.
This issue / pull request will be closed if no further activity occurs within two weeks.
# Comment to post when removing the stale label.
# unmarkComment: >
# Your comment here.
# Comment to post when closing a stale Issue or Pull Request.
closeComment: >
Automatically closing as inactive.
# Limit the number of actions per hour, from 1-30. Default is 30
limitPerRun: 30
# Limit to only `issues` or `pulls`
# only: issues
# Optionally, specify configuration settings that are specific to just 'issues' or 'pulls':
# pulls:
# daysUntilStale: 30
# markComment: >
# This pull request has been automatically marked as stale because it has not had
# recent activity. It will be closed if no further activity occurs. Thank you
# for your contributions.
# issues:
# exemptLabels:
# - confirmed
+127
View File
@@ -0,0 +1,127 @@
# GitHub Actions Workflows
This directory contains automated CI/CD workflows for the INAV project.
## Active Workflows
### Build and Test
#### `ci.yml` - Build Firmware
**Triggers:** Pull requests, pushes to maintenance branches
**Purpose:** Compiles INAV firmware for all targets to verify builds succeed
**Matrix:** 15 parallel build jobs for faster CI
#### `nightly-build.yml` - Nightly Builds
**Triggers:** Scheduled nightly
**Purpose:** Creates nightly development builds for testing
### Documentation
#### `docs.yml` - Documentation Build
**Triggers:** Pull requests affecting documentation
**Purpose:** Validates documentation builds correctly
### Code Quality
#### `pg-version-check.yml` - Parameter Group Version Check
**Triggers:** Pull requests to maintenance-9.x and maintenance-10.x
**Purpose:** Detects parameter group struct modifications and verifies version increments
**Why:** Prevents settings corruption when struct layout changes without version bump
**How it works:**
1. Scans changed .c/.h files for `PG_REGISTER` entries
2. Detects if associated struct typedefs were modified
3. Checks if the PG version parameter was incremented
4. Posts helpful comment if version not incremented
**Reference:** See `docs/development/parameter_groups/` for PG system documentation
**Script:** `.github/scripts/check-pg-versions.sh`
**When to increment PG versions:**
- ✅ Adding/removing fields from struct
- ✅ Changing field types or sizes
- ✅ Reordering fields
- ✅ Adding/removing packing attributes
- ❌ Only changing `PG_RESET_TEMPLATE` default values
- ❌ Only changing comments
### Pull Request Helpers
#### `pr-branch-suggestion.yml` - Branch Targeting Suggestion
**Triggers:** PRs targeting master branch
**Purpose:** Suggests using maintenance-9.x or maintenance-10.x instead
#### `non-code-change.yaml` - Non-Code Change Detection
**Triggers:** Pull requests
**Purpose:** Detects PRs with only documentation/formatting changes
## Configuration Files
- `../.github/stale.yml` - Stale issue/PR management
- `../.github/no-response.yml` - Auto-close issues without response
- `../.github/issue_label_bot.yaml` - Automatic issue labeling
## Adding New Workflows
When adding workflows:
1. **Use descriptive names** - Make purpose clear from filename
2. **Document in this README** - Add entry above with purpose and triggers
3. **Set appropriate permissions** - Principle of least privilege
4. **Test in fork first** - Verify before submitting to main repo
5. **Handle errors gracefully** - Don't block CI unnecessarily
### Common Patterns
**Checkout with history:**
```yaml
- uses: actions/checkout@v4
with:
fetch-depth: 0
```
**Post PR comments:**
```yaml
- uses: actions/github-script@v7
with:
script: |
await github.rest.issues.createComment({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: context.issue.number,
body: 'Comment text'
});
```
**Run bash scripts:**
```yaml
- run: bash .github/scripts/script-name.sh
env:
GITHUB_BASE_REF: ${{ github.base_ref }}
```
## Permissions
Workflows use GitHub's fine-grained permissions:
- `contents: read` - Read repository code
- `pull-requests: write` - Post/update PR comments
- `actions: read` - Read workflow run data
## Local Testing
Scripts in `.github/scripts/` can be run locally:
```bash
cd inav
export GITHUB_BASE_REF=maintenance-9.x
export GITHUB_HEAD_REF=feature-branch
bash .github/scripts/check-pg-versions.sh
```
## References
- [GitHub Actions Documentation](https://docs.github.com/en/actions)
- [Workflow Syntax](https://docs.github.com/en/actions/reference/workflow-syntax-for-github-actions)
- [GitHub Script Action](https://github.com/actions/github-script)
+382
View File
@@ -0,0 +1,382 @@
name: Build firmware
# Don't enable CI on push, just on PR. If you
# are working on the main repo and want to trigger
# a CI build submit a draft PR.
on:
push:
branches:
- '!maintenance-8.x.x'
pull_request:
paths:
- 'src/**'
- '.github/**'
- 'cmake/**'
- 'lib/**'
- 'docs/Settings.md'
- 'CMakeLists.txt'
- '*.sh'
workflow_call:
#inputs:
# release_build:
# description: 'Specifies if it is a build that should include commit hash in hex file names or not'
# default: false
# required: false
# type: boolean
jobs:
detect:
runs-on: ubuntu-latest
outputs:
single_target: ${{ steps.check.outputs.single_target }}
target_names: ${{ steps.check.outputs.target_names }}
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Detect single-target PR
id: check
run: |
if [ "${{ github.event_name }}" != "pull_request" ]; then
echo "single_target=false" >> $GITHUB_OUTPUT
exit 0
fi
CHANGED=$(git diff --name-only origin/${{ github.base_ref }}...HEAD)
if [ -z "$CHANGED" ]; then
echo "single_target=false" >> $GITHUB_OUTPUT
exit 0
fi
# Fail fast if any changed file is outside src/main/target/<dir>/
NON_TARGET=$(echo "$CHANGED" | grep -Ev '^src/main/target/[^/]+/.+' | head -1)
if [ -n "$NON_TARGET" ]; then
echo "Non-target file changed: $NON_TARGET — full build required"
echo "single_target=false" >> $GITHUB_OUTPUT
exit 0
fi
# Count how many distinct target directories were touched
TARGET_DIRS=$(echo "$CHANGED" | sed -n 's|^src/main/target/\([^/]*\)/.*|\1|p' | sort -u)
DIR_COUNT=$(echo "$TARGET_DIRS" | wc -l)
if [ "$DIR_COUNT" != "1" ]; then
echo "$DIR_COUNT target directories changed — full build required"
echo "single_target=false" >> $GITHUB_OUTPUT
exit 0
fi
TARGET_DIR="$TARGET_DIRS"
CMAKE="src/main/target/${TARGET_DIR}/CMakeLists.txt"
if [ ! -f "$CMAKE" ]; then
echo "No CMakeLists.txt for $TARGET_DIR — full build required"
echo "single_target=false" >> $GITHUB_OUTPUT
exit 0
fi
TARGET_NAMES=$(grep -oP '(?<=\()[^)]+' "$CMAKE" | tr '\n' ' ' | xargs)
if [ -z "$TARGET_NAMES" ]; then
echo "No target names in CMakeLists.txt — full build required"
echo "single_target=false" >> $GITHUB_OUTPUT
exit 0
fi
echo "Single-target PR: building $TARGET_NAMES"
echo "single_target=true" >> $GITHUB_OUTPUT
echo "target_names=$TARGET_NAMES" >> $GITHUB_OUTPUT
build:
needs: [detect]
if: needs.detect.outputs.single_target != 'true'
runs-on: ubuntu-latest
strategy:
matrix:
id: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14]
steps:
- uses: actions/checkout@v4
- name: Install dependencies
run: sudo apt-get update && sudo apt-get -y install ninja-build
- name: Setup environment
env:
ACTIONS_ALLOW_UNSECURE_COMMANDS: true
run: |
# This is the hash of the commit for the PR
# when the action is triggered by PR, empty otherwise
COMMIT_ID=${{ github.event.pull_request.head.sha }}
# This is the hash of the commit when triggered by push
# but the hash of refs/pull/<n>/merge, which is different
# from the hash of the latest commit in the PR, that's
# why we try github.event.pull_request.head.sha first
COMMIT_ID=${COMMIT_ID:-${{ github.sha }}}
BUILD_SUFFIX=ci-$(date '+%Y%m%d')-$(git rev-parse --short ${COMMIT_ID})
VERSION=$(grep project CMakeLists.txt|awk -F VERSION '{ gsub(/[ \t)]/, "", $2); print $2 }')
echo "BUILD_SUFFIX=${BUILD_SUFFIX}" >> $GITHUB_ENV
echo "BUILD_NAME=inav-${VERSION}-${BUILD_SUFFIX}" >> $GITHUB_ENV
echo "NUM_CORES=$(grep processor /proc/cpuinfo | wc -l)" >> $GITHUB_ENV
- uses: actions/cache@v4
with:
path: downloads
key: ${{ runner.os }}-downloads-${{ hashFiles('CMakeLists.txt') }}-${{ hashFiles('**/cmake/*')}}
- name: Build targets (${{ matrix.id }})
run: mkdir -p build && cd build && cmake -DWARNINGS_AS_ERRORS=ON -DCI_JOB_INDEX=${{ matrix.id }} -DCI_JOB_COUNT=${{ strategy.job-total }} -DBUILD_SUFFIX=${{ env.BUILD_SUFFIX }} -DMAIN_COMPILE_OPTIONS=-pipe -G Ninja .. && ninja -j${{ env.NUM_CORES }} ci
- name: Upload artifacts
uses: actions/upload-artifact@v4
with:
name: matrix-${{ env.BUILD_NAME }}.${{ matrix.id }}
path: ./build/*.hex
retention-days: 1
build-single-target:
needs: [detect]
if: needs.detect.outputs.single_target == 'true'
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Install dependencies
run: sudo apt-get update && sudo apt-get -y install ninja-build
- name: Setup environment
env:
ACTIONS_ALLOW_UNSECURE_COMMANDS: true
run: |
COMMIT_ID=${{ github.event.pull_request.head.sha }}
COMMIT_ID=${COMMIT_ID:-${{ github.sha }}}
BUILD_SUFFIX=ci-$(date '+%Y%m%d')-$(git rev-parse --short ${COMMIT_ID})
VERSION=$(grep project CMakeLists.txt|awk -F VERSION '{ gsub(/[ \t)]/, "", $2); print $2 }')
echo "BUILD_SUFFIX=${BUILD_SUFFIX}" >> $GITHUB_ENV
echo "BUILD_NAME=inav-${VERSION}-${BUILD_SUFFIX}" >> $GITHUB_ENV
echo "NUM_CORES=$(grep processor /proc/cpuinfo | wc -l)" >> $GITHUB_ENV
- uses: actions/cache@v4
with:
path: downloads
key: ${{ runner.os }}-downloads-${{ hashFiles('CMakeLists.txt') }}-${{ hashFiles('**/cmake/*')}}
- name: Build targets (${{ needs.detect.outputs.target_names }})
run: mkdir -p build && cd build && cmake -DWARNINGS_AS_ERRORS=ON -DBUILD_SUFFIX=${{ env.BUILD_SUFFIX }} -DMAIN_COMPILE_OPTIONS=-pipe -G Ninja .. && ninja -j${{ env.NUM_CORES }} ${{ needs.detect.outputs.target_names }}
- name: Upload artifacts
uses: actions/upload-artifact@v4
with:
name: matrix-${{ env.BUILD_NAME }}.single
path: ./build/*.hex
retention-days: 1
upload-artifacts:
runs-on: ubuntu-latest
needs: [build, build-single-target]
if: always() && !cancelled() && (needs.build.result == 'success' || needs.build-single-target.result == 'success')
steps:
- uses: actions/checkout@v4
- name: Setup environment
env:
ACTIONS_ALLOW_UNSECURE_COMMANDS: true
run: |
# This is the hash of the commit for the PR
# when the action is triggered by PR, empty otherwise
COMMIT_ID=${{ github.event.pull_request.head.sha }}
# This is the hash of the commit when triggered by push
# but the hash of refs/pull/<n>/merge, which is different
# from the hash of the latest commit in the PR, that's
# why we try github.event.pull_request.head.sha first
COMMIT_ID=${COMMIT_ID:-${{ github.sha }}}
BUILD_SUFFIX=ci-$(date '+%Y%m%d')-$(git rev-parse --short ${COMMIT_ID})
VERSION=$(grep project CMakeLists.txt|awk -F VERSION '{ gsub(/[ \t)]/, "", $2); print $2 }')
echo "BUILD_SUFFIX=${BUILD_SUFFIX}" >> $GITHUB_ENV
echo "BUILD_NAME=inav-${VERSION}-${BUILD_SUFFIX}" >> $GITHUB_ENV
echo "NUM_CORES=$(grep processor /proc/cpuinfo | wc -l)" >> $GITHUB_ENV
- name: Download artifacts
uses: actions/download-artifact@v4
with:
pattern: matrix-inav-*
merge-multiple: true
path: binaries
- name: Build target list
run: |
ls -1 binaries/*.hex | cut -d/ -f2 > targets.txt
- name: Upload firmware images
uses: actions/upload-artifact@v4
with:
name: ${{ env.BUILD_NAME }}
path: binaries/*.hex
- name: Upload firmware images
uses: actions/upload-artifact@v4
with:
name: targets
path: targets.txt
- name: Save PR number
if: github.event_name == 'pull_request'
run: echo "${{ github.event.pull_request.number }}" > pr_number.txt
- name: Upload PR number
if: github.event_name == 'pull_request'
uses: actions/upload-artifact@v4
with:
name: pr-number
path: pr_number.txt
retention-days: 1
build-SITL-Linux-arm64:
runs-on: ubuntu-22.04-arm
steps:
- uses: actions/checkout@v4
- name: Install dependencies
run: sudo apt-get update && sudo apt-get -y install ninja-build
- name: Setup environment
env:
ACTIONS_ALLOW_UNSECURE_COMMANDS: true
run: |
# This is the hash of the commit for the PR
# when the action is triggered by PR, empty otherwise
COMMIT_ID=${{ github.event.pull_request.head.sha }}
# This is the hash of the commit when triggered by push
# but the hash of refs/pull/<n>/merge, which is different
# from the hash of the latest commit in the PR, that's
# why we try github.event.pull_request.head.sha first
COMMIT_ID=${COMMIT_ID:-${{ github.sha }}}
BUILD_SUFFIX=ci-$(date '+%Y%m%d')-$(git rev-parse --short ${COMMIT_ID})
VERSION=$(grep project CMakeLists.txt|awk -F VERSION '{ gsub(/[ \t)]/, "", $2); print $2 }')
echo "BUILD_SUFFIX=${BUILD_SUFFIX}" >> $GITHUB_ENV
echo "BUILD_NAME=inav-${VERSION}-${BUILD_SUFFIX}" >> $GITHUB_ENV
echo "NUM_CORES=$(grep processor /proc/cpuinfo | wc -l)" >> $GITHUB_ENV
- name: Build SITL
run: mkdir -p build_SITL && cd build_SITL && cmake -DSITL=ON -DWARNINGS_AS_ERRORS=ON -G Ninja .. && ninja -j${{ env.NUM_CORES }}
- name: Strip version number
run: |
for f in build_SITL/*_SITL; do
mv $f $(echo $f | sed -e 's/_[0-9]\+\.[0-9]\+\.[0-9]\+//')
done
- name: Upload artifacts
uses: actions/upload-artifact@v4
with:
name: ${{ env.BUILD_NAME }}_SITL-Linux-aarch64
path: ./build_SITL/*_SITL
build-SITL-Linux:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Install dependencies
run: sudo apt-get update && sudo apt-get -y install ninja-build
- name: Setup environment
env:
ACTIONS_ALLOW_UNSECURE_COMMANDS: true
run: |
# This is the hash of the commit for the PR
# when the action is triggered by PR, empty otherwise
COMMIT_ID=${{ github.event.pull_request.head.sha }}
# This is the hash of the commit when triggered by push
# but the hash of refs/pull/<n>/merge, which is different
# from the hash of the latest commit in the PR, that's
# why we try github.event.pull_request.head.sha first
COMMIT_ID=${COMMIT_ID:-${{ github.sha }}}
BUILD_SUFFIX=ci-$(date '+%Y%m%d')-$(git rev-parse --short ${COMMIT_ID})
VERSION=$(grep project CMakeLists.txt|awk -F VERSION '{ gsub(/[ \t)]/, "", $2); print $2 }')
echo "BUILD_SUFFIX=${BUILD_SUFFIX}" >> $GITHUB_ENV
echo "BUILD_NAME=inav-${VERSION}-${BUILD_SUFFIX}" >> $GITHUB_ENV
echo "NUM_CORES=$(grep processor /proc/cpuinfo | wc -l)" >> $GITHUB_ENV
- name: Build SITL
run: mkdir -p build_SITL && cd build_SITL && cmake -DSITL=ON -DWARNINGS_AS_ERRORS=ON -G Ninja .. && ninja -j${{ env.NUM_CORES }}
- name: Strip version number
run: |
for f in build_SITL/*_SITL; do
mv $f $(echo $f | sed -e 's/_[0-9]\+\.[0-9]\+\.[0-9]\+//')
done
- name: Upload artifacts
uses: actions/upload-artifact@v4
with:
name: ${{ env.BUILD_NAME }}_SITL-Linux
path: ./build_SITL/*_SITL
build-SITL-Mac:
runs-on: macos-latest
steps:
- uses: actions/checkout@v4
- name: Install dependencies
run: |
brew install ruby
- name: Setup environment
env:
ACTIONS_ALLOW_UNSECURE_COMMANDS: true
run: |
# This is the hash of the commit for the PR
# when the action is triggered by PR, empty otherwise
COMMIT_ID=${{ github.event.pull_request.head.sha }}
# This is the hash of the commit when triggered by push
# but the hash of refs/pull/<n>/merge, which is different
# from the hash of the latest commit in the PR, that's
# why we try github.event.pull_request.head.sha first
COMMIT_ID=${COMMIT_ID:-${{ github.sha }}}
BUILD_SUFFIX=ci-$(date '+%Y%m%d')-$(git rev-parse --short ${COMMIT_ID})
VERSION=$(grep project CMakeLists.txt|awk -F VERSION '{ gsub(/[ \t)]/, "", $2); print $2 }')
echo "BUILD_SUFFIX=${BUILD_SUFFIX}" >> $GITHUB_ENV
echo "BUILD_NAME=inav-${VERSION}-${BUILD_SUFFIX}" >> $GITHUB_ENV
echo "NUM_CORES=$(grep processor /proc/cpuinfo | wc -l)" >> $GITHUB_ENV
- name: Build SITL
run: |
mkdir -p build_SITL && cd build_SITL
cmake -DSITL=ON -DWARNINGS_AS_ERRORS=ON -DCMAKE_OSX_ARCHITECTURES="arm64;x86_64" -G Ninja ..
ninja -j4
- name: Strip version number
run: |
for f in build_SITL/*_SITL; do
mv -v $f $(echo $f | sed -Ee 's/_[0-9]+\.[0-9]+\.[0-9]+//')
done
- name: Upload artifacts
uses: actions/upload-artifact@v4
with:
name: ${{ env.BUILD_NAME }}_SITL-MacOS
path: ./build_SITL/*_SITL
build-SITL-Windows:
runs-on: windows-latest
defaults:
run:
shell: C:\tools\cygwin\bin\bash.exe -o igncr '{0}'
steps:
- uses: actions/checkout@v4
- name: Setup Cygwin
uses: egor-tensin/setup-cygwin@v4
with:
packages: cmake ruby ninja gcc-g++ rubygems
- name: Setup environment
env:
ACTIONS_ALLOW_UNSECURE_COMMANDS: true
run: |
# This is the hash of the commit for the PR
# when the action is triggered by PR, empty otherwise
COMMIT_ID=${{ github.event.pull_request.head.sha }}
# This is the hash of the commit when triggered by push
# but the hash of refs/pull/<n>/merge, which is different
# from the hash of the latest commit in the PR, that's
# why we try github.event.pull_request.head.sha first
COMMIT_ID=${COMMIT_ID:-${{ github.sha }}}
BUILD_SUFFIX=ci-$(date '+%Y%m%d')-$(git rev-parse --short ${COMMIT_ID})
VERSION=$( grep project CMakeLists.txt|awk -F VERSION '{ gsub(/[ \t)]/, "", $2); print $2 }' )
echo "BUILD_SUFFIX=${BUILD_SUFFIX}" >> $GITHUB_ENV
echo "BUILD_NAME=inav-${VERSION}-${BUILD_SUFFIX}" >> $GITHUB_ENV
- name: Build SITL
run: gem install getoptlong && mkdir -p build_SITL && cd build_SITL && cmake -DSITL=ON -DWARNINGS_AS_ERRORS=ON -G Ninja .. && ninja -j4
- name: Strip version number
run: |
for f in ./build_SITL/*_SITL.exe; do
mv $f $(echo $f | sed -e 's/_[0-9]\+\.[0-9]\+\.[0-9]\+//')
done
- name: Copy cygwin1.dll
run: cp /bin/cygwin1.dll ./build_SITL/
- name: Upload artifacts
uses: actions/upload-artifact@v4
with:
name: ${{ env.BUILD_NAME }}_SITL-WIN
path: |
./build_SITL/*.exe
./build_SITL/cygwin1.dll
test:
#needs: [build]
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Install dependencies
run: sudo apt-get update && sudo apt-get -y install ninja-build
- name: Run Tests
run: mkdir -p build && cd build && cmake -DTOOLCHAIN=none -G Ninja .. && ninja check
+27
View File
@@ -0,0 +1,27 @@
name: Make sure docs are updated
on:
pull_request:
paths:
- src/main/fc/settings.yaml
- docs/Settings.md
push:
paths:
- src/main/fc/settings.yaml
- docs/Settings.md
jobs:
settings_md:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Install dependencies
run: sudo apt-get update && sudo apt-get -y install python3-yaml
- name: Check that Settings.md is up to date
run: |
cp docs/Settings.md{,.ci}
python3 src/utils/update_cli_docs.py -q
if ! diff -q docs/Settings.md{,.ci} >/dev/null; then
echo "::error ::\"docs/Settings.md\" is not up to date, please run \"src/utils/update_cli_docs.py\""
exit 1
fi
+105
View File
@@ -0,0 +1,105 @@
name: Build pre-release
# Don't enable CI on push, just on PR. If you
# are working on the main repo and want to trigger
# a CI build submit a draft PR.
on:
push:
branches:
- master
- maintenance-8.x.x
- maintenance-9.x
paths:
- 'src/**'
- '.github/**'
- 'cmake/**'
- 'lib/**'
- 'docs/Settings.md'
- 'CMakeLists.txt'
- '*.sh'
jobs:
build:
name: build
uses: ./.github/workflows/ci.yml
release:
name: Release
needs: [build]
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Get version
id: version
run: |
VERSION=$(grep project CMakeLists.txt|awk -F VERSION '{ gsub(/[ \t\)]/, "", $2); print $2 }')
echo "version=${VERSION}" >> $GITHUB_OUTPUT
- name: Get current date
id: date
run: echo "today=$(date '+%Y%m%d')" >> $GITHUB_OUTPUT
- name: download artifacts
uses: actions/download-artifact@v4
with:
path: hexes
pattern: matrix-inav-*
merge-multiple: true
- name: download sitl linux
uses: actions/download-artifact@v4
with:
path: resources/sitl/linux
pattern: inav-*SITL-Linux
merge-multiple: true
- name: download sitl linux aarch64
uses: actions/download-artifact@v4
with:
path: resources/sitl/linux/arm64
pattern: inav-*SITL-Linux-aarch64
merge-multiple: true
- name: download sitl windows
uses: actions/download-artifact@v4
with:
path: resources/sitl/windows
pattern: inav-*SITL-WIN
merge-multiple: true
- name: download sitl mac
uses: actions/download-artifact@v4
with:
path: resources/sitl/macos
pattern: inav-*SITL-MacOS
merge-multiple: true
- name: Consolidate sitl files
run: |
zip -r -9 sitl-resources.zip resources/
- name: Upload release artifacts
uses: softprops/action-gh-release@v2
with:
name: inav-${{ steps.version.outputs.version }}-dev-${{ steps.date.outputs.today }}-${{ github.run_number }}-${{ github.sha }}
tag_name: v${{ steps.version.outputs.version }}-${{ steps.date.outputs.today }}.${{ github.run_number }}
# To create release on a different repo, we need a token setup
token: ${{ secrets.NIGHTLY_TOKEN }}
repository: iNavFlight/inav-nightly
prerelease: true
draft: false
#generate_release_notes: true
make_latest: false
files: |
hexes/*.hex
sitl-resources.zip
body: |
${{ steps.notes.outputs.notes }}
### Flashing
These are nightly builds and configuration settings can be added and removed often. Flashing with Full chip erase is strongly recommended to avoid issues.
Firmware related issues should be opened in the iNavflight/inav repository, not in inav-nightly.
### Repository:
${{ github.repository }} ([link](${{ github.event.repository.html_url }}))
### Branch:
${{ github.ref_name }} ([link](${{ github.event.repository.html_url }}/tree/${{ github.ref_name }}))
### Latest changeset:
${{ github.event.head_commit.id }} ([link](${{ github.event.head_commit.url }}))
### Changes:
${{ github.event.head_commit.message }}
+25
View File
@@ -0,0 +1,25 @@
name: Build firmware
# Don't enable CI on push, just on PR. If you
# are working on the main repo and want to trigger
# a CI build submit a draft PR.
on:
pull_request:
paths-ignore:
- 'src/**'
- '.github/**'
- 'cmake/**'
- 'lib/**'
- 'docs/Settings.md'
- 'CMakeLists.txt'
- '*.sh'
jobs:
test:
#needs: [build]
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Install dependencies
run: sudo apt-get update && sudo apt-get -y install ninja-build
- name: Run Tests
run: mkdir -p build && cd build && cmake -DTOOLCHAIN=none -G Ninja .. && ninja check
+128
View File
@@ -0,0 +1,128 @@
name: Parameter Group Version Check
on:
pull_request:
types: [opened, synchronize, reopened]
branches:
- maintenance-9.x
- maintenance-10.x
paths:
- 'src/**/*.c'
- 'src/**/*.h'
jobs:
check-pg-versions:
runs-on: ubuntu-latest
permissions:
contents: read
pull-requests: write
steps:
- name: Checkout PR code
uses: actions/checkout@v4
with:
fetch-depth: 0 # Need full history to compare with base branch
- name: Fetch base branch
run: |
git fetch origin ${{ github.base_ref }}:refs/remotes/origin/${{ github.base_ref }}
- name: Run PG version check script
id: pg_check
run: |
set +e # Don't fail the workflow, just capture exit code
# Run script and capture output. Exit code 1 is expected for issues.
# The output is captured and encoded to be passed between steps.
output=$(bash .github/scripts/check-pg-versions.sh 2>&1)
exit_code=$?
echo "exit_code=${exit_code}" >> $GITHUB_OUTPUT
echo "output<<EOF" >> $GITHUB_OUTPUT
echo "$output" >> $GITHUB_OUTPUT
echo "EOF" >> $GITHUB_OUTPUT
env:
GITHUB_BASE_REF: ${{ github.base_ref }}
GITHUB_HEAD_REF: ${{ github.head_ref }}
- name: Post comment if issues found
if: steps.pg_check.outputs.exit_code == '1'
uses: actions/github-script@v7
with:
script: |
// Use the captured output from the previous step
const output = '${{ steps.pg_check.outputs.output }}';
let issuesContent = '';
try {
// Extract issues from output (everything after the warning line)
const lines = output.split('\n');
let capturing = false;
let issues = [];
for (const line of lines) {
if (line.includes('###')) {
capturing = true;
}
if (capturing) {
issues.push(line);
}
}
issuesContent = issues.join('\n');
} catch (err) {
console.log('Error capturing issues:', err);
issuesContent = '*Unable to extract detailed issues*';
}
const commentBody = '## ⚠️ Parameter Group Version Check\n\n' +
'The following parameter groups may need version increments:\n\n' +
issuesContent + '\n\n' +
'**Why this matters:**\n' +
'Modifying PG struct fields without incrementing the version can cause settings corruption when users flash new firmware. The `pgLoad()` function validates versions and will use defaults if there\'s a mismatch, preventing corruption.\n\n' +
'**When to increment the version:**\n' +
'- ✅ Adding/removing fields\n' +
'- ✅ Changing field types or sizes\n' +
'- ✅ Reordering fields\n' +
'- ✅ Adding/removing packing attributes\n' +
'- ❌ Only changing default values in `PG_RESET_TEMPLATE`\n' +
'- ❌ Only changing comments\n\n' +
'**Reference:**\n' +
'- [Parameter Group Documentation](../docs/development/parameter_groups/)\n' +
'- Example: [PR #11236](https://github.com/iNavFlight/inav/pull/11236) (field removal requiring version increment)\n\n' +
'---\n' +
'*This is an automated check. False positives are possible. If you believe the version increment is not needed, please explain in a comment.*';
try {
// Check if we already commented
const { data: comments } = await github.rest.issues.listComments({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: context.issue.number,
});
const botComment = comments.find(comment =>
comment.user.login === 'github-actions[bot]' &&
comment.body.includes('Parameter Group Version Check')
);
if (botComment) {
// Update existing comment
await github.rest.issues.updateComment({
owner: context.repo.owner,
repo: context.repo.repo,
comment_id: botComment.id,
body: commentBody
});
console.log('Updated existing PG version check comment');
} else {
// Post new comment
await github.rest.issues.createComment({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: context.issue.number,
body: commentBody
});
console.log('Posted new PG version check comment');
}
} catch (err) {
core.setFailed(`Failed to post comment: ${err}`);
}
@@ -0,0 +1,41 @@
name: PR Branch Suggestion
on:
pull_request_target:
types: [opened]
branches:
- master
jobs:
suggest-branch:
runs-on: ubuntu-latest
permissions:
pull-requests: write
steps:
- name: Suggest maintenance branch
uses: actions/github-script@v7
with:
script: |
const comment = `### Branch Targeting Suggestion
You've targeted the \`master\` branch with this PR. Please consider if a version branch might be more appropriate:
- **\`maintenance-9.x\`** - If your change is backward-compatible and won't create compatibility issues between INAV firmware and Configurator 9.x versions. This will allow your PR to be included in the next 9.x release.
- **\`maintenance-10.x\`** - If your change introduces compatibility requirements between firmware and configurator that would break 9.x compatibility. This is for PRs which will be included in INAV 10.x
If \`master\` is the correct target for this change, no action is needed.
---
*This is an automated suggestion to help route contributions to the appropriate branch.*`;
try {
await github.rest.issues.createComment({
issue_number: context.issue.number,
owner: context.repo.owner,
repo: context.repo.repo,
body: comment
});
} catch (err) {
core.setFailed(`Failed to post suggestion comment: ${err}`);
}
+151
View File
@@ -0,0 +1,151 @@
name: PR Test Builds
# Runs after "Build firmware" completes. Uses workflow_run (rather than
# pull_request directly) so that secrets are available even for PRs from forks.
#
# Requires a repository secret PR_BUILDS_TOKEN with Contents: write access
# to iNavFlight/pr-test-builds (fine-grained PAT or classic PAT with repo scope).
on:
workflow_run:
workflows: ["Build firmware"]
types: [completed]
jobs:
publish:
runs-on: ubuntu-latest
# Only act on pull_request-triggered runs that succeeded.
if: >
github.event.workflow_run.event == 'pull_request' &&
github.event.workflow_run.conclusion == 'success'
# Prevent concurrent runs for the same PR branch racing on the
# release delete/create cycle.
concurrency:
group: pr-test-build-${{ github.event.workflow_run.head_repository.full_name }}-${{ github.event.workflow_run.head_branch }}
cancel-in-progress: true
permissions:
actions: read # to download artifacts from the triggering workflow run
issues: write # github.rest.issues.* endpoints used to post PR comments
pull-requests: write # to post the PR comment
steps:
- name: Download PR number
uses: actions/download-artifact@v4
with:
name: pr-number
run-id: ${{ github.event.workflow_run.id }}
github-token: ${{ secrets.GITHUB_TOKEN }}
- name: Read PR number
id: pr
run: |
PR_NUM=$(tr -dc '0-9' < pr_number.txt)
if [ -z "$PR_NUM" ]; then
echo "::error::Invalid PR number in artifact"
exit 1
fi
echo "number=${PR_NUM}" >> $GITHUB_OUTPUT
- name: Download firmware artifacts
uses: actions/download-artifact@v4
with:
pattern: matrix-inav-*
merge-multiple: true
path: hexes
run-id: ${{ github.event.workflow_run.id }}
github-token: ${{ secrets.GITHUB_TOKEN }}
- name: Get build info
id: info
run: |
COUNT=$(find hexes -name '*.hex' -type f | wc -l)
if [ "$COUNT" -eq 0 ]; then
echo "::error::No .hex files found in downloaded artifacts"
exit 1
fi
echo "count=${COUNT}" >> $GITHUB_OUTPUT
echo "short_sha=$(echo '${{ github.event.workflow_run.head_sha }}' | cut -c1-7)" >> $GITHUB_OUTPUT
# Delete the previous release for this PR (if any) so assets are replaced
# cleanly on each new commit. --cleanup-tag removes the old tag so it is
# recreated fresh pointing to the new commit.
- name: Delete existing PR release
env:
GH_TOKEN: ${{ secrets.PR_BUILDS_TOKEN }}
run: |
gh release delete "pr-${{ steps.pr.outputs.number }}" \
--repo iNavFlight/pr-test-builds --cleanup-tag --yes 2>/dev/null || true
- name: Create PR release
env:
GH_TOKEN: ${{ secrets.PR_BUILDS_TOKEN }}
PR_NUMBER: ${{ steps.pr.outputs.number }}
SHORT_SHA: ${{ steps.info.outputs.short_sha }}
HEX_COUNT: ${{ steps.info.outputs.count }}
REPO: ${{ github.repository }}
run: |
PR_URL="https://github.com/${REPO}/pull/${PR_NUMBER}"
printf '%s\n\n%s\n\n%s\n' \
"Test build for [PR #${PR_NUMBER}](${PR_URL}) — commit \`${SHORT_SHA}\`" \
"**${HEX_COUNT} targets built.** Find your board's \`.hex\` file by name (e.g. \`MATEKF405SE.hex\`)." \
"> Development build for testing only. Use Full Chip Erase when flashing." \
> release-notes.md
gh release create "pr-${PR_NUMBER}" hexes/*.hex \
--repo iNavFlight/pr-test-builds \
--prerelease \
--title "PR #${PR_NUMBER} (${SHORT_SHA})" \
--notes-file release-notes.md
- name: Post or update PR comment
uses: actions/github-script@v7
env:
PR_NUMBER: ${{ steps.pr.outputs.number }}
SHORT_SHA: ${{ steps.info.outputs.short_sha }}
HEX_COUNT: ${{ steps.info.outputs.count }}
with:
script: |
const prNumber = parseInt(process.env.PR_NUMBER, 10);
if (isNaN(prNumber)) throw new Error(`Invalid PR number: ${process.env.PR_NUMBER}`);
const shortSha = process.env.SHORT_SHA;
const count = process.env.HEX_COUNT;
const releaseUrl = `https://github.com/iNavFlight/pr-test-builds/releases/tag/pr-${prNumber}`;
const body = [
'<!-- pr-test-build -->',
'**Test firmware build ready** — commit `' + shortSha + '`',
'',
`[Download firmware for PR #${prNumber}](${releaseUrl})`,
'',
`${count} targets built. Find your board's \`.hex\` file by name on that page ` +
'(e.g. `MATEKF405SE.hex`). Files are individually downloadable — no GitHub login required.',
'',
'> Development build for testing only. Use Full Chip Erase when flashing.',
].join('\n');
const comments = await github.paginate(
github.rest.issues.listComments,
{
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: prNumber,
}
);
const existing = comments.find(c =>
c.user.type === 'Bot' && c.body.includes('<!-- pr-test-build -->')
);
if (existing) {
await github.rest.issues.updateComment({
owner: context.repo.owner,
repo: context.repo.repo,
comment_id: existing.id,
body,
});
} else {
await github.rest.issues.createComment({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: prNumber,
body,
});
}