diff --git a/.devcontainer/.env b/.devcontainer/.env
new file mode 100644
index 000000000..e287b6e88
--- /dev/null
+++ b/.devcontainer/.env
@@ -0,0 +1,5 @@
+APP_PORT=8000
+SELENIUM_PORT_1=4444
+SELENIUM_PORT_2=5900
+MAILCATCHER_PORT=1080
+RAILS_DB_ADAPTER=postgresql
diff --git a/.devcontainer/Dockerfile b/.devcontainer/Dockerfile
new file mode 100644
index 000000000..f4adf9bb6
--- /dev/null
+++ b/.devcontainer/Dockerfile
@@ -0,0 +1,17 @@
+# [Choice] Ruby version (use -bullseye variants on local arm64/Apple Silicon): 3, 3.1, 3.0, 2, 2.7, 2.6, 3-bullseye, 3.1-bullseye, 3.0-bullseye, 2-bullseye, 2.7-bullseye, 2.6-bullseye, 3-buster, 3.1-buster, 3.0-buster, 2-buster, 2.7-buster, 2.6-buster
+ARG VARIANT=3.1-bullseye
+FROM mcr.microsoft.com/vscode/devcontainers/ruby:${VARIANT}
+
+# Default value to allow debug server to serve content over GitHub Codespace's port forwarding service
+# The value is a comma-separated list of allowed domains
+ENV RAILS_DEVELOPMENT_HOSTS=".githubpreview.dev"
+
+# [Choice] Node.js version: lts/*, 16, 14, 12, 10
+ARG NODE_VERSION="lts/*"
+RUN su vscode -c "source /usr/local/share/nvm/nvm.sh && nvm install ${NODE_VERSION} 2>&1"
+
+# [Optional] Uncomment this section to install additional OS packages.
+RUN apt-get update && export DEBIAN_FRONTEND=noninteractive \
+ && apt-get -y install --no-install-recommends bzr gsfonts imagemagick libmagick++-dev
+
+EXPOSE $APP_PORT
diff --git a/.devcontainer/create-db-user.sql b/.devcontainer/create-db-user.sql
new file mode 100644
index 000000000..24417a9bd
--- /dev/null
+++ b/.devcontainer/create-db-user.sql
@@ -0,0 +1,2 @@
+CREATE USER vscode CREATEDB;
+CREATE DATABASE vscode WITH OWNER vscode;
\ No newline at end of file
diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json
new file mode 100644
index 000000000..eb4acf502
--- /dev/null
+++ b/.devcontainer/devcontainer.json
@@ -0,0 +1,44 @@
+// Update the VARIANT arg in docker-compose.yml to pick a Ruby version
+{
+ "name": "Redmine dev mirror",
+ "dockerComposeFile": "docker-compose.yml",
+ "service": "app",
+ "workspaceFolder": "/workspace",
+ "shutdownAction": "stopCompose",
+ // Configure tool-specific properties.
+ "customizations": {
+ // Configure properties specific to VS Code.
+ "vscode": {
+ // Add the IDs of extensions you want installed when the container is created.
+ "extensions": [
+ "rebornix.ruby",
+ "eamodio.gitlens",
+ "kaiwood.endwise",
+ "mtxr.sqltools",
+ "mtxr.sqltools-driver-pg",
+ "ms-vsliveshare.vsliveshare"
+ ],
+ "settings": {
+ "workbench.colorCustomizations": {
+ "activityBar.background": "#ab3e3e"
+ },
+ "sqltools.connections": [
+ {
+ "previewLimit": 50,
+ "server": "postgresdb",
+ "port": 5432,
+ "driver": "PostgreSQL",
+ "name": "app_development",
+ "database": "app_development",
+ "username": "db_user",
+ "password": "password"
+ }
+ ]
+ }
+ }
+ },
+ "postCreateCommand": "bash .devcontainer/scripts/postCreateCommand.sh",
+ "postStartCommand": "bash .devcontainer/scripts/postStartCommand.sh",
+ // Comment out to connect as root instead. More info: https://aka.ms/vscode-remote/containers/non-root.
+ "remoteUser": "vscode"
+}
\ No newline at end of file
diff --git a/.devcontainer/docker-compose.yml b/.devcontainer/docker-compose.yml
new file mode 100644
index 000000000..bd519dda2
--- /dev/null
+++ b/.devcontainer/docker-compose.yml
@@ -0,0 +1,66 @@
+version: '3'
+services:
+
+ # PostgreSQL
+ postgresdb:
+ image: postgres:14
+ restart: on-failure:5
+ volumes:
+ - ./create-db-user.sql:/docker-entrypoint-initdb.d/create-db-user.sql
+ environment:
+ POSTGRES_USER: postgres
+ POSTGRES_PASSWORD: postgres
+
+ # MySQL
+ # mysqldb:
+ # image: mysql:5
+ # restart: on-failure:5
+ # environment:
+ # MYSQL_ROOT_PASSWORD: password
+ # MYSQL_PASSWORD: password
+ # MYSQL_USER: db_user
+
+ app:
+ build:
+ context: ..
+ dockerfile: .devcontainer/Dockerfile
+ args:
+ APP_PORT: $APP_PORT
+ # Update 'VARIANT' to pick a version of Ruby: 3, 3.1, 3.0, 2, 2.7, 2.6
+ # Append -bullseye or -buster to pin to an OS version.
+ # Use -bullseye variants on local arm64/Apple Silicon.
+ VARIANT: "3.0-bullseye"
+ # Optional Node.js version to install
+ NODE_VERSION: "14"
+ environment:
+ RAILS_DB_ADAPTER: postgresql
+ RAILS_DB_HOST: postgresdb
+ RAILS_DB: app
+ RAILS_DB_USERNAME: postgres
+ RAILS_DB_PASSWORD: postgres
+ RAILS_DB_ENCODING: utf8
+ RAILS_ENV: development
+ env_file: .env
+ tty: true
+ ports:
+ - $APP_PORT:3000
+ depends_on:
+ - postgresdb
+ # - mysqldb
+ command: sleep infinity
+ volumes:
+ - ..:/workspace:cached
+
+ # For selenium test
+ # chrome:
+ # M1の場合はselenium/standalone-chrome-debugが動かないため、seleniarm/standalone-chromium:latestを代わりに使うこと。
+ # image: selenium/standalone-chrome-debug:3.141.59-20210913
+ # ports:
+ # - $SELENIUM_PORT_1:4444
+ # - $SELENIUM_PORT_2:5900
+ # shm_size: 2gb
+
+ smtp:
+ image: schickling/mailcatcher
+ ports:
+ - $MAILCATCHER_PORT:1080
diff --git a/.devcontainer/files/.vscode/launch.json b/.devcontainer/files/.vscode/launch.json
new file mode 100644
index 000000000..95285ae0c
--- /dev/null
+++ b/.devcontainer/files/.vscode/launch.json
@@ -0,0 +1,17 @@
+{
+ "version": "0.2.0",
+ "configurations": [
+ {
+ "name": "Rails server",
+ "type": "Ruby",
+ "request": "launch",
+ "cwd": "${workspaceRoot}",
+ "program": "${workspaceRoot}/bin/rails",
+ "args": [
+ "server",
+ "-b",
+ "0"
+ ]
+ }
+ ]
+}
diff --git a/.devcontainer/files/Gemfile.local b/.devcontainer/files/Gemfile.local
new file mode 100644
index 000000000..ddfc5cca2
--- /dev/null
+++ b/.devcontainer/files/Gemfile.local
@@ -0,0 +1,16 @@
+gem 'pry-rails'
+gem 'pry-byebug'
+gem 'binding_of_caller'
+gem 'better_errors'
+gem 'view_source_map'
+gem 'parallel_tests'
+gem 'benchmark-ips'
+gem 'activeresource'
+gem 'timecop'
+if Gem.ruby_version < Gem::Version.new('3.1.0')
+ gem 'ruby-debug-ide'
+ gem 'debase', '~> 0.2.5beta2'
+end
+if Gem.ruby_version >= Gem::Version.new('2.7.0')
+ gem 'debug'
+end
diff --git a/.devcontainer/files/additional_environment.rb b/.devcontainer/files/additional_environment.rb
new file mode 100644
index 000000000..cb4d7a099
--- /dev/null
+++ b/.devcontainer/files/additional_environment.rb
@@ -0,0 +1,4 @@
+# redmine-dev-mirror用ファイル
+
+# ログの保存箇所をvolumesの対象外にして同期による負かを軽くする
+config.logger = Logger.new('/logs/redmine.log', 2, 1000000)
diff --git a/.devcontainer/files/configuration.yml b/.devcontainer/files/configuration.yml
new file mode 100644
index 000000000..6053be218
--- /dev/null
+++ b/.devcontainer/files/configuration.yml
@@ -0,0 +1,10 @@
+# redmine-dev-mirror
+
+development:
+ email_delivery:
+ delivery_method: :smtp
+ smtp_settings:
+ address: 'smtp'
+ port: 1025
+test:
+production:
diff --git a/.devcontainer/files/database.yml b/.devcontainer/files/database.yml
new file mode 100644
index 000000000..929f9f4d0
--- /dev/null
+++ b/.devcontainer/files/database.yml
@@ -0,0 +1,23 @@
+# redmine-dev-mirror
+
+production:
+ adapter: <%= ENV['RAILS_DB_ADAPTER'] %>
+ database: <%= ENV['RAILS_DB'] %>
+ username: <%= ENV['RAILS_DB_USERNAME'] %>
+ password: <%= ENV['RAILS_DB_PASSWORD'] %>
+ host: <%= ENV['RAILS_DB_HOST'] %>
+ encoding: <%= ENV['RAILS_DB_ENCODING'] %>
+development:
+ adapter: <%= ENV['RAILS_DB_ADAPTER'] %>
+ database: <%= ENV['RAILS_DB'] %>_development
+ username: <%= ENV['RAILS_DB_USERNAME'] %>
+ password: <%= ENV['RAILS_DB_PASSWORD'] %>
+ host: <%= ENV['RAILS_DB_HOST'] %>
+ encoding: <%= ENV['RAILS_DB_ENCODING'] %>
+test:
+ adapter: <%= ENV['RAILS_DB_ADAPTER'] %>
+ database: <%= ENV['RAILS_DB'] %>_test
+ username: <%= ENV['RAILS_DB_USERNAME'] %>
+ password: <%= ENV['RAILS_DB_PASSWORD'] %>
+ host: <%= ENV['RAILS_DB_HOST'] %>
+ encoding: <%= ENV['RAILS_DB_ENCODING'] %>
\ No newline at end of file
diff --git a/.devcontainer/scripts/postCreateCommand.sh b/.devcontainer/scripts/postCreateCommand.sh
new file mode 100644
index 000000000..391fa1ecf
--- /dev/null
+++ b/.devcontainer/scripts/postCreateCommand.sh
@@ -0,0 +1,15 @@
+#!/bin/bash
+
+cp .devcontainer/files/Gemfile.local Gemfile.local
+cp .devcontainer/files/database.yml config/database.yml
+cp .devcontainer/files/configuration.yml config/configuration.yml
+cp .devcontainer/files/additional_environment.rb config/additional_environment.rb
+cp -r .devcontainer/files/.vscode .vscode
+
+sudo mkdir /logs
+sudo touch /logs/redmine.log
+sudo chown -R vscode /logs
+
+bundle install
+
+rake db:create
diff --git a/.devcontainer/scripts/postStartCommand.sh b/.devcontainer/scripts/postStartCommand.sh
new file mode 100644
index 000000000..53b70d08a
--- /dev/null
+++ b/.devcontainer/scripts/postStartCommand.sh
@@ -0,0 +1,9 @@
+#!/bin/bash
+
+bundle update
+rake generate_secret_token
+
+rake db:migrate
+rake redmine:plugins:migrate
+
+rake log:clear
diff --git a/.gitignore b/.gitignore
index d90a44f34..f3e4ea254 100644
--- a/.gitignore
+++ b/.gitignore
@@ -46,4 +46,6 @@
/node_modules
yarn-error.log
-docker-compose.yml
+/docker-compose.yml
+
+/.vscode
\ No newline at end of file
diff --git a/README.md b/README.md
index 2e0ca5628..7895a2911 100644
--- a/README.md
+++ b/README.md
@@ -38,4 +38,125 @@ https://redmine-patch.connpass.com/
### 4. イベントの時間になったらDiscordを開いて、ボイスチャンネルに参加しよう!
-(時間になったら他の参加者も参加しているはず)
\ No newline at end of file
+(時間になったら他の参加者も参加しているはず)
+
+## VSCode Remote ContainerによるRedmineの開発環境の作り方 / 機能
+
+Redmineの開発環境を作るやり方のうちの一つです。開発環境がすでにある人はこの手順を使わなくても大丈夫です。
+
+### 前提条件
+
+* Docker Desktopを起動している
+* Visual Studio Codeが利用できる
+
+### 利用手順
+
+* このリポジトリを手元にClone
+
+```bash session
+git clone --config=core.autocrlf=input https://github.com/redmine-patch-meetup/redmine-dev-mirror.git
+cd ./redmine-dev-mirror
+```
+
+* 必要に応じて.devcontainer/.envを書き換える(portの衝突がなければデフォルトでも動きます)
+
+```bash
+# 開発中のRedmineに http://localhost:8000 でアクセス出来るようになる。8000を既に使っている場合は変える
+APP_PORT=8000
+# Seleniumのテストを実行するときに利用するポート。4444, 5900を既に使っている場合は変える
+SELENIUM_PORT_1=4444
+SELENIUM_PORT_2=5900
+# Redmineから送信したメールを http://localhost:1080 で確認出来るようになる。1080を既に使っている場合は変える
+MAILCATCHER_PORT=1080
+# mysqlやsqlite3に変えても良い。mysqlの場合、.devcontainer/docker-compose.ymlのMySQL関連のコメントアウトを外す
+RAILS_DB_ADAPTER=postgresql
+```
+
+* VScodeに拡張機能[Remote-Containers](https://marketplace.visualstudio.com/items?itemName=ms-vscode-remote.remote-containers)をインストール
+
+* VScodeで/your/path/redmine-dev-mirror を開く
+
+
+
+* 右下に出てくるポップアップのReopen in Containerを選択(出てこなかったらVSCodeのコマンドパレットからRemote Containers: Rebuild and Reopen in Containerを選択) => ビルドが始まるはず
+
+
+
+* VSCodeの左側のバーが赤くなり、左側のファイルツリーも表示されたらコンテナ内に入れている状態
+
+画面下のターミナルに"Press any key"と表示されるため、「キー入力を行い(ターミナルが閉じる)、メニューからターミナルを開く」か 「"Press any key"を放置したままターミナル右上のプラスを押す」 という流れでコマンドを入力できるようにする。
+
+
+↓
+
+
+* 画面下のターミナル内で
+```bash
+rails s -b 0.0.0.0
+```
+* 少し待つと、ブラウザから http://localhost:[.devcontainer/.envで指定したAPP_PORT] でRedmineにアクセスできるようになる。
+
+
+
+* テストの実行
+```bash
+bundle exec rake test RAILS_ENV=test
+```
+
+### おまけ
+
+#### 1. VSCodeの拡張機能を増やしたい
+
+.devcontainer/devcontainer.jsonのextensionsに拡張機能を追加し、VSCodeのコマンドパレットからRebuild and Reopen container
+
+#### 2. Redmineから送信されるメールの内容をチェック
+
+http://localhost:[.devcontainer/.envで指定したMAILCATCHER_PORT] でにアクセスするとメールキャッチャーを開ける
+
+#### 3. Ruby3.0系以外のバージョンで動作検証やテストをしたい
+
+.devcontainer/docker-compose.yml ファイルの `VARIANT: "3.0-bullseye"` の3.0-bulleseye 部分を利用したいバージョンに書き換えて、VSCodeのコマンドパレットからRebuild and Reopen container
+
+#### 4. test/systemのテストを実行する場合
+
+.devcontainer/docker-compose.yml内のchrome:の塊のコメントアウトを外し、VSCodeのコマンドパレットからRebuild and Reopen container
+
+ selenium/standalone-chrome-debugイメージから持ってきたchromeを動かすためにCapybara周りで下のように設定を追加する。
+ app == docker-composeでrailsアプリケーションが動いているところのサービス名
+ chrome:4444 == docker-compose selenium/standalone-chrome-debugイメージのサービス名 + port
+
+```diff
+diff --git a/test/application_system_test_case.rb b/test/application_system_test_case.rb
+index 1a1e0cb4a..fedbe7d15 100644
+--- a/test/application_system_test_case.rb
++++ b/test/application_system_test_case.rb
+@@ -43,13 +43,17 @@ class ApplicationSystemTestCase < ActionDispatch::SystemTestCase
+ }
+ }
+ )
+-
++ options[:browser] = :remote
++ Capybara.server_host = 'app'
++ Capybara.server_port = <.devcontainer/.envのAPP_PORT(デフォルト8000)に入れた値に書き換える>
+ driven_by(
+ :selenium, using: :chrome, screen_size: [1024, 900],
+ options: options
+ )
+
+ setup do
++ Capybara.app_host = "http://#{Capybara.server_host}:#{Capybara.server_port}"
+ # Allow defining a custom app host (useful when using a remote Selenium hub)
+ if ENV['CAPYBARA_APP_HOST']
+ Capybara.configure do |config|
+
+```
+
+```
+ bundle exec rake test TEST=test/system RAILS_ENV=test
+```
+
+そのときホスト側で
+```
+open vnc://localhost:5900
+```
+を実行すると実際に動いているChromeの画面を見ることができる。 (パスワードを要求されたら `secret` と入れる)