feat(devcontainer): upgrade dev environment with better prompts, extensions, and configs (#95)

* chore(devcontainer): optimize Dockerfile for Ruby dev environment

* chore(devcontainer): update container name and improve VSCode settings

- Rename devcontainer from 'Maybe' to 'Sure'
- Add GIT_EDITOR env var for VSCode integration
- Add Shopify Ruby extensions pack

* feat(devcontainer): add custom Bash prompt with Git info

- Implement Git branch, status markers in prompt
- Show username, current dir, and Git info with colors
- Mount custom .bashrc into container for prompt enhancements

* fix(devcontainer): improve branch detection & status markers in prompt

- Support detached HEAD by showing short SHA
- Show detailed git states: rebase, merge, bisect, am
- Fix prompt formatting and trailing colors

* Better solution to GitHub Codespaces CSRF issue

* feat(devcontainer): add Git autocompletion support in bashrc

* refactor(devcontainer): reorder volumes and service settings

- Added volume mounts for workspace & bundle cache to worker service.

---------

Co-authored-by: Juan José Mata <juanjo.mata@gmail.com>
This commit is contained in:
Himank Dave
2025-08-10 01:53:46 -04:00
committed by GitHub
parent b7d9c89471
commit 1ae9e3e8fb
5 changed files with 181 additions and 30 deletions

116
.devcontainer/.bashrc Normal file
View File

@@ -0,0 +1,116 @@
#!/bin/bash
########
# Git
########
function git_branch() {
local branch
branch="$( { git symbolic-ref -q --short HEAD || git rev-parse -q --short --verify HEAD; } 2>&- )"
if [[ -n "$branch" ]]; then
echo -n "$branch"
return 0
fi
return 1
}
function in_git_dir() {
git rev-parse --is-inside-work-tree > /dev/null 2>&1
}
function git_name() {
git config user.name 2> /dev/null
}
function git_has_no_diff() {
git diff --quiet HEAD 2> /dev/null
}
function git_status_marker() {
if ! in_git_dir; then
return 1
fi
local git_dir
git_dir=$(git rev-parse --git-dir 2>/dev/null)
# Rebase states
if [[ -d "$git_dir/rebase-merge" ]]; then
echo -n " REBASE-i"
return 0
elif [[ -d "$git_dir/rebase-apply" ]]; then
if [[ -f "$git_dir/rebase-apply/rebasing" ]]; then
echo -n " REBASE"
return 0
elif [[ -f "$git_dir/rebase-apply/applying" ]]; then
echo -n " AM"
return 0
else
echo -n " REBASE"
return 0
fi
fi
# Merge state
if [[ -f "$git_dir/MERGE_HEAD" ]]; then
echo -n " MERGING"
return 0
fi
# Bisect state
if [[ -f "$git_dir/BISECT_LOG" ]]; then
echo -n " BISECTING"
return 0
fi
# Dirty state: unstaged or staged changes
if ! git_has_no_diff; then
echo -n " *"
return 0
fi
return 0
}
########
# PROMPT
########
export WHITE='\[\033[1;37m\]'
export LIGHT_GREEN='\[\033[0;32m\]'
export LIGHT_BLUE='\[\033[0;94m\]'
export LIGHT_BLUE_BOLD='\[\033[1;94m\]'
export RED_BOLD='\[\033[1;31m\]'
export YELLOW_BOLD='\[\033[1;33m\]'
export COLOR_OFF='\[\033[0m\]'
function prompt_command() {
local P=""
P="[\$?] "
P+="${LIGHT_GREEN}$(git_name || echo -n \$USER)"
P+="${WHITE}"
P+="${LIGHT_BLUE_BOLD}\w"
if in_git_dir; then
P+=" ${LIGHT_BLUE}("
P+="${RED_BOLD}\$(git_branch)"
P+="${YELLOW_BOLD}\$(git_status_marker)"
P+="${LIGHT_BLUE})"
fi
P+="${COLOR_OFF} "
P+='$ '
export PS1="$P"
}
export PROMPT_COMMAND='prompt_command'
########
# Git autocompletion
########
if [[ -f /usr/share/bash-completion/completions/git ]]; then
. /usr/share/bash-completion/completions/git
elif [[ -f /etc/bash_completion.d/git ]]; then
. /etc/bash_completion.d/git
fi

View File

@@ -1,26 +1,29 @@
ARG RUBY_VERSION=3.4.4
FROM ruby:${RUBY_VERSION}-slim-bullseye
RUN apt-get update && export DEBIAN_FRONTEND=noninteractive \
&& apt-get -y install --no-install-recommends \
apt-utils \
build-essential \
curl \
git \
imagemagick \
iproute2 \
libpq-dev \
libyaml-dev \
libyaml-0-2 \
openssh-client \
postgresql-client \
vim
ENV DEBIAN_FRONTEND=noninteractive
RUN gem install bundler
RUN gem install foreman
RUN apt-get update -qq \
&& apt-get -y install --no-install-recommends \
apt-utils \
build-essential \
curl \
git \
imagemagick \
iproute2 \
libpq-dev \
libyaml-dev \
libyaml-0-2 \
openssh-client \
postgresql-client \
vim \
&& rm -rf /var/lib/apt/lists /var/cache/apt/archives
RUN gem install bundler foreman
# Install Node.js 20
RUN curl -fsSL https://deb.nodesource.com/setup_20.x | bash - \
&& apt-get install -y nodejs
&& apt-get install -y nodejs \
&& rm -rf /var/lib/apt/lists /var/cache/apt/archives
WORKDIR /workspace

View File

@@ -1,9 +1,10 @@
{
"name": "Maybe",
"name": "Sure",
"dockerComposeFile": "docker-compose.yml",
"service": "app",
"workspaceFolder": "/workspace",
"containerEnv": {
"GIT_EDITOR": "code --wait",
"GITHUB_TOKEN": "${localEnv:GITHUB_TOKEN}",
"GITHUB_USER": "${localEnv:GITHUB_USER}"
},
@@ -15,8 +16,14 @@
"vscode": {
"extensions": [
"biomejs.biome",
"EditorConfig.EditorConfig"
]
"EditorConfig.EditorConfig",
"Shopify.ruby-extensions-pack"
],
"settings": {
"terminal.integrated.defaultProfile.linux": "bash",
"terminal.integrated.defaultProfile.osx": "zsh",
"terminal.integrated.defaultProfile.windows": "pwsh"
}
}
}
}

View File

@@ -16,19 +16,15 @@ services:
build:
context: ..
dockerfile: .devcontainer/Dockerfile
volumes:
- ./.bashrc:/root/.bashrc:ro,cached
- ..:/workspace:cached
- bundle_cache:/bundle
ports:
- "3000:3000"
command: sleep infinity
environment:
<<: *rails_env
depends_on:
- db
- redis
@@ -37,6 +33,9 @@ services:
build:
context: ..
dockerfile: .devcontainer/Dockerfile
volumes:
- ..:/workspace:cached
- bundle_cache:/bundle
command: bundle exec sidekiq
restart: unless-stopped
environment:
@@ -46,20 +45,21 @@ services:
redis:
image: redis:latest
volumes:
- redis-data:/data
ports:
- "6379:6379"
restart: unless-stopped
volumes:
- redis-data:/data
db:
image: postgres:latest
restart: unless-stopped
volumes:
- postgres-data:/var/lib/postgresql/data
environment:
<<: *db_env
ports:
- "5432:5432"
restart: unless-stopped
environment:
<<: *db_env
volumes:
postgres-data: