diff --git a/.github/workflows/release.yaml b/.github/workflows/release.yaml index 683e1b8..bcbdb49 100644 --- a/.github/workflows/release.yaml +++ b/.github/workflows/release.yaml @@ -50,5 +50,7 @@ jobs: # Instead, we use the publish script which pushes the correct container (residing in src/s-core-devcontainer). push: "never" runCmd: | + # manually login to ghcr.io for publishing + echo "${{ secrets.GITHUB_TOKEN }}" | docker login ghcr.io -u ${{ github.actor }} --password-stdin # Note: "${{ github.ref_name }}" will be the tag name, e.g., "1.0.0" ./scripts/publish.sh "${{ github.ref_name }}" diff --git a/src/s-core-devcontainer/.devcontainer/devcontainer-lock.json b/src/s-core-devcontainer/.devcontainer/devcontainer-lock.json index 6c39aa0..4f40819 100644 --- a/src/s-core-devcontainer/.devcontainer/devcontainer-lock.json +++ b/src/s-core-devcontainer/.devcontainer/devcontainer-lock.json @@ -6,9 +6,9 @@ "integrity": "sha256:4f464ab97a59439286a55490b55ba9851616f6f76ac3025e134127ac08ad79e2" }, "ghcr.io/devcontainers/features/common-utils": { - "version": "2.5.3", - "resolved": "ghcr.io/devcontainers/features/common-utils@sha256:3cf7ca93154faf9bdb128f3009cf1d1a91750ec97cc52082cf5d4edef5451f85", - "integrity": "sha256:3cf7ca93154faf9bdb128f3009cf1d1a91750ec97cc52082cf5d4edef5451f85" + "version": "2.5.4", + "resolved": "ghcr.io/devcontainers/features/common-utils@sha256:00fd45550f578d9d515044d9e2226e908dbc3d7aa6fcb9dee4d8bdb60be114cf", + "integrity": "sha256:00fd45550f578d9d515044d9e2226e908dbc3d7aa6fcb9dee4d8bdb60be114cf" }, "ghcr.io/devcontainers/features/git": { "version": "1.3.4", diff --git a/src/s-core-devcontainer/.devcontainer/devcontainer.json b/src/s-core-devcontainer/.devcontainer/devcontainer.json index fb39b6f..b9ab2ca 100644 --- a/src/s-core-devcontainer/.devcontainer/devcontainer.json +++ b/src/s-core-devcontainer/.devcontainer/devcontainer.json @@ -29,32 +29,7 @@ "ghcr.io/devcontainers/features/python": { "version": "3.12.11" }, - "./s-core-local": { - "BAZEL_VERSION": "8.3.0", - "BUILDIFIER_VERSION": "8.2.1", - // The following sha256sum is for the binary buildifier-linux-amd64 - // from the GitHub release page of buildtools - // It is generated by running 'sha256sum buildifier-linux-amd64' - "BUILDIFIER_SHA256": "6ceb7b0ab7cf66fceccc56a027d21d9cc557a7f34af37d2101edb56b92fcfa1a", - "STARPLS_VERSION": "0.1.21", - // The following sha256sum is for the binary starpls-linux-amd64 - // from the GitHub release page of starpls - // It is generated by running 'sha256sum starpls-linux-amd64' - "STARPLS_SHA256": "45692ecb9d94a19a15b1e7b240acdff5702f78cd22188dac41e1879cb8bdcdcf", - "BAZEL_COMPILE_COMMANDS_VERSION": "0.17.2", - // The following sha256sums are for the deb package bazel-compile-commands_-_amd64.deb - // where is the Ubuntu codename (e.g., jammy, focal, noble) - // and is the version of bazel-compile-commands - // The format is: :;:;... - // For example: jammy:6cde78e1a58c8f9047446cce25a81a676b0f293194175c9fe61586224c0b6f84;noble:97239b316df58fd3370a8aa6350790ececd5e4a1de30efb42d45cb1c300a179a;... - // It is generated by running 'sha256sum bazel-compile-commands_-_amd64.deb' - "BAZEL_COMPILE_COMMANDS_SHA256": "jammy:6cde78e1a58c8f9047446cce25a81a676b0f293194175c9fe61586224c0b6f84;noble:97239b316df58fd3370a8aa6350790ececd5e4a1de30efb42d45cb1c300a179a;focal:c861f4f36cc2884eefbd488f19c49a9674ac093210a503bce032eac8b94b3660", - // required by the rust-analyzer VS Code extension - "RUST_ANALYZER_VERSION": "2025-06-30", - // The following sha256sum is for the binary rust-analyzer-x86_64-unknown-linux-gnu.gz - // It is generated by running 'sha256sum rust-analyzer-x86_64-unknown-linux-gnu.gz' - "RUST_ANALYZER_SHA256": "9f40579d05a54ff084e449c3721a3bc8c907aab676e745c78de31c62e74ea778" - } + "./s-core-local": {} }, "remoteUser": "vscode", "initializeCommand": "mkdir -p ${localEnv:HOME}/.cache/bazel", @@ -75,7 +50,8 @@ "hediet.vscode-drawio", // Draw.IO integration "swyddfa.esbonio", // for Sphinx documentation support "rust-lang.rust-analyzer", // Rust language support for Visual Studio Code; see also tasks below - "github.vscode-pull-request-github" + "github.vscode-pull-request-github", // GitHub integration + "bierner.markdown-preview-github-styles" // GitHub style for Markdown preview ], "settings": { "files.insertFinalNewline": true, diff --git a/src/s-core-devcontainer/.devcontainer/s-core-local/devcontainer-feature.json b/src/s-core-devcontainer/.devcontainer/s-core-local/devcontainer-feature.json index 66e185e..e05ea5a 100644 --- a/src/s-core-devcontainer/.devcontainer/s-core-local/devcontainer-feature.json +++ b/src/s-core-devcontainer/.devcontainer/s-core-local/devcontainer-feature.json @@ -3,42 +3,23 @@ "id": "s-core-local", "version": "1.0.0", "description": "Tools which are not available as already existing development container feature", - "options": { - "BAZEL_VERSION": { - "type": "string", - "default": "8.3.0", - "description": "Version of Bazel to install" - }, - "BUILDIFIER_VERSION": { - "type": "string", - "default": "8.2.1", - "description": "Version of Buildifier to install" - }, - "BUILDIFIER_SHA256": { - "type": "string", - "default": "", - "description": "sha256sum of the Buildifier binary to verify the download" - }, - "BAZEL_COMPILE_COMMANDS_VERSION": { - "type": "string", - "default": "0.17.2", - "description": "Version of Bazel Compile Commands to install" - }, - "BAZEL_COMPILE_COMMANDS_SHA256": { - "type": "string", - "default": "", - "description": "sha256sums of Bazel Compile Commands to verify the download; format: :;:;..." - } - }, "onCreateCommand": "/devcontainer/features/s-core-local/on_create_command.sh", - // The repos in S-CORE may use different Bazel versions. This ensures that the required version is installed. - // Should be removed once we provide versions of the devcontainer. - "postCreateCommand": "if [ -f .bazelversion ] && [ \"$(cat .bazelversion)\" != \"$(dpkg --list | grep 'ii bazel ' | awk '{print $3}')\" ]; then sudo apt-get update && sudo apt-get install -y --allow-downgrades bazel=$(cat .bazelversion); fi", + "postCreateCommand": { + // The repos in S-CORE may use different Bazel versions. This ensures that the required version is installed. + // Should be removed once we provide versions of the devcontainer. + "Install matching Bazel version": "bash /devcontainer/features/s-core-local/install_matching_bazel_version.sh", + "Setup persistent bash history": "bash /devcontainer/features/s-core-local/setup_command_history.sh" + }, "mounts": [ { "source": "eclipse-s-core-bazel-cache", "target": "/var/cache/bazel", "type": "volume" + }, + { + "source": "eclipse-s-core-bash-history-${devcontainerId}", + "target": "/commandhistory", + "type": "volume" } ] } diff --git a/src/s-core-devcontainer/.devcontainer/s-core-local/install.sh b/src/s-core-devcontainer/.devcontainer/s-core-local/install.sh index 6eb71ff..c6f7714 100755 --- a/src/s-core-devcontainer/.devcontainer/s-core-local/install.sh +++ b/src/s-core-devcontainer/.devcontainer/s-core-local/install.sh @@ -10,40 +10,23 @@ COPY_TARGET="${FEATURES_DIR}/$(basename "${SCRIPT_DIR%%_*}")" cp -R "${SCRIPT_DIR}" "${COPY_TARGET}" rm -f "${COPY_TARGET}/devcontainer-features.env" "${COPY_TARGET}/devcontainer-features-install.sh" -# Check if required variables are set -if [ -z "${BAZEL_VERSION:-}" ]; then - echo "Error: BAZEL_VERSION is not set." - exit 1 -fi -if [ -z "${BUILDIFIER_VERSION:-}" ]; then - echo "Error: BUILDIFIER_VERSION is not set." - exit 1 -fi -if [ -z "${BUILDIFIER_SHA256:-}" ]; then - echo "Error: BUILDIFIER_SHA256 is not set." - exit 1 -fi -if [ -z "${BAZEL_COMPILE_COMMANDS_VERSION:-}" ]; then - echo "Error: BAZEL_COMPILE_COMMANDS_VERSION is not set." - exit 1 -fi -if [ -z "${BAZEL_COMPILE_COMMANDS_SHA256:-}" ]; then - echo "Error: BAZEL_COMPILE_COMMANDS_SHA256 is not set." - exit 1 -fi - DEBIAN_FRONTEND=noninteractive -# Install "common" tools +# Read tool versions + metadata into environment variables +. /devcontainer/features/s-core-local/versions.sh + apt-get update -apt-get install -y \ - curl + +# INSTALL CONTAINER BUILD DEPENDENCIES +# Container build dependencies are not pinned, since they are removed anyway after container creation. +apt-get install apt-transport-https -y # GraphViz -apt-get install -y graphviz +# The Ubuntu Noble package of GraphViz +apt-get install -y graphviz="${graphviz_version}*" # Protobuf compiler, via APT (needed by FEO) -apt-get install -y protobuf-compiler +apt-get install -y protobuf-compiler="${protobuf_compiler_version}*" # Bazel, via APT # - ghcr.io/devcontainers-community/features/bazel uses bazelisk, which has a few problems: @@ -52,51 +35,52 @@ apt-get install -y protobuf-compiler # - In general, pre-built containers *shall not* download "more tools" from the internet. # This is an operational risk (security, availability); it makes the build non-reproducible, # and it prevents the container from working in air-gapped environments. -apt-get install apt-transport-https curl gnupg -y curl -fsSL https://bazel.build/bazel-release.pub.gpg | gpg --dearmor > bazel-archive-keyring.gpg mv bazel-archive-keyring.gpg /usr/share/keyrings echo "deb [arch=amd64 signed-by=/usr/share/keyrings/bazel-archive-keyring.gpg] https://storage.googleapis.com/bazel-apt stable jdk1.8" | tee /etc/apt/sources.list.d/bazel.list apt-get update -apt-get install -y bazel=${BAZEL_VERSION} +apt-get install -y bazel=${bazel_version} # Buildifier, directly from GitHub (apparently no APT repository available) # The version is pinned to a specific release, and the SHA256 checksum is provided by the devcontainer-features.json file. -curl -L "https://github.com/bazelbuild/buildtools/releases/download/v${BUILDIFIER_VERSION}/buildifier-linux-amd64" -o /usr/local/bin/buildifier -echo "${BUILDIFIER_SHA256} /usr/local/bin/buildifier" | sha256sum -c - || exit -1 +curl -L "https://github.com/bazelbuild/buildtools/releases/download/v${buildifier_version}/buildifier-linux-amd64" -o /usr/local/bin/buildifier +echo "${buildifier_amd64_sha256} /usr/local/bin/buildifier" | sha256sum -c - || exit -1 chmod +x /usr/local/bin/buildifier # Starlark Language Server, directly from GitHub (apparently no APT repository available) -curl -L "https://github.com/withered-magic/starpls/releases/download/v${STARPLS_VERSION}/starpls-linux-amd64" -o /usr/local/bin/starpls -echo "${STARPLS_SHA256} /usr/local/bin/starpls" | sha256sum -c - || exit -1 +curl -L "https://github.com/withered-magic/starpls/releases/download/v${starpls_version}/starpls-linux-amd64" -o /usr/local/bin/starpls +echo "${starpls_amd64_sha256} /usr/local/bin/starpls" | sha256sum -c - || exit -1 chmod +x /usr/local/bin/starpls # Code completion for C++ code of Bazel projects # (see https://github.com/kiron1/bazel-compile-commands) # The version is pinned to a specific release, and the SHA256 checksum is provided by the devcontainer-features.json file. source /etc/lsb-release -curl -L "https://github.com/kiron1/bazel-compile-commands/releases/download/v${BAZEL_COMPILE_COMMANDS_VERSION}/bazel-compile-commands_${BAZEL_COMPILE_COMMANDS_VERSION}-${DISTRIB_CODENAME}_amd64.deb" -o /tmp/bazel-compile-commands.deb +curl -L "https://github.com/kiron1/bazel-compile-commands/releases/download/v${bazel_compile_commands_version}/bazel-compile-commands_${bazel_compile_commands_version}-${DISTRIB_CODENAME}_amd64.deb" -o /tmp/bazel-compile-commands.deb # Extract correct sha256 for current DISTRIB_CODENAME and check -BAZEL_COMPILE_COMMANDS_DEB_SHA256=$(echo "${BAZEL_COMPILE_COMMANDS_SHA256}" | tr ';' '\n' | grep "^${DISTRIB_CODENAME}:" | cut -d: -f2) -echo "${BAZEL_COMPILE_COMMANDS_DEB_SHA256} /tmp/bazel-compile-commands.deb" | sha256sum -c - || exit -1 +echo "${bazel_compile_commands_amd64_sha256} /tmp/bazel-compile-commands.deb" | sha256sum -c - || exit -1 apt-get install -y --no-install-recommends --fix-broken /tmp/bazel-compile-commands.deb rm /tmp/bazel-compile-commands.deb # Code completion for Rust code of Bazel projects (language server part) # (see https://bazelbuild.github.io/rules_rust/rust_analyzer.html and https://rust-analyzer.github.io/book/rust_analyzer_binary.html) # The version is pinned to a specific release, and the SHA256 checksum is provided by the devcontainer-features.json file. -curl -L https://github.com/rust-lang/rust-analyzer/releases/download/${RUST_ANALYZER_VERSION}/rust-analyzer-x86_64-unknown-linux-gnu.gz > /tmp/rust-analyzer.gz -echo "${RUST_ANALYZER_SHA256} /tmp/rust-analyzer.gz" | sha256sum -c - || exit -1 +# NOTE: For an unknown reason, rust-analyzer uses dates for downloading of releases, while the executable reports an actual release. +curl -L https://github.com/rust-lang/rust-analyzer/releases/download/${rust_analyzer_date}/rust-analyzer-x86_64-unknown-linux-gnu.gz > /tmp/rust-analyzer.gz +echo "${rust_analyzer_amd64_sha256} /tmp/rust-analyzer.gz" | sha256sum -c - || exit -1 gunzip -d /tmp/rust-analyzer.gz mv /tmp/rust-analyzer /usr/local/bin/rust-analyzer chmod +x /usr/local/bin/rust-analyzer -# qemu-system-aarch64 -apt-get install -y qemu-system-aarch64 +# qemu-system-arm +apt-get install -y --no-install-recommends --fix-broken qemu-system-arm="${qemu_system_arm_version}*" # sshpass -apt-get install -y sshpass +apt-get install -y sshpass="${sshpass_version}*" # Cleanup +# REMOVE CONTAINER BUILD DEPENDENCIES +apt-get remove --purge -y apt-transport-https apt-get autoremove -y apt-get clean rm -rf /var/lib/apt/lists/* diff --git a/src/s-core-devcontainer/.devcontainer/s-core-local/install_matching_bazel_version.sh b/src/s-core-devcontainer/.devcontainer/s-core-local/install_matching_bazel_version.sh new file mode 100755 index 0000000..c3b1c76 --- /dev/null +++ b/src/s-core-devcontainer/.devcontainer/s-core-local/install_matching_bazel_version.sh @@ -0,0 +1,6 @@ +#!/usr/bin/env bash +set -eo pipefail + +if [ -f .bazelversion ] && [ "$(cat .bazelversion)" != "$(dpkg --list | grep 'ii bazel ' | awk '{print $3}')" ]; then + sudo apt-get update && sudo apt-get install -y --allow-downgrades bazel=$(cat .bazelversion) +fi diff --git a/src/s-core-devcontainer/.devcontainer/s-core-local/setup_command_history.sh b/src/s-core-devcontainer/.devcontainer/s-core-local/setup_command_history.sh new file mode 100755 index 0000000..389d882 --- /dev/null +++ b/src/s-core-devcontainer/.devcontainer/s-core-local/setup_command_history.sh @@ -0,0 +1,24 @@ +#!/usr/bin/env bash +set -eo pipefail + +USERNAME=$(whoami) +GROUPNAME=$(id -gn) +COMMANDHISTORY_DIR="/commandhistory" +BASH_HISTORY_FILE="${COMMANDHISTORY_DIR}/.bash_history" +SNIPPET="export PROMPT_COMMAND='history -a' && export HISTFILE=${BASH_HISTORY_FILE}" +BASHRC_FILE="${HOME}/.bashrc" + +# Ensure the directory exists and set permissions +sudo mkdir -p "${COMMANDHISTORY_DIR}" +sudo chown "${USERNAME}:${GROUPNAME}" "${COMMANDHISTORY_DIR}" +sudo chmod 755 "${COMMANDHISTORY_DIR}" + +# Create .bash_history file if it doesn't exist and set permissions +if [[ ! -f "${BASH_HISTORY_FILE}" ]]; then + touch "${BASH_HISTORY_FILE}" + sudo chown "${USERNAME}:${GROUPNAME}" "${BASH_HISTORY_FILE}" + sudo chmod 600 "${BASH_HISTORY_FILE}" +fi + +# Add snippet to .bashrc if not already present +grep -qF -- "${SNIPPET}" "${BASHRC_FILE}" || echo "${SNIPPET}" >> "${BASHRC_FILE}" diff --git a/src/s-core-devcontainer/.devcontainer/s-core-local/tests/test_default.sh b/src/s-core-devcontainer/.devcontainer/s-core-local/tests/test_default.sh index e0d4675..8603845 100755 --- a/src/s-core-devcontainer/.devcontainer/s-core-local/tests/test_default.sh +++ b/src/s-core-devcontainer/.devcontainer/s-core-local/tests/test_default.sh @@ -1,21 +1,27 @@ #!/usr/bin/env bash set -euo pipefail +# Read tool versions + metadata into environment variables +. /devcontainer/features/s-core-local/versions.sh + # Common tooling +# For an unknown reason, dot -V reports on Ubuntu Noble a version 2.43.0, while the package has a different version. +# Hence, we have to work around that. check "validate graphviz is working" bash -c "dot -V" -check "validate curl is working" bash -c "curl --version" +check "validate graphviz has the correct version" bash -c "dpkg -s graphviz | grep 'Version: ${graphviz_version}'" + +# Other build-related tools +check "validate protoc is working and has the correct version" bash -c "protoc --version | grep 'libprotoc ${protobuf_compiler_version}'" # Bazel and related tools -check "validate bazel is working" bash -c "bazel version" -check "validate bazel-compile-commands is working" bash -c "bazel-compile-commands --version" -check "validate buildifier is working" bash -c "buildifier --version" +check "validate bazel is working and has the correct version" bash -c "bazel version | grep '${bazel_version}'" +check "validate buildifier is working and has the correct version" bash -c "buildifier --version | grep '${buildifier_version}'" +check "validate starpls is working and has the correct version" bash -c "starpls version | grep '${starpls_version}'" +check "validate bazel-compile-commands is working and has the correct version" bash -c "bazel-compile-commands --version 2>&1 | grep '${bazel_compile_commands_version}'" # Rust tooling -check "validate rust-analyzer is working" bash -c "rust-analyzer --version" - -# Other build-related tools -check "validate protoc is working" bash -c "protoc --version" +check "validate rust-analyzer is working and has the correct version" bash -c "rust-analyzer --version 2>&1 | grep '${rust_analyzer_version}'" # Qemu target-related tools -check "validate qemu-system-aarch64 is working" bash -c "qemu-system-aarch64 --version" -check "validate sshpass is working" bash -c "sshpass -V" +check "validate qemu-system-aarch64 is working and has the correct version" bash -c "qemu-system-aarch64 --version | grep '${qemu_system_arm_version}'" +check "validate sshpass is working and has the correct version" bash -c "sshpass -V | grep '${sshpass_version}'" diff --git a/src/s-core-devcontainer/.devcontainer/s-core-local/versions.sh b/src/s-core-devcontainer/.devcontainer/s-core-local/versions.sh new file mode 100755 index 0000000..a85ee08 --- /dev/null +++ b/src/s-core-devcontainer/.devcontainer/s-core-local/versions.sh @@ -0,0 +1,12 @@ +#!/usr/bin/env bash +set -euo pipefail + +curl -L "https://github.com/mikefarah/yq/releases/download/v4.47.1/yq_linux_amd64" -o /tmp/yq +echo "0fb28c6680193c41b364193d0c0fc4a03177aecde51cfc04d506b1517158c2fb /tmp/yq" | sha256sum -c - || exit -1 +chmod +x /tmp/yq + +# Read tool versions and metadata into environment variables +export $(/tmp/yq eval '.. | select((tag == "!!map" or tag == "!!seq") | not) | (path | join("_")) + "=" + .' /devcontainer/features/s-core-local/versions.yaml | awk '!/=$/{print }' | xargs) + +# Clean up +rm -f /tmp/yq diff --git a/src/s-core-devcontainer/.devcontainer/s-core-local/versions.yaml b/src/s-core-devcontainer/.devcontainer/s-core-local/versions.yaml new file mode 100644 index 0000000..874dc32 --- /dev/null +++ b/src/s-core-devcontainer/.devcontainer/s-core-local/versions.yaml @@ -0,0 +1,46 @@ +bazel: + version: 8.3.0 + +graphviz: + version: 2.42.2 + +protobuf_compiler: + version: 3.21.12 + +qemu_system_arm: + version: 1:8.2.2 + +sshpass: + version: 1.09 + +buildifier: + version: 8.2.1 + amd64: + # The following sha256sum is for the binary buildifier-linux-amd64 + # from the GitHub release page of buildtools + # It is generated by running 'sha256sum buildifier-linux-amd64' + sha256: 6ceb7b0ab7cf66fceccc56a027d21d9cc557a7f34af37d2101edb56b92fcfa1a + +starpls: + version: 0.1.22 + amd64: + # The following sha256sum is for the binary starpls-linux-amd64 + # from the GitHub release page of starpls + # It is generated by running 'sha256sum starpls-linux-amd64' + sha256: 7c661cdde0d1c026665086d07523d825671e29056276681616bb32d0273c5eab + +bazel_compile_commands: + version: 0.17.2 + amd64: + # The following sha256sums are for the deb package bazel-compile-commands_-noble_amd64.deb + # It is generated by running 'sha256sum bazel-compile-commands_-noble_amd64.deb' + sha256: 97239b316df58fd3370a8aa6350790ececd5e4a1de30efb42d45cb1c300a179a + +rust_analyzer: + date: 2025-08-25 + version: 0.3.2593-standalone + amd64: + # The following sha256sum is for the binary rust-analyzer-x86_64-unknown-linux-gnu.gz + # from the GitHub release page of rust-analyzer + # It is generated by running 'sha256sum rust-analyzer-x86_64-unknown-linux-gnu.gz' + sha256: 487fb1cb99e567fd6b818cc88a7c1452d5260da57dbc171fc1359a4b604348ae diff --git a/src/s-core-devcontainer/test-project/test.sh b/src/s-core-devcontainer/test-project/test.sh index ab80200..1b1d94e 100755 --- a/src/s-core-devcontainer/test-project/test.sh +++ b/src/s-core-devcontainer/test-project/test.sh @@ -6,15 +6,15 @@ SCRIPT_DIR=$(dirname -- "${SCRIPT_PATH}") source "${SCRIPT_DIR}/../../../scripts/test-utils.sh" vscode # Common tooling -check "validate git is working" bash -c "git --version" -check "validate git-lfs is working" bash -c "git lfs version" -check "validate python3 is working" bash -c "python3 --version" +check "validate git is working and has the correct version" bash -c "git --version | grep '2.49.0'" +check "validate git-lfs is working and has the correct version" bash -c "git lfs version | grep '3.7.0' " +check "validate python3 is working and has the correct version" bash -c "python3 --version | grep '3.12.11'" # C++ tooling -check "validate clangd is working" bash -c "clangd --version" -check "validate clang-format is working" bash -c "clang-format --version" -check "validate clang-tidy is working" bash -c "clang-tidy --version" -check "validate clang is working" bash -c "clang --version" +check "validate clangd is working and has the correct version" bash -c "clangd --version | grep '20.1.8'" +check "validate clang-format is working and has the correct version" bash -c "clang-format --version | grep '20.1.8'" +check "validate clang-tidy is working and has the correct version" bash -c "clang-tidy --version | grep '20.1.8'" +check "validate clang is working and has the correct version" bash -c "clang --version | grep '20.1.8'" # Tests from the local s-core-local feature source /devcontainer/features/s-core-local/tests/test_default.sh