Compare commits

...
6 Commits
Author SHA1 Message Date
quafzi ce6f009473 Bump OpenProject version 2026-09-29 17:53:29 +02:00
quafzi 88e4eb7cfc Fix Github source 2026-09-29 17:51:00 +02:00
quafzi 8dcb499289 Use docker-compose.override.yml pattern for Docker installation
Editing docker-compose.yml directly is overwritten on every pull.
The correct approach is a separate Dockerfile.gitea (owned by the
operator) referenced from docker-compose.override.yml, which is
never touched by upstream updates.
2026-08-29 16:58:35 +02:00
quafzi ef1953ad62 Improve README: docker-compose installation and WP reference syntax
- Replace vague Docker paragraph with concrete docker-compose
  instructions: custom Dockerfile, docker-compose snippet, build/migrate
  commands
- Update referencing section to reflect that semantic IDs (PROJ-42)
  no longer require the OP# prefix
2026-08-29 16:22:52 +02:00
quafzi f704afec51 Match semantic IDs (e.g. KS-10) without requiring OP# prefix
Bare numeric IDs like #10 still require OP# to avoid collision with
Gitea issue numbers. Semantic identifiers (PROJ-42 style) are
unambiguous and matched with or without the prefix, as well as via
full OpenProject URL.

Update the tab empty-state message accordingly.
2026-08-29 16:16:49 +02:00
quafzi 29b922b708 Use git-pull-request icon for admin menu entry
op-logo-gitea does not exist in the OpenProject octicons set.
Use the standard git-pull-request octicon as a placeholder,
matching what is available.
2026-08-28 23:35:03 +02:00
4 changed files with 96 additions and 10 deletions

No files matched your search

+80 -4
View File
@@ -26,8 +26,9 @@ When a pull request in Gitea references an OpenProject work package (via a URL o
In a pull request title, description, or comment, reference a work package using:
- A full URL: `https://openproject.example.com/work_packages/42`
- A short reference: `OP#42` or `OP#PROJ-42`
- Its semantic ID: `KS-10`, `PROJ-42` — matched automatically, no prefix needed
- A prefixed numeric ID: `OP#42` — prefix required to avoid collision with Gitea issue numbers
- A full OpenProject URL: `https://openproject.example.com/work_packages/42`
Multiple references in the same text are all picked up.
@@ -57,9 +58,84 @@ openproject config:set RECOMPILE_ANGULAR_ASSETS=true
sudo openproject configure
```
### Docker installation
### Docker / docker-compose installation
Follow the [OpenProject Docker plugin guide](https://www.openproject.org/docs/installation-and-operations/installation/docker/#openproject-plugins). Add the gem to your custom Gemfile and rebuild the image.
The official OpenProject Docker image bakes all gems and frontend assets in at
build time, so installing a third-party plugin requires building a custom image.
The `docker-compose.yml` provided by OpenProject is overwritten on every update,
so all local changes go into `docker-compose.override.yml` and a separate
`Dockerfile` that you own.
#### 1. Clone the plugin
```shell
git clone https://github.com/quafzi/openproject-gitea-plugin.git \
openproject-gitea-plugin
```
Place it anywhere convenient — this guide assumes it sits next to your
`docker-compose.yml`.
#### 2. Create `Dockerfile.gitea`
```dockerfile
FROM openproject/openproject:17
USER root
# Copy the plugin source into the image
COPY --chown=app:app openproject-gitea-plugin \
/app/modules/gitea_integration
# Register the gem and recompile assets
RUN echo 'group :opf_plugins do\n gem "openproject-gitea_integration", path: "modules/gitea_integration"\nend' \
> /app/Gemfile.plugins && \
cd /app && \
bundle install --without development test && \
RAILS_ENV=production bundle exec rake \
openproject:plugins:register_frontend \
assets:precompile
USER app
```
#### 3. Create `docker-compose.override.yml`
This file is never touched by OpenProject updates. Point both `web` and
`worker` at your custom image — they must use the same image so the plugin is
loaded in both processes.
```yaml
services:
web:
build:
context: .
dockerfile: Dockerfile.gitea
image: openproject-with-gitea:latest
worker:
build:
context: .
dockerfile: Dockerfile.gitea
image: openproject-with-gitea:latest
```
#### 4. Build and start
```shell
docker compose build
docker compose up -d
docker compose exec web bundle exec rails db:migrate
```
#### Updating the plugin
```shell
cd openproject-gitea_integration && git pull && cd ..
docker compose build --no-cache
docker compose up -d
docker compose exec web bundle exec rails db:migrate
```
### Manual / monorepo installation
+1 -1
View File
@@ -46,7 +46,7 @@ en:
title: Quick snippets for Git
title: "Pull requests"
tab_prs:
empty: There are no pull requests linked yet. Link an existing PR by using the code <code>OP#%{wp_id}</code> in the PR title/description or create a new PR.
empty: There are no pull requests linked yet. Reference this work package in the PR title or description using its ID (e.g. <code>%{wp_id}</code>) or a full OpenProject URL.
updated_on: Updated on
work_packages:
tab_name: "Gitea"
+1 -1
View File
@@ -58,7 +58,7 @@ module OpenProject::GiteaIntegration
parent: :admin_integrations,
if: ->(_) { User.current.admin? },
caption: "Gitea",
icon: :"op-logo-gitea"
icon: "git-pull-request"
end
project_module(:gitea, dependencies: :work_package_tracking) do
@@ -31,13 +31,23 @@ module OpenProject::GiteaIntegration
module Helper
def extract_work_package_ids(text)
host_name = Regexp.escape(Setting.host_name)
wp_id = WorkPackage::SemanticIdentifier::ID_ROUTE_CONSTRAINT
url_part = /http(?:s?):\/\/#{host_name}\/(?:\S+?\/)*(?:work_packages|wp)\/(#{wp_id})/
numeric_id = /\d+/
semantic_id = WorkPackage::SemanticIdentifier::SEMANTIC_ID_PATTERN
any_id = WorkPackage::SemanticIdentifier::ID_ROUTE_CONSTRAINT
wp_regex = /OP#(#{wp_id})|#{url_part}/
# Full OpenProject URL — matches both numeric and semantic IDs
url_part = /http(?:s?):\/\/#{host_name}\/(?:\S+?\/)*(?:work_packages|wp)\/(#{any_id})/
# OP# prefix — required for bare numeric IDs to avoid collision with
# Gitea issue numbers (e.g. "Fix #10" refers to a Gitea issue, not an OP WP)
op_prefix_numeric = /OP#(#{numeric_id})/
# Semantic identifiers (e.g. KS-10, PROJ-42) are unambiguous enough to
# match without any prefix, both with and without OP#
op_prefix_semantic = /(?:OP#)?(#{semantic_id})/
String(text)
.scan(wp_regex)
.scan(/#{url_part}|#{op_prefix_numeric}|#{op_prefix_semantic}/)
.filter_map { |groups| groups.compact.first }
.uniq
end