- Ruby 100%
| app | ||
| config | ||
| db/migrate | ||
| .gitignore | ||
| about.json | ||
| CLAUDE.md | ||
| LICENSE | ||
| plugin.rb | ||
| README.md | ||
Discourse GitLab Plugin
A Discourse plugin that integrates with GitLab (hosted or self-hosted) to provide linkbacks, badges, and permalinks. This plugin is adapted from the original discourse-github plugin.
Features
This plugin provides three main features for GitLab integration:
Linkback
Automatically creates comments (notes) on GitLab issues, merge requests, and commits when they're mentioned in Discourse posts. When users discuss GitLab content on your Discourse forum, a linkback comment is posted on GitLab with an excerpt and link to the discussion.
Example: If a user posts "Check out this fix: https://gitlab.com/myorg/myproject/-/merge_requests/42", the plugin will post a comment on MR #42 linking back to your Discourse discussion.
Badges
Automatically grants badges to Discourse users based on their contributions to tracked GitLab repositories. Distinguishes between:
- Committers: Users who commit directly to repositories
- Contributors: Users who contribute via merge requests
Badge Tiers:
- Bronze: 1 commit/contribution
- Silver: 25 commits/contributions (configurable)
- Gold: 250 commits/contributions (configurable)
Permalinks
Automatically converts branch-based GitLab file links to permanent commit-based links after a 1-hour grace period. This ensures that links in your Discourse posts don't break when branches are updated or deleted.
Example: https://gitlab.com/myorg/myproject/-/blob/main/README.md → https://gitlab.com/myorg/myproject/-/blob/abc123def456.../README.md
Installation
Follow the standard Discourse plugin installation guide:
- Add the plugin to your
app.yml:
hooks:
after_code:
- exec:
cd: $home/plugins
cmd:
- git clone https://github.com/discourse/discourse-gitlab.git
- Rebuild your Discourse container:
cd /var/discourse
./launcher rebuild app
- Enable the plugin in your Discourse admin settings (Settings → Plugins → discourse-gitlab)
Configuration
Required Settings
- Enable the plugin: Check "enable discourse gitlab plugin" in settings
- GitLab Base URL: Set to
https://gitlab.comfor hosted GitLab, or your self-hosted URL (e.g.,https://gitlab.example.com) - Access Token: Generate a GitLab Personal Access Token with
apiscope
Generating a GitLab Access Token
- Log into your GitLab instance
- Go to User Settings → Access Tokens (or visit
https://gitlab.com/-/user_settings/personal_access_tokens) - Create a new token with these settings:
- Token name: "Discourse Integration" (or any name you prefer)
- Scopes: Check
api(Full API access) - Expiration: Optional (recommended: set to 1 year and create calendar reminder)
- Click "Create personal access token"
- Copy the token immediately (it won't be shown again)
- Paste the token into the "gitlab linkback access token" setting in Discourse
Important: Keep this token secure. Anyone with this token can access your GitLab API.
Feature Configuration
Linkback Settings
- Enable: Check "gitlab linkback enabled"
- Projects: Specify repositories in pipe-separated format:
myorg/repo1|myorg/repo2- Supports wildcards:
myorg/*matches all projects undermyorg - Supports nested groups:
parent/child/project
- Supports wildcards:
- Maximum Links: Limit links processed per post (default: 25)
Example configuration:
myorg/main-project|myorg/docs|otherorg/shared-lib
Badge Settings
- Enable: Check "gitlab badges enabled"
- Repositories: List repositories to track (pipe-separated):
myorg/repo1|myorg/repo2- Format:
namespace/projector full URL - Supports nested groups:
parent/child/project
- Format:
- Thresholds:
- Bronze: 1 commit (automatic)
- Silver: 25 commits (configurable via "gitlab silver badge min commits")
- Gold: 250 commits (configurable via "gitlab gold badge min commits")
User Matching: The plugin matches GitLab contributors to Discourse users by:
- OAuth account linkage (if users signed in with GitLab OAuth)
- Email address matching
- Parsing GitLab no-reply emails (
12345-username@users.noreply.gitlab.com)
Example configuration:
myorg/main-project|myorg/api-server
Permalink Settings
- Enable: Check "gitlab permalinks enabled"
- Exclude Patterns: Files to skip (pipe-separated):
README.md|*/test/*|*.lock- Supports wildcards:
*matches any characters - Patterns match against file path or full
project/path/to/file
- Supports wildcards:
Example configuration:
README.md|CHANGELOG.md|*.lock|*/test/*
Key Differences from GitHub Plugin
Architecture Changes
- Configurable Base URL: Supports both gitlab.com and self-hosted GitLab instances
- Merge Requests vs Pull Requests: GitLab calls them "merge requests" (MRs)
- Notes vs Comments: GitLab API uses "notes" for MR/issue comments, "comments" for commits
- IID-based Resources: GitLab uses project-scoped IIDs (internal IDs) for issues/MRs
- Project Identifiers: Uses
namespace/projectformat, URL-encoded for API calls - Nested Namespaces: GitLab supports subgroups like
parent/child/project
API Differences
| Feature | GitHub | GitLab |
|---|---|---|
| API Base Path | / |
/api/v4/ |
| Auth Header | Authorization: token X |
PRIVATE-TOKEN: X |
| MR/PR Comments | POST /repos/{owner}/{repo}/issues/{number}/comments |
POST /api/v4/projects/:id/merge_requests/:iid/notes |
| Commit Comments | POST /repos/{owner}/{repo}/commits/{sha}/comments |
POST /api/v4/projects/:id/repository/commits/:sha/comments |
| Commit URL | github.com/{owner}/{repo}/commit/{sha} |
gitlab.com/{namespace}/{project}/-/commit/{sha} |
| MR/PR URL | github.com/{owner}/{repo}/pull/{number} |
gitlab.com/{namespace}/{project}/-/merge_requests/{iid} |
| Issue URL | github.com/{owner}/{repo}/issues/{number} |
gitlab.com/{namespace}/{project}/-/issues/{iid} |
Removed Features
None! All three main features from the GitHub plugin work with GitLab:
- ✅ Linkback (comments on issues/MRs/commits)
- ✅ Badges (grant badges based on commits)
- ✅ Permalinks (convert branch links to commit links)
Enhanced Features
Contributor Detection: GitLab provides a /commits/:sha/merge_requests endpoint that allows accurate detection of whether a commit came through a merge request, improving contributor vs committer badge accuracy compared to the GitHub plugin.
Troubleshooting
Linkbacks not appearing
Symptoms: GitLab comments aren't being created when GitLab links are posted
Solutions:
- Verify access token has
apiscope (not justread_api) - Check GitLab base URL is correct with no trailing slash
- Ensure project is in "gitlab linkback projects" list
- Check for wildcard match:
myorg/*should matchmyorg/myproject - Verify post was created/edited after plugin was enabled
- Check Discourse logs for errors:
tail -f /var/discourse/shared/standalone/log/rails/production.log - Verify GitLab project permissions allow API access
Common errors in logs:
401 Unauthorized: Token is invalid or lacks required scope404 Not Found: Project path is incorrect or not accessible403 Forbidden: Token doesn't have permission to comment
Badges not being granted
Symptoms: Users aren't receiving GitLab badges despite having commits
Solutions:
- Ensure "gitlab badges enabled" is checked
- Verify access token has
apiscope - Check repositories are correctly specified in "gitlab badges repos"
- Wait up to 4 hours for scheduled job, or trigger manually:
# In Rails console: discourse/bin/rails c Jobs::GrantGitlabBadges.new.execute({}) - Verify user email matches GitLab commit email OR user has OAuth account linked:
# Check user's linked accounts User.find_by_email("user@example.com").user_associated_accounts - Check commits are being fetched:
# View fetched commits DiscourseGitlabPlugin::GitlabRepo.first.commits.count - Check badges were created:
Badge.where("name LIKE '%GitLab%'").pluck(:name)
Common issues:
- Email mismatch: User's Discourse email doesn't match their GitLab commit email
- No commits fetched: Access token can't read repository
- Wrong role_id: All commits showing as contributors (0) or committers (1)
Permalinks not converting
Symptoms: Branch-based file links aren't being converted to commit permalinks
Solutions:
- Confirm "gitlab permalinks enabled" is checked
- Verify GitLab instance URL matches link format exactly
- Check file isn't in exclusion list (see "gitlab permalinks exclude")
- Remember: 1-hour grace period before conversion
- Ensure branch exists and API access is granted
- Check for errors in logs:
tail -f /var/discourse/shared/standalone/log/rails/production.log | grep Permalink - Verify link format matches:
/-/blob/{branch}/(GitLab uses/-/separator)
Common issues:
- Too recent: Post is less than 1 hour old (grace period)
- Wrong URL format: Link doesn't match GitLab URL pattern
- Branch doesn't exist: Branch was already deleted
- Permission denied: Token can't access branch information
Self-Hosted GitLab Issues
Symptoms: Plugin doesn't work with self-hosted GitLab instance
Solutions:
- SSL Certificate Errors: Ensure your self-hosted GitLab has valid SSL certificates
- Check certificate:
curl -v https://gitlab.example.com - If using self-signed certificates, this plugin won't work (Discourse requires valid certs)
- Check certificate:
- Firewall: Verify Discourse server can reach GitLab instance
- Test connectivity:
curl -H "PRIVATE-TOKEN: your-token" https://gitlab.example.com/api/v4/version
- Test connectivity:
- API Version: Plugin requires GitLab 13.0+ (API v4 support)
- Check version:
curl https://gitlab.example.com/api/v4/version
- Check version:
- Base URL: Ensure "gitlab base url" setting matches your instance exactly
- Correct:
https://gitlab.example.com - Incorrect:
https://gitlab.example.com/(trailing slash)
- Correct:
- Port Numbers: If using non-standard ports, include in base URL
- Example:
https://gitlab.example.com:8443
- Example:
Development
Testing API Connectivity
From Rails console (discourse/bin/rails c):
# Test repository access
require 'excon'
url = "https://gitlab.com/api/v4/projects/namespace%2Fproject"
response = Excon.get(url, headers: { "PRIVATE-TOKEN" => "your-token" })
puts JSON.pretty_generate(JSON.parse(response.body))
# Test posting a note to merge request
url = "https://gitlab.com/api/v4/projects/namespace%2Fproject/merge_requests/1/notes"
response = Excon.post(url,
body: { body: "Test comment from Discourse" }.to_json,
headers: {
"PRIVATE-TOKEN" => "your-token",
"Content-Type" => "application/json"
}
)
puts response.status # Should be 201
# Test commit comment
url = "https://gitlab.com/api/v4/projects/namespace%2Fproject/repository/commits/abc123/comments"
response = Excon.post(url,
body: { note: "Test commit comment" }.to_json,
headers: {
"PRIVATE-TOKEN" => "your-token",
"Content-Type" => "application/json"
}
)
puts response.status # Should be 201
Manual Badge Granting
To immediately grant badges without waiting for the 4-hour scheduled job:
# In Rails console
Jobs::GrantGitlabBadges.new.execute({})
Checking Plugin Status
# Verify plugin is enabled
SiteSetting.enable_discourse_gitlab_plugin
# Check configuration
SiteSetting.gitlab_base_url
SiteSetting.gitlab_linkback_enabled
SiteSetting.gitlab_badges_enabled
SiteSetting.gitlab_permalinks_enabled
# View tracked repositories
DiscourseGitlabPlugin::GitlabRepo.repos
# Count fetched commits
DiscourseGitlabPlugin::GitlabCommit.count
# View commits for specific repo
repo = DiscourseGitlabPlugin::GitlabRepo.find_by(name: "myorg/myproject")
repo.commits.count
repo.commits.where(role_id: 0).count # Contributors (via MR)
repo.commits.where(role_id: 1).count # Committers (direct)
Debugging Background Jobs
# Check job queue
Sidekiq::ScheduledSet.new.each { |job| puts "#{job.klass} - #{job.args}" }
# Check failed jobs
Sidekiq::RetrySet.new.each { |job| puts "#{job.klass} - #{job.error_message}" }
# Manually trigger linkback
post = Post.last
Jobs.enqueue(:create_gitlab_linkback, post_id: post.id)
# Manually trigger permalink replacement
Jobs.enqueue(:replace_gitlab_non_permalinks, post_id: post.id)
Support and Contributing
This plugin is maintained as part of the Discourse ecosystem. For issues, feature requests, or contributions:
- Report issues: GitHub Issues
- Community support: Discourse Meta
- Contributing: Pull requests welcome! Please follow Discourse coding standards.
License
MIT License - see LICENSE file for details.
Credits
This plugin is adapted from the discourse-github plugin originally created by Robin Ward and Sam Saffron.
Changelog
Version 0.1 (2026-01-15)
- Initial release
- GitLab linkback feature (issues, MRs, commits)
- GitLab badges feature (committers and contributors)
- GitLab permalinks feature (branch to commit conversion)
- Support for self-hosted GitLab instances
- Enhanced MR detection using GitLab-specific API endpoints