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
20 changes: 20 additions & 0 deletions .claude/settings.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
{
"permissions": {
"allow": [
"Bash(gh pr *)",
"Bash(gh repo *)",
"Bash(gh label *)",
"Bash(find /usr/local/redmine/plugins/redmine_code_review/.claude -maxdepth 3 2>&1; echo \"---\"; find /workspaces/.claude -maxdepth 2 -iname \"*skill*\" 2>&1)",
"Read(//workspaces/.claude/**)",
"Bash(mkdir -p /usr/local/redmine/plugins/redmine_code_review/.claude/skills/create-pr && ls /usr/local/redmine/plugins/redmine_code_review/.claude/skills)",
"Edit(/.claude/skills/create-pr/**)",
"Bash(xargs -I{} echo {})"
],
"additionalDirectories": [
"/usr/local/redmine/plugins/redmine_code_review/.claude/skills"
]
},
"enabledPlugins": {
"skill-creator@claude-plugins-official": true
}
}
92 changes: 92 additions & 0 deletions .claude/skills/create-pr/SKILL.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
---
name: create-pr
description: Create (or update) a GitHub pull request for the current branch in this repo using the gh CLI, with a generated English title, a bulleted English summary of the actual diff, and an enhancement/bug label when one clearly applies. Use this whenever the user asks to open a PR, make a pull request, "PRを作って"/"PR作成して", or otherwise wants the current branch's work turned into a reviewable GitHub PR — not just when they explicitly say "use gh".
---

# Create PR

Turn the current branch into a GitHub pull request against `develop`, with a title and
description derived from what actually changed — not from what the branch name or commit
messages merely claim.

## Why these specific rules

This repo follows git-flow (see `AGENTS.md`): `feature/*` and `bugfix/*` branches always merge
back into `develop`, never `main`. PR text is always written in English regardless of the
language the user asks in, matching the repo's convention that commit messages and code comments
are English (`AGENTS.md` → "Project conventions"). Labels are only applied when they clearly
fit — a PR that only touches tooling/CI/docs, with no application-code feature or fix, should
get no label rather than a forced one.

## Steps

1. **Inspect the branch.**
```bash
git branch --show-current
git status
git log develop..HEAD --oneline
git diff develop...HEAD --stat
```
If there are uncommitted changes, stop and tell the user — don't create a PR out of a dirty
tree without asking first.

2. **Check for an existing PR** for this branch before creating a new one:
```bash
gh pr list --head "$(git branch --show-current)" --state all
```
If one is already open, this is an *update*, not a create — use `gh pr edit` for
title/body/labels instead of `gh pr create`, and say so to the user.

3. **Read the real diff**, not just the stat summary — `git diff develop...HEAD` (or per-file, if
large). The stat line tells you *which* files changed; only the actual diff tells you *what*
changed and therefore what the title/body/label should say. Don't infer content from file
names or commit subjects alone.

4. **Push the branch if needed.** `gh pr create` requires the branch to exist on the remote.
Check with `git status` / `git rev-parse --abbrev-ref @{u}` whether it's already tracked and
up to date. If a push is required, tell the user what you're about to push and proceed only
if that matches what they asked for — pushing is a visible, shared-state action, not a purely
local one.

5. **Write the title**: concise, English, under ~70 characters, describing the net effect of the
change (not a list of file names). Prefer a conventional-commit-ish lead verb (Add/Fix/Update/
Refactor) when it fits naturally, but clarity wins over format.

6. **Write the body** as a short bulleted summary in English, one bullet per logically distinct
change (group related file edits into one bullet rather than one bullet per file). Use this
shape:
```markdown
## Summary
- <change 1>
- <change 2>
```
Add a `## Test plan` section only when there's something concrete and checkable to verify
(e.g. specific commands, a CI matrix, a manual repro step) — don't pad it with vague
checkboxes just to have the section.

7. **Decide the label** by reading the diff, not the branch name:
- Diff adds new application behavior (new feature, new option, new endpoint, etc.) → `enhancement`.
- Diff fixes incorrect behavior → `bug`.
- Diff is purely tooling/CI/devcontainer/docs/refactor-with-no-behavior-change → no label.
Confirm the label actually exists first (`gh label list`) — don't pass a label name that isn't
defined in the repo.

8. **Create or update the PR:**
```bash
gh pr create --base develop --title "<title>" --body "$(cat <<'EOF'
## Summary
- ...
EOF
)" ${label:+--label "$label"}
```
Use a heredoc for `--body` so multi-line formatting survives quoting. Report the resulting PR
URL back to the user — don't just say "done."

## Non-goals

- Don't guess a label just to fill the field — an unlabeled PR is correct output when neither
`enhancement` nor `bug` fits.
- Don't invent a base branch other than `develop` for `feature/*`/`bugfix/*` work; if the current
branch is a `release/*` or `hotfix/*` branch (which target `main` per `AGENTS.md`), ask the
user to confirm the base rather than assuming `develop`.
- Don't force-push, amend existing commits, or rewrite history as part of this flow.
11 changes: 11 additions & 0 deletions .devcontainer/Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,14 @@ FROM haru/redmine_devcontainer:${REDMINE_VERSION}-ruby${RUBY_VERSION}
COPY .devcontainer/post-create.sh /post-create.sh


