diff --git a/.claude/settings.json b/.claude/settings.json new file mode 100644 index 0000000..d62a768 --- /dev/null +++ b/.claude/settings.json @@ -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 + } +} diff --git a/.claude/skills/create-pr/SKILL.md b/.claude/skills/create-pr/SKILL.md new file mode 100644 index 0000000..859e04c --- /dev/null +++ b/.claude/skills/create-pr/SKILL.md @@ -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 + - + - + ``` + 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 "" --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. diff --git a/.devcontainer/Dockerfile b/.devcontainer/Dockerfile index 973fdda..c9e281f 100644 --- a/.devcontainer/Dockerfile +++ b/.devcontainer/Dockerfile @@ -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 + +RUN curl -fsSL https://claude.ai/install.sh | bash +RUN curl -fsSL https://opencode.ai/install | bash +RUN curl https://qlty.sh | sh diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json index 15c047b..1a9293a 100644 --- a/.devcontainer/devcontainer.json +++ b/.devcontainer/devcontainer.json @@ -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", @@ -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}" }, - - "forwardPorts": [3000] + "forwardPorts": [ + 3000 + ], + "customizations": { + "vscode": { + "settings": { + "autoOpenWorkspace.enableAutoOpenAlwaysFirst": true + } + } + } } \ No newline at end of file diff --git a/.devcontainer/docker-compose.yml b/.devcontainer/docker-compose.yml index f19220e..dcec809 100644 --- a/.devcontainer/docker-compose.yml +++ b/.devcontainer/docker-compose.yml @@ -1,4 +1,4 @@ -version: '3' +version: "3" services: app: @@ -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. @@ -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 @@ -39,10 +44,10 @@ 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: @@ -50,6 +55,45 @@ services: MYSQL_USER: redmine MYSQL_DB: redmine MYSQL_PASSWORD: remine + + 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 diff --git a/.devcontainer/post-create.sh b/.devcontainer/post-create.sh index b194b73..29a79fd 100644 --- a/.devcontainer/post-create.sh +++ b/.devcontainer/post-create.sh @@ -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 diff --git a/.devcontainer/redmine.code-workspace b/.devcontainer/redmine.code-workspace new file mode 100644 index 0000000..11c9823 --- /dev/null +++ b/.devcontainer/redmine.code-workspace @@ -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 + } + } +} \ No newline at end of file diff --git a/.github/dependabot.yml b/.github/dependabot.yml new file mode 100644 index 0000000..aacc20d --- /dev/null +++ b/.github/dependabot.yml @@ -0,0 +1,13 @@ +version: 2 +updates: + - package-ecosystem: "bundler" + directory: "/" + target-branch: "develop" + schedule: + interval: "weekly" + + - package-ecosystem: "github-actions" + directory: "/" + target-branch: "develop" + schedule: + interval: "weekly" diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 1b2b3a7..b0cf071 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -20,23 +20,19 @@ jobs: strategy: matrix: db: [sqlite3, mysql, postgres] - ruby_version: ["3.0", "3.1", "3.2", "3.3", "3.4"] - redmine_version: [5.1-stable, 6.0-stable, master] + ruby_version: ["3.1", "3.2", "3.3", "3.4", "4.0"] + redmine_version: [6.0-stable, 6.1-stable, 7.0-stable, master] exclude: - - ruby_version: "3.3" - redmine_version: 5.1-stable - ruby_version: "3.4" - redmine_version: 5.1-stable - - ruby_version: "3.0" redmine_version: 6.0-stable - - ruby_version: "3.4" + - ruby_version: "4.0" redmine_version: 6.0-stable - - ruby_version: "3.0" - redmine_version: 6.1-stable - ruby_version: "3.1" redmine_version: 6.1-stable - - ruby_version: "3.0" - redmine_version: master + - ruby_version: "4.0" + redmine_version: 6.1-stable + - ruby_version: "3.1" + redmine_version: 7.0-stable - ruby_version: "3.1" redmine_version: master services: diff --git a/.gitignore b/.gitignore index 58695ae..9bee3dc 100644 --- a/.gitignore +++ b/.gitignore @@ -2,4 +2,4 @@ coverage Gemfile Gemfile.lock test/tmp/* -CLAUDE.md +tmp/* diff --git a/.redmine.code-workspace b/.redmine.code-workspace deleted file mode 100644 index 51dc8f7..0000000 --- a/.redmine.code-workspace +++ /dev/null @@ -1,11 +0,0 @@ -{ - "folders": [ - { - "path": "." - }, - { - "path": "../../usr/local/redmine" - } - ], - "settings": {} -} \ No newline at end of file diff --git a/AGENTS.md b/AGENTS.md new file mode 100644 index 0000000..f5e40d0 --- /dev/null +++ b/AGENTS.md @@ -0,0 +1,97 @@ +# AGENTS.md + +This file provides guidance to coding agents (Claude Code, and other AGENTS.md-compatible tools) when working with code in this repository. + +## What this is + +A Redmine plugin (`redmine_code_review`) that adds in-browser code review to the repository browser: reviewers annotate diffs/changesets/attachments, and each review is backed by a Redmine `Issue`. Requires Redmine >= 6.0 (see `init.rb`, which pins `requires_redmine`). + +This directory (`plugins/redmine_code_review`) only works when mounted inside a full Redmine checkout at `plugins/redmine_code_review` — tests and rake tasks rely on that relative position (e.g. `test/test_runner.rb` requires `../../../test/test_helper`, i.e. the host Redmine's test helper). + +## Commands + +All commands below are run from the Redmine root (`/usr/local/redmine`), not from the plugin directory, unless noted. + +```bash +# install/update gems (Gemfile_for_test adds simplecov-cobertura, factory_bot_rails, shoulda) +bundle install + +# run plugin migrations (dev and test envs) +bundle exec rake redmine:plugins:migrate +bundle exec rake redmine:plugins:migrate RAILS_ENV=test + +# run the full plugin test suite +bundle exec rake redmine:plugins:test NAME=redmine_code_review + +# run a single test file +bundle exec rake redmine:plugins:test NAME=redmine_code_review TEST=plugins/redmine_code_review/test/unit/code_review_test.rb + +# alternative: SimpleCov-instrumented runner (from the plugin directory; auto-copies fixtures, chdir's, requires every *test.rb) +ruby plugins/redmine_code_review/test/test_runner.rb +``` + +The devcontainer (`.devcontainer/`) provisions MySQL and Postgres test databases and runs `post-create.sh`, which copies `Gemfile_for_test` over `Gemfile`, copies plugin fixtures into the host `test/fixtures`, and migrates both dev and test DBs for each adapter. + +`build-scripts/` and `travis/` are CI-oriented helpers (clone a fresh Redmine, symlink/copy this plugin in, migrate, run tests with coverage) — not needed for local iteration inside this devcontainer, where Redmine is already checked out. + +## Architecture + +### Everything hangs off `Issue`, not a custom status model + +`CodeReview` (`app/models/code_review.rb`) has no subject/status/author of its own — it `belongs_to :issue` and delegates almost every field to it (`subject`, `user`, `status_id`, `comment` all read/write through `issue`). `is_closed?` just calls `issue.closed?`. When touching review state, check the `issue` delegation first; there is no separate review status enum in active use (the `STATUS_OPEN`/`STATUS_CLOSED` constants are vestigial, real status comes from `IssueStatus`). + +A `CodeReview` optionally links to a `Change` (repository diff line) *or* an `Attachment` (patch file review) — `path`, `revision`, `repository` all branch on which one is present. + +### Redmine core is extended via monkey patches in `lib/`, loaded explicitly by `init.rb` + +Patch load order in `init.rb` matters and is: `code_review_application_hooks` → `code_review_change_patch` → `code_review_changeset_patch` → `code_review_issue_patch` → `code_review_issue_hooks` → `code_review_projects_helper_patch` → `code_review_attachment_patch`. + +- `code_review_change_patch.rb` — adds `has_many :code_reviews` / `:code_review_assignments` to `Change`, and hooks `after_save :review_auto_assign` to trigger auto-assignment on new changes. +- `code_review_changeset_patch.rb` — similar extensions on `Changeset`. +- `code_review_issue_patch.rb` / `code_review_issue_hooks.rb` — extend `Issue` and hook into issue views so review-linked issues render review UI. +- `code_review_projects_helper_patch.rb` — project listing integration. +- `code_review_attachment_patch.rb` — lets attachments be reviewed like diffs. +- `code_review_application_hooks.rb` — a `Redmine::Hook::ViewListener` injecting the plugin's JS/CSS into every page (`view_layouts_base_html_head`, `view_layouts_base_body_bottom`). + +Because these are monkey patches on core Redmine classes, changes here can affect non-plugin Redmine behavior — check for overlap with other plugins patching the same classes (`Change`, `Changeset`, `Issue`, `Attachment`). + +### Auto-assignment + +`CodeReviewAssignment` + `lib/code_review_auto_assign_settings.rb` (`AutoAssignSettings` / `AssignmentFilter`) implement per-project rules for automatically assigning a reviewer to new changesets: `Change#review_auto_assign` (in `code_review_change_patch.rb`) fires on save, checks `CodeReviewProjectSetting#auto_assign_settings`, and if enabled and the changed paths match the configured `AssignmentFilter` regexes, calls `CodeReviewAssignment.create_with_changeset`. Settings are persisted as a YAML blob on the project setting (`AutoAssignSettings#to_s` / `.load`), not normalized columns — read `code_review_auto_assign_settings.rb` before changing the settings schema. + +### Permissions and routes + +`init.rb` registers the `:code_review` project module with six permissions (`view_code_review`, `add_code_review`, `edit_code_review`, `delete_code_review`, `assign_code_review`, `code_review_setting`), each mapped to specific controller actions. `config/routes.rb` wires `projects/:id/code_review/:action` and `projects/:id/code_review_settings/:action` directly to `code_review#*` / `code_review_settings#*` — new controller actions need a matching permission entry in `init.rb` to be reachable, not just a route. + +### Migrations + +`db/migrate/` mixes legacy numbered migrations (`0001_*.rb` … `0021_*.rb`) with newer Rails-timestamped ones (`20220312104356_*.rb`). New migrations should use the timestamped format. + +### Tests + +- `test/test_helper.rb` requires the host Redmine's `test/test_helper`, then defines FactoryBot factories (`code_review`, `code_review_assignment`, `changeset`, `change`, `attachment`, `repository`, `issue`, `code_review_project_setting`) used across unit/functional tests — check here before adding ad hoc fixtures. +- `test/exemplars/` + `test/code_review_object_daddy_helpers.rb` provide Object Daddy exemplars, an older fixture-generation style still used alongside FactoryBot. +- `test/fixtures/*.yml` get copied into the host Redmine's `test/fixtures/` (by `post-create.sh` or `test_runner.rb`) — they must not collide with core Redmine fixture IDs. + +## Project conventions + +- Write all git commit messages and code comments in English. +- Follow Ruby/Rails conventions already used in the file you're editing (the codebase mixes older Redmine-plugin idioms with newer Rails style — match the surrounding code rather than introducing a new pattern). +- Keep designs KISS / DRY / YAGNI: the simplest thing that works, no duplicated logic, no speculative abstractions for hypothetical future needs. +- Practice TDD: write the failing test first, then the implementation. +- Maintain C0 (statement) test coverage of at least 90%. Check `coverage/` (SimpleCov) after running the suite before considering work done. +- No easy fallbacks: don't swallow or silently default around errors (rescuing broadly, `rescue nil`, silent empty-array/false returns). Let unexpected conditions raise and be handled explicitly; only validate at true system boundaries. + +### Docs and ADRs + +- Reference material lives under `docs/` — check there for existing documentation before assuming behavior; filenames are the index, so look for a filename matching the topic. When adding a new doc, give it a clear, descriptive filename. +- Record architecturally significant decisions as ADRs under `docs/adr/` (one file per decision). The log is append-only: never edit or delete a past ADR's content — if a decision changes, add a new ADR that supersedes it and note that link in both files. Every ADR must be listed in `docs/adr/README.md`, which is the index. If it's unclear whether a decision is significant enough to warrant an ADR, ask the user rather than guessing. + +### Branching (git-flow) + +- `main` — production releases only. +- `develop` — integration branch; base and target for feature work. +- `feature/*` — new functionality, branched from and merged back into `develop`. +- `bugfix/*` — non-urgent fixes, branched from and merged back into `develop`. +- `release/*` — release stabilization, branched from `develop`, merged into both `main` and `develop`. +- `hotfix/*` — urgent production fixes, branched from `main`, merged into both `main` and `develop`. diff --git a/CLAUDE.md b/CLAUDE.md new file mode 100644 index 0000000..340124a --- /dev/null +++ b/CLAUDE.md @@ -0,0 +1,5 @@ +# CLAUDE.md + +This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository. + +See @AGENTS.md for commands, architecture, and project conventions — kept as a single source of truth shared across coding agents. diff --git a/README.md b/README.md index c025daa..c2748e8 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,7 @@ [![Maintainability](https://api.codeclimate.com/v1/badges/adc7bcbf7bfd8e80a97b/maintainability)](https://codeclimate.com/github/haru/redmine_code_review/maintainability) [![codecov](https://codecov.io/gh/haru/redmine_code_review/branch/develop/graph/badge.svg?token=37CJ55KBUU)](https://codecov.io/gh/haru/redmine_code_review) [![Ask DeepWiki](https://deepwiki.com/badge.svg)](https://deepwiki.com/haru/redmine_code_review) -![Redmine](https://img.shields.io/badge/redmine->=5.1-blue?logo=redmine&logoColor=%23B32024&labelColor=f0f0f0&link=https%3A%2F%2Fwww.redmine.org) +![Redmine](https://img.shields.io/badge/redmine->=6.0-blue?logo=redmine&logoColor=%23B32024&labelColor=f0f0f0&link=https%3A%2F%2Fwww.redmine.org) # Redmine Code Review Plugin @@ -11,7 +11,7 @@ A comprehensive code review plugin for Redmine that enables collaborative source ## Features - **In-browser Code Review**: Annotate and review source code directly in Redmine's repository browser -- **Issue Integration**: Link code reviews to Redmine issues for comprehensive project tracking +- **Issue Integration**: Link code reviews to Redmine issues for comprehensive project tracking - **Reviewer Assignment**: Automatic and manual reviewer assignment with notification support - **Project Configuration**: Per-project settings for trackers and auto-assignment rules - **Permission Control**: Granular permissions integrated with Redmine's role-based access control @@ -21,7 +21,7 @@ A comprehensive code review plugin for Redmine that enables collaborative source ## Requirements -- **Redmine**: Version 5.1.0 or higher +- **Redmine**: Version 6.0.0 or higher - **Ruby**: Compatible with Redmine-supported Ruby versions - **Database**: Any database supported by Redmine (MySQL, PostgreSQL, SQLite) - **Repository**: Git, Subversion, or other VCS supported by Redmine @@ -107,7 +107,7 @@ Restart your Redmine application server (Apache, Nginx, Passenger, etc.). The plugin sends email notifications for: - New review assignments -- Review comments and replies +- Review comments and replies - Review status changes - Assignment changes @@ -150,7 +150,7 @@ ruby test/test_runner.rb The `build-scripts/` directory contains useful development tools: - `install.sh` - Set up development environment -- `build.sh` - Run tests with coverage reporting +- `build.sh` - Run tests with coverage reporting - `cleanup.sh` - Clean up after test runs - `env.sh` - Environment configuration @@ -186,7 +186,7 @@ The plugin extends Redmine through: The plugin creates several database tables: - `code_reviews` - Main review data -- `code_review_assignments` - Reviewer assignments +- `code_review_assignments` - Reviewer assignments - `code_review_project_settings` - Project configuration - `code_review_user_settings` - User preferences @@ -234,5 +234,3 @@ See [GPL.txt](GPL.txt) for the full license text. - Various bug fixes and improvements For detailed changelog, see the commit history on GitHub. - - diff --git a/docs/adr/README.md b/docs/adr/README.md new file mode 100644 index 0000000..10d38b3 --- /dev/null +++ b/docs/adr/README.md @@ -0,0 +1,9 @@ +# Architecture Decision Records + +Index of ADRs for `redmine_code_review`. This log is append-only: once an ADR is added, its content is never edited or deleted. A decision that changes later gets a new ADR that supersedes the old one; link the two together. + +File naming: `NNNN-short-title.md`, numbered sequentially (e.g. `0001-example-decision.md`). + +## Index + +_No ADRs yet._ diff --git a/init.rb b/init.rb index 04b138b..99715c9 100644 --- a/init.rb +++ b/init.rb @@ -14,45 +14,45 @@ # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -require 'redmine' +require "redmine" begin - require 'config/initializers/session_store.rb' + require "config/initializers/session_store.rb" rescue LoadError end $LOAD_PATH.unshift "#{File.dirname(__FILE__)}/lib" -require 'code_review_application_hooks' -require 'code_review_change_patch' -require 'code_review_changeset_patch' -require 'code_review_issue_patch' -require 'code_review_issue_hooks' -require 'code_review_projects_helper_patch' -require 'code_review_attachment_patch' +require "code_review_application_hooks" +require "code_review_change_patch" +require "code_review_changeset_patch" +require "code_review_issue_patch" +require "code_review_issue_hooks" +require "code_review_projects_helper_patch" +require "code_review_attachment_patch" Redmine::Plugin.register :redmine_code_review do - name 'Redmine Code Review plugin' - author 'Haruyuki Iida' - author_url 'http://twitter.com/haru_iida' + name "Redmine Code Review plugin" + author "Haruyuki Iida" + author_url "http://twitter.com/haru_iida" url "http://www.redmine.org/plugins/redmine_code_review" if respond_to?(:url) - description 'This is a Code Review plugin for Redmine' - version '1.2.2' - requires_redmine :version_or_higher => '5.1.0' + description "This is a Code Review plugin for Redmine" + version "1.2.2" + requires_redmine :version_or_higher => "6.0.0" project_module :code_review do - permission :view_code_review, {:code_review => [:update_diff_view, :update_attachment_view, :update_revisions_view, :index, :show]}, {:read => true} - permission :add_code_review, {:code_review => [:new, :reply, :forward_to_revision, :preview]}, :require => :member - permission :edit_code_review, {:code_review => [:update]}, :require => :member - permission :delete_code_review, {:code_review => [:destroy]}, :require => :member - permission :assign_code_review, {:code_review => [:assign]}, :require => :member - permission :code_review_setting, {:code_review_settings => [:show, :update, :add_filter, :edit_filter, :sort]}, :require => :member + permission :view_code_review, { :code_review => [:update_diff_view, :update_attachment_view, :update_revisions_view, :index, :show] }, { :read => true } + permission :add_code_review, { :code_review => [:new, :reply, :forward_to_revision, :preview] }, :require => :member + permission :edit_code_review, { :code_review => [:update] }, :require => :member + permission :delete_code_review, { :code_review => [:destroy] }, :require => :member + permission :assign_code_review, { :code_review => [:assign] }, :require => :member + permission :code_review_setting, { :code_review_settings => [:show, :update, :add_filter, :edit_filter, :sort] }, :require => :member end - menu :project_menu, :code_review, {:controller => 'code_review', :action => 'index'}, :caption => :code_reviews, - :if => Proc.new { |project| - setting = CodeReviewProjectSetting.find_or_create(project) - project.repository != nil and setting and !setting.hide_code_review_tab - }, :after => :repository + menu :project_menu, :code_review, { :controller => "code_review", :action => "index" }, :caption => :code_reviews, + :if => Proc.new { |project| + setting = CodeReviewProjectSetting.find_or_create(project) + project.repository != nil and setting and !setting.hide_code_review_tab + }, :after => :repository Redmine::WikiFormatting::Macros.register do desc "This is my macro link to code review" @@ -62,7 +62,7 @@ return nil if review_id == 0 review = CodeReview.find(review_id) return nil unless review - link_to(l(:label_review) + '#' + review.id.to_s, :controller => 'code_review', :action => 'show', :id => review.project, :review_id => review.id) + link_to(l(:label_review) + "#" + review.id.to_s, :controller => "code_review", :action => "show", :id => review.project, :review_id => review.id) end end end