Skip to content
4 changes: 1 addition & 3 deletions .github/actions/build-cmake/action.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -23,10 +23,10 @@ runs:
using: "composite"
steps:
- shell: bash
working-directory: ${{ inputs.build-path }}
run: |
# Source the container entrypoint script
. /entrypoint.sh
cd "$GITHUB_WORKSPACE/$BUILD_PATH"

# Determine parallel jobs
if [ -n "$PARALLEL_JOBS" ]; then
Expand All @@ -47,8 +47,6 @@ runs:
# Build
cmake --build . $jobs_arg $target_arg
env:
SOURCE_PATH: ${{ inputs.source-path }}
BUILD_PATH: ${{ inputs.build-path }}
TARGET: ${{ inputs.target }}
PARALLEL_JOBS: ${{ inputs.parallel-jobs }}
CICOLOR_FORCE: 1
3 changes: 1 addition & 2 deletions .github/actions/configure-cmake/action.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -43,11 +43,11 @@ runs:
using: "composite"
steps:
- shell: bash
working-directory: ${{ inputs.build-path }}
run: |
# Source the container entrypoint script
. /entrypoint.sh

cd "$GITHUB_WORKSPACE/$BUILD_PATH"
SOURCE_DIR="$GITHUB_WORKSPACE/$SOURCE_PATH"
echo "Configuring with CMake preset: $PRESET"

Expand Down Expand Up @@ -80,7 +80,6 @@ runs:
echo "C++ compiler: $CPP_COMPILER"
env:
SOURCE_PATH: ${{ inputs.source-path }}
BUILD_PATH: ${{ inputs.build-path }}
EXTRA_OPTIONS: ${{ inputs.extra-options }}
ENABLE_FORM: ${{ inputs.enable-form }}
FORM_ROOT_STORAGE: ${{ inputs.form-root-storage }}
Expand Down
4 changes: 1 addition & 3 deletions .github/actions/generate-build-matrix/generate_matrix.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,10 @@

