diff --git a/MODULE.bazel b/MODULE.bazel index f81ba10..fce91a3 100644 --- a/MODULE.bazel +++ b/MODULE.bazel @@ -26,6 +26,7 @@ multitool.hub(lockfile = "//tools:lockfiles/buildifier.lock.json") multitool.hub(lockfile = "//tools:lockfiles/starpls.lock.json") multitool.hub(lockfile = "//tools:lockfiles/bazelisk.lock.json") multitool.hub(lockfile = "//tools:lockfiles/apm.lock.json") +multitool.hub(lockfile = "//tools:lockfiles/opencode.lock.json") use_repo(multitool, "multitool") diff --git a/README.md b/README.md index 3584f0c..8ced69a 100644 --- a/README.md +++ b/README.md @@ -140,6 +140,14 @@ should run successfully. > `/var/cache/bazel/` is the path onto which a Docker volume is mounted. > Unless you have setup the same on your host, this will only make `linux-sandbox` work within the devcontainer. +### `gh` and `opencode` configuration + +This devcontainer includes the `gh` and `opencode` tools, but does not include any configuration for them. +Configuration is *not* copied from the host into the container, but is instead stored in Docker volumes. + +This avoids any host dependencies and a complex machinery to copy configuration from the host into the container. +Configure these tools inside the container and they will be kept until the volumes are removed across container rebuilds and different repositories. + ### How to use: codeql The devcontainer codeql installation supports C, C++ and Rust source code analysis. All publicly available diff --git a/scripts/create_builder.sh b/scripts/create_builder.sh index 12724b3..b0d3e70 100755 --- a/scripts/create_builder.sh +++ b/scripts/create_builder.sh @@ -44,6 +44,9 @@ if docker buildx inspect multiarch &>/dev/null; then if ! check_proxy_config; then echo "Builder 'multiarch' exists but has incorrect proxy configuration. Recreating..." docker buildx rm multiarch + elif ! docker buildx inspect multiarch --bootstrap &>/dev/null; then + echo "Builder 'multiarch' exists but is unhealthy. Recreating..." + docker buildx rm multiarch else echo "Builder 'multiarch' already exists with correct configuration." docker buildx use multiarch diff --git a/src/s-core-devcontainer/.devcontainer/devcontainer.json b/src/s-core-devcontainer/.devcontainer/devcontainer.json index f1394b0..fdc8675 100644 --- a/src/s-core-devcontainer/.devcontainer/devcontainer.json +++ b/src/s-core-devcontainer/.devcontainer/devcontainer.json @@ -54,6 +54,7 @@ "llvm-vs-code-extensions.vscode-clangd", "jebbs.plantuml", // preview PlantUML diagrams "hediet.vscode-drawio", // Draw.IO integration + "sst-dev.opencode", // OpenCode VS Code extension "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 integration 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 c6e0d0f..0faca54 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 @@ -10,6 +10,7 @@ }, "onCreateCommand": "/devcontainer/features/s-core-local/on_create_command.sh", "postCreateCommand": { + "Fix ownership of mounted config volumes": "bash /devcontainer/features/s-core-local/fix_config_volume_ownership.sh", "Setup persistent bash history": "bash /devcontainer/features/s-core-local/setup_command_history.sh", "Enable pre-commit hooks": "bash /devcontainer/features/s-core-local/enable_pre_commit_hooks.sh" }, @@ -18,6 +19,26 @@ "source": "eclipse-s-core-bash-history-${devcontainerId}", "target": "/commandhistory", "type": "volume" + }, + // Persisting the configuration of the OpenCode CLI and GitHub CLI tools. + // A nice way would be to copy the configuration files to the host machine, + // but this is not possible in a devcontainer feature or prebuild devcontainer image, + // so we use volumes instead. + // `initializeCommand` is only run by the `devcontainer.json` of the using repo and from the image. + { + "source": "opencode-config", + "target": "/home/vscode/.config/opencode", + "type": "volume" + }, + { + "source": "opencode-config", + "target": "/home/vscode/.local/share/opencode", + "type": "volume" + }, + { + "source": "gh-config", + "target": "/home/vscode/.config/gh", + "type": "volume" } ] } diff --git a/src/s-core-devcontainer/.devcontainer/s-core-local/fix_config_volume_ownership.sh b/src/s-core-devcontainer/.devcontainer/s-core-local/fix_config_volume_ownership.sh new file mode 100755 index 0000000..ea3362d --- /dev/null +++ b/src/s-core-devcontainer/.devcontainer/s-core-local/fix_config_volume_ownership.sh @@ -0,0 +1,41 @@ +#!/usr/bin/env bash + +# ******************************************************************************* +# Copyright (c) 2026 Contributors to the Eclipse Foundation +# +# See the NOTICE file(s) distributed with this work for additional +# information regarding copyright ownership. +# +# This program and the accompanying materials are made available under the +# terms of the Apache License Version 2.0 which is available at +# https://www.apache.org/licenses/LICENSE-2.0 +# +# SPDX-License-Identifier: Apache-2.0 +# ******************************************************************************* + +set -euo pipefail + +current_user_group="$(id -un):$(id -gn)" + +ensure_owner() { + local target_dir="$1" + + if [ ! -d "${target_dir}" ]; then + echo "Error: Config Volume: ${target_dir} does not exist." + exit 1 + fi + + local current_owner_group + current_owner_group=$(stat -c "%U:%G" "${target_dir}") + + if [ "${current_owner_group}" = "${current_user_group}" ]; then + echo "Config Volume: ${target_dir} is already owned by ${current_user_group}." + else + echo "Config Volume: ${target_dir} is owned by ${current_owner_group}. Setting ownership to ${current_user_group}..." + sudo chown -R "${current_user_group}" "${target_dir}" + fi +} + +ensure_owner "/home/vscode/.config/opencode" +ensure_owner "/home/vscode/.local/share/opencode" +ensure_owner "/home/vscode/.config/gh" 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 7a38f21..7d88719 100755 --- a/src/s-core-devcontainer/.devcontainer/s-core-local/install.sh +++ b/src/s-core-devcontainer/.devcontainer/s-core-local/install.sh @@ -58,7 +58,7 @@ apt-get install -y "python${python_version}" python3-pip python3-venv apt-get install -y flake8 python3-autopep8 black python3-yapf mypy pydocstyle pycodestyle bandit pipenv virtualenv pylint # Lockfile-managed local developer tools -/usr/local/share/score-tools/tool_installer.py install shellcheck ruff actionlint yamlfmt uv uvx apm +/usr/local/share/score-tools/tool_installer.py install shellcheck ruff actionlint yamlfmt uv uvx apm opencode # GraphViz # The Ubuntu Noble package of GraphViz 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 0c41974..ce7a42d 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 @@ -28,6 +28,7 @@ yamlfmt_lockfile_version="$(/usr/local/share/score-tools/tool_installer.py versi uv_lockfile_version="$(/usr/local/share/score-tools/tool_installer.py version uv)" uvx_lockfile_version="$(/usr/local/share/score-tools/tool_installer.py version uvx)" apm_lockfile_version="$(/usr/local/share/score-tools/tool_installer.py version apm)" +opencode_lockfile_version="$(/usr/local/share/score-tools/tool_installer.py version opencode)" # pre-commit, it is available via $PATH in login shells, but not in non-login shells check "validate pre-commit is working and has the correct version" bash -c "pre-commit --version | grep '4.5.1'" @@ -75,6 +76,9 @@ check "validate yamlfmt is working and has the correct version" bash -c "yamlfmt # apm check "validate apm is working and has the correct version" bash -c "apm --version | grep '${apm_lockfile_version}'" +# opencode +check "validate opencode is working and has the correct version" bash -c "opencode --version | grep '${opencode_lockfile_version}'" + # uv check "validate uv is working and has the correct version" bash -c "uv --version | grep '${uv_lockfile_version}'" check "validate uvx is working and has the correct version" bash -c "uvx --version | grep '${uvx_lockfile_version}'" 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 f60ade4..68f865d 100644 --- a/src/s-core-devcontainer/.devcontainer/s-core-local/versions.yaml +++ b/src/s-core-devcontainer/.devcontainer/s-core-local/versions.yaml @@ -53,3 +53,5 @@ lcov: version: 2.0 apm: version: 0.27.0 +opencode: + version: 1.18.15 diff --git a/tools/BUILD.bazel b/tools/BUILD.bazel index 4dc1500..0864323 100644 --- a/tools/BUILD.bazel +++ b/tools/BUILD.bazel @@ -26,3 +26,5 @@ multitool_aliases("starpls") multitool_aliases("uv") multitool_aliases("uvx") multitool_aliases("yamlfmt") +multitool_aliases("apm") +multitool_aliases("opencode") diff --git a/tools/lockfiles/opencode.lock.json b/tools/lockfiles/opencode.lock.json new file mode 100644 index 0000000..fbcb3be --- /dev/null +++ b/tools/lockfiles/opencode.lock.json @@ -0,0 +1,44 @@ +{ + "$schema": "https://raw.githubusercontent.com/bazel-contrib/rules_multitool/main/lockfile.schema.json", + "opencode": { + "version": "1.18.15", + "binaries": [ + { + "kind": "archive", + "file": "opencode", + "url": "https://github.com/anomalyco/opencode/releases/download/v1.18.15/opencode-darwin-arm64.zip", + "sha256": "bd60b57cb9fe0494a5352c807424d36d6d7853cf6dbddb97065c7ccd3c5d391c", + "type": "zip", + "os": "macos", + "cpu": "arm64" + }, + { + "kind": "archive", + "file": "opencode", + "url": "https://github.com/anomalyco/opencode/releases/download/v1.18.15/opencode-darwin-x64.zip", + "sha256": "e97e8185e7b7942f6e14f51b8727dbe023b54772e075bc16fead813680455d17", + "type": "zip", + "os": "macos", + "cpu": "x86_64" + }, + { + "kind": "archive", + "file": "opencode", + "url": "https://github.com/anomalyco/opencode/releases/download/v1.18.15/opencode-linux-x64.tar.gz", + "sha256": "d842e0e8c622c672a481b7dc6f0329009b64db96b2ba6041e56f4f93f0293b1c", + "type": "tar.gz", + "os": "linux", + "cpu": "x86_64" + }, + { + "kind": "archive", + "file": "opencode", + "url": "https://github.com/anomalyco/opencode/releases/download/v1.18.15/opencode-linux-arm64.tar.gz", + "sha256": "500611819ff88916b185649990505a9be76ad13ca5bb4b9323e5abdd39b1c6fb", + "type": "tar.gz", + "os": "linux", + "cpu": "arm64" + } + ] + } +}