Project

General

Profile

Task #244

Updated by Sanghoon Lee 5 days ago

Install the bitname package for Redmine and configure Redmine to use as an external issue tracker for GitLab 

 <pre> 
 [GitLab] ──→ External Issue Tracker Setting ──→ [Bitnami Redmine:3000] 
                                                                 │ 
                                                         [MariaDB Container] 
 </pre> 

 ----------------------- 

 h1. Redmine Installation & GitLab Integration Procedures Guide 

 {{toc}} 

 --- 

 h2. 1. System Architecture Overview 

 <pre> 
                         ┌─────────────────────────────────────────────────────────┐ 
                         │                         GitLab                              │ 
                         │                                                           │ 
                         │     Repository     │     Issues     │     Commit Messages           │ 
                         └───────┬────────┴─────┬──────┴───────────┬───────────────┘ 
                                 │                │                    │ 
           [1] Webhook             │                │ [2] Integration    │ [3] Commit message 
           push event triggered    │                │ issue URL link     │ XCP-#42 (refs #42) 
                                 │                │                    │ 
                                 v                v                    │ 
                         ┌───────────────────────────────┐           │ 
                         │             Redmine               │           │ 
                         │                                 │ <───────┘ 
                         │    redmine_gitlab_hook plugin     │      refs #42 → issue link 
                         │              │                    │ 
                         │              v                    │ 
                         │     git fetch --all -p            │ 
                         │     (update mirror repository)    │ 
                         │              │                    │ 
                         │              v                    │ 
                         │     fetch_changesets              │ 
                         │     (sync commits to DB)          │ 
                         │                                 │ 
                         │    Issues    │    Repository    │ DB    │ 
                         └───────────────────────────────┘ 

  [1] Webhook      : GitLab push → automatically syncs commits to Redmine repository 
  [2] Integration: GitLab Settings → Integrations → Redmine issue tracker URL linking 
  [3] Commit ref : "XCP-#42 (refs #42)" → creates issue links in both GitLab and Redmine 
 </pre> 

 |_.Component|_.Version / Details| 
 |Redmine|6.1 (redmine:6.1-trixie)| 
 |Database|MySQL 8.0| 
 |Plugin|redmine_gitlab_hook v4.0.0 (phlegx/redmine_gitlab_hook)| 
 |Host IP|192.168.1.102| 
 |Redmine Port|3000| 
 |GitLab URL|http://git.xela.com:8888| 

 --- 

 h2. 2. Prerequisites 

 h3. 2-1. Verify Docker & Docker Compose Installation 

 <pre><code class="bash"> 
 docker --version 
 docker compose version 
 </code></pre> 

 h3. 2-2. Create Required Directories 

 <pre><code class="bash"> 
 mkdir -p /home/xela/redmine/redmine_data 
 mkdir -p /home/xela/redmine/mysql_data 
 mkdir -p /home/xela/redmine/redmine_repos 
 mkdir -p /home/xela/redmine/plugins 
 </code></pre> 

 h3. 2-3. Generate a GitLab Access Token 

 A token is required for authentication during git fetch operations. 

 # Go to GitLab → *User Settings → Access Tokens* (or project *Settings → Repository → Deploy tokens*) 
 # Select scope: @read_repository@ 
 # Note down the generated *username* and *token* value 

 bq. *Deploy Token recommended*: Grants read-only access scoped to a specific project, and is not affected by account password changes. 

 --- 

 h2. 3. Directory Structure & File Configuration 

 <pre> 
 /home/xela/redmine/ 
 ├── docker-compose.yml            # Container orchestration 
 ├── Dockerfile                    # Custom image with plugins included 
 ├── SETUP.md                      # Korean setup guide 
 ├── SETUP_EN.md                   # Markdown version 
 ├── SETUP_EN.textile              # This document (Redmine wiki format) 
 ├── plugins/ 
 │     └── redmine_gitlab_hook/      # GitLab webhook integration plugin 
 ├── redmine_data/                 # Persistent Redmine data (file attachments, etc.) 
 ├── redmine_repos/                # Git mirror repositories (host path) 
 │     └── XCP.git/                  # Example bare mirror repository 
 └── mysql_data/                   # Persistent MySQL data 
 </pre> 

 h3. Key docker-compose.yml Settings 

 <pre><code class="yaml"> 
 services: 
   redmine_db: 
     image: mysql:8.0 
     environment: 
       MYSQL_ROOT_PASSWORD: <change this> 
       MYSQL_USER: redmine 
       MYSQL_PASSWORD: <change this> 
       MYSQL_DATABASE: redmine 
     volumes: 
       - /home/xela/redmine/mysql_data:/var/lib/mysql 

   redmine: 
     build: .                            # Custom build from Dockerfile 
     ports: 
       - "192.168.1.102:3000:3000"       # Bind to specific IP only 
     volumes: 
       - /home/xela/redmine/redmine_data:/usr/src/redmine/files 
       - /home/xela/redmine/redmine_repos:/var/lib/redmine/repositories:rw 
 </code></pre> 

 bq. *Volume mount note*: @redmine_repos@ (host) → @/var/lib/redmine/repositories@ (container). 
 Any changes to repository files on the host are immediately reflected inside the container. 

 h3. Dockerfile Overview 

 <pre><code class="dockerfile"> 
 FROM redmine:6.1-trixie 

 # Install build tools 
 RUN apt-get install -y build-essential gcc make git default-libmysqlclient-dev 

 # Copy plugins and set ownership 
 COPY ./plugins /usr/src/redmine/plugins 
 RUN chown -R redmine:redmine /usr/src/redmine/plugins 

 # Install plugin gem dependencies 
 USER redmine 
 RUN bundle install 
 </code></pre> 

 bq. *When adding or updating plugins*, the image must be rebuilt: @docker compose build --no-cache@ 

 --- 

 h2. 4. Git Mirror Repository Setup 

 For each GitLab project to be integrated, create a local mirror repository on the Redmine server. 

 h3. 4-1. Create Mirror Clone 

 <pre><code class="bash"> 
 # Format: git clone --mirror http://USER:TOKEN@GITLAB_HOST/NAMESPACE/REPO.git DEST.git 
 git clone --mirror \ 
   http://invokelshn:TOKEN@git.xela.com:8888/software/XCP.git \ 
   /home/xela/redmine/redmine_repos/XCP.git 
 </code></pre> 

 h3. 4-2. Verify Credentials Are Embedded in the Remote URL 

 <pre><code class="bash"> 
 cat /home/xela/redmine/redmine_repos/XCP.git/config 
 </code></pre> 

 The @url@ field under @[remote "origin"]@ must include credentials in the format @http://USER:TOKEN@...:@ 

 <pre><code class="ini"> 
 [remote "origin"] 
     url = http://USERNAME:TOKEN@git.xela.com:8888/software/XCP.git 
     fetch = +refs/*:refs/* 
     mirror = true 
 </code></pre> 

 bq. *Important*: The Redmine container runs git fetch in a non-interactive environment — there is no TTY available to prompt for username/password. 
 Credentials must be embedded in the URL or configured via a credential store. 

 If the repository was cloned without credentials, update the URL: 

 <pre><code class="bash"> 
 git --git-dir="/home/xela/redmine/redmine_repos/XCP.git" \ 
   remote set-url origin \ 
   "http://USERNAME:TOKEN@git.xela.com:8888/software/XCP.git" 
 </code></pre> 

 h3. 4-3. Verify fetch Works (Test from Host) 

 <pre><code class="bash"> 
 git --git-dir="/home/xela/redmine/redmine_repos/XCP.git" fetch --all -p 
 </code></pre> 

 Expected output: 

 <pre> 
 From http://git.xela.com:8888/software/XCP 
    4acdd59..1caf25e    main -> main 
 </pre> 

 --- 

 h2. 5. Build & Run Docker Containers 

 h3. 5-1. Build Image and Start Containers 

 <pre><code class="bash"> 
 cd /home/xela/redmine 
 docker compose build 
 docker compose up -d 
 </code></pre> 

 h3. 5-2. Verify Container Status 

 <pre><code class="bash"> 
 docker compose ps 
 docker logs redmine --tail=30 
 </code></pre> 

 When Puma starts successfully: 

 <pre> 
 * Listening on http://0.0.0.0:3000 
 </pre> 

 h3. 5-3. Rebuild After Plugin Changes 

 <pre><code class="bash"> 
 docker compose down 
 docker compose build --no-cache 
 docker compose up -d 
 </code></pre> 

 --- 

 h2. 6. Redmine Initial Configuration (Web UI) 

 Redmine Web UI: @http://192.168.1.102:3000@ (or @http://redmine.xela.com:3000@) 

 Default admin credentials: @admin@ / @admin@ — *change immediately after first login* 

 h3. 6-1. Retrieve API Key 

 The plugin uses this key to authenticate incoming webhook requests. 

 *Administration → Settings → Repository* tab → Check *"Enable WS for repository management"* → Copy the API key 

 h3. 6-2. Register a Git Repository for a Redmine Project 

 For each project to be integrated: 

 # Go to the project → *Settings → Repositories* → *New repository* 
 # Fill in the settings: 

 |_.Field|_.Value| 
 |SCM|Git| 
 |Identifier|@xcp_mirror@ (must match the @repository_name@ parameter in the webhook URL)| 
 |Path to repository|@/var/lib/redmine/repositories/XCP.git@ (path inside the container)| 
 |Is default repository|Check| 

 3. Click *Create* and verify the repository is recognized correctly 

 h3. 6-3. Configure the redmine_gitlab_hook Plugin 

 *Administration → Plugins → Redmine GitLab Hook plugin → Configure* 

 |_.Setting|_.Value|_.Description| 
 |All Branches|Yes|Fetch all branches from all remotes| 
 |Prune|Yes|Remove stale remote-tracking references| 
 |Auto Create|Yes|Auto-create repository on first webhook (optional)| 
 |Fetch Updates|Yes|Run git fetch when webhook is received| 
 |Local Repositories Path|@/var/lib/redmine/repositories@|Required when Auto Create is enabled| 

 --- 

 h2. 7. GitLab Webhook Configuration 

 h3. 7-1. Webhook URL Format 

 <pre> 
 http://redmine.xela.com:3000/gitlab_hook?project_id=REDMINE_PROJECT_ID&repository_name=REPO_IDENTIFIER&key=REDMINE_API_KEY 
 </pre> 

 |_.Parameter|_.Description|_.Example| 
 |@project_id@|Redmine project identifier|@fy26_xcp-project@| 
 |@repository_name@|Redmine repository identifier|@xcp_mirror@| 
 |@key@|Redmine API key (from section 6-1)|@u67PN12c2bDK5HyaTUdC@| 

 bq. *Important*: Use *@repository_name@*, not @repository_id@. 
 The plugin reads @params[:repository_name]@ — the @repository_id@ parameter is ignored entirely. 

 h3. 7-2. Register the Webhook in GitLab 

 # GitLab project → *Settings → Webhooks* 
 # Configure: 

 |_.Field|_.Value| 
 |URL|The webhook URL from above| 
 |Trigger|Check *Push events*| 
 |SSL verification|Configure as needed| 

 3. Click *Add webhook* 

 h3. 7-3. Example Configuration (XCP Project) 

 <pre> 
 http://redmine.xela.com:3000/gitlab_hook?project_id=fy26_xcp-project&repository_name=xcp_mirror&key=u67PN12c2bDK5HyaTUdC 
 </pre> 

 --- 

 h2. 8. GitLab Integrations Setup (Issue Tracker Linking) 

 The *Settings → Integrations → Redmine* feature in GitLab allows issue numbers referenced in commit messages or merge requests to become clickable links that navigate directly to Redmine issues. 

 bq. *Webhook vs Integrations* 
 * *Webhook* (section 7): GitLab push event → automatically updates the Redmine repository mirror (commit sync) 
 * *Integrations* (this section): Links issue references in the GitLab UI to the Redmine issue tracker 

 h3. 8-1. Enable the Redmine Integration in GitLab 

 # GitLab project → *Settings → Integrations* → select *Redmine* 
 # Configure the following fields: 

 |_.Field|_.Value|_.Description| 
 |Active|Checked|Enable the integration| 
 |Project URL|@http://redmine.xela.com:3000/projects/fy26_xcp-project@|URL of the Redmine project| 
 |Issues URL|@http://redmine.xela.com:3000/issues/:id@|Issue URL pattern (keep @:id@ as-is)| 
 |New issue URL|@http://redmine.xela.com:3000/projects/fy26_xcp-project/issues/new@|URL to create a new issue| 

 3. Click *Save changes* 

 bq. The project identifier in *Project URL* and *New issue URL* must match the Redmine project identifier exactly. 
 Example: if the Redmine project identifier is @fy26_xcp-project@, use the same value in the URLs. 

 h3. 8-2. Referencing Issues in Commit Messages 

 Once the integration is active, use the following format to create issue links in both GitLab and Redmine simultaneously: 

 <pre><code class="bash"> 
 # Format: "commit message GITLAB_PROJECT_ID-#issue_number (refs #issue_number)" 
 git commit -m "Fix sensor calibration logic XCP-#42 (refs #42)" 
 git push origin main 
 </code></pre> 

 |_.Reference format|_.Recognized by|_.Description| 
 |@XCP-#42@|GitLab|GitLab project ID (@XCP@) + issue number → links to GitLab issue| 
 |@refs #42@|Redmine|Redmine issue number → links to Redmine issue| 

 bq. *GitLab Project ID*: find it at GitLab project → Settings → General → *Project ID* 
 Replace @XCP@ with the actual project ID of your GitLab project. 

 In the GitLab commit detail page, @refs #42@ will appear as a clickable link that navigates to: 

 <pre> 
 http://redmine.xela.com:3000/issues/42 
 </pre> 

 h3. 8-3. Verify the Integration 

 * GitLab → project → *Settings → Integrations → Redmine* → click the *Test* button 
 * A successful connection shows a green checkmark with a success message 

 --- 

 h2. 9. Integration Testing Procedure 

 h3. Step 1: Test git fetch Directly 

 Verify that git fetch works from inside the container. 

 <pre><code class="bash"> 
 docker exec redmine git \ 
   --git-dir="/var/lib/redmine/repositories/XCP.git" \ 
   fetch --all -p 
 </code></pre> 

 * *Success*: Branch update information is printed 
 * *Failure*: See Troubleshooting section below 

 h3. Step 2: Manually Trigger Webhook from GitLab UI 

 # GitLab → project → *Settings → Webhooks* 
 # Click *Test → Push events* on the registered webhook 
 # Check the response: 
 ** *@HTTP 200@*: Success 
 ** *@HTTP 406@*: git fetch failed (authentication or path issue) 
 ** *@HTTP 500@*: Redmine internal error (project/repository configuration issue) 

 h3. Step 3: Test Webhook via curl 

 <pre><code class="bash"> 
 curl -X POST \ 
   "http://redmine.xela.com:3000/gitlab_hook?project_id=fy26_xcp-project&repository_name=xcp_mirror&key=u67PN12c2bDK5HyaTUdC" \ 
   -H "Content-Type: application/json" \ 
   -d '{"object_kind":"push","ref":"refs/heads/main"}' 
 </code></pre> 

 *Expected response*: @OK@ 

 h3. Step 4: Monitor Logs in Real Time 

 <pre><code class="bash"> 
 # Terminal 1: watch logs 
 docker logs -f redmine 

 # Terminal 2: trigger webhook or push to GitLab 
 </code></pre> 

 Expected log on successful processing: 

 <pre> 
 Started POST "/gitlab_hook?..." for ... 
 Processing by GitlabHookController#index 
 Completed 200 OK 
 </pre> 

 h3. Step 5: Verify Commits Appear in Redmine UI 

 # Redmine → the project → *Repository* tab 
 # Confirm that commits pushed to GitLab are now visible 

 h3. Step 6: End-to-End Test 

 <pre><code class="bash"> 
 # 1. Create a test commit (from a local development environment) 
 git commit --allow-empty -m "test: redmine webhook integration" 
 git push origin main 

 # 2. After a few seconds, check Redmine 
 # Project → Repository → verify the commit appears in the list 
 </code></pre> 

 --- 

 h2. 10. Troubleshooting 

 h3. Error 1: HTTP 500 — "has no repository or repository not found" 

 <pre> 
 TypeError: Project 'XXX' has no repository or repository not found with identifier 'yyy' 
 </pre> 

 *Cause A*: Webhook URL uses @repository_id@ instead of @repository_name@ 
 * *Fix*: Replace @repository_id=...@ with @repository_name=...@ in the webhook URL 

 *Cause B*: No repository registered for the Redmine project 
 * *Fix*: Register a Git repository under project Settings → Repositories (see section 6-2) 

 *Cause C*: Mismatch between @repository_name@ parameter and the Redmine repository identifier 
 * *Fix*: Ensure the Redmine repository identifier exactly matches the @repository_name@ value in the webhook URL 

 --- 

 h3. Error 2: HTTP 406 — "Git command failed" 

 <pre> 
 GitLabHook: Command 'git --git-dir="..." fetch --all -p' didn't exit properly. 
 fatal: could not read Username for 'http://...': No such device or address 
 </pre> 

 *Cause*: The mirror repository's remote URL does not contain credentials 

 *Fix*: 

 <pre><code class="bash"> 
 git --git-dir="/home/xela/redmine/redmine_repos/XCP.git" \ 
   remote set-url origin \ 
   "http://USERNAME:TOKEN@git.xela.com:8888/software/XCP.git" 
 </code></pre> 

 --- 

 h3. Error 3: Cannot Reach GitLab Host from Inside the Container 

 <pre> 
 fatal: unable to access 'http://git.xela.com:8888/...': Could not resolve host 
 </pre> 

 *Check*: 

 <pre><code class="bash"> 
 docker exec redmine curl -I http://git.xela.com:8888 
 </code></pre> 

 *Fix*: Add @extra_hosts@ to @docker-compose.yml@ or verify DNS configuration on the host. 

 --- 

 h3. How to Check Logs 

 <pre><code class="bash"> 
 # Container logs (last 100 lines) 
 docker logs --tail=100 redmine 

 # Follow logs in real time 
 docker logs -f redmine 

 # Redmine production.log (inside container) 
 docker exec redmine tail -100 /usr/src/redmine/log/production.log 
 </code></pre> 

 --- 

 h2. 11. Maintenance 

 h3. Adding a New GitLab Project Integration 

 # Create a mirror repository (see section 4) 
 # Register the repository in the Redmine project (see section 6-2) 
 # Add a webhook in GitLab (see section 7) 
 # Run through the test procedure (see section 9) 

 h3. Restart Containers 

 <pre><code class="bash"> 
 cd /home/xela/redmine 
 docker compose restart 
 </code></pre> 

 h3. Update the Plugin 

 <pre><code class="bash"> 
 cd /home/xela/redmine/plugins/redmine_gitlab_hook 
 git pull 

 cd /home/xela/redmine 
 docker compose down 
 docker compose build --no-cache 
 docker compose up -d 
 </code></pre> 

 h3. Backup 

 <pre><code class="bash"> 
 # MySQL database 
 docker exec redmine_db mysqldump -u redmine -pPASSWORD redmine > backup_$(date +%Y%m%d).sql 

 # Persistent Redmine data (file attachments, etc.) 
 tar -czf redmine_data_$(date +%Y%m%d).tar.gz /home/xela/redmine/redmine_data 

 # Git mirror repositories 
 tar -czf redmine_repos_$(date +%Y%m%d).tar.gz /home/xela/redmine/redmine_repos 
 </code></pre> 

Back