Skip to content
Merged
128 changes: 128 additions & 0 deletions .github/workflows/pr-test.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,128 @@
name: PR test

on:
workflow_dispatch:
pull_request:

permissions:
contents: read

jobs:
test:
name: Runtime behavior tests
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4

- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3

- name: Read version
id: version
run: |
VERSION=$(cat version.txt | tr -d '[:space:]')
echo "version=${VERSION}" >> "$GITHUB_OUTPUT"

- name: Build image
uses: docker/build-push-action@v6
with:
context: .
load: true
build-args: OPENCODE_VERSION=${{ steps.version.outputs.version }}
tags: opencode-test:latest

- name: Run runtime tests
id: tests
env:
GITHUB_TOKEN: ${{ github.token }}
run: |
set -e
PASS=0
FAIL=0
REPORT=""

test() {
local desc="$1" cmd="$2"
echo "::group::${desc}"
if eval "$cmd" 2>&1; then
PASS=$((PASS+1))
REPORT="${REPORT}- [x] ${desc}\n"
echo "PASS: ${desc}"
else
FAIL=$((FAIL+1))
REPORT="${REPORT}- [ ] ${desc}\n"
echo "FAIL: ${desc}"
fi
echo "::endgroup::"
}

IN="docker run --rm -e GITHUB_TOKEN --entrypoint bash opencode-test:latest"

echo "=== Pre-installed tools (interactive) ==="

test "node works in interactive shell" \
"$IN -i -c 'source ~/.bashrc 2>/dev/null; node --version'"

test "npm works in interactive shell" \
"$IN -i -c 'source ~/.bashrc 2>/dev/null; npm --version'"

test "npx works in interactive shell" \
"$IN -i -c 'source ~/.bashrc 2>/dev/null; npx --version'"

test "gh works in interactive shell" \
"$IN -i -c 'source ~/.bashrc 2>/dev/null; gh --version'"

echo "=== mise use (interactive) ==="

test "mise use go works in interactive shell" \
"$IN -i -c 'source ~/.bashrc 2>/dev/null; mise use go@latest && go version'"

echo "=== Pre-installed tools (non-interactive, via BASH_ENV) ==="

test "node works in non-interactive shell" \
"$IN -c 'which node && node --version'"

test "npm works in non-interactive shell" \
"$IN -c 'which npm && npm --version'"

test "npx works in non-interactive shell" \
"$IN -c 'which npx && npx --version'"

echo "=== mise use (non-interactive, via BASH_ENV fallback) ==="

test "mise use go works in non-interactive shell" \
"$IN -c 'mise use go@latest && go version'"

echo "=== Shim path verification (non-interactive) ==="

test "node resolves from auto-install-shims" \
"$IN -c 'which node | grep -q /opt/auto-install-shims/node'"

test "npm resolves from auto-install-shims" \
"$IN -c 'which npm | grep -q /opt/auto-install-shims/npm'"

test "npx resolves from auto-install-shims" \
"$IN -c 'which npx | grep -q /opt/auto-install-shims/npx'"

echo ""
echo "=== Results: $PASS passed, $FAIL failed ==="

# Write to step summary
{
echo "## Runtime test results"
echo ""
echo "**${PASS} passed, ${FAIL} failed**"
echo ""
printf "%b" "$REPORT"
echo ""
echo "### Shorthand"
echo ""
echo "| Scope | Interactive | Non-interactive |"
echo "|---|---|---|"
echo "| Pre-installed tools | \`node --version\`, \`npm --version\`, \`npx --version\`, \`gh --version\` | \`which node\`, \`which npm\`, \`which npx\` |"
echo "| mise use | \`mise use go && go version\` | \`mise use go && go version\` |"
} >> "$GITHUB_STEP_SUMMARY"

# Fail the step if any test failed
[ "$FAIL" -eq 0 ]
21 changes: 13 additions & 8 deletions Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ ENV DEBIAN_FRONTEND=noninteractive

# CLI utilities for day-to-day dev work (git, curl, etc.).
RUN apt-get update && apt-get install -y --no-install-recommends \
ca-certificates curl git unzip \
ca-certificates curl git openssh-client unzip \
less libatomic1 sudo tini tzdata \
&& rm -rf /var/lib/apt/lists/* /var/cache/apt/archives/*.deb \
&& rm -rf /usr/share/doc /usr/share/man /usr/share/locale \
Expand Down Expand Up @@ -109,6 +109,7 @@ ENV HOMEBREW_NO_AUTO_UPDATE=1
ENV HOMEBREW_INSTALL_FROM_API=1
ENV MISE_DATA_DIR=/opt/mise
ENV MISE_ALWAYS_INSTALL=1
ENV BASH_ENV=/etc/opencode-mise.bash

LABEL io.artifacthub.package.readme-url="https://raw.githubusercontent.com/sprisa/opencode-server/refs/heads/main/README.md" \
org.opencontainers.image.created="${IMAGE_CREATED}" \
Expand Down Expand Up @@ -144,23 +145,27 @@ COPY --from=builder /opt/opencode /usr/local/bin/opencode
RUN opencode --version \
&& printf 'for d in "$HOME/.local/bin" "/home/linuxbrew/.linuxbrew/bin" "/home/linuxbrew/.linuxbrew/sbin" "$HOME/.local/share/zerobrew/prefix/bin"; do case ":$PATH:" in *":$d:"*) ;; *) PATH="$d:$PATH";; esac; done\nexport PATH\n' > /etc/profile.d/brew-path.sh \
&& chmod 0644 /etc/profile.d/brew-path.sh \
&& printf '\neval "$(mise activate bash)"\n' >> /home/opencode/.bashrc \
&& printf '\n# Mise activation for interactive shells\nsource /etc/opencode-mise.bash\neval "$(mise activate bash)"\n' >> /home/opencode/.bashrc \
&& printf '\neval "$(mise activate zsh)"\n' >> /home/opencode/.zshrc \
&& mkdir -p /home/opencode/.config/fish \
&& printf '\nmise activate fish | source\n' >> /home/opencode/.config/fish/config.fish \
&& printf '\neval "$(mise activate sh)"\n' >> /home/opencode/.profile \
&& printf '#!/usr/bin/env bash\n# Route unknown commands through mise (fallback for non-interactive shells)\nif [ -n "${BASH_VERSION-}" ]; then\n command_not_found_handle() {\n if /usr/local/bin/mise which "$1" &>/dev/null; then\n /usr/local/bin/mise exec "$1" -- "$@"\n return $?\n fi\n return 127\n }\nfi\n' > /etc/opencode-mise.bash \
&& chmod 0644 /etc/opencode-mise.bash \
&& mkdir -p /opt/auto-install-shims \
&& grep -E '^\s*"' /etc/mise/config.toml | while IFS='=' read -r key value; do \
key="$(echo "$key" | tr -d ' "')" \
&& shim="$(echo "$value" | sed -n 's/.*# shim:\([^ ]*\).*/\1/p')" \
&& if [ -z "$shim" ]; then \
&& shim_list="$(echo "$value" | sed -n 's/.*# shim:\([^ ]*\).*/\1/p')" \
&& if [ -z "$shim_list" ]; then \
case "$key" in \
github:*) shim="${key##*/}" ;; \
*) shim="${key#*:}" ;; \
github:*) shim_list="${key##*/}" ;; \
*) shim_list="${key#*:}" ;; \
esac; \
fi \
&& printf '#!/usr/bin/env bash\nexec /usr/local/bin/mise exec "%s" -- %s "$@"\n' "$key" "$shim" > "/opt/auto-install-shims/$shim" \
&& chmod 0755 "/opt/auto-install-shims/$shim"; \
&& for shim in $(echo "$shim_list" | tr ',' ' '); do \
printf '#!/usr/bin/env bash\nexec /usr/local/bin/mise exec "%s" -- %s "$@"\n' "$key" "$shim" > "/opt/auto-install-shims/$shim" \
&& chmod 0755 "/opt/auto-install-shims/$shim"; \
done; \
done \
&& chown -R opencode:opencode /opt/auto-install-shims \
&& mkdir -p /home/opencode/workspace \
Expand Down
1 change: 1 addition & 0 deletions mise-config.toml
Original file line number Diff line number Diff line change
Expand Up @@ -11,4 +11,5 @@
"zerobrew:nano" = "latest"
"zerobrew:python" = "latest"
"node" = "latest"
"npm" = "latest" # shim:npm,npx
"github:facebook/sapling" = "latest" # shim:sl
Loading