From 1ae9e3e8fb7c875b71ccb75e7242c565f515c7a8 Mon Sep 17 00:00:00 2001 From: Himank Dave <93311724+steadyfall@users.noreply.github.com> Date: Sun, 10 Aug 2025 01:53:46 -0400 Subject: [PATCH] feat(devcontainer): upgrade dev environment with better prompts, extensions, and configs (#95) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * 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 --- .devcontainer/.bashrc | 116 ++++++++++++++++++++++++++++++ .devcontainer/Dockerfile | 37 +++++----- .devcontainer/devcontainer.json | 13 +++- .devcontainer/docker-compose.yml | 20 +++--- config/initializers/codespaces.rb | 25 +++++++ 5 files changed, 181 insertions(+), 30 deletions(-) create mode 100644 .devcontainer/.bashrc create mode 100644 config/initializers/codespaces.rb diff --git a/.devcontainer/.bashrc b/.devcontainer/.bashrc new file mode 100644 index 000000000..ef5673751 --- /dev/null +++ b/.devcontainer/.bashrc @@ -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 diff --git a/.devcontainer/Dockerfile b/.devcontainer/Dockerfile index 9ae237ff4..511013a97 100644 --- a/.devcontainer/Dockerfile +++ b/.devcontainer/Dockerfile @@ -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 diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json index 60b1866e9..fcbdfb53e 100644 --- a/.devcontainer/devcontainer.json +++ b/.devcontainer/devcontainer.json @@ -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" + } } } } diff --git a/.devcontainer/docker-compose.yml b/.devcontainer/docker-compose.yml index cf22c08ab..2c13c513f 100644 --- a/.devcontainer/docker-compose.yml +++ b/.devcontainer/docker-compose.yml @@ -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: diff --git a/config/initializers/codespaces.rb b/config/initializers/codespaces.rb new file mode 100644 index 000000000..bf759d3f5 --- /dev/null +++ b/config/initializers/codespaces.rb @@ -0,0 +1,25 @@ +# Dev-only adjustments for GitHub Codespaces +if Rails.env.development? && ENV["CODESPACES"] == "true" + # Example: forwarded URLs like https://--.app.github.dev + forwarding_domain = ENV["GITHUB_CODESPACES_PORT_FORWARDING_DOMAIN"] # typically "app.github.dev" + + # Append allowed hosts ONLY if Host Authorization is enabled (config.hosts is an Array). + # If it's nil, Host Authorization is disabled and we leave it alone. + if Rails.application.config.hosts.is_a?(Array) + if forwarding_domain.present? + Rails.application.config.hosts << /\A.*\.#{Regexp.escape(forwarding_domain)}\z/ + end + # Older/alternative preview domain + Rails.application.config.hosts << /\A.*\.githubpreview\.dev\z/ + end + + # If you use the VS Code "Preview" (iframe), you need SameSite=None; Secure + # Codespaces serves over HTTPS, so secure: true is OK here. + Rails.application.config.session_store :cookie_store, + key: "_app_session", + same_site: :none, + secure: true + + # Behind the proxy, Origin can differ; relax the origin check instead of disabling CSRF entirely. + Rails.application.config.action_controller.forgery_protection_origin_check = false +end