# Install MySQL client
RUN apt-get update && apt-get install -y default-mysql-client && rm -rf /var/lib/apt/lists/*

# Install uv (includes uvx) for Serena MCP server
RUN curl -LsSf https://astral.sh/uv/install.sh | sh

USER vscode

Comment on lines +10 to +14
RUN curl -fsSL https://claude.ai/install.sh | bash
RUN curl -fsSL https://opencode.ai/install | bash
RUN curl https://qlty.sh | sh
66 changes: 23 additions & 43 deletions .devcontainer/devcontainer.json
Original file line number Diff line number Diff line change
@@ -1,48 +1,16 @@
// For format details, see https://aka.ms/devcontainer.json. For config options, see the README at:
// https://github.com/microsoft/vscode-dev-containers/tree/v0.202.5/containers/ruby-rails-postgres
// Update the VARIANT arg in docker-compose.yml to pick a Ruby version
// Redmine plugin boilerplate
// version: 1.0.0
{
"name": "Ruby on Rails & Postgres",
"name": "Redmine plugin",
"dockerComposeFile": "docker-compose.yml",
"service": "app",

"mounts": [
"source=${localWorkspaceFolder},target=/workspaces/${localWorkspaceFolderBasename},type=bind"
],
"workspaceFolder": "/workspaces/${localWorkspaceFolderBasename}",
// "workspaceFolder": "/workspaces/dev.code-workspace",

// Set *default* container specific settings.json values on container create.
"settings": {
"sqltools.connections": [
{
"name": "Rails Development Database",
"driver": "PostgreSQL",
"previewLimit": 50,
"server": "localhost",
"port": 5432,

// update this to match config/database.yml
"database": "app_development",
"username": "vscode"
},
{
"name": "Rails Test Database",
"driver": "PostgreSQL",
"previewLimit": 50,
"server": "localhost",
"port": 5432,

// update this to match config/database.yml
"database": "app_test",
"username": "vscode"
}
]
},

// Add the IDs of extensions you want installed when the container is created.
"extensions": [
"rebornix.Ruby",
"mtxr.sqltools",
"mtxr.sqltools-driver-pg",
"craigmaslowski.erb",
Expand All @@ -53,24 +21,36 @@
"ms-azuretools.vscode-docker",
"KoichiSasada.vscode-rdbg",
"Serhioromano.vscode-gitflow",
"github.vscode-github-actions"
"github.vscode-github-actions",
"Shopify.ruby-extensions-pack",
"ritwickdey.LiveServer",
"aliariff.vscode-erb-beautify",
"bysabi.prettier-vscode-standard",
"GitHub.copilot",
"Shunqian.prettier-plus",
"Gruntfuggly.todo-tree",
"zoma.vscode-auto-open-workspace"
],

// Use 'forwardPorts' to make a list of ports inside the container available locally.
// "forwardPorts": [3000, 5432],

// Use 'postCreateCommand' to run commands after the container is created.
"postCreateCommand": "sh -x /post-create.sh",

"postCreateCommand": "sh -x .devcontainer/post-create.sh",
// Comment out connect as root instead. More info: https://aka.ms/vscode-remote/containers/non-root.
"remoteUser": "vscode",
"features": {
// "git": "latest"
},

"containerEnv": {
"PLUGIN_NAME": "${localWorkspaceFolderBasename}"
},
Comment on lines 43 to 45

"forwardPorts": [3000]
"forwardPorts": [
3000
],
"customizations": {
"vscode": {
"settings": {
"autoOpenWorkspace.enableAutoOpenAlwaysFirst": true
}
}
}
}
66 changes: 55 additions & 11 deletions .devcontainer/docker-compose.yml
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
version: '3'
version: "3"

services:
app:
Expand All @@ -9,14 +9,20 @@ services:
# Update 'VARIANT' to pick a version of Ruby: 3, 3.1, 3.2, 3.3, 3.4
# Append -bullseye or -buster to pin to an OS version.
# Use -bullseye variants on local arm64/Apple Silicon.
RUBY_VERSION: "3.4"
RUBY_VERSION: "${RUBY_VERSION:-4.0}"
# Optional Node.js version to install
NODE_VERSION: "lts/*"
REDMINE_VERSION: "6.1-stable"
REDMINE_VERSION: "${REDMINE_VERSION:-7.0-stable}"

# Overrides default command so things don't shut down after the process ends.
command: sleep infinity

env_file:
- path: .env
required: false
environment:
- TZ=${TZ:-UTC}
volumes:
- ..:/usr/local/redmine/plugins/redmine_code_review
# Runs app on the same network as the database container, allows "forwardPorts" in devcontainer.json function.
# network_mode: service:postgres
# Uncomment the next line to use a non-root user for all processes.
Expand All @@ -26,11 +32,10 @@ services:
# (Adding the "ports" property to this file will not forward from a Codespace.)

postgres:
image: postgres:latest
image: postgres:14
restart: unless-stopped
volumes:
- postgres-data:/var/lib/postgresql/data
- ./create-db-user.sql:/docker-entrypoint-initdb.d/create-db-user.sql
- postgres-data-code-review:/var/lib/postgresql/data
environment:
POSTGRES_USER: postgres
POSTGRES_DB: redmine
Expand All @@ -39,17 +44,56 @@ services:
# (Adding the "ports" property to this file will not forward from a Codespace.)

mysql:
image: mysql:latest
image: mysql:8.1
restart: unless-stopped
volumes:
- mysql-data:/var/lib/mysql
- mysql-data-code-revew:/var/lib/mysql
# network_mode: service:postgres
command: mysqld --character-set-server=utf8mb4 --collation-server=utf8mb4_unicode_ci
environment:
MYSQL_ROOT_PASSWORD: root
MYSQL_USER: redmine
MYSQL_DB: redmine
MYSQL_PASSWORD: remine
Comment on lines 54 to 57

browserless:
image: browserless/chrome
restart: unless-stopped
# ports:
# - 3000:3000
environment:
# Maximum concurrent sessions
MAX_CONCURRENT_SESSIONS: 10
# Connection timeout in milliseconds
CONNECTION_TIMEOUT: 60000
# Maximum queue length
MAX_QUEUE_LENGTH: 10
# Enable debugger for Playwright
ENABLE_DEBUGGER: "false"
# Token for authentication (optional, set to empty for no auth)
TOKEN: ""
# weaviate:
# command:
# - --host
# - 0.0.0.0
# - --port
# - "8080"
# - --scheme
# - http
# image: cr.weaviate.io/semitechnologies/weaviate:1.30.0
# # ports:
# # - 8080:8080
# # - 50051:50051
# volumes:
# - ./weaviate_data:/var/lib/weaviate
# restart: on-failure:0
# environment:
# QUERY_DEFAULTS_LIMIT: 25
# AUTHENTICATION_ANONYMOUS_ACCESS_ENABLED: "true"
# PERSISTENCE_DATA_PATH: "/var/lib/weaviate"
# DEFAULT_VECTORIZER_MODULE: "text2vec-openai"
# ENABLE_MODULES: "text2vec-openai,ref2vec-centroid,generative-openai,generative-aws,reranker-cohere"
# CLUSTER_HOSTNAME: "node1"
volumes:
postgres-data: null
mysql-data: null
postgres-data-code-review: null
mysql-data-code-revew: null
5 changes: 3 additions & 2 deletions .devcontainer/post-create.sh
Original file line number Diff line number Diff line change
@@ -1,19 +1,20 @@
#!/bin/sh
cd /usr/local/redmine

ln -s /workspaces/${PLUGIN_NAME} plugins/${PLUGIN_NAME}

if [ -f plugins/${PLUGIN_NAME}/Gemfile_for_test ]
then
cp plugins/${PLUGIN_NAME}/Gemfile_for_test plugins/${PLUGIN_NAME}/Gemfile
fi
cp plugins/${PLUGIN_NAME}/test/fixtures/*.yml test/fixtures
ln -s /workspaces/${PLUGIN_NAME}/.devcontainer/launch.json .vscode/launch.json


bundle install
bundle exec rake redmine:plugins:migrate
bundle exec rake redmine:plugins:migrate RAILS_ENV=test

initdb() {
rm -f db/schema.rb
bundle exec rake db:create
bundle exec rake db:migrate
bundle exec rake redmine:plugins:migrate
Expand Down
37 changes: 37 additions & 0 deletions .devcontainer/redmine.code-workspace
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
{
"folders": [
{
"path": "/usr/local/redmine/plugins/redmine_code_review"
},
{
"path": "/usr/local/redmine"
}
],
"settings": {
"editor.formatOnSave": true,
"editor.wordWrap": "on",
"files.trimFinalNewlines": true,
"files.insertFinalNewline": true,
"files.trimTrailingWhitespace": true,
"git.ignoredRepositories": [
"/usr/local/redmine"
],
"liveServer.settings.multiRootWorkspaceName": "redmine_code_review",
"[ruby]": {
"editor.defaultFormatter": "jnbt.vscode-rufo",
"editor.formatOnSave": true
},
"files.associations": {
"*.html.erb": "erb"
},
"[erb]": {
"editor.defaultFormatter": "aliariff.vscode-erb-beautify"
},
"vscode-erb-beautify.useBundler": true,
"github.copilot.nextEditSuggestions.enabled": false,
"rubyLsp.formatter": "auto",
"chat.tools.terminal.autoApprove": {
"bundle": true
}
}
}
Loading
Loading