diff --git a/.devcontainer/post_create_command.sh b/.devcontainer/post_create_command.sh index ebeac73..161532c 100755 --- a/.devcontainer/post_create_command.sh +++ b/.devcontainer/post_create_command.sh @@ -1,3 +1,5 @@ #!/usr/bin/env bash npm install -g @devcontainers/cli pre-commit install + +scripts/create_builder.sh diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index 0f3ea2a..24fde92 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -41,6 +41,9 @@ jobs: # Check pre-commit run --show-diff-on-failure --color=always --all-files || exit -1 + # Create builder for multi-arch builds + ./scripts/create_builder.sh + # Build ./scripts/build.sh @@ -58,4 +61,4 @@ jobs: runCmd: | # manually login to ghcr.io for publishing echo "${{ secrets.GITHUB_TOKEN }}" | docker login ghcr.io -u ${{ github.actor }} --password-stdin - ./scripts/publish.sh "latest" + ./scripts/publish.sh "main" diff --git a/.github/workflows/release.yaml b/.github/workflows/release.yaml index bcbdb49..5cc6630 100644 --- a/.github/workflows/release.yaml +++ b/.github/workflows/release.yaml @@ -36,6 +36,9 @@ jobs: # Check pre-commit run --show-diff-on-failure --color=always --all-files || exit -1 + # Create builder for multi-arch builds + ./scripts/create_builder.sh + # Build ./scripts/build.sh @@ -53,4 +56,4 @@ jobs: # 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 }}" + ./scripts/publish.sh "${{ github.ref_name }}" "latest" diff --git a/README.md b/README.md index a984f10..be12767 100644 --- a/README.md +++ b/README.md @@ -29,7 +29,7 @@ It should contain the following: ```` The `` must be a [valid, published release](https://github.com/eclipse-score/devcontainer/tags). -You can also use `latest` as `` to automatically follow the `main` branch - but be aware that this can result in undesired updates. +You can also use `main` as `` to automatically follow the `main` branch, and `latest` to follow release tags - but be aware that this can result in undesired updates. To start using the container, click the **Reopen in Container** button when prompted by Visual Studio Code: diff --git a/scripts/build.sh b/scripts/build.sh index d8c570f..e4a23ff 100755 --- a/scripts/build.sh +++ b/scripts/build.sh @@ -1,4 +1,5 @@ #!/usr/bin/env bash set -euxo pipefail -devcontainer build --workspace-folder src/s-core-devcontainer --image-name ghcr.io/eclipse-score/devcontainer:latest --cache-from ghcr.io/eclipse-score/devcontainer +devcontainer build --platform linux/aarch64 --workspace-folder src/s-core-devcontainer --image-name ghcr.io/eclipse-score/devcontainer --cache-from ghcr.io/eclipse-score/devcontainer +devcontainer build --platform linux/amd64 --workspace-folder src/s-core-devcontainer --image-name ghcr.io/eclipse-score/devcontainer --cache-from ghcr.io/eclipse-score/devcontainer diff --git a/scripts/create_builder.sh b/scripts/create_builder.sh new file mode 100755 index 0000000..cd9366a --- /dev/null +++ b/scripts/create_builder.sh @@ -0,0 +1,4 @@ +#!/usr/bin/env bash +set -euxo pipefail + +docker buildx create --name multiarch --driver docker-container --use diff --git a/scripts/publish.sh b/scripts/publish.sh index b8e7ad7..6bca3f4 100755 --- a/scripts/publish.sh +++ b/scripts/publish.sh @@ -1,10 +1,19 @@ #!/usr/bin/env bash set -euxo pipefail -TAG="${1:-latest}" - -if [[ "$TAG" != "latest" ]]; then - docker tag "ghcr.io/eclipse-score/devcontainer:latest" "ghcr.io/eclipse-score/devcontainer:${TAG}" +IMAGES=("--image-name \"ghcr.io/eclipse-score/devcontainer:main\"") +if [ "$#" -gt 0 ]; then + IMAGES=() + for arg in "$@"; do + IMAGES+=("--image-name \"ghcr.io/eclipse-score/devcontainer:${arg}\"") + done fi -docker push "ghcr.io/eclipse-score/devcontainer:${TAG}" +DEVCONTAINER_CALL="devcontainer build --push --workspace-folder src/s-core-devcontainer --cache-from ghcr.io/eclipse-score/devcontainer" + +for IMAGE in "${IMAGES[@]}"; do + DEVCONTAINER_CALL+=" $IMAGE" +done + +eval "$DEVCONTAINER_CALL --platform linux/aarch64" +eval "$DEVCONTAINER_CALL --platform linux/amd64" diff --git a/src/s-core-devcontainer/.devcontainer/devcontainer.json b/src/s-core-devcontainer/.devcontainer/devcontainer.json index d792496..4b774fa 100644 --- a/src/s-core-devcontainer/.devcontainer/devcontainer.json +++ b/src/s-core-devcontainer/.devcontainer/devcontainer.json @@ -42,8 +42,18 @@ }, "./s-core-local": {} }, + "overrideFeatureInstallOrder": [ + // this order makes it more convenient to develop the s-core-local feature, since it will be installed last + // which means changes to it will be applied without needing to rebuild all other features + "ghcr.io/devcontainers/features/git", + "ghcr.io/devcontainers/features/git-lfs", + "ghcr.io/devcontainers/features/common-utils", + "ghcr.io/devcontainers-community/features/llvm", + "ghcr.io/devcontainers/features/rust", + "ghcr.io/devcontainers/features/python", + "./s-core-local" + ], "remoteUser": "vscode", - "initializeCommand": "mkdir -p ${localEnv:HOME}/.cache/bazel", "customizations": { "vscode": { "extensions": [ 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 7861486..1e0a2fa 100755 --- a/src/s-core-devcontainer/.devcontainer/s-core-local/install.sh +++ b/src/s-core-devcontainer/.devcontainer/s-core-local/install.sh @@ -15,6 +15,8 @@ DEBIAN_FRONTEND=noninteractive # Read tool versions + metadata into environment variables . /devcontainer/features/s-core-local/versions.sh +ARCHITECTURE=$(dpkg --print-architecture) + apt-get update # INSTALL CONTAINER BUILD DEPENDENCIES @@ -28,37 +30,62 @@ apt-get install -y graphviz="${graphviz_version}*" # Protobuf compiler, via APT (needed by FEO) 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: -# - It does not install bash autocompletion. -# - The bazel version is not pinned, which is required to be reproducible and to have coordinated, tested tool updates. -# - 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. -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} +# Bazelisk, directly from GitHub +# Using the existing devcontainer feature is not optimal: +# - it does not check the SHA256 checksum of the downloaded file +# - it cannot pre-install a specific version of Bazel, or prepare bash completion +BAZELISK_VARIANT="amd64" +SHA256SUM="${bazelisk_amd64_sha256}" +if [ "${ARCHITECTURE}" = "arm64" ]; then + BAZELISK_VARIANT="arm64" + SHA256SUM="${bazelisk_arm64_sha256}" +fi +curl -L "https://github.com/bazelbuild/bazelisk/releases/download/v${bazelisk_version}/bazelisk-${BAZELISK_VARIANT}.deb" -o /tmp/bazelisk.deb +echo "${SHA256SUM} /tmp/bazelisk.deb" | sha256sum -c - || exit -1 +apt-get install -y --no-install-recommends --fix-broken /tmp/bazelisk.deb +rm /tmp/bazelisk.deb + +# Pre-install a fixed Bazel version, setup the bash command completion +export USE_BAZEL_VERSION=${bazel_version} +bazel help completion bash > /tmp/bazel-complete.bash +ls -lah /tmp/bazel-complete.bash +mkdir -p /etc/bash_completion.d +mv /tmp/bazel-complete.bash /etc/bash_completion.d/bazel-complete.bash +sh -c "echo 'export USE_BAZEL_VERSION=${bazel_version}' >> /etc/profile.d/bazel.sh" # 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_amd64_sha256} /usr/local/bin/buildifier" | sha256sum -c - || exit -1 +BUILDIFIER_VARIANT="amd64" +SHA256SUM="${buildifier_amd64_sha256}" +if [ "${ARCHITECTURE}" = "arm64" ]; then + BUILDIFIER_VARIANT="arm64" + SHA256SUM="${buildifier_arm64_sha256}" +fi +curl -L "https://github.com/bazelbuild/buildtools/releases/download/v${buildifier_version}/buildifier-linux-${BUILDIFIER_VARIANT}" -o /usr/local/bin/buildifier +echo "${SHA256SUM} /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_amd64_sha256} /usr/local/bin/starpls" | sha256sum -c - || exit -1 +STARPLS_VARIANT="amd64" +SHA256SUM="${starpls_amd64_sha256}" +if [ "${ARCHITECTURE}" = "arm64" ]; then + STARPLS_VARIANT="aarch64" + SHA256SUM="${starpls_arm64_sha256}" +fi +curl -L "https://github.com/withered-magic/starpls/releases/download/v${starpls_version}/starpls-linux-${STARPLS_VARIANT}" -o /usr/local/bin/starpls +echo "${SHA256SUM} /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}_${ARCHITECTURE}.deb" -o /tmp/bazel-compile-commands.deb # Extract correct sha256 for current DISTRIB_CODENAME and check -echo "${bazel_compile_commands_amd64_sha256} /tmp/bazel-compile-commands.deb" | sha256sum -c - || exit -1 +SHA256SUM="${bazel_compile_commands_amd64_sha256}" +if [ "${ARCHITECTURE}" = "arm64" ]; then + SHA256SUM="${bazel_compile_commands_arm64_sha256}" +fi +echo "${SHA256SUM} /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 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 index c3b1c76..642fbff 100755 --- 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 @@ -1,6 +1,10 @@ #!/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) +if [ -f .bazelversion ] && [ "$(cat .bazelversion)" != "$(bazel version | grep 'Build label:' | awk '{print $3}')" ]; then + # Pre-install the matching Bazel version, setup the bash command completion + USE_BAZEL_VERSION=$(cat .bazelversion) + bazel help completion bash > /tmp/bazel-complete.bash + sudo mv /tmp/bazel-complete.bash /etc/bash_completion.d/bazel-complete.bash + sudo sed -i '/^USE_BAZEL_VERSION=/c\USE_BAZEL_VERSION=${USE_BAZEL_VERSION}' /etc/profile.d/bazel.sh || true fi 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 585dd83..686bd2f 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 @@ -13,7 +13,8 @@ check "validate graphviz has the correct version" bash -c "dpkg -s graphviz | gr # 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 +# Bazel-related tools +check "validate bazelisk is working and has the correct version" bash -c "bazelisk version | grep '${bazelisk_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}'" diff --git a/src/s-core-devcontainer/.devcontainer/s-core-local/versions.sh b/src/s-core-devcontainer/.devcontainer/s-core-local/versions.sh index a85ee08..64760fa 100755 --- a/src/s-core-devcontainer/.devcontainer/s-core-local/versions.sh +++ b/src/s-core-devcontainer/.devcontainer/s-core-local/versions.sh @@ -1,8 +1,16 @@ #!/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 +ARCHITECTURE=$(dpkg --print-architecture) +VERSION="v4.47.2" + +SHA256_FIELD="1bb99e1019e23de33c7e6afc23e93dad72aad6cf2cb03c797f068ea79814ddb0" # Default to amd64 +if [ "${ARCHITECTURE}" = "arm64" ]; then + SHA256_FIELD="05df1f6aed334f223bb3e6a967db259f7185e33650c3b6447625e16fea0ed31f" +fi + +curl -L "https://github.com/mikefarah/yq/releases/download/${VERSION}/yq_linux_${ARCHITECTURE}" -o /tmp/yq +echo "${SHA256_FIELD} /tmp/yq" | sha256sum -c - || exit -1 chmod +x /tmp/yq # Read tool versions and metadata into environment variables diff --git a/src/s-core-devcontainer/.devcontainer/s-core-local/versions.yaml b/src/s-core-devcontainer/.devcontainer/s-core-local/versions.yaml index d76d4e8..ab4436e 100644 --- a/src/s-core-devcontainer/.devcontainer/s-core-local/versions.yaml +++ b/src/s-core-devcontainer/.devcontainer/s-core-local/versions.yaml @@ -1,6 +1,3 @@ -bazel: - version: 8.3.0 - graphviz: version: 2.42.2 @@ -13,6 +10,11 @@ qemu_system_arm: sshpass: version: 1.09 +bazel: + # https://github.com/bazelbuild/bazel/releases -- latest version as of 2025-09-24 + version: 8.4.1 + # no need to define sha256 here, as bazel is installed via bazelisk + buildifier: version: 8.2.1 amd64: @@ -20,6 +22,22 @@ buildifier: # from the GitHub release page of buildtools # It is generated by running 'sha256sum buildifier-linux-amd64' sha256: 6ceb7b0ab7cf66fceccc56a027d21d9cc557a7f34af37d2101edb56b92fcfa1a + arm64: + # The following sha256sum is for the binary buildifier-linux-arm64 + # from the GitHub release page of buildtools + # It is generated by running 'sha256sum buildifier-linux-arm64' + sha256: 3baa1cf7eb41d51f462fdd1fff3a6a4d81d757275d05b2dd5f48671284e9a1a5 + +bazelisk: + version: 1.27.0 + amd64: + # The following sha256sums are for the deb package bazelisk__amd64.deb + # It is generated by running 'sha256sum bazelisk__amd64.deb' + sha256: d8b00ea975c823e15263c80200ac42979e17368547fbff4ab177af035badfa83 + arm64: + # The following sha256sums are for the deb package bazelisk__arm64.deb + # It is generated by running 'sha256sum bazelisk__arm64.deb' + sha256: 173c5b367b485a30ce58c1d0d560b39d257a2d7a3c859c45d7d05eb61605a2a1 starpls: version: 0.1.22 @@ -28,10 +46,19 @@ starpls: # from the GitHub release page of starpls # It is generated by running 'sha256sum starpls-linux-amd64' sha256: 7c661cdde0d1c026665086d07523d825671e29056276681616bb32d0273c5eab + arm64: + # The following sha256sum is for the binary starpls-linux-arm64 + # from the GitHub release page of starpls + # It is generated by running 'sha256sum starpls-linux-arm64' + sha256: 55877ec4c3ff03e1d90d59c76f69a3a144b6c29688747c8ac4d77993e2eef1ad bazel_compile_commands: - version: 0.17.2 + version: 0.18.0 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 + sha256: 6735ea846241497094719792ad3d4f67b1d3123048693d34fcdf7190f8c2da4e + arm64: + # The following sha256sums are for the deb package bazel-compile-commands_-noble_arm64.deb + # It is generated by running 'sha256sum bazel-compile-commands_-noble_arm64.deb' + sha256: d73998efa01cbd501b82ad6266642464b78ecd9fc6224a60c9cb558182d52d88