ci: nightly develop build published to github.io firmware-nightly/ (#10957)
Adds a scheduled (09:00 UTC) run of the CI build off develop that does everything a workflow_dispatch build does except create a GitHub release. Instead it refreshes a single, stable firmware-nightly/ folder on meshtastic.github.io with the current develop build, leaving that folder's hand-maintained release_notes.md untouched so it can be edited manually. On a nightly run (the schedule, or a manual nightly=true dispatch) only the firmware build + gather-artifacts + the new publish-nightly job run; the tests/docker/wasm/macOS/debian-src/size jobs and the three release jobs are skipped, so no release or tag is created. publish-nightly downloads the per-board artifacts, generates the firmware-<version>.json release manifest and an index.json version pointer (read by the web-flasher), then publishes to firmware-nightly/ via the same peaceiris/actions-gh-pages action used for releases. keep_files:false is scoped to destination_dir, so it clears stale nightly binaries while leaving sibling release folders untouched; the hand-maintained release_notes.md is fetched and carried forward first (fail-closed) so it is never clobbered.
This commit is contained in:
@@ -26,7 +26,19 @@ on:
|
||||
- "**.md"
|
||||
#- "**.yml"
|
||||
|
||||
schedule:
|
||||
# Nightly develop build, published to meshtastic.github.io firmware-nightly/ (no GitHub release).
|
||||
# Scheduled runs execute on the default branch (develop). 09:00 UTC avoids the 00:00 tests
|
||||
# and 02:00 daily_packaging crons.
|
||||
- cron: 0 9 * * * # Nightly develop build/publish (default branch is develop)
|
||||
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
# trunk-ignore(checkov/CKV_GHA_7): intentional manual-test switch for the nightly publish path
|
||||
nightly:
|
||||
description: "Nightly mode: build + publish develop to github.io firmware-nightly/ (skips creating a GitHub release)"
|
||||
type: boolean
|
||||
default: false
|
||||
|
||||
permissions: read-all
|
||||
|
||||
@@ -85,7 +97,7 @@ jobs:
|
||||
# Runs on GitHub-hosted runners so checks don't compete with builds for the
|
||||
# self-hosted 'arctastic' pool (which builds use).
|
||||
runs-on: ubuntu-latest
|
||||
if: ${{ github.event_name != 'workflow_dispatch' && github.repository == 'meshtastic/firmware' }}
|
||||
if: ${{ github.event_name != 'workflow_dispatch' && github.repository == 'meshtastic/firmware' && github.event_name != 'schedule' && github.event.inputs.nightly != 'true' }}
|
||||
steps:
|
||||
- uses: actions/checkout@v7
|
||||
with:
|
||||
@@ -110,7 +122,7 @@ jobs:
|
||||
platform: ${{ matrix.build.platform }}
|
||||
|
||||
build-debian-src:
|
||||
if: github.repository == 'meshtastic/firmware'
|
||||
if: ${{ github.repository == 'meshtastic/firmware' && github.event_name != 'schedule' && github.event.inputs.nightly != 'true' }}
|
||||
uses: ./.github/workflows/build_debian_src.yml
|
||||
with:
|
||||
series: UNRELEASED
|
||||
@@ -118,6 +130,7 @@ jobs:
|
||||
secrets: inherit
|
||||
|
||||
MacOS:
|
||||
if: ${{ github.event_name != 'schedule' && github.event.inputs.nightly != 'true' }}
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
@@ -139,7 +152,7 @@ jobs:
|
||||
secrets: inherit
|
||||
|
||||
test-native:
|
||||
if: ${{ !contains(github.ref_name, 'event/') && github.repository == 'meshtastic/firmware' }}
|
||||
if: ${{ !contains(github.ref_name, 'event/') && github.repository == 'meshtastic/firmware' && github.event_name != 'schedule' && github.event.inputs.nightly != 'true' }}
|
||||
permissions: # Needed for dorny/test-reporter.
|
||||
contents: read
|
||||
actions: read
|
||||
@@ -147,6 +160,7 @@ jobs:
|
||||
uses: ./.github/workflows/test_native.yml
|
||||
|
||||
build-wasm:
|
||||
if: ${{ github.event_name != 'schedule' && github.event.inputs.nightly != 'true' }}
|
||||
# Build the WebAssembly portduino node ([env:native-wasm]) as part of normal CI,
|
||||
# like the other platforms. It's a dedicated job (not a row in the `build`
|
||||
# matrix) because its artifact is meshnode.{mjs,wasm} - not a flashable
|
||||
@@ -155,6 +169,7 @@ jobs:
|
||||
uses: ./.github/workflows/build_portduino_wasm.yml
|
||||
|
||||
docker:
|
||||
if: ${{ github.event_name != 'schedule' && github.event.inputs.nightly != 'true' }}
|
||||
permissions: # Needed for pushing to GHCR.
|
||||
contents: read
|
||||
packages: write
|
||||
@@ -255,7 +270,7 @@ jobs:
|
||||
retention-days: 30
|
||||
|
||||
firmware-size-report:
|
||||
if: github.repository == 'meshtastic/firmware'
|
||||
if: ${{ github.repository == 'meshtastic/firmware' && github.event_name != 'schedule' && github.event.inputs.nightly != 'true' }}
|
||||
continue-on-error: true
|
||||
permissions:
|
||||
contents: read
|
||||
@@ -379,6 +394,7 @@ jobs:
|
||||
# exceeds its static RAM (.data+.bss) or flash budget. Kept separate from
|
||||
# firmware-size-report, which is informational and continue-on-error.
|
||||
size-budget-gate:
|
||||
if: ${{ github.event_name != 'schedule' && github.event.inputs.nightly != 'true' }}
|
||||
permissions:
|
||||
contents: read
|
||||
actions: read
|
||||
@@ -407,7 +423,7 @@ jobs:
|
||||
permissions: # Needed for 'gh release upload'.
|
||||
contents: write
|
||||
runs-on: ubuntu-latest
|
||||
if: ${{ github.event_name == 'workflow_dispatch' && github.repository == 'meshtastic/firmware' }}
|
||||
if: ${{ github.event_name == 'workflow_dispatch' && github.repository == 'meshtastic/firmware' && github.event.inputs.nightly != 'true' }}
|
||||
outputs:
|
||||
upload_url: ${{ steps.create_release.outputs.upload_url }}
|
||||
needs:
|
||||
@@ -516,7 +532,7 @@ jobs:
|
||||
- rp2350
|
||||
- stm32
|
||||
runs-on: ubuntu-latest
|
||||
if: ${{ github.event_name == 'workflow_dispatch' && github.repository == 'meshtastic/firmware'}}
|
||||
if: ${{ github.event_name == 'workflow_dispatch' && github.repository == 'meshtastic/firmware' && github.event.inputs.nightly != 'true' }}
|
||||
needs: [release-artifacts, version]
|
||||
steps:
|
||||
- name: Checkout
|
||||
@@ -568,7 +584,7 @@ jobs:
|
||||
|
||||
publish-firmware:
|
||||
runs-on: ubuntu-24.04
|
||||
if: ${{ github.event_name == 'workflow_dispatch' }}
|
||||
if: ${{ github.event_name == 'workflow_dispatch' && github.event.inputs.nightly != 'true' }}
|
||||
needs: [release-firmware, version]
|
||||
env:
|
||||
targets: |-
|
||||
@@ -620,3 +636,78 @@ jobs:
|
||||
user_email: github-actions[bot]@users.noreply.github.com
|
||||
commit_message: ${{ needs.version.outputs.long }}
|
||||
enable_jekyll: true
|
||||
|
||||
# Nightly publish: refresh the single, stable firmware-nightly/ folder on
|
||||
# meshtastic.github.io with the current develop build. Runs on the cron schedule
|
||||
# (or a manual nightly=true dispatch) and never creates a GitHub release. The
|
||||
# folder's release_notes.md is maintained by hand and deliberately left untouched.
|
||||
publish-nightly:
|
||||
runs-on: ubuntu-24.04
|
||||
if: ${{ (github.event_name == 'schedule' || github.event.inputs.nightly == 'true') && github.repository == 'meshtastic/firmware' }}
|
||||
needs: [setup, version, gather-artifacts]
|
||||
env:
|
||||
targets: |-
|
||||
esp32,esp32s3,esp32c3,esp32c6,nrf52840,rp2040,rp2350,stm32
|
||||
steps:
|
||||
- name: Get firmware artifacts
|
||||
uses: actions/download-artifact@v8
|
||||
with:
|
||||
pattern: firmware-{${{ env.targets }}}-${{ needs.version.outputs.long }}
|
||||
merge-multiple: true
|
||||
path: ./stage
|
||||
|
||||
- name: Generate Release manifest
|
||||
run: |
|
||||
jq -n --arg ver "${{ needs.version.outputs.long }}" --argjson targets ${{ toJson(needs.setup.outputs.all) }} '{
|
||||
"version": $ver,
|
||||
"targets": $targets
|
||||
}' > ./stage/firmware-${{ needs.version.outputs.long }}.json
|
||||
|
||||
- name: Generate nightly pointer
|
||||
run: |
|
||||
jq -n \
|
||||
--arg ver "${{ needs.version.outputs.long }}" \
|
||||
--arg sha "${{ github.sha }}" \
|
||||
'{version: $ver, id: ("v" + $ver), title: ("Meshtastic Firmware " + $ver + " Nightly"), commit: $sha}' \
|
||||
> ./stage/index.json
|
||||
|
||||
- name: Preserve manually-maintained release notes
|
||||
# firmware-nightly/release_notes.md is edited by hand. Carry the current
|
||||
# copy into ./stage so the keep_files:false publish (which refreshes the
|
||||
# folder and clears stale nightly binaries) does not drop it. Seed a
|
||||
# placeholder on the first run (404); fail closed on any other error so a
|
||||
# transient fetch failure never clobbers the notes.
|
||||
run: |
|
||||
set -euo pipefail
|
||||
url=https://raw.githubusercontent.com/meshtastic/meshtastic.github.io/master/firmware-nightly/release_notes.md
|
||||
code=$(curl -sSL -o ./stage/release_notes.md -w '%{http_code}' --retry 5 --retry-all-errors "$url" || echo 000)
|
||||
if [ "$code" = "200" ]; then
|
||||
echo "Preserved existing release_notes.md"
|
||||
elif [ "$code" = "404" ]; then
|
||||
echo "No existing release_notes.md; seeding placeholder"
|
||||
printf '# Nightly (develop)\n\nAutomated nightly build from the `develop` branch. Edit these notes by hand.\n' > ./stage/release_notes.md
|
||||
else
|
||||
echo "Unexpected HTTP $code fetching release_notes.md; refusing to publish to avoid clobbering manual notes"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# For diagnostics
|
||||
- name: Display structure of files to publish
|
||||
run: ls -lR ./stage
|
||||
|
||||
- name: Publish nightly to meshtastic.github.io
|
||||
uses: peaceiris/actions-gh-pages@v4
|
||||
with:
|
||||
deploy_key: ${{ secrets.DIST_PAGES_DEPLOY_KEY }}
|
||||
external_repository: meshtastic/meshtastic.github.io
|
||||
publish_branch: master
|
||||
publish_dir: ./stage
|
||||
# keep_files:false is scoped to destination_dir, so this refreshes only
|
||||
# firmware-nightly/ (clearing stale nightly binaries) while sibling
|
||||
# release folders stay untouched; release_notes.md is carried in above.
|
||||
destination_dir: firmware-nightly
|
||||
keep_files: false
|
||||
user_name: github-actions[bot]
|
||||
user_email: github-actions[bot]@users.noreply.github.com
|
||||
commit_message: Nightly ${{ needs.version.outputs.long }}
|
||||
enable_jekyll: true
|
||||
|
||||
Reference in New Issue
Block a user