Commit bb766baa authored by Sean McGivern's avatar Sean McGivern

Merge branch 'ewm-proj-service' into 'master'

Add RTC project service to GitLab

See merge request gitlab-org/gitlab!36662
parents 1212e598 1269412b
...@@ -146,6 +146,7 @@ class Project < ApplicationRecord ...@@ -146,6 +146,7 @@ class Project < ApplicationRecord
has_one :discord_service has_one :discord_service
has_one :drone_ci_service has_one :drone_ci_service
has_one :emails_on_push_service has_one :emails_on_push_service
has_one :ewm_service
has_one :pipelines_email_service has_one :pipelines_email_service
has_one :irker_service has_one :irker_service
has_one :pivotaltracker_service has_one :pivotaltracker_service
......
# frozen_string_literal: true
class EwmService < IssueTrackerService
validates :project_url, :issues_url, :new_issue_url, presence: true, public_url: true, if: :activated?
def self.reference_pattern(only_long: true)
@reference_pattern ||= %r{(?<issue>\b(bug|task|work item|workitem|rtcwi|defect)\b\s+\d+)}i
end
def title
'EWM'
end
def description
s_('IssueTracker|EWM work items tracker')
end
def self.to_param
'ewm'
end
def can_test?
false
end
def issue_url(iid)
issues_url.gsub(':id', iid.to_s.split(' ')[-1])
end
end
...@@ -13,7 +13,7 @@ class Service < ApplicationRecord ...@@ -13,7 +13,7 @@ class Service < ApplicationRecord
SERVICE_NAMES = %w[ SERVICE_NAMES = %w[
alerts asana assembla bamboo bugzilla buildkite campfire confluence custom_issue_tracker discord alerts asana assembla bamboo bugzilla buildkite campfire confluence custom_issue_tracker discord
drone_ci emails_on_push external_wiki flowdock hangouts_chat hipchat irker jira drone_ci emails_on_push ewm external_wiki flowdock hangouts_chat hipchat irker jira
mattermost mattermost_slash_commands microsoft_teams packagist pipelines_email mattermost mattermost_slash_commands microsoft_teams packagist pipelines_email
pivotaltracker prometheus pushover redmine slack slack_slash_commands teamcity unify_circuit webex_teams youtrack pivotaltracker prometheus pushover redmine slack slack_slash_commands teamcity unify_circuit webex_teams youtrack
].freeze ].freeze
......
---
title: Added EWM work item tracker integration
merge_request: 36662
author:
type: added
...@@ -16054,6 +16054,7 @@ enum ServiceType { ...@@ -16054,6 +16054,7 @@ enum ServiceType {
DISCORD_SERVICE DISCORD_SERVICE
DRONE_CI_SERVICE DRONE_CI_SERVICE
EMAILS_ON_PUSH_SERVICE EMAILS_ON_PUSH_SERVICE
EWM_SERVICE
EXTERNAL_WIKI_SERVICE EXTERNAL_WIKI_SERVICE
FLOWDOCK_SERVICE FLOWDOCK_SERVICE
GITHUB_SERVICE GITHUB_SERVICE
......
...@@ -46953,6 +46953,12 @@ ...@@ -46953,6 +46953,12 @@
"isDeprecated": false, "isDeprecated": false,
"deprecationReason": null "deprecationReason": null
}, },
{
"name": "EWM_SERVICE",
"description": null,
"isDeprecated": false,
"deprecationReason": null
},
{ {
"name": "EXTERNAL_WIKI_SERVICE", "name": "EXTERNAL_WIKI_SERVICE",
"description": null, "description": null,
...@@ -3373,6 +3373,7 @@ State of a Sentry error ...@@ -3373,6 +3373,7 @@ State of a Sentry error
| `DISCORD_SERVICE` | | | `DISCORD_SERVICE` | |
| `DRONE_CI_SERVICE` | | | `DRONE_CI_SERVICE` | |
| `EMAILS_ON_PUSH_SERVICE` | | | `EMAILS_ON_PUSH_SERVICE` | |
| `EWM_SERVICE` | |
| `EXTERNAL_WIKI_SERVICE` | | | `EXTERNAL_WIKI_SERVICE` | |
| `FLOWDOCK_SERVICE` | | | `FLOWDOCK_SERVICE` | |
| `GITHUB_SERVICE` | | | `GITHUB_SERVICE` | |
......
...@@ -15,6 +15,7 @@ GitLab can be integrated with the following external issue trackers: ...@@ -15,6 +15,7 @@ GitLab can be integrated with the following external issue trackers:
- Jira - Jira
- Redmine - Redmine
- Bugzilla - Bugzilla
- EWM
- YouTrack - YouTrack
## Authentication sources ## Authentication sources
......
# External issue tracker # External issue tracker
GitLab has a great [issue tracker](../user/project/issues/index.md) but you can also use an external one GitLab has a great [issue tracker](../user/project/issues/index.md) but you can also use an external one
such as Jira, Redmine, YouTrack, or Bugzilla. External issue trackers are configurable per GitLab project. such as Jira, Redmine, YouTrack, Bugzilla, or EWM. External issue trackers are configurable per GitLab project.
Once configured, you can reference external issues using the format `CODE-123`, where: Once configured, you can reference external issues using the format `CODE-123`, where:
...@@ -26,6 +26,7 @@ Visit the links below for details: ...@@ -26,6 +26,7 @@ Visit the links below for details:
- [YouTrack](../user/project/integrations/youtrack.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)
- [EWM](../user/project/integrations/ewm.md)
- [Custom Issue Tracker](../user/project/integrations/custom_issue_tracker.md) - [Custom Issue Tracker](../user/project/integrations/custom_issue_tracker.md)
### Service Template ### Service Template
......
# IBM Engineering Workflow Management (EWM) Integration **(CORE)**
This service allows you to navigate from GitLab to EWM work items mentioned in merge request descriptions and commit messages. Each work item reference is automatically converted to a link back to the work item.
NOTE: **Note:**
This IBM product was [formerly named Rational Team Concert](https://jazz.net/blog/index.php/2019/04/23/renaming-the-ibm-continuous-engineering-portfolio/)(RTC). This integration is also compatible with all versions of RTC and EWM.
1. From a GitLab project, navigate to **Settings > Integrations**, and then click **EWM**.
1. Enter the information listed below.
| Field | Description |
| ----- | ----------- |
| `project_url` | URL of the EWM project area to link to the GitLab project. To obtain your project area URL, navigate to the path `/ccm/web/projects` and copy the listed project's URL. For example, `https://example.com/ccm/web/Example%20Project` |
| `issues_url` | URL to the work item editor in the EWM project area. The format is `<your-server-url>/resource/itemName/com.ibm.team.workitem.WorkItem/:id`. For example, `https://example.com/ccm/resource/itemName/com.ibm.team.workitem.WorkItem/:id` |
| `new_issue_url` | URL to create a new work item in the EWM project area. Append the following fragment to your project area URL: `#action=com.ibm.team.workitem.newWorkItem`. For example, `https://example.com/ccm/web/projects/JKE%20Banking#action=com.ibm.team.workitem.newWorkItem` |
## Reference EWM work items in commit messages
You can use any of the keywords supported by the EWM Git Integration Toolkit to refer to work items. Work items can be referenced using the format: `<keyword> <id>`.
You can use the following keywords:
- `bug`
- `task`
- `defect`
- `rtcwi`
- `workitem`
- `work item`
For more details, see the EWM documentation page [Creating links from commit comments](https://www.ibm.com/support/knowledgecenter/SSYMRC_7.0.0/com.ibm.team.connector.cq.doc/topics/t_creating_links_through_comments.html), which recommends against using the additionally-supported keyword `#` because of incompatibility with GitLab.
...@@ -59,6 +59,7 @@ Click on the service links to see further configuration instructions and details ...@@ -59,6 +59,7 @@ Click on the service links to see further configuration instructions and details
| [Prometheus](prometheus.md) | Monitor the performance of your deployed apps | No | | [Prometheus](prometheus.md) | Monitor the performance of your deployed apps | No |
| Pushover | Pushover makes it easy to get real-time notifications on your Android device, iPhone, iPad, and Desktop | No | | Pushover | Pushover makes it easy to get real-time notifications on your Android device, iPhone, iPad, and Desktop | No |
| [Redmine](redmine.md) | Redmine issue tracker | No | | [Redmine](redmine.md) | Redmine issue tracker | No |
| [EWM](ewm.md) | EWM work item tracker | No |
| [Unify Circuit](unify_circuit.md) | Receive events notifications in Unify Circuit | No | | [Unify Circuit](unify_circuit.md) | Receive events notifications in Unify Circuit | No |
| [Webex Teams](webex_teams.md) | Receive events notifications in Webex Teams | No | | [Webex Teams](webex_teams.md) | Receive events notifications in Webex Teams | No |
| [YouTrack](youtrack.md) | YouTrack issue tracker | No | | [YouTrack](youtrack.md) | YouTrack issue tracker | No |
......
...@@ -221,4 +221,4 @@ Feature.disable(:save_issuable_health_status) ...@@ -221,4 +221,4 @@ Feature.disable(:save_issuable_health_status)
- [Export issues](csv_export.md) - [Export issues](csv_export.md)
- [Issues API](../../../api/issues.md) - [Issues API](../../../api/issues.md)
- Configure an [external issue tracker](../../../integration/external-issue-tracker.md) - Configure an [external issue tracker](../../../integration/external-issue-tracker.md)
such as Jira, Redmine, or Bugzilla. such as Jira, Redmine, Bugzilla, or EWM.
...@@ -633,6 +633,26 @@ module API ...@@ -633,6 +633,26 @@ module API
desc: 'The issues URL' desc: 'The issues URL'
} }
], ],
'ewm' => [
{
required: true,
name: :new_issue_url,
type: String,
desc: 'New Issue URL'
},
{
required: true,
name: :project_url,
type: String,
desc: 'Project URL'
},
{
required: true,
name: :issues_url,
type: String,
desc: 'Issues URL'
}
],
'youtrack' => [ 'youtrack' => [
{ {
required: true, required: true,
...@@ -735,6 +755,7 @@ module API ...@@ -735,6 +755,7 @@ module API
::DiscordService, ::DiscordService,
::DroneCiService, ::DroneCiService,
::EmailsOnPushService, ::EmailsOnPushService,
::EwmService,
::ExternalWikiService, ::ExternalWikiService,
::FlowdockService, ::FlowdockService,
::HangoutsChatService, ::HangoutsChatService,
......
...@@ -13911,6 +13911,9 @@ msgstr "" ...@@ -13911,6 +13911,9 @@ msgstr ""
msgid "IssueTracker|Custom issue tracker" msgid "IssueTracker|Custom issue tracker"
msgstr "" msgstr ""
msgid "IssueTracker|EWM work items tracker"
msgstr ""
msgid "IssueTracker|Redmine issue tracker" msgid "IssueTracker|Redmine issue tracker"
msgstr "" msgstr ""
......
...@@ -392,6 +392,12 @@ FactoryBot.define do ...@@ -392,6 +392,12 @@ FactoryBot.define do
end end
end end
factory :ewm_project, parent: :project do
has_external_issue_tracker { true }
ewm_service
end
factory :project_with_design, parent: :project do factory :project_with_design, parent: :project do
after(:create) do |project| after(:create) do |project|
issue = create(:issue, project: project) issue = create(:issue, project: project)
......
...@@ -116,6 +116,12 @@ FactoryBot.define do ...@@ -116,6 +116,12 @@ FactoryBot.define do
issue_tracker issue_tracker
end end
factory :ewm_service do
project
active { true }
issue_tracker
end
trait :issue_tracker do trait :issue_tracker do
transient do transient do
create_data { true } create_data { true }
......
...@@ -16,7 +16,7 @@ RSpec.describe 'User activates issue tracker', :js do ...@@ -16,7 +16,7 @@ RSpec.describe 'User activates issue tracker', :js do
fill_in 'service_new_issue_url', with: url unless skip_new_issue_url fill_in 'service_new_issue_url', with: url unless skip_new_issue_url
end end
shared_examples 'external issue tracker activation' do |tracker:, skip_new_issue_url: false| shared_examples 'external issue tracker activation' do |tracker:, skip_new_issue_url: false, skip_test: false|
describe 'user sets and activates the Service' do describe 'user sets and activates the Service' do
context 'when the connection test succeeds' do context 'when the connection test succeeds' do
before do before do
...@@ -25,7 +25,11 @@ RSpec.describe 'User activates issue tracker', :js do ...@@ -25,7 +25,11 @@ RSpec.describe 'User activates issue tracker', :js do
visit_project_integration(tracker) visit_project_integration(tracker)
fill_form(skip_new_issue_url: skip_new_issue_url) fill_form(skip_new_issue_url: skip_new_issue_url)
click_test_integration if skip_test
click_button('Save changes')
else
click_test_integration
end
end end
it 'activates the service' do it 'activates the service' do
...@@ -47,7 +51,11 @@ RSpec.describe 'User activates issue tracker', :js do ...@@ -47,7 +51,11 @@ RSpec.describe 'User activates issue tracker', :js do
visit_project_integration(tracker) visit_project_integration(tracker)
fill_form(skip_new_issue_url: skip_new_issue_url) fill_form(skip_new_issue_url: skip_new_issue_url)
click_test_then_save_integration if skip_test
click_button('Save changes')
else
click_test_then_save_integration
end
expect(page).to have_content("#{tracker} activated.") expect(page).to have_content("#{tracker} activated.")
expect(current_path).to eq(edit_project_service_path(project, tracker.parameterize(separator: '_'))) expect(current_path).to eq(edit_project_service_path(project, tracker.parameterize(separator: '_')))
...@@ -80,4 +88,5 @@ RSpec.describe 'User activates issue tracker', :js do ...@@ -80,4 +88,5 @@ RSpec.describe 'User activates issue tracker', :js do
it_behaves_like 'external issue tracker activation', tracker: 'YouTrack', skip_new_issue_url: true it_behaves_like 'external issue tracker activation', tracker: 'YouTrack', skip_new_issue_url: true
it_behaves_like 'external issue tracker activation', tracker: 'Bugzilla' it_behaves_like 'external issue tracker activation', tracker: 'Bugzilla'
it_behaves_like 'external issue tracker activation', tracker: 'Custom Issue Tracker' it_behaves_like 'external issue tracker activation', tracker: 'Custom Issue Tracker'
it_behaves_like 'external issue tracker activation', tracker: 'EWM', skip_test: true
end end
...@@ -208,4 +208,47 @@ RSpec.describe Banzai::Filter::ExternalIssueReferenceFilter do ...@@ -208,4 +208,47 @@ RSpec.describe Banzai::Filter::ExternalIssueReferenceFilter do
end end
end end
end end
context "ewm project" do
let_it_be(:project) { create(:ewm_project) }
before do
project.update!(issues_enabled: false)
end
context "rtcwi keyword" do
let(:issue) { ExternalIssue.new("rtcwi 123", project) }
let(:reference) { issue.to_reference }
it_behaves_like "external issue tracker"
end
context "workitem keyword" do
let(:issue) { ExternalIssue.new("workitem 123", project) }
let(:reference) { issue.to_reference }
it_behaves_like "external issue tracker"
end
context "defect keyword" do
let(:issue) { ExternalIssue.new("defect 123", project) }
let(:reference) { issue.to_reference }
it_behaves_like "external issue tracker"
end
context "task keyword" do
let(:issue) { ExternalIssue.new("task 123", project) }
let(:reference) { issue.to_reference }
it_behaves_like "external issue tracker"
end
context "bug keyword" do
let(:issue) { ExternalIssue.new("bug 123", project) }
let(:reference) { issue.to_reference }
it_behaves_like "external issue tracker"
end
end
end end
...@@ -365,6 +365,7 @@ project: ...@@ -365,6 +365,7 @@ project:
- youtrack_service - youtrack_service
- custom_issue_tracker_service - custom_issue_tracker_service
- bugzilla_service - bugzilla_service
- ewm_service
- external_wiki_service - external_wiki_service
- mock_ci_service - mock_ci_service
- mock_deployment_service - mock_deployment_service
......
# frozen_string_literal: true
require 'spec_helper'
RSpec.describe EwmService 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 "ReferencePatternValidation" do
it "extracts bug" do
expect(described_class.reference_pattern.match("This is bug 123")[:issue]).to eq("bug 123")
end
it "extracts task" do
expect(described_class.reference_pattern.match("This is task 123.")[:issue]).to eq("task 123")
end
it "extracts work item" do
expect(described_class.reference_pattern.match("This is work item 123 now")[:issue]).to eq("work item 123")
end
it "extracts workitem" do
expect(described_class.reference_pattern.match("workitem 123 at the beginning")[:issue]).to eq("workitem 123")
end
it "extracts defect" do
expect(described_class.reference_pattern.match("This is defect 123 defect")[:issue]).to eq("defect 123")
end
it "extracts rtcwi" do
expect(described_class.reference_pattern.match("This is rtcwi 123")[:issue]).to eq("rtcwi 123")
end
end
end
...@@ -61,6 +61,7 @@ RSpec.describe Project do ...@@ -61,6 +61,7 @@ RSpec.describe Project do
it { is_expected.to have_one(:youtrack_service) } it { is_expected.to have_one(:youtrack_service) }
it { is_expected.to have_one(:custom_issue_tracker_service) } it { is_expected.to have_one(:custom_issue_tracker_service) }
it { is_expected.to have_one(:bugzilla_service) } it { is_expected.to have_one(:bugzilla_service) }
it { is_expected.to have_one(:ewm_service) }
it { is_expected.to have_one(:external_wiki_service) } it { is_expected.to have_one(:external_wiki_service) }
it { is_expected.to have_one(:confluence_service) } it { is_expected.to have_one(:confluence_service) }
it { is_expected.to have_one(:project_feature) } it { is_expected.to have_one(:project_feature) }
......
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