Commit 04daa0b9 authored by Yauhen Kotau's avatar Yauhen Kotau

Added YouTrack integration

Fixes gitlab-org/gitlab-ce#42595
parent fe10964a
...@@ -160,6 +160,7 @@ class Project < ActiveRecord::Base ...@@ -160,6 +160,7 @@ class Project < ActiveRecord::Base
has_one :pushover_service has_one :pushover_service
has_one :jira_service has_one :jira_service
has_one :redmine_service has_one :redmine_service
has_one :youtrack_service
has_one :custom_issue_tracker_service has_one :custom_issue_tracker_service
has_one :bugzilla_service has_one :bugzilla_service
has_one :gitlab_issue_tracker_service, inverse_of: :project has_one :gitlab_issue_tracker_service, inverse_of: :project
......
# frozen_string_literal: true
class YoutrackService < IssueTrackerService
validates :project_url, :issues_url, :new_issue_url, presence: true, public_url: true, if: :activated?
prop_accessor :title, :description, :project_url, :issues_url, :new_issue_url
# {PROJECT-KEY}-{NUMBER} Examples: YT-1, PRJ-1
def self.reference_pattern(only_long: false)
if only_long
/(?<issue>\b[A-Z][A-Z0-9_]*-\d+)/
else
/(?<issue>\b[A-Z][A-Z0-9_]*-\d+)|(#{Issue.reference_prefix}(?<issue>\d+))/
end
end
def title
if self.properties && self.properties['title'].present?
self.properties['title']
else
'YouTrack'
end
end
def description
if self.properties && self.properties['description'].present?
self.properties['description']
else
'YouTrack issue tracker'
end
end
def self.to_param
'youtrack'
end
end
...@@ -266,6 +266,7 @@ class Service < ActiveRecord::Base ...@@ -266,6 +266,7 @@ class Service < ActiveRecord::Base
prometheus prometheus
pushover pushover
redmine redmine
youtrack
slack_slash_commands slack_slash_commands
slack slack
teamcity teamcity
......
# External issue tracker # External issue tracker
GitLab has a great issue tracker but you can also use an external one such as GitLab has a great issue tracker but you can also use an external one such as
Jira, Redmine, or Bugzilla. Issue trackers are configurable per GitLab project and allow Jira, Redmine, YouTrack, or Bugzilla. Issue trackers are configurable per GitLab project
you to do the following: and allow you to do the following:
- you can reference these external issues inside GitLab interface - you can reference these external issues inside GitLab interface
(merge requests, commits, comments) and they will be automatically converted (merge requests, commits, comments) and they will be automatically converted
...@@ -20,6 +20,7 @@ To enable an external issue tracker you must configure the appropriate **Service ...@@ -20,6 +20,7 @@ To enable an external issue tracker you must configure the appropriate **Service
Visit the links below for details: Visit the links below for details:
- [Redmine](../user/project/integrations/redmine.md) - [Redmine](../user/project/integrations/redmine.md)
- [YouTrack](../user/project/integrations/youtrack.md)
- [Jira](../user/project/integrations/jira.md) - [Jira](../user/project/integrations/jira.md)
- [Bugzilla](../user/project/integrations/bugzilla.md) - [Bugzilla](../user/project/integrations/bugzilla.md)
- [Custom Issue Tracker](../user/project/integrations/custom_issue_tracker.md) - [Custom Issue Tracker](../user/project/integrations/custom_issue_tracker.md)
......
...@@ -50,6 +50,7 @@ Click on the service links to see further configuration instructions and details ...@@ -50,6 +50,7 @@ Click on the service links to see further configuration instructions and details
| [Prometheus](prometheus.md) | Monitor the performance of your deployed apps | | [Prometheus](prometheus.md) | Monitor the performance of your deployed apps |
| Pushover | Pushover makes it easy to get real-time notifications on your Android device, iPhone, iPad, and Desktop | | Pushover | Pushover makes it easy to get real-time notifications on your Android device, iPhone, iPad, and Desktop |
| [Redmine](redmine.md) | Redmine issue tracker | | [Redmine](redmine.md) | Redmine issue tracker |
| [YouTrack](youtrack.md) | YouTrack issue tracker |
## Services templates ## Services templates
......
# YouTrack Service
1. To enable the YouTrack integration in a project, navigate to the
[Integrations page](project_services.md#accessing-the-project-services), click
the **YouTrack** service, and fill in the required details on the page as described
in the table below.
| Field | Description |
| ----- | ----------- |
| `description` | A name for the issue tracker (to differentiate between instances, for example) |
| `project_url` | The URL to the project in YouTrack which is being linked to this GitLab project |
| `issues_url` | The URL to the issue in YouTrack project that is linked to this GitLab project. Note that the `issues_url` requires `:id` in the URL. This ID is used by GitLab as a placeholder to replace the issue number. |
| `new_issue_url` | This is the URL to create a new issue in YouTrack for the project linked to this GitLab project. **This is currently not being used and will be removed in a future release.** |
Once you have configured and enabled YouTrack you'll see the YouTrack link on the GitLab project pages that takes you to the appropriate YouTrack project.
1. To disable the internal issue tracking system in a project, navigate to the General page, expand [Permissions](../settings/index.md#sharing-and-permissions), and slide the Issues switch invalid.
![Issue configuration](img/issue_configuration.png)
## Referencing issues in YouTrack
Issues in YouTrack can be referenced as `<PROJECT>-<ID>` where `<PROJECT>`
starts with a capital letter which is then followed by capital letters, numbers
or underscores, and `<ID>` is a number (example `API_32-143`).
`<PROJECT>` part is included into issue_id and links can point any YouTrack
project (`issues_url` + issue_id)
...@@ -155,7 +155,7 @@ For further details, see [Importing issues from CSV](csv_import.md) ...@@ -155,7 +155,7 @@ For further details, see [Importing issues from CSV](csv_import.md)
Alternatively to GitLab's built-in Issue Tracker, you can also use an [external Alternatively to GitLab's built-in Issue Tracker, you can also use an [external
tracker](../../../integration/external-issue-tracker.md) such as Jira, Redmine, tracker](../../../integration/external-issue-tracker.md) such as Jira, Redmine,
or Bugzilla. YouTrack, or Bugzilla.
### Issue API ### Issue API
......
...@@ -592,6 +592,32 @@ module API ...@@ -592,6 +592,32 @@ module API
desc: 'The description of the tracker' desc: 'The description of the tracker'
} }
], ],
'youtrack' => [
{
required: true,
name: :new_issue_url,
type: String,
desc: 'The new issue URL'
},
{
required: true,
name: :project_url,
type: String,
desc: 'The project URL'
},
{
required: true,
name: :issues_url,
type: String,
desc: 'The issues URL'
},
{
required: false,
name: :description,
type: String,
desc: 'The description of the tracker'
}
],
'slack' => [ 'slack' => [
CHAT_NOTIFICATION_SETTINGS, CHAT_NOTIFICATION_SETTINGS,
CHAT_NOTIFICATION_FLAGS, CHAT_NOTIFICATION_FLAGS,
...@@ -665,6 +691,7 @@ module API ...@@ -665,6 +691,7 @@ module API
PrometheusService, PrometheusService,
PushoverService, PushoverService,
RedmineService, RedmineService,
YoutrackService,
SlackService, SlackService,
MattermostService, MattermostService,
MicrosoftTeamsService, MicrosoftTeamsService,
......
...@@ -313,6 +313,21 @@ FactoryBot.define do ...@@ -313,6 +313,21 @@ FactoryBot.define do
end end
end end
factory :youtrack_project, parent: :project do
has_external_issue_tracker true
after :create do |project|
project.create_youtrack_service(
active: true,
properties: {
'project_url' => 'http://youtrack/projects/project_guid_in_youtrack',
'issues_url' => 'http://youtrack/issues/:id',
'new_issue_url' => 'http://youtrack/newIssue'
}
)
end
end
factory :jira_project, parent: :project do factory :jira_project, parent: :project do
has_external_issue_tracker true has_external_issue_tracker true
jira_service jira_service
......
...@@ -121,6 +121,28 @@ describe Banzai::Filter::ExternalIssueReferenceFilter do ...@@ -121,6 +121,28 @@ describe Banzai::Filter::ExternalIssueReferenceFilter do
end end
end end
context "youtrack project" do
let(:project) { create(:youtrack_project) }
before do
project.update!(issues_enabled: false)
end
context "with right markdown" do
let(:issue) { ExternalIssue.new("YT-123", project) }
let(:reference) { issue.to_reference }
it_behaves_like "external issue tracker"
end
context "with a single-letter prefix" do
let(:issue) { ExternalIssue.new("T-123", project) }
let(:reference) { issue.to_reference }
it_behaves_like "external issue tracker"
end
end
context "jira project" do context "jira project" do
let(:project) { create(:jira_project) } let(:project) { create(:jira_project) }
let(:reference) { issue.to_reference } let(:reference) { issue.to_reference }
......
...@@ -232,6 +232,7 @@ project: ...@@ -232,6 +232,7 @@ project:
- pushover_service - pushover_service
- jira_service - jira_service
- redmine_service - redmine_service
- youtrack_service
- custom_issue_tracker_service - custom_issue_tracker_service
- bugzilla_service - bugzilla_service
- gitlab_issue_tracker_service - gitlab_issue_tracker_service
......
...@@ -6629,6 +6629,26 @@ ...@@ -6629,6 +6629,26 @@
], ],
"deploy_keys": [], "deploy_keys": [],
"services": [ "services": [
{
"id": 101,
"title": "YouTrack",
"project_id": 5,
"created_at": "2016-06-14T15:01:51.327Z",
"updated_at": "2016-06-14T15:01:51.327Z",
"active": false,
"properties": {},
"template": false,
"push_events": true,
"issues_events": true,
"merge_requests_events": true,
"tag_push_events": true,
"note_events": true,
"job_events": true,
"type": "YoutrackService",
"category": "issue_tracker",
"default": false,
"wiki_page_events": true
},
{ {
"id": 100, "id": 100,
"title": "JetBrains TeamCity CI", "title": "JetBrains TeamCity CI",
......
require 'spec_helper'
describe YoutrackService do
describe 'Associations' do
it { is_expected.to belong_to :project }
it { is_expected.to have_one :service_hook }
end
describe 'Validations' do
context 'when service is active' do
before do
subject.active = true
end
it { is_expected.to validate_presence_of(:project_url) }
it { is_expected.to validate_presence_of(:issues_url) }
it { is_expected.to validate_presence_of(:new_issue_url) }
it_behaves_like 'issue tracker service URL attribute', :project_url
it_behaves_like 'issue tracker service URL attribute', :issues_url
it_behaves_like 'issue tracker service URL attribute', :new_issue_url
end
context 'when service is inactive' do
before do
subject.active = false
end
it { is_expected.not_to validate_presence_of(:project_url) }
it { is_expected.not_to validate_presence_of(:issues_url) }
it { is_expected.not_to validate_presence_of(:new_issue_url) }
end
end
describe '.reference_pattern' do
it_behaves_like 'allows project key on reference pattern'
it 'does allow project prefix on the reference' do
expect(described_class.reference_pattern.match('YT-123')[:issue]).to eq('YK-123')
end
end
end
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment