Add extracted tools: CitrineOS, OpenOCPP, ShapeShifter

- CitrineOS core extracted (CSMS OCPP 2.0.1)
- OpenOCPP extracted (firmware OCPP 1.6J/2.0.1)
- ShapeShifter library installed (pip install -e)
- ShapeShifter specification extracted
- EVerest extracted

TODO updated with progress
This commit is contained in:
Eric F
2026-06-08 00:38:27 -04:00
parent 468cfeaa50
commit d398a6ced2
7326 changed files with 1177561 additions and 7 deletions

View File

@@ -0,0 +1,92 @@
name: Create Coverage Badge
on:
workflow_call:
inputs:
runner:
description: 'Which runner to use'
required: false
default: 'ubuntu-24.04'
type: string
ref_everest_ci:
description: 'The ref of the everest-ci repository to checkout'
required: true
type: string
is_fork:
description: 'Whether the current repository is a fork'
required: true
type: string
artifact_deploy_target_repo:
description: 'Repository to deploy artifacts to'
required: true
type: string
coverage_report_artifact_name:
description: 'The name of the coverage report artifact to download'
required: true
type: string
coverage_xml_artifact_name:
description: 'The name of the coverage xml artifact to download'
required: true
type: string
secrets:
coverage_deploy_token:
description: 'The token to use to deploy the coverage report'
required: true
jobs:
create-coverage-badge:
name: Create Coverage Badge
runs-on: ${{ inputs.runner }}
steps:
- name: Checkout local github actions
uses: actions/checkout@v4
with:
repository: ${{ github.repository_owner }}/everest-ci
ref: ${{ inputs.ref_everest_ci }}
path: everest-ci
- name: Download xml coverage report
uses: actions/download-artifact@v5.0.0
with:
if-no-files-found: error
name: ${{ inputs.coverage_xml_artifact_name }}
path: coverage-xml
- name: Parse coverage report
id: parse_coverage_report
shell: python3 {0}
run: |
import xml.etree.ElementTree
import os
tree = xml.etree.ElementTree.parse("${{ github.workspace }}/coverage-xml/gcovr-coverage-xml.xml")
line_coverage = tree.getroot().get("line-rate")
with open(os.environ["GITHUB_OUTPUT"], "a") as f:
f.write(f"line_coverage={line_coverage}\n")
f.write(f"line_coverage_percentage={float(line_coverage) * 100}\n")
- name: Generate coverage badge
run: |
pip install anybadge
mkdir -p ${{ github.workspace }}/coverage-badge/
anybadge -o --label Coverage --value ${{ steps.parse_coverage_report.outputs.line_coverage_percentage }} -s "%" --file ${{ github.workspace }}/coverage-badge/coverage-badge.svg 20=red 40=orange 60=yellow 80=yellowgreen 100=green
- name: Deploy coverage badge
uses: ./everest-ci/github-actions/deploy-ci-artifact
if: ${{ inputs.is_fork == 'false' }}
with:
target_repo: ${{ inputs.artifact_deploy_target_repo }}
github_token: ${{ secrets.coverage_deploy_token }}
artifact_name: coverage-badge
artifact_directory: ${{ github.workspace }}/coverage-badge/
deploy_global_artifact: true
- name: Download html coverage report
uses: actions/download-artifact@v5.0.0
with:
if-no-files-found: error
name: ${{ inputs.coverage_report_artifact_name }}
path: coverage-report
- name: Deploy html coverage report
uses: ./everest-ci/github-actions/deploy-ci-artifact
if: ${{ inputs.is_fork == 'false' }}
with:
target_repo: ${{ inputs.artifact_deploy_target_repo }}
github_token: ${{ secrets.coverage_deploy_token }}
artifact_name: ${{ inputs.coverage_report_artifact_name }}
artifact_directory: ${{ github.workspace }}/coverage-report/
deploy_global_artifact: true

View File

@@ -0,0 +1,35 @@
name: DCO Check
on:
workflow_call:
inputs:
runner:
description: 'Which runner to use'
required: false
default: 'ubuntu-24.04'
type: string
jobs:
dco_check:
name: DCO Check
runs-on: ${{ inputs.runner }}
steps:
- uses: actions/checkout@v3
if: github.event_name == 'pull_request'
- name: Set up Python 3.x
if: github.event_name == 'pull_request'
uses: actions/setup-python@v4
with:
python-version: '3.x'
- name: Install dco-check
if: github.event_name == 'pull_request'
run: pip3 install -U dco-check==0.5.0
- name: Check DCO pull_request
if: github.event_name == 'pull_request'
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
dco-check --default-branch main -v --exclude-pattern ".*@users\.noreply\.github\.com"
- name: Check DCO merge_group
if: github.event_name == 'merge_group'
run: |
echo "DCO check is skipped for merge_group events."

View File

@@ -0,0 +1,131 @@
name: Integration Tests
on:
workflow_call:
inputs:
runner:
description: 'Which runner to use'
required: false
default: 'ubuntu-24.04'
type: string
build_kit_artifact_name:
description: 'The name of the build-kit artifact to download'
required: true
type: string
build_kit_image_tag:
description: 'The tag of the build-kit image to use for building the project'
required: true
type: string
build_kit_scripts_directory:
description: 'Directory in the repository where the build kit scripts are located'
required: false
default: '.ci/build-kit/scripts'
type: string
docker_compose_file_path:
description: 'The path to the docker-compose file, relative to the repository root'
required: false
default: '.ci/e2e/docker-compose.yaml'
type: string
test_service_name:
description: 'The name of the service to run integration tests on'
required: false
default: 'e2e-test-server'
type: string
result_xml_path:
description: 'The path to the result xml file, relative to the github workspace'
required: false
default: 'result.xml'
type: string
report_html_path:
description: 'The path to the report html file, relative to the github workspace'
required: false
default: 'report.html'
type: string
dist_artifact_name:
description: 'The name of the dist artifact to download'
required: true
type: string
wheels_artifact_name:
description: 'The name of the wheels artifact to download'
required: true
type: string
outputs:
integration_tests_artifact_name:
description: 'The name of the integration tests artifact'
value: ${{ jobs.integration-tests.outputs.integration_tests_artifact_name }}
jobs:
integration-tests:
name: Run Integration Tests
runs-on: ${{ inputs.runner }}
env:
INTEGRATION_IMAGE_NAME: integration-image
BUILD_KIT_IMAGE: ${{ inputs.build_kit_image_tag }}
INTEGRATION_TESTS_ARTIFACT_NAME: integration-tests-artifacts
outputs:
integration_tests_artifact_name: ${{ env.INTEGRATION_TESTS_ARTIFACT_NAME }}
steps:
- name: Download dist dir
uses: actions/download-artifact@v5.0.0
with:
name: ${{ inputs.dist_artifact_name }}
- name: Extract dist.tar.gz
run: |
tar -xzf ${{ github.workspace }}/dist.tar.gz -C ${{ github.workspace }}
- name: Download wheels
uses: actions/download-artifact@v5.0.0
with:
name: ${{ inputs.wheels_artifact_name }}
path: wheels
- name: Checkout repository
uses: actions/checkout@v4.2.2
with:
path: source
- name: Setup run scripts
run: |
mkdir scripts
rsync -a source/${{ inputs.build_kit_scripts_directory }}/ scripts
- name: Download build-kit image
uses: actions/download-artifact@v5
with:
name: ${{ inputs.build_kit_artifact_name }}
- name: Load build-kit image
run: |
docker load -i build-kit.tar
docker image tag ${{ env.BUILD_KIT_IMAGE }} build-kit
- name: Create integration-image
run: |
docker run \
--volume "${{ github.workspace }}:/ext" \
--name integration-container \
build-kit run-script create_integration_image
docker commit integration-container ${{ env.INTEGRATION_IMAGE_NAME }}
- name: Run integration tests
id: run_integration_tests
run: |
docker compose \
-f source/${{ inputs.docker_compose_file_path }} \
run \
${{ inputs.test_service_name }} \
tests/run-tests.sh integration \
--everest-prefix /ext/dist \
--junitxml /ext/${{ inputs.result_xml_path }} \
--html /ext/${{ inputs.report_html_path }}
- name: Upload result and report as artifact
if: ${{ always() && (steps.run_integration_tests.outcome == 'success' || steps.run_integration_tests.outcome == 'failure') }}
uses: actions/upload-artifact@v4.6.2
with:
if-no-files-found: error
name: ${{ env.INTEGRATION_TESTS_ARTIFACT_NAME }}
path: |
${{ inputs.result_xml_path }}
${{ inputs.report_html_path }}
- name: Render result
if: ${{ always() && (steps.run_integration_tests.outcome == 'success' || steps.run_integration_tests.outcome == 'failure') }}
uses: pmeier/pytest-results-action@v0.7.2
with:
path: ${{ inputs.result_xml_path }}
summary: True
display-options: fEX
fail-on-empty: True
title: Test results

