Commit 63e1db26 authored by Andy Soiron's avatar Andy Soiron

Merge branch '334500-mount-rest-endpoints-as-integrations-endpoints' into 'master'

Mount services REST endpoints as integrations endpoints

See merge request gitlab-org/gitlab!71216
parents 0fdee391 0398c12b
...@@ -42,6 +42,7 @@ The following API resources are available in the project context: ...@@ -42,6 +42,7 @@ The following API resources are available in the project context:
| [Events](events.md) | `/projects/:id/events` (also available for users and standalone) | | [Events](events.md) | `/projects/:id/events` (also available for users and standalone) |
| [Feature Flags](feature_flags.md) | `/projects/:id/feature_flags` | | [Feature Flags](feature_flags.md) | `/projects/:id/feature_flags` |
| [Feature Flag User Lists](feature_flag_user_lists.md) | `/projects/:id/feature_flags_user_lists` | | [Feature Flag User Lists](feature_flag_user_lists.md) | `/projects/:id/feature_flags_user_lists` |
| [Integrations](integrations.md) | `/projects/:id/integrations` |
| [Invitations](invitations.md) | `/projects/:id/invitations` (also available for groups) | | [Invitations](invitations.md) | `/projects/:id/invitations` (also available for groups) |
| [Issues](issues.md) | `/projects/:id/issues` (also available for groups and standalone) | | [Issues](issues.md) | `/projects/:id/issues` (also available for groups and standalone) |
| [Issues Statistics](issues_statistics.md) | `/projects/:id/issues_statistics` (also available for groups and standalone) | | [Issues Statistics](issues_statistics.md) | `/projects/:id/issues_statistics` (also available for groups and standalone) |
...@@ -82,7 +83,7 @@ The following API resources are available in the project context: ...@@ -82,7 +83,7 @@ The following API resources are available in the project context:
| [Resource label events](resource_label_events.md) | `/projects/:id/issues/.../resource_label_events`, `/projects/:id/merge_requests/.../resource_label_events` (also available for groups) | | [Resource label events](resource_label_events.md) | `/projects/:id/issues/.../resource_label_events`, `/projects/:id/merge_requests/.../resource_label_events` (also available for groups) |
| [Runners](runners.md) | `/projects/:id/runners` (also available standalone) | | [Runners](runners.md) | `/projects/:id/runners` (also available standalone) |
| [Search](search.md) | `/projects/:id/search` (also available for groups and standalone) | | [Search](search.md) | `/projects/:id/search` (also available for groups and standalone) |
| [Services](services.md) | `/projects/:id/services` | | [Services](services.md) (renamed to [Integrations](integrations.md)) | `/projects/:id/services` |
| [Tags](tags.md) | `/projects/:id/repository/tags` | | [Tags](tags.md) | `/projects/:id/repository/tags` |
| [User-starred metrics dashboards](metrics_user_starred_dashboards.md ) | `/projects/:id/metrics/user_starred_dashboards` | | [User-starred metrics dashboards](metrics_user_starred_dashboards.md ) | `/projects/:id/metrics/user_starred_dashboards` |
| [Visual Review discussions](visual_review_discussions.md) **(PREMIUM)** | `/projects/:id/merge_requests/:merge_request_id/visual_review_discussions` | | [Visual Review discussions](visual_review_discussions.md) **(PREMIUM)** | `/projects/:id/merge_requests/:merge_request_id/visual_review_discussions` |
......
This diff is collapsed.
This diff is collapsed.
...@@ -4,9 +4,9 @@ group: Integrations ...@@ -4,9 +4,9 @@ group: Integrations
info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/engineering/ux/technical-writing/#assignments info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/engineering/ux/technical-writing/#assignments
--- ---
# Asana service **(FREE)** # Asana integration **(FREE)**
This service adds commit messages as comments to Asana tasks. This integration adds commit messages as comments to Asana tasks.
Once enabled, commit messages are checked for Asana task URLs (for example, Once enabled, commit messages are checked for Asana task URLs (for example,
`https://app.asana.com/0/123456/987654`) or task IDs starting with `#` `https://app.asana.com/0/123456/987654`) or task IDs starting with `#`
(for example, `#987654`). Every task ID found gets the commit comment added to it. (for example, `#987654`). Every task ID found gets the commit comment added to it.
...@@ -23,7 +23,7 @@ You can use either of these words: ...@@ -23,7 +23,7 @@ You can use either of these words:
- `closed` - `closed`
- `closing` - `closing`
See also the [Asana service API documentation](../../../api/services.md#asana). See also the [Asana integration API documentation](../../../api/integrations.md#asana).
## Setup ## Setup
......
...@@ -32,7 +32,7 @@ Click on the service links to see further configuration instructions and details ...@@ -32,7 +32,7 @@ Click on the service links to see further configuration instructions and details
| [Bugzilla](bugzilla.md) | Use Bugzilla as the issue tracker. | **{dotted-circle}** No | | [Bugzilla](bugzilla.md) | Use Bugzilla as the issue tracker. | **{dotted-circle}** No |
| Buildkite | Run CI/CD pipelines with Buildkite. | **{check-circle}** Yes | | Buildkite | Run CI/CD pipelines with Buildkite. | **{check-circle}** Yes |
| Campfire | Connect to chat. | **{dotted-circle}** No | | Campfire | Connect to chat. | **{dotted-circle}** No |
| [Confluence Workspace](../../../api/services.md#confluence-service) | Replace the link to the internal wiki with a link to a Confluence Cloud Workspace. | **{dotted-circle}** No | | [Confluence Workspace](../../../api/integrations.md#confluence-integration) | Replace the link to the internal wiki with a link to a Confluence Cloud Workspace. | **{dotted-circle}** No |
| [Custom issue tracker](custom_issue_tracker.md) | Use a custom issue tracker. | **{dotted-circle}** No | | [Custom issue tracker](custom_issue_tracker.md) | Use a custom issue tracker. | **{dotted-circle}** No |
| [Datadog](../../../integration/datadog.md) | Trace your GitLab pipelines with Datadog. | **{check-circle}** Yes | | [Datadog](../../../integration/datadog.md) | Trace your GitLab pipelines with Datadog. | **{check-circle}** Yes |
| [Discord Notifications](discord_notifications.md) | Send notifications about project events to a Discord channel. | **{dotted-circle}** No | | [Discord Notifications](discord_notifications.md) | Send notifications about project events to a Discord channel. | **{dotted-circle}** No |
...@@ -40,7 +40,7 @@ Click on the service links to see further configuration instructions and details ...@@ -40,7 +40,7 @@ Click on the service links to see further configuration instructions and details
| [Emails on push](emails_on_push.md) | Send commits and diff of each push by email. | **{dotted-circle}** No | | [Emails on push](emails_on_push.md) | Send commits and diff of each push by email. | **{dotted-circle}** No |
| [EWM](ewm.md) | Use IBM Engineering Workflow Management as the issue tracker. | **{dotted-circle}** No | | [EWM](ewm.md) | Use IBM Engineering Workflow Management as the issue tracker. | **{dotted-circle}** No |
| [External wiki](../wiki/index.md#link-an-external-wiki) | Link an external wiki. | **{dotted-circle}** No | | [External wiki](../wiki/index.md#link-an-external-wiki) | Link an external wiki. | **{dotted-circle}** No |
| [Flowdock](../../../api/services.md#flowdock) | Send notifications from GitLab to Flowdock flows. | **{dotted-circle}** No | | [Flowdock](../../../api/integrations.md#flowdock) | Send notifications from GitLab to Flowdock flows. | **{dotted-circle}** No |
| [GitHub](github.md) | Obtain statuses for commits and pull requests. | **{dotted-circle}** No | | [GitHub](github.md) | Obtain statuses for commits and pull requests. | **{dotted-circle}** No |
| [Google Chat](hangouts_chat.md) | Send notifications from your GitLab project to a room in Google Chat.| **{dotted-circle}** No | | [Google Chat](hangouts_chat.md) | Send notifications from your GitLab project to a room in Google Chat.| **{dotted-circle}** No |
| [irker (IRC gateway)](irker.md) | Send IRC messages. | **{dotted-circle}** No | | [irker (IRC gateway)](irker.md) | Send IRC messages. | **{dotted-circle}** No |
......
...@@ -29,7 +29,7 @@ Read more about the ...@@ -29,7 +29,7 @@ Read more about the
[Source Commits endpoint](https://www.pivotaltracker.com/help/api/rest/v5#Source_Commits) in [Source Commits endpoint](https://www.pivotaltracker.com/help/api/rest/v5#Source_Commits) in
the Pivotal Tracker API documentation. the Pivotal Tracker API documentation.
See also the [Pivotal Tracker service API documentation](../../../api/services.md#pivotal-tracker). See also the [Pivotal Tracker integration API documentation](../../../api/integrations.md#pivotal-tracker).
## Set up Pivotal Tracker ## Set up Pivotal Tracker
......
...@@ -28,7 +28,7 @@ module EE ...@@ -28,7 +28,7 @@ module EE
{ {
required: false, required: false,
name: :static_context, name: :static_context,
type: ::API::Services::Boolean, type: ::API::Integrations::Boolean,
desc: 'Append instance name instead of branch to status check name' desc: 'Append instance name instead of branch to status check name'
} }
] ]
...@@ -63,7 +63,7 @@ module EE ...@@ -63,7 +63,7 @@ module EE
{ {
required: false, required: false,
name: :vulnerability_events, name: :vulnerability_events,
type: ::API::Services::Boolean, type: ::API::Integrations::Boolean,
desc: 'Enable notifications for vulnerability_events' desc: 'Enable notifications for vulnerability_events'
} }
].freeze ].freeze
......
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
module EE module EE
module API module API
module Services module Integrations
extend ActiveSupport::Concern extend ActiveSupport::Concern
prepended do prepended do
......
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
require "spec_helper" require "spec_helper"
RSpec.describe API::Services do RSpec.describe API::Integrations do
let_it_be(:user) { create(:user) } let_it_be(:user) { create(:user) }
let_it_be(:project) do let_it_be(:project) do
......
...@@ -260,7 +260,7 @@ module API ...@@ -260,7 +260,7 @@ module API
mount ::API::ResourceAccessTokens mount ::API::ResourceAccessTokens
mount ::API::RubygemPackages mount ::API::RubygemPackages
mount ::API::Search mount ::API::Search
mount ::API::Services mount ::API::Integrations
mount ::API::Settings mount ::API::Settings
mount ::API::SidekiqMetrics mount ::API::SidekiqMetrics
mount ::API::SnippetRepositoryStorageMoves mount ::API::SnippetRepositoryStorageMoves
......
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
module API module API
module Helpers module Helpers
# Helpers module for API::Services # Helpers module for API::Integrations
# #
# The data structures inside this model are returned using class methods, # The data structures inside this model are returned using class methods,
# allowing EE to extend them where necessary. # allowing EE to extend them where necessary.
......
# frozen_string_literal: true # frozen_string_literal: true
module API module API
class Services < ::API::Base class Integrations < ::API::Base
feature_category :integrations feature_category :integrations
integrations = Helpers::IntegrationsHelpers.integrations integrations = Helpers::IntegrationsHelpers.integrations
...@@ -12,7 +12,7 @@ module API ...@@ -12,7 +12,7 @@ module API
required: true, required: true,
name: :mock_service_url, name: :mock_service_url,
type: String, type: String,
desc: 'URL to the mock service' desc: 'URL to the mock integration'
} }
] ]
integrations['mock-deployment'] = [] integrations['mock-deployment'] = []
...@@ -52,117 +52,122 @@ module API ...@@ -52,117 +52,122 @@ module API
] ]
}.freeze }.freeze
params do helpers do
requires :id, type: String, desc: 'The ID of a project' def integration_attributes(integration)
end integration.fields.inject([]) do |arr, hash|
resource :projects, requirements: API::NAMESPACE_OR_PROJECT_REQUIREMENTS do arr << hash[:name].to_sym
before { authenticate! }
before { authorize_admin_project }
helpers do
def integration_attributes(integration)
integration.fields.inject([]) do |arr, hash|
arr << hash[:name].to_sym
end
end end
end end
end
desc 'Get all active project integrations' do # The API officially documents only the `:id/integrations` API paths.
success Entities::ProjectIntegrationBasic # We support the older `id:/services` path for backwards-compatibility in API V4.
# The support for `:id/services` can be dropped if we create an API V5.
[':id/services', ':id/integrations'].each do |path|
params do
requires :id, type: String, desc: 'The ID of a project'
end end
get ":id/services" do resource :projects, requirements: API::NAMESPACE_OR_PROJECT_REQUIREMENTS do
integrations = user_project.integrations.active before { authenticate! }
before { authorize_admin_project }
present integrations, with: Entities::ProjectIntegrationBasic desc 'Get all active project integrations' do
end success Entities::ProjectIntegrationBasic
end
get path do
integrations = user_project.integrations.active
INTEGRATIONS.each do |slug, settings| present integrations, with: Entities::ProjectIntegrationBasic
desc "Set #{slug} integration for project" end
params do
settings.each do |setting| INTEGRATIONS.each do |slug, settings|
if setting[:required] desc "Set #{slug} integration for project"
requires setting[:name], type: setting[:type], desc: setting[:desc] params do
else settings.each do |setting|
optional setting[:name], type: setting[:type], desc: setting[:desc] if setting[:required]
requires setting[:name], type: setting[:type], desc: setting[:desc]
else
optional setting[:name], type: setting[:type], desc: setting[:desc]
end
end end
end end
end put "#{path}/#{slug}" do
put ":id/services/#{slug}" do integration = user_project.find_or_initialize_integration(slug.underscore)
integration = user_project.find_or_initialize_integration(slug.underscore) params = declared_params(include_missing: false).merge(active: true)
params = declared_params(include_missing: false).merge(active: true)
if integration.update(params)
if integration.update(params) present integration, with: Entities::ProjectIntegration
present integration, with: Entities::ProjectIntegration else
else render_api_error!('400 Bad Request', 400)
render_api_error!('400 Bad Request', 400) end
end end
end end
end
desc "Delete an integration from a project" desc "Delete an integration from a project"
params do params do
requires :slug, type: String, values: INTEGRATIONS.keys, desc: 'The name of the service' requires :slug, type: String, values: INTEGRATIONS.keys, desc: 'The name of the integration'
end end
delete ":id/services/:slug" do delete "#{path}/:slug" do
integration = user_project.find_or_initialize_integration(params[:slug].underscore) integration = user_project.find_or_initialize_integration(params[:slug].underscore)
destroy_conditionally!(integration) do destroy_conditionally!(integration) do
attrs = integration_attributes(integration).index_with { nil }.merge(active: false) attrs = integration_attributes(integration).index_with { nil }.merge(active: false)
render_api_error!('400 Bad Request', 400) unless integration.update(attrs) render_api_error!('400 Bad Request', 400) unless integration.update(attrs)
end
end end
end
desc 'Get the integration settings for a project' do desc 'Get the integration settings for a project' do
success Entities::ProjectIntegration success Entities::ProjectIntegration
end end
params do params do
requires :slug, type: String, values: INTEGRATIONS.keys, desc: 'The name of the service' requires :slug, type: String, values: INTEGRATIONS.keys, desc: 'The name of the integration'
end end
get ":id/services/:slug" do get "#{path}/:slug" do
integration = user_project.find_or_initialize_integration(params[:slug].underscore) integration = user_project.find_or_initialize_integration(params[:slug].underscore)
not_found!('Service') unless integration&.persisted? not_found!('Integration') unless integration&.persisted?
present integration, with: Entities::ProjectIntegration present integration, with: Entities::ProjectIntegration
end
end end
end
TRIGGER_INTEGRATIONS.each do |integration_slug, settings| TRIGGER_INTEGRATIONS.each do |integration_slug, settings|
helpers do helpers do
def slash_command_integration(project, integration_slug, params) def slash_command_integration(project, integration_slug, params)
project.integrations.active.find do |integration| project.integrations.active.find do |integration|
integration.try(:token) == params[:token] && integration.to_param == integration_slug.underscore integration.try(:token) == params[:token] && integration.to_param == integration_slug.underscore
end
end end
end end
end
params do
requires :id, type: String, desc: 'The ID of a project'
end
resource :projects, requirements: API::NAMESPACE_OR_PROJECT_REQUIREMENTS do
desc "Trigger a slash command for #{integration_slug}" do
detail 'Added in GitLab 8.13'
end
params do params do
settings.each do |setting| requires :id, type: String, desc: 'The ID of a project'
requires setting[:name], type: setting[:type], desc: setting[:desc]
end
end end
post ":id/services/#{integration_slug.underscore}/trigger" do resource :projects, requirements: API::NAMESPACE_OR_PROJECT_REQUIREMENTS do
project = find_project(params[:id]) desc "Trigger a slash command for #{integration_slug}" do
detail 'Added in GitLab 8.13'
end
params do
settings.each do |setting|
requires setting[:name], type: setting[:type], desc: setting[:desc]
end
end
post "#{path}/#{integration_slug.underscore}/trigger" do
project = find_project(params[:id])
# This is not accurate, but done to prevent leakage of the project names # This is not accurate, but done to prevent leakage of the project names
not_found!('Service') unless project not_found!('Integration') unless project
integration = slash_command_integration(project, integration_slug, params) integration = slash_command_integration(project, integration_slug, params)
result = integration.try(:trigger, params) result = integration.try(:trigger, params)
if result if result
status result[:status] || 200 status result[:status] || 200
present result present result
else else
not_found!('Service') not_found!('Integration')
end
end end
end end
end end
...@@ -170,4 +175,4 @@ module API ...@@ -170,4 +175,4 @@ module API
end end
end end
API::Services.prepend_mod_with('API::Services') API::Integrations.prepend_mod_with('API::Integrations')
...@@ -30,7 +30,7 @@ module Gitlab ...@@ -30,7 +30,7 @@ module Gitlab
# Returns a class which inherits from the BaseService # Returns a class which inherits from the BaseService
# class that can be used to obtain a dashboard for # class that can be used to obtain a dashboard for
# the provided params. # the provided params.
# @return [Gitlab::Metrics::Dashboard::Services::BaseService] # @return [Metrics::Dashboard::BaseService]
def call(params) def call(params)
service = services.find do |service_class| service = services.find do |service_class|
service_class.valid_params?(params) service_class.valid_params?(params)
......
{ {
"type": "array", "type": "array",
"items": { "$ref": "service.json" } "items": { "$ref": "integration.json" }
} }
This diff is collapsed.
This diff is collapsed.
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