-
-
Notifications
You must be signed in to change notification settings - Fork 4.5k
ci: Comprehensive GitHub Actions improvements #13813
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Conversation
- Uncomment CodeQL init and analyze steps in linux.yml (Debug builds) - Add zizmor pre-commit hook for GitHub Actions security scanning
Add --unittest-output CLI option to generate JUnit XML test results: - QGCCommandLineParser: Add --unittest-output <file> option - UnitTest::run(): Pass -o flag to QTest::qExec() when output specified - UnitTestList::runTests(): Thread output file parameter through Update linux.yml CI workflow: - Use --unittest-output to generate junit-results.xml - Add dorny/test-reporter for PR test visualization - Activate trunk.io flaky test detection (requires TRUNK_ORG_SLUG/TOKEN) - Include JUnit XML in test artifacts
Upload action improvements: - Add retention_days input (default: 7 for PRs, 30 for pushes) - Add compression_level input (use 0 for pre-compressed binaries) Linux workflow: - Dynamic test artifact retention (3 days for PRs, 14 for pushes) - Add unity_build workflow_dispatch input (experimental, opt-in) - Unity Build uses batch size 16 for optimal parallelization Note: Submodule caching skipped - QGC has no submodules
- Replace actions/setup-java gradle cache with gradle/actions/setup-gradle@v4 - Add cache-read-only for PR builds (save storage) - Enable gradle-home-cache-cleanup to remove stale entries - Add GRADLE_OPTS to enable configuration cache and build caching NDK caching already in place via nttld/setup-ndk with local-cache: true
Restore file timestamps from git history after checkout to improve ccache hit rates. Without this, all files appear modified at checkout time, causing ccache misses on unchanged files. Changes: - Add chetan/git-restore-mtime-action@v2 to ios.yml and macos.yml - Use fetch-depth: 0 (required for mtime restoration)
Merge queue support: - Add merge_group trigger to linux, windows, macos, android workflows - Enables GitHub merge queue for automated PR merging SBOM attestation: - Add actions/attest-sbom@v3 for release artifacts (AppImage, DMG, EXE, APK) - Uses SPDX SBOM generated by anchore/sbom-action - Add job-level permissions (id-token, attestations) for signing
Refactor release workflow for manual version control: - Trigger on tag push (v*) instead of workflow_dispatch - Remove semantic-release job and Node.js dependency - Remove tools/release.sh (no longer needed) - Simplify to: wait-for-builds → upload-artifacts Flow: push tag → platform builds run → release workflow waits → downloads artifacts → generates SBOMs → attests → uploads to release
Clazy workflow (workflow_dispatch): - Input: path to analyze (file or directory) - Option to analyze all source files - Generates compile_commands.json then runs clazy - Uses tools/analyze.sh for consistent analysis Sanitizers workflow (workflow_dispatch): - Choice of ASAN, UBSAN, TSAN, or ASAN+UBSAN - Debug build with sanitizer flags - Runs unit tests and checks for sanitizer errors - Uploads output as artifact for debugging
Manual workflow_dispatch trigger for IWYU analysis: - Optional path input to analyze specific directories - Uses Clang compiler with cmake/modules/IWYU.cmake - Outputs include suggestions to artifact - Useful for cleaning up unnecessary #includes Note: Qt generates many false positives, review suggestions carefully
Skip unnecessary Docker builds on PRs when only one platform's files changed: - If only android/** changes, skip Linux Docker build (~2 hours saved) - If only deploy/linux/** changes, skip Android Docker build - If shared files (src/**, cmake/**) change, build both platforms Uses dorny/paths-filter@v3 to detect which paths changed, then conditionally skips build steps for unaffected platforms.
Consolidate repeated setup steps into a reusable composite action: - Harden Runner - Checkout with configurable fetch-depth - build-config - common - cache - qt-install Applied to linux.yml, windows.yml, macos.yml workflows. Reduces duplication by ~79 lines across workflows. Platform-specific steps (dependencies, Xcode, MSVC, CodeQL, packaging) remain in individual workflows.
Add manual dispatch workflows to build GStreamer with only the plugins needed for QGC video streaming (RTSP, RTP, UDP, H.264/H.265, MPEG-TS, Qt6 integration). Workflows: - build-gstreamer-windows.yml: Native and cross-compile for x64/ARM64 - build-gstreamer-macos.yml: Universal, ARM64, or x86_64 builds - build-gstreamer-linux.yml: x86_64 and aarch64 builds - build-gstreamer-ios.yml: Device and simulator builds via Cerbero - build-gstreamer-android.yml: All ABIs via Cerbero Build scripts in tools/setup/gstreamer/: - Windows uses Meson with MSVC, supports ARM64 cross-compilation - macOS uses Meson with universal binary support via lipo - Linux uses Meson with VA-API and Wayland support - iOS/Android use GStreamer's Cerbero build system Features: - Version configurable or read from build-config.json - Artifacts uploaded to GitHub (30 days) and S3 - Qt6 integration for qml6 video sink plugin - Minimal plugin set reduces binary size Also updates: - src/pch.h: Optimize precompiled header includes - install-dependencies-windows.ps1: ARM64 GStreamer support
Add workflow that tracks reliable size metrics and optional runtime benchmarks using benchmark-action/github-action-benchmark. Size metrics (reliable, no variance): - Binary size (raw and stripped) - Symbol count - Section sizes via `size -A` - Top symbols and compilation units via bloaty Runtime benchmarks (optional, on push to master): - Catch2 benchmarks if available - Falls back to startup time measurement - 150% threshold for alerts (accounts for runner variance) Features: - Charts published to GitHub Pages at /dev/size and /dev/bench - PR comments on size regressions >5% - Only runs on src/cmake changes - Manual dispatch option to force benchmark run Note: Runtime benchmarks have ~3x variance on shared runners. Size metrics are the reliable indicator for tracking bloat.
Add Qt Test benchmarks for core MAVLink operations: - benchmarkHeartbeatPack: Pack heartbeat message (most frequent) - benchmarkHeartbeatUnpack: Unpack heartbeat message - benchmarkAttitudePack: Pack attitude (high-frequency telemetry) - benchmarkAttitudeUnpack: Unpack attitude - benchmarkGpsRawPack: Pack GPS raw (complex payload) - benchmarkMessageRoundTrip: Full pack + CRC + unpack cycle - benchmarkParseByteStream: Parse message from byte stream Run locally with: ./QGroundControl --unittest:MAVLinkBenchmark Updates performance.yml workflow to: - Run MAVLinkBenchmark on push to master - Parse Qt Test QBENCHMARK output to JSON - Track results via github-action-benchmark These benchmarks measure operations critical for real-time vehicle communication. Results are normalized to microseconds per iteration.
- Enable ccache by default for Linux, macOS, Android, iOS - Enable sccache by default for Windows - Remove separate ccache/sccache preset variants - Keep only essential presets: release, debug, coverage (Linux) - Add usage documentation to CMakePresets.json.template - Add platform conditions to show relevant presets only
- Downgrade CMake preset version from 6 to 5 for Qt Creator compatibility - Comment out relative paths in ccache.conf (CMake sets via env vars) The relative paths caused ccache errors when IDEs loaded the config directly without CMake's environment variable overrides.
Workflow consolidation (~320 lines saved): - Merge clazy/iwyu/sanitizers into single analysis.yml with tool selector - Merge 5 GStreamer build workflows into single build-gstreamer.yml - Merge Crowdin upload/download into single crowdin.yml Security and reliability: - Add harden-runner to GStreamer and performance workflows - Add timeout-minutes to performance.yml jobs (60/90 min) - Use build-config and qt-install actions in performance.yml - Standardize artifact retention-days (flatpak.yml: 14 days) - Enable iOS workflow on push/PR (was manual-only, never tested) The consolidated workflows use conditional jobs based on input parameters, reducing duplication while maintaining platform-specific configurations.
GStreamer build consolidation: - Merge 5 duplicate jobs (640 lines) into single parameterized job (98 lines) - Create unified gstreamer action handling all platforms - Dynamic runner selection based on platform/arch inputs - Single action handles: deps, Qt, build, verify, archive, S3 upload, summary Python setup consolidation: - Add tools/pyproject.toml with dependency groups (ci, qt, coverage, dev, lsp) - Add tools/setup/install-python.sh for local development (uses uv or pip) - Add setup-python composite action that calls the script - Skip pip installs in Qt/GStreamer scripts if tools already available Action simplifications: - build-config: Use read-config.sh --github-output (125→67 lines) - install-dependencies: Use nick-fields/retry@v3 (115→85 lines) - read-config.sh: Add --github-output and --get modes Total reduction: ~300 lines removed, improved maintainability
- Add aws_role_arn input to aws-upload and upload actions - Both OIDC and static credentials work via conditional steps - OIDC preferred when AWS_ROLE_ARN secret exists, falls back to static - Update all platform workflows to pass aws_role_arn - Reduce GStreamer build timeout from 180 to 120 minutes Migration: Once AWS IAM role is configured, add AWS_ROLE_ARN secret and optionally remove AWS_ACCESS_KEY_ID/AWS_SECRET_ACCESS_KEY.
Remove redundant content and streamline documentation for tools/, tools/coding-style/, and tools/qtcreator/ directories.
- Add CPMUsePackageLock() to CMakeLists.txt - Generate and commit package-lock.cmake with versioned dependencies - Update cache action to hash only lock file instead of all CMake files This eliminates spurious cache invalidation when CMake files change without affecting dependencies. Update lock with: cmake --build build --target cpm-update-package-lock
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pull request overview
This is a comprehensive GitHub Actions infrastructure overhaul focused on security, performance, and maintainability improvements for the QGroundControl CI/CD pipeline.
Key Changes:
- Security: AWS OIDC authentication, SBOM attestations, harden-runner, CodeQL/zizmor scanning, action version standardization (@v6)
- Performance: CPM package lock caching (cache only on dependency changes), ARM64 ccache support, GStreamer workflow consolidation (614→98 lines), retry wrappers for network failures
- New Capabilities: GStreamer build-from-source workflows for all platforms, performance metrics tracking, MAVLink benchmarks, JUnit XML test output with GitHub annotations
Reviewed changes
Copilot reviewed 64 out of 65 changed files in this pull request and generated 3 comments.
Show a summary per file
| File | Description |
|---|---|
tools/setup/read-config.sh |
Added --github-output mode for CI integration |
tools/setup/install-python.sh |
New unified Python environment setup with uv support |
tools/setup/install-qt-*.{sh,ps1} |
Skip reinstallation if aqtinstall exists (venv optimization) |
tools/setup/install-dependencies-windows.ps1 |
ARM64 GStreamer support via ZIP archives |
tools/setup/gstreamer/build-gstreamer-*.{sh,ps1} |
New cross-platform GStreamer build scripts |
package-lock.cmake |
CPM dependency lock file for stable caching |
cmake/presets/*.json |
Consolidated presets, downgraded version 6→5, added ARM64 variants |
test/**/UnitTest.* |
JUnit XML output support |
test/MAVLink/MAVLinkBenchmark.* |
New MAVLink performance benchmarks |
src/pch.h |
Optimized precompiled headers |
.github/workflows/*.yml |
Security hardening, performance tracking, consolidation |
.github/actions/build-setup/ |
New composite action consolidating setup steps |
.github/actions/gstreamer/ |
Comprehensive GStreamer build action |
.github/actions/cache/ |
ARM64 ccache, CPM lock-based caching |
.github/actions/aws-upload/ |
OIDC authentication support |
tools/README.md |
Condensed documentation |
.pre-commit-config.yaml |
Added zizmor security scanning |
| @@ -1,37 +1,25 @@ | |||
| { | |||
| "version": 6, | |||
| "version": 5, | |||
Copilot
AI
Dec 27, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Downgrading CMake presets from version 6 to version 5 may lose features. CMake 3.25 (specified in cmakeMinimumRequired) supports preset version 5, but newer CMake versions support version 6 with additional features. Verify that no version 6-specific features are needed, or document why the downgrade is necessary.
.github/actions/cache/action.yml
Outdated
| key: ${{ github.workflow }}-cpm-modules-${{ hashFiles('**/CMakeLists.txt', '**/*.cmake') }} | ||
| restore-keys: ${{ github.workflow }}-cpm-modules- | ||
| key: ${{ github.workflow }}-cpm-${{ hashFiles('package-lock.cmake') }} | ||
| restore-keys: ${{ github.workflow }}-cpm- |
Copilot
AI
Dec 27, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The cache key now depends only on package-lock.cmake instead of all CMakeLists.txt and .cmake files. This is a significant improvement for cache hit rates, but ensure that the CPM lock file is properly updated when dependencies change. Consider adding a CI check or pre-commit hook to verify package-lock.cmake is in sync with dependency declarations.
| restore-keys: ${{ github.workflow }}-cpm- |
| wait-for-builds: | ||
| name: Wait for Platform Builds | ||
| runs-on: ubuntu-latest | ||
| timeout-minutes: 15 | ||
| outputs: | ||
| new_release: ${{ steps.release.outputs.new_release }} | ||
| version: ${{ steps.release.outputs.version }} | ||
| timeout-minutes: 180 | ||
|
|
||
| steps: | ||
| - name: Harden Runner | ||
| uses: step-security/harden-runner@v2 | ||
| with: | ||
| egress-policy: audit | ||
|
|
||
| - name: Checkout | ||
| uses: actions/checkout@v6 | ||
| with: | ||
| fetch-depth: 0 | ||
| persist-credentials: false | ||
|
|
||
| - name: Setup Node.js | ||
| uses: actions/setup-node@v6 | ||
| with: | ||
| node-version: 'lts/*' | ||
|
|
||
| - name: Run semantic-release | ||
| id: release | ||
| env: | ||
| GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} | ||
| run: | | ||
| ./tools/release.sh --install | ||
| # Capture semantic-release output | ||
| set +e | ||
| OUTPUT=$(./tools/release.sh --run 2>&1) | ||
| EXIT_CODE=$? | ||
| echo "$OUTPUT" | ||
| set -e | ||
| # Check if a new release was created | ||
| if echo "$OUTPUT" | grep -q "Published release"; then | ||
| VERSION=$(printf '%s\n' "$OUTPUT" | sed -n 's/.*Published release \([0-9]\+\.[0-9]\+\.[0-9]\+\).*/\1/p' | head -n1) | ||
| echo "new_release=true" >> $GITHUB_OUTPUT | ||
| echo "version=$VERSION" >> $GITHUB_OUTPUT | ||
| echo "New release: v$VERSION" | ||
| else | ||
| echo "new_release=false" >> $GITHUB_OUTPUT | ||
| echo "No new release" | ||
| fi | ||
| wait-for-builds: | ||
| name: Wait for Platform Builds | ||
| needs: semantic-release | ||
| if: needs.semantic-release.outputs.new_release == 'true' | ||
| runs-on: ubuntu-latest | ||
| timeout-minutes: 180 | ||
|
|
||
| steps: | ||
| - name: Wait for builds to complete | ||
| uses: int128/wait-for-workflows-action@v1 | ||
| with: |
Copilot
AI
Dec 27, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The release workflow no longer validates that semantic-release created a new release before waiting for builds. This means the workflow will wait for builds even if no release was created. Consider adding a check to skip the wait-for-builds step if the tag doesn't trigger any platform builds, or document that this is intentional for manual tag pushes.
- Create qt-ios composite action (replaces 7 steps with 1) - Create test-report composite action for unified test reporting - Refactor qt-android to use qt-install composite action - Refactor gstreamer action to use qt-install instead of direct jurplel - Update all platform workflows to use install-dependencies action - Add restore-timestamps option to build-setup action - Add --autodesktop flag to Qt install scripts for cross-compilation - Add libpulse-dev to Linux dependencies (audio support) - Consolidate ccache install steps with arch parameterization - Add minisign verification for ccache binaries (supply chain security) - Update ccache to 4.12.2 - Fix shell quoting in gstreamer action (use env vars) - Fix GSTREAMER_MACOS_VERSION variable name in macOS script - Add CMakeLists.txt to CPM cache key - Add logs/ to gitignore (puppeteer MCP)
Security (H2): - Add step-security/harden-runner to 10 utility workflows - Consistent security hardening across all workflows New actions (M1): - Create checkout-setup composite action with optional harden-runner and initial-setup flags for flexible reuse Reliability (M3): - Add nick-fields/retry to gstreamer apt-get steps (Linux, Android) - Consistent retry behavior across all dependency installations Consolidation (M4, M5, M6): - Update performance.yml to use install-dependencies action - Update analysis.yml to use install-dependencies for iwyu/sanitizers - Update custom-build.yml to use install-dependencies action - Reduces code duplication and ensures consistent retry behavior
Local composite actions require the repository to be checked out before they can be used. The build-setup action contains checkout but can't be invoked until checkout happens first. Fixes: - Linux, MacOS, Windows workflows: Add checkout step before build-setup - setup-python action: Set cache-dependency-glob="" since no uv.lock exists This resolves "Can't find action.yml" errors in CI.
GitHub Actions composite actions do not support pre/post execution hooks. The step-security/harden-runner action uses these hooks, causing "'pre' execution is not supported for local action" errors. Fixes: - Remove harden-runner from build-setup and checkout-setup actions (workflows already have harden-runner at job level) - Change qt-install to use setup-python: true so jurplel/install-qt-action manages its own Python with aqtinstall, instead of using project venv
Fixes: - Skip sccache for Windows ARM64 (no binaries available, 404 error) - Use ccache instead of sccache for Windows ARM64 native builds - Download minisign from GitHub releases instead of apt (not in Ubuntu repos) - Handle both x86_64 and aarch64 minisign binaries for Linux builds - Explicitly set CMAKE_OSX_ARCHITECTURES=arm64 for iOS to avoid x86_64h
- Remove gstreamer_good_plugins from package-lock.cmake to allow version to match per-platform GStreamer binaries (Android uses 1.22.12, others use 1.24.13). Locking caused header mismatches where 1.24.13 sources required gst-plugins-bad headers not in 1.22.12 Android binaries. - Fix iOS x86_64h architecture error by using CMake initial cache file to set CMAKE_OSX_ARCHITECTURES before platform detection. CMake 4.x on ARM Macs defaults to multi-arch builds including x86_64h which doesn't exist for iOS. - Fix bloaty installation in performance workflow by building from source since it's not in Ubuntu apt repositories. Includes timeout to prevent CI hangs.
iOS: - Pass CMAKE_OSX_ARCHITECTURES directly on command line instead of via -C cache file. CMake 4.x runs platform detection before processing cache files, causing it to try building for x86_64h on ARM Macs. Command-line -D options take precedence and are applied earlier. Size Metrics: - Fix binary path from build/QGroundControl to build/Release/QGroundControl. With CMAKE_BUILD_TYPE=Release, CMake places the binary in a Release/ subdirectory. Add fallback to handle both paths. - Fix the same path issue in Bloaty analysis and benchmarks steps.
CMake: - Pin to CMake 3.31.6 in common action. CMake 4.x has breaking changes for Apple platforms causing x86_64h architecture detection issues on ARM runners. This fixes both iOS and macOS builds. macOS: - Add explicit CMAKE_OSX_ARCHITECTURES=arm64 for extra robustness. Performance: - Add continue-on-error to PR comparison step since gh-pages branch may not exist yet (first run of size metrics).
879d2b7 to
8343711
Compare
Use qt-cmake directly without architecture overrides or toolchain wrappers. Let Qt's toolchain handle platform detection natively.
8343711 to
79e6cdf
Compare
- Fix coverage/action.yml path to coverage-comment.py script - Remove unused checkout-setup action (checkout must be in workflow) - Inline coverage-comment functionality into coverage action - Use build-setup in custom-build workflow instead of manual steps - Delete checkout-setup and coverage-comment actions (no references)
- size-metrics uploads the built binary as artifact - benchmarks downloads binary instead of rebuilding - Reduces benchmarks timeout from 90 to 30 minutes - Saves ~30 minutes of redundant build time
Phase 1 - Bug fixes: - Fix coverage.sh XML_ONLY logic bug (both branches were identical) - Add get_default_branch() to common.sh for dynamic branch detection - Fix configure.sh unsafe glob expansion (ls -d $pattern) - Add error verification to qgc-lupdate.sh Phase 2 - Consolidation (~1,630 lines removed): - Delete 4 legacy gstreamer shell scripts (build-gstreamer.py is unified) - Extend install-qt.py with Android/iOS support, convert shell to wrappers - Simplify read-config.sh (153→41 lines) and read-config.ps1 (174→72 lines) - Consolidate logging: configure.sh, run-tests.sh, profile.sh now source common.sh Phase 3 - Infrastructure: - Add tools/smoke-test.sh for end-to-end tool validation - Add --timeout option to profile.sh (prevents CI hangs) - Improve clean.sh --dry-run with sizes and summary - Add tools/lint-fix.sh for auto-applying formatting fixes Architecture: Python as single source of truth with thin shell wrappers.
Phase 2 - Cleanup & Consistency: - Rename param-docs.py → param_docs.py, update-headers.py → update_headers.py - Delete build-gstreamer-windows.ps1 (Python handles Windows) - Fix relative paths in coverage action to use github.workspace Phase 3 - Platform Portability: - Add CCACHE_PREFIX env var override in install_ccache.py - Add GSTREAMER_PREFIX env var override in gstreamer_archive.py - Add Linux/macOS AWS CLI installation support - Add run_command() helper for better subprocess error output Phase 4 - Testing & Documentation: - Add unit tests for install_ccache.py (10 tests) - Add unit tests for gstreamer_archive.py (14 tests) - Add unit tests for generate-matrix.py (6 tests) - Create .github/scripts/README.md documenting CI scripts - Update tools/README.md with Python-first script listing - Add pyproject.toml entry points for CLI tools - Add .envrc for direnv development environment
The generated translation file belongs in translations/, not tools/translations/. Accidentally committed during the tools overhaul.
- Remove unused 'docs' output from all platform workflows - Consolidate Python setup to use 3.12 consistently across: - common/action.yml - performance.yml benchmarks job - Remove redundant setup from qt-install/action.yml - Extract duplicate attestation condition checks into new attest-condition action (used by attest and attest-sbom) - Remove unused --no-fail backwards compat flag from check_sizes.py - Create detect-changes action for platform-specific path filtering - Create generate-matrix action for sparse checkout + matrix generation - Convert build-action to Python script with tests - Add build_action.py for building GitHub Actions from source - Continue Python migration for tools/ directory
- Create common/logging.py with unified Colors and Logger classes - Create common/errors.py with QGCToolError exception hierarchy - Add shared pytest fixtures in tests/conftest.py - Add test suites for 7 Python tools (119 new tests): - test_analyze.py (24 tests) - test_check_deps.py (12 tests) - test_lint_fix.py (18 tests) - test_coverage_tool.py (13 tests) - test_generate_docs.py (15 tests) - test_pre_commit.py (15 tests) - test_run_tests_tool.py (22 tests) - Refactor scripts to use common utilities (net -293 lines) - Fix factgroup generator msg_id_constant to use uppercase
Summary
Major CI/CD infrastructure improvements focused on security, performance, and maintainability.
Security Hardening
Performance Optimization
New Capabilities
Consolidation
Documentation
Test Plan
Migration Notes
AWS OIDC (optional): Once AWS IAM role is configured, add
AWS_ROLE_ARNsecret. Current static credentials continue working.CPM lock update: Run
cmake --build build --target cpm-update-package-lockwhen dependencies change.