View File

@@ -0,0 +1,36 @@
name: Lint Repository
on:
workflow_call:
inputs:
runner:
description: 'Which runner to use'
required: false
default: 'ubuntu-24.04'
type: string
ref_everest_ci:
description: 'The ref of the everest-ci repository to checkout'
required: true
type: string
jobs:
lint:
name: Lint Repository
runs-on: ${{ inputs.runner }}
steps:
- name: Checkout local github actions
uses: actions/checkout@v4
with:
repository: ${{ github.repository_owner }}/everest-ci
ref: ${{ inputs.ref_everest_ci }}
path: everest-ci
- name: Checkout repository
uses: actions/checkout@v4
with:
path: source
- name: Run clang-format
uses: ./everest-ci/github-actions/run-clang-format
with:
source-dir: source/
extensions: hpp,cpp
exclude: cache

View File

@@ -0,0 +1,115 @@
name: OCPP Tests
on:
workflow_call:
inputs:
runner:
description: 'Which runner to use'
required: false
default: 'ubuntu-24.04'
type: string
dist_artifact_name:
description: 'The name of the dist artifact to download'
required: true
type: string
wheels_artifact_name:
description: 'The name of the wheels artifact to download'
required: true
type: string
build_kit_artifact_name:
description: 'The name of the build-kit artifact to download'
required: true
type: string
build_kit_image_tag:
description: 'The tag of the build-kit image to use for building the project'
required: true
type: string
build_kit_scripts_directory:
description: 'Directory in the repository where the build kit scripts are located'
required: false
default: '.ci/build-kit/scripts'
type: string
outputs:
ocpp_tests_artifact_name:
description: 'The name of the OCPP tests artifact'
value: ${{ jobs.ocpp-tests.outputs.ocpp_tests_artifact_name }}
jobs:
ocpp-tests:
name: Run OCPP Tests
runs-on: ${{ inputs.runner }}
env:
OCPP_TESTS_ARTIFACT_NAME: ocpp-tests-artifacts
outputs:
ocpp_tests_artifact_name: ${{ env.OCPP_TESTS_ARTIFACT_NAME }}
steps:
- name: Download dist dir
uses: actions/download-artifact@v4.1.8
with:
name: ${{ inputs.dist_artifact_name }}
- name: Extract dist.tar.gz
run: |
tar -xzf ${{ github.workspace }}/dist.tar.gz -C ${{ github.workspace }}
- name: Download wheels
uses: actions/download-artifact@v4.1.8
with:
name: ${{ inputs.wheels_artifact_name }}
path: wheels
- name: Checkout repository
uses: actions/checkout@v4.2.2
with:
path: source
- name: Setup run scripts
run: |
mkdir scripts
rsync -a source/${{ inputs.build_kit_scripts_directory }}/ scripts
- name: Download build-kit image
uses: actions/download-artifact@v4
with:
name: ${{ inputs.build_kit_artifact_name }}
- name: Load build-kit image
run: |
docker load -i build-kit.tar
docker image tag ${{ inputs.build_kit_image_tag }} build-kit
- name: Create integration-image
run: |
docker run \
--volume "${{ github.workspace }}:/ext" \
--name integration-container \
build-kit run-script create_ocpp_tests_image
docker commit integration-container integration-image
- name: Run OCPP tests
id: run_ocpp_tests
continue-on-error: true
run: |
docker compose \
-f source/.ci/e2e/docker-compose.yaml \
run \
e2e-test-server \
tests/run-tests.sh ocpp \
--everest-prefix /ext/dist \
--junitxml /ext/ocpp-tests-result.xml \
--html /ext/ocpp-tests-report.html
- name: Upload result and report as artifact
continue-on-error: true
if: ${{ steps.run_ocpp_tests.outcome == 'success' || steps.run_ocpp_tests.outcome == 'failure' }}
uses: actions/upload-artifact@v4.4.3
with:
if-no-files-found: error
name: ${{ env.OCPP_TESTS_ARTIFACT_NAME }}
path: |
ocpp-tests-result.xml
ocpp-tests-report.html
- name: Render OCPP tests result
if: ${{ steps.run_ocpp_tests.outcome == 'success' || steps.run_ocpp_tests.outcome == 'failure' }}
uses: pmeier/pytest-results-action@v0.7.1
with:
path: ocpp-tests-result.xml
summary: True
display-options: fEX
fail-on-empty: True
title: Test results
- name: Check if OCPP tests failed
if: ${{ steps.run_ocpp_tests.outcome == 'failure' }}
run: exit 1

