Skip to content
Merged
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
48 changes: 24 additions & 24 deletions .github/workflows/rspec-action.yaml
Original file line number Diff line number Diff line change
@@ -1,35 +1,35 @@
name: Test
on:
on:
push:
branches:
- main
pull_request:
branches:
- main
jobs:
jobs:
rspec:
name: Run rspec with ruby
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v3
- name: Cache
uses: actions/cache@v2.1.3
with:
path: vendor/bundle
key: '2.3'
- name: Setup Ruby
uses: ruby/setup-ruby@v1.59.1
with:
ruby-version: '2.3'
- name: Dependencies
run: |
bundle config path vendor/bundle
bundle install
- name: Rspec
run: 'bundle exec rspec'
- name: Publish Test Report
uses: mikepenz/action-junit-report@v3
if: always() # always run even if the previous step fails
with:
report_paths: '**/build/test-results/test/TEST-*.xml'
- name: Checkout code
uses: actions/checkout@v3
- name: Cache
uses: actions/cache@v4.2.3
with:
path: vendor/bundle
key: "2.3"
- name: Setup Ruby
uses: ruby/setup-ruby@v1.59.1
with:
ruby-version: "2.3"
- name: Dependencies
run: |
bundle config path vendor/bundle
bundle install
- name: Rspec
run: "bundle exec rspec"
- name: Publish Test Report
uses: mikepenz/action-junit-report@v3
if: always() # always run even if the previous step fails
with:
report_paths: "**/build/test-results/test/TEST-*.xml"
4 changes: 3 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -8,4 +8,6 @@
/spec/reports/
/tmp/
**/.#*
/public/*
/public/*
/proxy/localhost*
.tool-versions
60 changes: 54 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,28 +17,76 @@ Stack Car is an opinionated set of tools around Docker and Rails. It provides c
Because stack_car will be used to run your application in side of Docker, you want to install stack car in to your system Ruby instead of putting in your applications Gemfile

```bash
gem install stack_car
gem install stack_car
```

## Usage

Commands are accesible via the "sc" short cut. Note: this will need to be in your command path in front of the spreadsheet command (sc), which is a fairly archaiac unix spreadsheet tool. We're guessing you don't edit a lot of spreadsheets in your terminal, but if you do, we also figure you can override your path order pretty easily. Many of these commands have short versions or alias to make remembering them easier. If there are obvious aliases missing, PRs are welcome.
Commands are accessible via the "sc" short cut. Note: this will need to be in your command path in front of the spreadsheet command (sc), which is a fairly archaiac unix spreadsheet tool. We're guessing you don't edit a lot of spreadsheets in your terminal, but if you do, we also figure you can override your path order pretty easily. Many of these commands have short versions or alias to make remembering them easier. If there are obvious aliases missing, PRs are welcome.

```ruby
Commands:
stack_car bundle_exec ARGS # wraps docker compose exec web bundle exec unless --service is used to specify (sc be ARGS)
stack_car console ARGS # shortcut to start rails console
stack_car dockerize DIR # Will copy the docker tempates in to your project, see options for supported dependencies
stack_car dockerize DIR # Will copy the docker templates in to your project, see options for supported dependencies
stack_car exec ARGS # wraps docker compose exec web unless --service is used to specify
stack_car help [COMMAND] # Describe available commands or one specific command
stack_car stop # starts docker compose with rebuild and orphan removal, defaults to all
stack_car up # starts docker compose with rebuild and orphan removal, defaults to web
stack_car walk ARGS # wraps docker compose run web unless --service is used to specify
stack_car proxy up # starts proxy container for SSL termination
stack_car proxy down # stops running proxy container
stack_car proxy cert # generates SSL certificates for local development, uses *.localhost.direct
```

## Proxy
StackCar has a built-in proxy designed to simplify local SSL development. The proxy provides SSL termination for your web services, allowing you to run your applications with HTTPS locally.

### Getting Started with the Proxy

To use the StackCar proxy:
1. **Download and Install the SSL certificates** for local development:
```bash
sc proxy cert
```
This will download the SSL certificates for `*.localhost.direct`. This only needs to be done once per version of stack_car.

2. **Start the proxy**:
```bash
sc proxy up
```

3. If you application is running in Docker, make sure you application has labels:
```yaml
labels:
- "traefik.enable=true"
- "traefik.http.routers.my-app.tls=true"
- "traefik.http.routers.my-app.entrypoints=websecure"
- "traefik.http.routers.my-app.rule=HostRegexp(`my-app.localhost.direct`)"
- "traefik.http.services.my-app.loadbalancer.server.port=3000"
```

4. **Access your application** using `https://my-app.localhost.direct`

### Proxy Configuration

The proxy configuration can be customized in your `docker-compose.yml` file. By default, it's configured to handle SSL termination on port 443 and forward traffic to your application services.

### Stopping the Proxy

When you're done working with SSL, you can stop the proxy:
```bash
sc proxy down
```

### Troubleshooting

- **Certificate issues**: If your browser doesn't trust the certificate, you may need to add the generated certificate to your system's trust store.
- **Port conflicts**: Ensure port 443 is available on your local machine.

## Development

After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake spec` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake spec` to run the tests. You can run `bin/test_sc` to run the command but from your local check out. You can also run `bin/console` for an interactive prompt that will allow you to experiment.

**To install this gem onto your local machine**
- Run `bundle exec rake install`
Expand Down Expand Up @@ -79,7 +127,7 @@ Alternatively, set it in your shell's `rc` file (`~/.bashrc`, `~/.zshrc`, etc.)

With `THOR_MERGE` set, you can enter `m` at the command prompt when there is a conflict between app and `sc` template files.

*Note*: For best experience, set `THOR_MERGE` to **GUI text editor** (ie. `code` or `atom`).
*Note*: For best experience, set `THOR_MERGE` to **GUI text editor** (ie. `code` or `atom`).

Initiating a merge pulls 2 versions of the file to the editor. One is what is proposed by stack_car, the other is the original. **Add what you need from the template version to the original file and save the changes**.

Expand Down Expand Up @@ -107,7 +155,7 @@ stack_car will have provided sensible defaults for your services but customizati
- Do a text search to find and replace any instances `CHANGEME` in the generated files
- Add any **general environment variables** to `.env`
- This sets defaults for all docker compose environments
- Add any **development environment variables** to `.env.development`
- Add any **development environment variables** to `.env.development`
- These set up any new values or overrides specific to your development env
- Run `sc build` to build your image
- On failed build, browse the terminal output to track down and squash any misconfigurations. Rebuild
Expand Down
5 changes: 5 additions & 0 deletions bin/test_sc
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
#!/usr/bin/env ruby
ENV['STACK_CAR_DEBUG'] = 'true'
load "#{File.dirname(__FILE__)}/../lib/stack_car.rb"

StackCar::HammerOfTheGods.start(ARGV)
8 changes: 5 additions & 3 deletions lib/stack_car.rb
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
require "stack_car/version"
require "stack_car/cli"
require "stack_car/dot_rc"
require_relative './stack_car/version'
require_relative './stack_car/os'
require_relative './stack_car/proxy'
require_relative './stack_car/cli'
require_relative './stack_car/dot_rc'

##
# Ruby 3.x removed {File.exists?} in favor of {File.exist?}. This shim ensures that we can run
Expand Down
10 changes: 10 additions & 0 deletions lib/stack_car/cli.rb
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
require 'erb'
require 'dotenv'
require 'json'
require 'byebug' if ENV['STACK_CAR_DEBUG']

module StackCar
class HammerOfTheGods < Thor
Expand All @@ -11,10 +12,17 @@ def self.source_root
File.join(File.dirname(__FILE__), '..', '..', 'templates')
end

def self.gem_root
File.join(File.dirname(__FILE__), '..', '..')
end

def self.exit_on_failure?
true
end

desc 'proxy COMMAND', 'Manage the traefik proxy for local development'
subcommand 'proxy', Proxy

method_option :service, default: 'web', type: :string, aliases: '-s'
method_option :build, default: false, type: :boolean, aliases: '-b'
method_option :logs, default: true, type: :boolean
Expand Down Expand Up @@ -330,6 +338,7 @@ def dockerize(dir=".")
end

protected

def compose_depends(*excludes)
@compose_depends = []
services = [:fcrepo, :postgres, :mysql, :elasticsearch, :sidekiq, :solr, :redis, :mongodb, :memcached] - excludes
Expand Down Expand Up @@ -370,6 +379,7 @@ def run_with_exit(*args)
if !result
exit(1)
end
result
end

def file_config
Expand Down
64 changes: 64 additions & 0 deletions lib/stack_car/os.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
# From Dory https://github.com/FreedomBen/dory/blob/master/lib/dory/os.rb
module StackCar
module Os
def self.bash(command)
system("bash -c '#{command}'")
end

def self.ubuntu?
self.bash(self.ubuntu_cmd)
end

def self.fedora?
self.bash(self.fedora_cmd)
end

def self.arch?
self.bash(self.arch_cmd)
end

def self.macos?
self.bash('uname -a | grep "Darwin" > /dev/null')
end

def self.wsl?
self.bash(self.wsl_cmd)
end

def self.wsl_cmd
%q(
grep -i "microsoft\|wsl" /proc/version > /dev/null 2>&1
)
end

def self.ubuntu_cmd
%q(
if $(which lsb_release >/dev/null 2>&1); then
lsb_release -d | grep --color=auto "Ubuntu" > /dev/null
else
uname -a | grep --color=auto "Ubuntu" > /dev/null
fi
)
end

def self.fedora_cmd
%q(
if $(which lsb_release >/dev/null 2>&1); then
lsb_release -d | grep --color=auto "Fedora" > /dev/null
else
uname -r | grep --color=auto "fc" > /dev/null
fi
)
end

def self.arch_cmd
%q(
if $(which lsb_release >/dev/null 2>&1); then
lsb_release -d | grep --color=auto "Arch" > /dev/null
else
uname -a | grep --color=auto "ARCH" > /dev/null
fi
)
end
end
end
83 changes: 83 additions & 0 deletions lib/stack_car/proxy.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
require 'thor'
require 'open-uri'
require 'fileutils'
require 'archive/zip'

module StackCar
class Proxy < Thor
include Thor::Actions

desc 'up', 'Launch traefik proxy for local development, assumes localhost.direct is the domain'
def up
#find the socket
set_proxy_env
run("docker compose -f #{HammerOfTheGods.gem_root}/proxy/compose.yaml up -d")
end

desc 'down', 'Stop traefik proxy for local development'
def down
set_proxy_env
run("docker compose -f #{HammerOfTheGods.gem_root}/proxy/compose.yaml down")
end

desc 'cert', 'Add a self-signed certificate for localhost.direct to the system'
def cert
say("Downloading certificate package...")

IO.copy_stream(URI.open(download_url), output_file)
say("Download complete.")
unzip_file

if Os.macos?
run("sudo security add-trusted-cert -d -r trustRoot -k /Library/Keychains/System.keychain #{proxy_dir}/localhost.direct.SS.crt")
elsif Os.ubuntu?
run("sudo cp #{proxy_dir}/localhost.direct.SS.crt /usr/local/share/ca-certificates/localhost.direct.SS.crt")
run("sudo update-ca-certificates")
elsif Os.wsl?
say("\n\n\nFor WSL, you need to add the certificate to Windows certificate store:\n")
say("1. Copy the certificate to a Windows-accessible location:\n")
run("cp #{proxy_dir}/localhost.direct.SS.crt /mnt/c/temp/localhost.direct.SS.crt")
say("\n2. Now run this Windows command to import the certificate (requires admin rights):\n")
run("powershell.exe -Command \"Start-Process powershell -Verb RunAs -ArgumentList '-Command Import-Certificate -FilePath C:\\temp\\localhost.direct.SS.crt -CertStoreLocation Cert:\\LocalMachine\\Root'\"")
say("\n3. Then restart your browser to apply the changes\n\n")
else
say("\n\n\nPlease figure out how to add a certificate to your system, then open a PR for your OS/Distro")
say("Files are located #{ENV['PWD']}/proxy/localhost.direct.SS.crt and #{ENV['PWD']}/proxy/localhost.direct.SS.key\n\n\n")
exit(1)
end
end

protected

def unzip_file
say("\n\n\nEnter the password found https://github.com/Upinel/localhost.direct?tab=readme-ov-file#a-non-public-ca-certificate-if-you-have-admin-right-on-your-development-environment-you-can-use-the-following-10-years-long-pre-generated-self-signed-certificate\n\n\n")
password = ask('[Required] Enter the unzip password::')
zip_file = "#{proxy_dir}/localhost-ss"
Archive::Zip.extract(zip_file, proxy_dir, :password => password)
say("Successfully unzipped certificate files.")
rescue Zlib::DataError
say("Incorrect password. Please try again.")
exit(1)
end

def set_proxy_env
ENV['DOCKER_SOCKET'] ||= "/var/run/docker.sock"
unless File.exist?("#{HammerOfTheGods.gem_root}/proxy/localhost.direct.SS.crt")
say("you must run proxy cert once after installing this gem before using the proxy")
exit(1)
end
end

def proxy_dir
@proxy_dir ||= "#{HammerOfTheGods.gem_root}/proxy"
end

def download_url
@download_url ||= "https://aka.re/localhost-ss"
end

def output_file
@output_file ||= File.join(proxy_dir, "localhost-ss")
end
end
end
2 changes: 1 addition & 1 deletion lib/stack_car/version.rb
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
# frozen_string_literal: true

module StackCar
VERSION = '0.18.0'
VERSION = '0.19.0'
end
Loading
Loading