Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
53 changes: 53 additions & 0 deletions .devcontainer/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
FROM mcr.microsoft.com/devcontainers/base:trixie

# Install libaio1t64 and provide a libaio.so.1 symlink for Oracle Instant Client
# Install rlwrap for readline support in sqlplus
RUN rm -f /etc/apt/sources.list.d/yarn.list \
&& apt-get update \
&& apt-get install -y libaio1t64 rlwrap \
&& rm -rf /var/lib/apt/lists/* \
&& DEB_HOST_MULTIARCH="$(dpkg-architecture -qDEB_HOST_MULTIARCH)" \
&& ln -sf /usr/lib/${DEB_HOST_MULTIARCH}/libaio.so.1t64 \
/usr/lib/${DEB_HOST_MULTIARCH}/libaio.so.1 \
&& echo "alias sqlplus='rlwrap sqlplus'" >> /etc/bash.bashrc

# Create directory structure for Oracle
RUN mkdir -p /opt/oracle

# Download and install Oracle Instant Client based on architecture.
# x86_64 uses Oracle's version-less "always latest" URLs; arm64 must pin a
# version because Oracle does not publish version-less arm64 zips.
WORKDIR /tmp
RUN ARCH=$(uname -m) && \
if [ "$ARCH" = "aarch64" ] || [ "$ARCH" = "arm64" ]; then \
IC_VERSION="23.26.1.0.0"; \
IC_PATH="2326100"; \
BASE_URL="https://download.oracle.com/otn_software/linux/instantclient/${IC_PATH}"; \
BASIC="instantclient-basic-linux.arm64-${IC_VERSION}.zip"; \
SDK="instantclient-sdk-linux.arm64-${IC_VERSION}.zip"; \
SQLPLUS="instantclient-sqlplus-linux.arm64-${IC_VERSION}.zip"; \
else \
BASE_URL="https://download.oracle.com/otn_software/linux/instantclient"; \
BASIC="instantclient-basic-linuxx64.zip"; \
SDK="instantclient-sdk-linuxx64.zip"; \
SQLPLUS="instantclient-sqlplus-linuxx64.zip"; \
fi && \
wget -q "${BASE_URL}/${BASIC}" \
&& wget -q "${BASE_URL}/${SDK}" \
&& wget -q "${BASE_URL}/${SQLPLUS}" \
&& unzip -qo "${BASIC}" \
&& unzip -qo "${SDK}" \
&& unzip -qo "${SQLPLUS}" \
&& mv instantclient_*/ /opt/oracle/instantclient \
&& rm -f instantclient-*.zip

# Set Oracle environment variables
ENV ORACLE_HOME=/opt/oracle/instantclient \
LD_LIBRARY_PATH=/opt/oracle/instantclient:$LD_LIBRARY_PATH \
PATH=/opt/oracle/instantclient:$PATH

# Switch to vscode user
USER vscode

# Set working directory
WORKDIR /workspaces/ruby-plsql
31 changes: 31 additions & 0 deletions .devcontainer/devcontainer.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
{
"name": "Ruby PL/SQL",
"dockerComposeFile": "docker-compose.yml",
"service": "app",
"workspaceFolder": "/workspaces/ruby-plsql",
"features": {
"ghcr.io/rails/devcontainer/features/ruby:2": {
"version": "4.0.3"
}
},
"customizations": {
"vscode": {
"extensions": [
"shopify.ruby-lsp"
]
}
},
"initializeCommand": "docker pull gvenzl/oracle-free:latest",
"postCreateCommand": "bash .devcontainer/postCreateCommand.sh",
"remoteEnv": {
"DATABASE_NAME": "FREEPDB1",
"DATABASE_SYS_PASSWORD": "Oracle18",
"NLS_LANG": "American_America.AL32UTF8",
"TNS_ADMIN": "/workspaces/ruby-plsql/ci/network/admin",
"TWO_TASK": "FREEPDB1"
},
"remoteUser": "vscode",
"mounts": [
"source=${localWorkspaceFolder}/.bundle,target=/home/vscode/.bundle,type=bind,consistency=delegated"
]
}
27 changes: 27 additions & 0 deletions .devcontainer/docker-compose.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
services:
app:
build:
context: .
dockerfile: Dockerfile
volumes:
- ../..:/workspaces:cached
command: sleep infinity
network_mode: service:oracle

oracle:
image: gvenzl/oracle-free:latest
ports:
- "1521:1521"
environment:
TZ: Europe/Riga
ORACLE_PASSWORD: Oracle18
healthcheck:
test: ["CMD", "healthcheck.sh"]
interval: 10s
timeout: 5s
retries: 10
volumes:
- oracle-data:/opt/oracle/oradata

volumes:
oracle-data:
25 changes: 25 additions & 0 deletions .devcontainer/postCreateCommand.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
#!/bin/bash

set -e

gem update --system
bundle install

echo "Waiting for Oracle to be ready..."
oracle_ready=false
for i in $(seq 1 30); do
if echo "exit" | sqlplus -s "system/${DATABASE_SYS_PASSWORD}@${DATABASE_NAME}" > /dev/null 2>&1; then
oracle_ready=true
break
fi
echo "Attempt $i/30 failed, retrying in 10s..."
sleep 10
done
if [ "$oracle_ready" != "true" ]; then
echo "Oracle did not become ready after 30 attempts; aborting container setup." >&2
exit 1
fi

ci/setup_accounts.sh

echo "Dev container setup complete. You are ready to start developing ruby-plsql!"
28 changes: 28 additions & 0 deletions .github/workflows/devcontainer.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
name: devcontainer

on:
schedule:
- cron: "0 6 1 * *" # 1st of every month at 6:00 AM UTC
workflow_dispatch:

env:
RUBYOPT: "-w"

jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6

- name: Ensure .bundle mount source exists
run: mkdir -p .bundle

- name: Boot dev container and run tests
uses: devcontainers/ci@v0.3
with:
runCmd: |
uname -a
lsb_release -a
ruby --version
bundle exec rake spec
bundle exec rubocop