View File

@@ -0,0 +1,81 @@
name: Setup Environment
on:
workflow_call:
inputs:
runner:
description: 'Which runner to use'
required: false
default: 'ubuntu-24.04'
type: string
ref_everest_ci:
description: 'The reference of the everest-ci repository to checkout'
required: true
type: string
outputs:
ref_everest_ci:
description: 'The reference of the everest-ci repository to checkout'
value: ${{ inputs.ref_everest_ci }}
closest_tag_everest_ci:
description: 'The closest tag of the everest-ci repository to use'
value: ${{ jobs.setup-env.outputs.closest_tag_everest_ci }}
is_fork:
description: 'Whether the current repository is a fork'
value: ${{ jobs.setup-env.outputs.is_fork }}
jobs:
setup-env:
name: Setup Environment
runs-on: ${{ inputs.runner }}
outputs:
is_fork: ${{ steps.is_fork.outputs.is_fork }}
closest_tag_everest_ci: ${{ steps.set_tag_everest_ci.outputs.closest_tag }}
steps:
- name: Determine closest tag of everest-ci
id: set_tag_everest_ci
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
TARGET_SHA="${{ steps.set_sha_everest_ci.outputs.sha }}"
OWNER="everest"
REPO="everest-ci"
COMMITS=$(gh api repos/$OWNER/$REPO/commits?sha=$TARGET_SHA\&per_page=100 --jq '.[].sha')
for COMMIT in $COMMITS; do
TAG=$(gh api repos/$OWNER/$REPO/tags --jq '.[] | select(.commit.sha == "'$COMMIT'") | .name')
if [ -n "$TAG" ]; then
break
fi
done
if [ -z "$TAG" ]; then
echo "No tag found for commit $TARGET_SHA (only last 100 commits were checked)"
exit 1
fi
# if inputs.build_kit_base_image_tag is != "", use it as the tag
if [ -n "${{ inputs.build_kit_base_image_tag }}" ]; then
echo "Using inputs.build_kit_base_image_tag as tag"
TAG="${{ inputs.build_kit_base_image_tag }}"
fi
echo "closest_tag=$TAG" >> $GITHUB_OUTPUT
- name: Determine whether the PR comes from fork
id: is_fork
run: |
if [ "${{ github.event_name }}" == "pull_request" ]; then
if [ "${{ github.event.pull_request.head.repo.full_name }}" != "${{ github.repository }}" ]; then
is_fork=true
else
is_fork=false
fi
else
is_fork=false
fi
echo "is_fork=${is_fork}" >> $GITHUB_OUTPUT
if [ "${is_fork}" == "true" ]; then
echo "This is a forked PR"
else
echo "This is not a forked PR"
fi

View File

@@ -0,0 +1,51 @@
# Inspired by:
# Nixpkgs: https://github.com/NixOS/nixpkgs/blob/a698ac1214cd924d4394ca9cd2691618765aa03c/.github/workflows/backport.yml
# NixOS-WSL: https://github.com/nix-community/NixOS-WSL/blob/be894604b2aa2184c0b3d3b44995acd0da14dc0c/.github/workflows/on_label.yml
name: "Backport"
on:
pull_request_target:
types:
- closed
- labeled
jobs:
backport:
if: github.event.pull_request.labels && contains(join(github.event.pull_request.labels.*.name, ', '), 'backport ')
name: Backport PR 🔙
runs-on: ubuntu-24.04
permissions:
contents: write
pull-requests: write
outputs:
created_pull_numbers: ${{ steps.backport.outputs.created_pull_numbers }}
steps:
- name: Check actor permissions
id: check-permissions
uses: prince-chrismc/check-actor-permissions-action@v3.0.2
with:
permission: write
- name: Generate App Token
id: app-token
uses: actions/create-github-app-token@v1
with:
app-id: ${{ secrets.BACKPORT_APP_ID }}
private-key: ${{ secrets.BACKPORT_APP_PRIVATE_KEY }}
- name: Checkout
uses: actions/checkout@v6
- name: Create backport PR
id: backport
uses: korthout/backport-action@v4.5.1
with:
github_token: ${{ steps.app-token.outputs.token }}
merge_commits: "skip"
add_author_as_assignee: true
copy_requested_reviewers: true
experimental: >-
{
"conflict_resolution": "draft_commit_conflicts"
}