def get_default_combinations(event_name, all_combinations):
"""Gets the default build combinations based on the GitHub event type."""
if event_name in ("push", "pull_request", "pull_request_target"):
if event_name in ("push", "pull_request", "pull_request_target", "workflow_dispatch"):
return ["gcc/none"]
elif event_name == "issue_comment":
return ["gcc/none", "clang/none"]
elif event_name == "workflow_dispatch":
return all_combinations
else:
# Default to a minimal safe configuration for unknown events
return ["gcc/none"]
Expand Down
6 changes: 6 additions & 0 deletions .github/actions/run-change-detection/action.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,12 @@ runs:
with:
fetch-depth: 0
path: ${{ inputs.checkout-path }}
# This action is never called from a pull_request_target workflow; all callers
# use pull_request, issue_comment, workflow_dispatch, or workflow_call triggers.
# Even if it were called from pull_request_target, the empty sparse checkout
# below ensures no files from the ref are materialized on disk — only git
# objects are fetched — so no code from the PR is ever executed.
# codeql[actions/pull-request-target-injection]
ref: ${{ inputs.ref }}
repository: ${{ inputs.repo }}
persist-credentials: false
Expand Down
17 changes: 5 additions & 12 deletions .github/workflows/clang-tidy-fix.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -111,19 +111,17 @@ jobs:
if:
needs.setup.outputs.tidy_checks == '' && (steps.download_fixes_check.outcome == 'success' ||
steps.download_fixes_fix.outcome == 'success')
env:
CHECKOUT_PATH: ${{ needs.setup.outputs.checkout_path }}
working-directory: ${{ needs.setup.outputs.checkout_path }}
run: |
# The artifact preserves the build directory prefix in its path structure.
FIXES_FILE=""
if [ -d fixes ]; then
FIXES_FILE=$(find fixes -name "clang-tidy-fixes.yaml" | head -1)
if [ -d "$GITHUB_WORKSPACE/fixes" ]; then
FIXES_FILE=$(find "$GITHUB_WORKSPACE/fixes" -name "clang-tidy-fixes.yaml" | head -1)
fi
if [ -n "$FIXES_FILE" ]; then
echo "Applying fixes from existing artifact..."
. /entrypoint.sh
FIXES_DIR="$(realpath "${FIXES_FILE%/*}")"
cd "${CHECKOUT_PATH}"
clang-apply-replacements "${FIXES_DIR}" || true
echo "applied=true" >> "$GITHUB_OUTPUT"
else
Expand All @@ -143,7 +141,6 @@ jobs:
TIDY_CHECKS: ${{ needs.setup.outputs.tidy_checks }}
run: |
. /entrypoint.sh
cd "$GITHUB_WORKSPACE"

CLANG_TIDY_OPTS="clang-tidy;--export-fixes=clang-tidy-fixes.yaml"
if [ -n "$TIDY_CHECKS" ]; then
Expand All @@ -165,20 +162,16 @@ jobs:

- name: Generate clang-tidy fixes using CMake build
if: steps.apply_from_artifact.outputs.applied != 'true'
env:
BUILD_PATH: ${{ needs.setup.outputs.build_path }}
working-directory: ${{ needs.setup.outputs.build_path }}
run: |
. /entrypoint.sh
cd "$GITHUB_WORKSPACE/${BUILD_PATH}"
cmake --build . -j "$(nproc)" || true

- name: Apply clang-tidy fixes
if: steps.apply_from_artifact.outputs.applied != 'true'
env:
BUILD_PATH: ${{ needs.setup.outputs.build_path }}
working-directory: ${{ needs.setup.outputs.build_path }}
run: |
. /entrypoint.sh
cd "$GITHUB_WORKSPACE/${BUILD_PATH}"
if [ -f clang-tidy-fixes.yaml ]; then
clang-apply-replacements . || true
fi
Expand Down
33 changes: 24 additions & 9 deletions .github/workflows/cmake-build.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ run-name: "${{ github.actor }} building and testing ${{ github.repository }}"
- `all` (run all combinations)
- `all -clang/none -clang/valgrind` (run all except specified)
- `+clang/none +clang/valgrind` (run default matrix plus specified)
Default (if empty): Run all except clang/none and clang/valgrind.
Default (if empty): Run `gcc/none`
required: false
default: ""
workflow_call:
Expand Down Expand Up @@ -109,7 +109,12 @@ jobs:

generate-matrix:
needs: setup
if: needs.setup.result == 'success'
if: >
needs.setup.result == 'success' && (
github.event_name == 'workflow_dispatch' ||
inputs.skip-relevance-check ||
needs.setup.outputs.has_changes == 'true'
)
runs-on: ubuntu-latest
outputs:
matrix: ${{ steps.generate.outputs.matrix }}
Expand Down Expand Up @@ -179,11 +184,9 @@ jobs:

- name: Run tests
if: matrix.sanitizer != 'valgrind'
env:
BUILD_PATH: ${{ needs.setup.outputs.build_path }}
working-directory: ${{ needs.setup.outputs.build_path }}
run: |
. /entrypoint.sh
cd "$GITHUB_WORKSPACE/${BUILD_PATH}"

echo "➡️ Running tests..."
echo "::group::Running ctest"
Expand All @@ -198,11 +201,9 @@ jobs:

- name: Run Valgrind tests
if: matrix.sanitizer == 'valgrind'
env:
BUILD_PATH: ${{ needs.setup.outputs.build_path }}
working-directory: ${{ needs.setup.outputs.build_path }}
run: |
. /entrypoint.sh
cd "$GITHUB_WORKSPACE/${BUILD_PATH}"

echo "➡️ Running Valgrind tests..."
echo "::group::Running ctest -T memcheck"
Expand All @@ -214,6 +215,20 @@ jobs:
echo "⚠️ Valgrind tests failed, but the workflow will continue."
fi

cmake-build-skipped:
needs: [setup]
if: >
needs.setup.result == 'success' && github.event_name != 'workflow_dispatch' &&
!inputs.skip-relevance-check && needs.setup.outputs.is_act != 'true' &&
needs.setup.outputs.has_changes != 'true'
runs-on: ubuntu-latest
permissions:
contents: read

steps:
- name: No relevant C++ or CMake changes detected
run: echo "::notice::No relevant C++ or CMake changes detected; build skipped."

build-complete:
needs: [setup, build]
if: >
Expand All @@ -233,7 +248,7 @@ jobs:
**Result:** ${{ needs.build.result == 'success' && '✅ All builds and tests passed.'
|| needs.build.result == 'failure' && '❌ Some builds or tests failed.'
|| needs.build.result == 'cancelled' && '⚠️ Build was cancelled before completion.'
|| needs.build.result == 'skipped' && 'ℹ️ Build job was skipped.'
|| needs.build.result == 'skipped' && 'ℹ️ No relevant C++ or CMake changes detected; build skipped.'
|| format('ℹ️ Build job completed with status: {0}.', needs.build.result) }}

See the [workflow run](${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}) for detailed results.
Expand Down
26 changes: 7 additions & 19 deletions .github/workflows/coverage.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -162,14 +162,12 @@ jobs:
build-path: ${{ needs.setup.outputs.build_path }}

- name: Run tests with coverage
env:
BUILD_PATH: ${{ needs.setup.outputs.build_path }}
working-directory: ${{ needs.setup.outputs.build_path }}
run: |
. /entrypoint.sh
cd "$GITHUB_WORKSPACE/${BUILD_PATH}"

echo "➡️ Running tests with coverage..."
PROFILE_ROOT="$GITHUB_WORKSPACE/${BUILD_PATH}/test/profraw"
PROFILE_ROOT="$(pwd)/test/profraw"
echo "Cleaning LLVM profile directory: $PROFILE_ROOT"
rm -rf "$PROFILE_ROOT"
mkdir -p "$PROFILE_ROOT"
Expand All @@ -189,11 +187,9 @@ jobs:
id: report_gcc
if: ${{ steps.coverage_options.outputs.compiler == 'gcc' }}
shell: bash
env:
BUILD_PATH: ${{ needs.setup.outputs.build_path }}
working-directory: ${{ needs.setup.outputs.build_path }}
run: |
. /entrypoint.sh
cd "$GITHUB_WORKSPACE/${BUILD_PATH}"

echo "➡️ Generating coverage reports for GCC..."
echo "::group::Running coverage-gcov target"
Expand All @@ -210,11 +206,9 @@ jobs:
id: report_clang
if: ${{ steps.coverage_options.outputs.compiler == 'clang' }}
shell: bash
env:
BUILD_PATH: ${{ needs.setup.outputs.build_path }}
working-directory: ${{ needs.setup.outputs.build_path }}
run: |
. /entrypoint.sh
cd "$GITHUB_WORKSPACE/${BUILD_PATH}"

echo "➡️ Generating coverage reports for Clang..."
echo "::group::Running coverage-llvm target"
Expand All @@ -231,11 +225,9 @@ jobs:
id: report_python
if: ${{ steps.report_gcc.outcome != 'skipped' || steps.report_clang.outcome != 'skipped' }}
shell: bash
env:
BUILD_PATH: ${{ needs.setup.outputs.build_path }}
working-directory: ${{ needs.setup.outputs.build_path }}
run: |
. /entrypoint.sh
cd "$GITHUB_WORKSPACE/${BUILD_PATH}"

echo "➡️ Generating Python coverage report..."
echo "::group::Running coverage-python target"
Expand All @@ -258,10 +250,8 @@ jobs:
id: coverage_outputs
if: ${{ steps.report_gcc.outcome != 'skipped' || steps.report_clang.outcome != 'skipped' }}
shell: bash
env:
BUILD_PATH: ${{ needs.setup.outputs.build_path }}
working-directory: ${{ needs.setup.outputs.build_path }}
run: |
cd "$GITHUB_WORKSPACE/${BUILD_PATH}"
if [ -f coverage.xml ]; then
echo "has_coverage_xml=true" >> "$GITHUB_OUTPUT"
else
Expand Down Expand Up @@ -292,14 +282,12 @@ jobs:
- name: Prepare coverage artifact bundle
if: ${{ steps.report_gcc.outcome != 'skipped' || steps.report_clang.outcome != 'skipped' }}
shell: bash
env:
BUILD_PATH: ${{ needs.setup.outputs.build_path }}
working-directory: ${{ needs.setup.outputs.build_path }}
run: |
set -euo pipefail
ARTIFACT_DIR="$GITHUB_WORKSPACE/coverage-artifacts"
rm -rf "$ARTIFACT_DIR"
mkdir -p "$ARTIFACT_DIR"
cd "$GITHUB_WORKSPACE/${BUILD_PATH}"
for file in \
coverage-llvm.txt \
coverage-llvm.info \
Expand Down
51 changes: 45 additions & 6 deletions .github/workflows/dependabot-auto-merge.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -67,14 +67,53 @@ jobs:
# yamllint disable rule:line-length
run: |
set -o pipefail
if ! gh pr merge --auto --rebase "${PR_NUMBER}" --repo "$GITHUB_REPOSITORY" 2>&1 | tee /tmp/gh-output.txt; then
if grep -qE "auto-merge is already enabled|[Rr]equired.*status.*check|[Rr]equired approving review|[Rr]equired.*review" /tmp/gh-output.txt; then
echo "Auto-merge not enabled yet - this is expected when requirements are not met or already enabled"
exit 0
else
echo "Unexpected error enabling auto-merge:"

attempt_merge() {
gh pr merge --auto --rebase "${PR_NUMBER}" --repo "$GITHUB_REPOSITORY" 2>&1 | tee /tmp/gh-output.txt
}

if attempt_merge; then
exit 0
fi

# Not a real failure: requirements not yet met, or auto-merge already enabled.
if grep -qE "auto-merge is already enabled|[Rr]equired.*status.*check|[Rr]equired approving review|[Rr]equired.*review" /tmp/gh-output.txt; then
echo "Auto-merge not enabled yet - this is expected when requirements are not met or already enabled"
exit 0
fi

# The repository-level "Allow auto-merge" setting is off. Re-enable it and retry once.
# This can happen if the setting is accidentally toggled in the repository admin UI.
if grep -qF "Auto merge is not allowed for this repository" /tmp/gh-output.txt; then
echo "Repository Allow auto-merge is disabled; attempting to re-enable..."
if ! gh api "repos/${GITHUB_REPOSITORY}" --method PATCH --field allow_auto_merge=true > /dev/null; then
echo "Could not re-enable Allow auto-merge on the repository. Manual intervention required."
exit 1
fi
echo "Repository setting re-enabled; retrying..."
if ! attempt_merge; then
echo "Auto-merge still failed after re-enabling repository setting:"
cat /tmp/gh-output.txt
exit 1
fi
exit 0
fi

# Concurrent merge race: another PR merged while this one was being processed,
# moving the base branch. Request a Dependabot rebase to update this branch;
# this workflow re-triggers naturally via check_suite:completed when the rebased
# branch passes checks. With N concurrent Dependabot PRs, this converges in N-1
# rounds: each round merges one PR, and any PRs that fall behind again each get
# a fresh rebase request on the next trigger.
if grep -qF "Base branch was modified" /tmp/gh-output.txt; then
echo "Base branch was modified by a concurrent merge. Requesting Dependabot rebase..."
gh pr comment "${PR_NUMBER}" --repo "$GITHUB_REPOSITORY" --body "@dependabot rebase" || true
echo "Rebase requested; workflow will re-trigger when the rebased branch passes checks."
exit 0
fi

# Unexpected error.
echo "Unexpected error enabling auto-merge:"
cat /tmp/gh-output.txt
exit 1
# yamllint enable
Loading