View File

@@ -0,0 +1,74 @@
name: Build, Lint and Test
on:
push:
branches:
- main
jobs:
setup-env:
name: Setup Environment
uses: ./.github/workflows/job_setup-env.yml
with:
runner: ${{ inputs.runner || 'ubuntu-24.04' }}
ref_everest_ci: v1.5.5
build-build-kit:
name: Build the build-kit
uses: ./.github/workflows/job_build-build-kit.yml
needs:
- setup-env
with:
runner: ${{ inputs.runner || 'ubuntu-24.04' }}
base_image_tag_everest_ci: ${{ needs.setup-env.outputs.closest_tag_everest_ci }}
build-cmake-gcc:
name: Build with CMake and GCC
uses: ./.github/workflows/job_build-cmake-gcc.yml
needs:
- setup-env
- build-build-kit
secrets:
coverage_deploy_token: "abcd"
with:
runner: ${{ inputs.runner || 'ubuntu-24.04' }}
ref_everest_ci: ${{ needs.setup-env.outputs.ref_everest_ci }}
is_fork: ${{ needs.setup-env.outputs.is_fork }}
build-kit-artifact-name: ${{ needs.build-build-kit.outputs.build_kit_artifact_name }}
build_kit_image_tag: ${{ needs.build-build-kit.outputs.build_kit_image_tag }}
artifact_deploy_target_repo: ${{ github.repository_owner }}/everest.github.io
# create-coverage-badge:
# uses: ./.github/workflows/job_create-coverage-badge.yml
# needs:
# - setup-env
# - build-cmake-gcc
# secrets:
# coverage_deploy_token: ${{ secrets.coverage_deploy_token }}
# with:
# runner: ${{ inputs.runner || 'ubuntu-24.04' }}
# ref_everest_ci: ${{ needs.setup-env.outputs.ref_everest_ci }}
# is_fork: ${{ needs.setup-env.outputs.is_fork }}
# artifact_deploy_target_repo: ${{ github.repository_owner }}/everest.github.io
# coverage_report_artifact_name: ${{ needs.build-cmake-gcc.outputs.coverage_report_artifact_name }}
# coverage_xml_artifact_name: ${{ needs.build-cmake-gcc.outputs.coverage_xml_artifact_name }}
build-docs:
name: Build and Deploy Documentation
needs:
- setup-env
- build-build-kit
uses: ./.github/workflows/job_build-docs.yaml
secrets:
SA_GITHUB_SSH_KEY: ${{ secrets.SA_GITHUB_SSH_KEY }}
with:
runner: ${{ inputs.runner || 'ubuntu-24.04' }}
is_fork: ${{ needs.setup-env.outputs.is_fork == 'true' }}
build_kit_artifact_name: ${{ needs.build-build-kit.outputs.build_kit_artifact_name }}
build_kit_image_tag: ${{ needs.build-build-kit.outputs.build_kit_image_tag }}
deploy_docs: true

View File

@@ -0,0 +1,139 @@
name: Build, Lint and Test
on:
pull_request: {}
merge_group: {}
workflow_dispatch:
inputs:
runner:
description: Which runner to use
type: choice
default: 'ubuntu-24.04'
required: true
options:
- 'ubuntu-24.04'
- 'large-ubuntu-24.04-xxl'
schedule:
- cron: '37 13,1 * * *'
jobs:
setup-env:
name: Setup Environment
uses: ./.github/workflows/job_setup-env.yml
with:
runner: ${{ inputs.runner || 'ubuntu-24.04' }}
ref_everest_ci: v1.5.5
build-build-kit:
name: Build the build-kit
uses: ./.github/workflows/job_build-build-kit.yml
needs:
- setup-env
with:
runner: ${{ inputs.runner || 'ubuntu-24.04' }}
base_image_tag_everest_ci: ${{ needs.setup-env.outputs.closest_tag_everest_ci }}
build-cmake-gcc:
name: Build with CMake and GCC
uses: ./.github/workflows/job_build-cmake-gcc.yml
needs:
- setup-env
- build-build-kit
secrets:
coverage_deploy_token: ""
with:
runner: ${{ inputs.runner || 'ubuntu-24.04' }}
ref_everest_ci: ${{ needs.setup-env.outputs.ref_everest_ci }}
is_fork: ${{ needs.setup-env.outputs.is_fork }}
build-kit-artifact-name: ${{ needs.build-build-kit.outputs.build_kit_artifact_name }}
build_kit_image_tag: ${{ needs.build-build-kit.outputs.build_kit_image_tag }}
artifact_deploy_target_repo: ${{ github.repository_owner }}/everest.github.io
integration-tests:
name: Run Integration Tests
uses: ./.github/workflows/job_integrations-tests.yml
needs:
- setup-env
- build-cmake-gcc
- build-build-kit
with:
runner: ${{ inputs.runner || 'ubuntu-24.04' }}
build_kit_artifact_name: ${{ needs.build-build-kit.outputs.build_kit_artifact_name }}
build_kit_image_tag: ${{ needs.build-build-kit.outputs.build_kit_image_tag }}
dist_artifact_name: ${{ needs.build-cmake-gcc.outputs.dist_artifact_name }}
wheels_artifact_name: ${{ needs.build-cmake-gcc.outputs.wheels_artifact_name }}
ocpp-tests:
name: Run OCPP Tests
uses: ./.github/workflows/job_ocpp-tests.yml
needs:
- setup-env
- build-cmake-gcc
- build-build-kit
with:
runner: ${{ inputs.runner || 'ubuntu-24.04' }}
build_kit_artifact_name: ${{ needs.build-build-kit.outputs.build_kit_artifact_name }}
build_kit_image_tag: ${{ needs.build-build-kit.outputs.build_kit_image_tag }}
dist_artifact_name: ${{ needs.build-cmake-gcc.outputs.dist_artifact_name }}
wheels_artifact_name: ${{ needs.build-cmake-gcc.outputs.wheels_artifact_name }}
lint:
name: Lint Repository
uses: ./.github/workflows/job_lint.yml
needs:
- setup-env
with:
runner: ${{ inputs.runner || 'ubuntu-24.04' }}
ref_everest_ci: ${{ needs.setup-env.outputs.ref_everest_ci }}
build-docs:
name: Call Build Documentation
needs:
- setup-env
- build-build-kit
uses: ./.github/workflows/job_build-docs.yaml
secrets:
SA_GITHUB_SSH_KEY: ${{ secrets.SA_GITHUB_SSH_KEY }}
with:
runner: ${{ inputs.runner || 'ubuntu-24.04' }}
is_fork: ${{ needs.setup-env.outputs.is_fork == 'true' }}
build_kit_artifact_name: ${{ needs.build-build-kit.outputs.build_kit_artifact_name }}
build_kit_image_tag: ${{ needs.build-build-kit.outputs.build_kit_image_tag }}
deploy_docs: false
dco-check:
name: DCO Check
uses: ./.github/workflows/job_dco-check.yaml
with:
runner: ${{ inputs.runner || 'ubuntu-24.04' }}
bazel-build-and-test:
name: Bazel Build And Test
uses: ./.github/workflows/job_bazel-build-test.yaml
with:
runner: ${{ inputs.runner || 'ubuntu-24.04' }}
bazel-cross-build:
name: Bazel Cross-Build (${{ matrix.platform }})
strategy:
fail-fast: false
matrix:
platform:
- aarch64-linux-gnu
- aarch64-linux-musl
- armv7-linux-gnueabihf
- armv7-linux-musleabihf
uses: ./.github/workflows/job_bazel-cross-build.yaml
with:
runner: ${{ inputs.runner || 'ubuntu-24.04' }}
platform: ${{ matrix.platform }}