diff --git a/.rubocop_todo/gitlab/feature_flag_without_actor.yml b/.rubocop_todo/gitlab/feature_flag_without_actor.yml index 066465d03fc2441159110d9c271e1e764806ffe5..5fbb5cac62ea2bd778504bc6547b365284818b1e 100644 --- a/.rubocop_todo/gitlab/feature_flag_without_actor.yml +++ b/.rubocop_todo/gitlab/feature_flag_without_actor.yml @@ -153,7 +153,7 @@ Gitlab/FeatureFlagWithoutActor: - 'ee/spec/models/gitlab_subscriptions/features_spec.rb' - 'lib/api/features.rb' - 'lib/api/helpers/packages/dependency_proxy_helpers.rb' - - 'lib/api/integrations.rb' + - 'lib/api/integrations/integratable_operations.rb' - 'lib/api/internal/base.rb' - 'lib/api/markdown.rb' - 'lib/api/pagination_params.rb' diff --git a/app/models/group.rb b/app/models/group.rb index 5df5af5b2b6970bcbc6159caba6aa99c345e5a23..a1e545480b13c9ec696291f78dff698ef2418c36 100644 --- a/app/models/group.rb +++ b/app/models/group.rb @@ -850,6 +850,10 @@ def execute_hooks(data, hooks_scope) # TODO: group hooks https://gitlab.com/gitlab-org/gitlab/-/issues/216904 end + def find_or_initialize_integration(integration) + Integration.find_or_initialize_non_project_specific_integration(integration, group_id: id) + end + def execute_integrations(data, hooks_scope) integrations.public_send(hooks_scope).each do |integration| # rubocop:disable GitlabSecurity/PublicSend integration.async_execute(data) diff --git a/app/services/integrations/update_service.rb b/app/services/integrations/update_service.rb index ba8af9c5cfbca0b47404ec7c29b73e06f2627218..ba5a547814ee67a48099c3a4eafbfb5cab98168d 100644 --- a/app/services/integrations/update_service.rb +++ b/app/services/integrations/update_service.rb @@ -14,11 +14,15 @@ def initialize(current_user:, integration:, attributes:) def execute return error('Integration not found.', :not_found) unless integration - if handle_inherited_settings? - handle_inherited_settings - else - handle_default_settings - end + response = if handle_inherited_settings? + handle_inherited_settings + else + handle_default_settings + end + + PropagateIntegrationWorker.perform_async(integration.id) unless response.error? || integration.project_level? + + response end private diff --git a/doc/api/group_integrations.md b/doc/api/group_integrations.md new file mode 100644 index 0000000000000000000000000000000000000000..23ce28b0cdaac5ebf49617a37ad6caf123de8a78 --- /dev/null +++ b/doc/api/group_integrations.md @@ -0,0 +1,2082 @@ +--- +stage: Foundations +group: Import and Integrate +info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://handbook.gitlab.com/handbook/product/ux/technical-writing/#assignments +--- + +# Group integrations API + +DETAILS: +**Tier:** Free, Premium, Ultimate +**Offering:** GitLab.com, Self-managed, GitLab Dedicated + +> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/328496) in GitLab 17.7. + +Use this API to work with external services that integrate with GitLab. + +This API requires an access token with the Maintainer or Owner role. + +## List all active integrations + +Get a list of all active group integrations. The `vulnerability_events` field is only available for GitLab Enterprise Edition. + +```plaintext +GET /groups/:id/integrations +``` + +Example response: + +```json +[ + { + "id": 75, + "title": "Jenkins CI", + "slug": "jenkins", + "created_at": "2019-11-20T11:20:25.297Z", + "updated_at": "2019-11-20T12:24:37.498Z", + "active": true, + "commit_events": true, + "push_events": true, + "issues_events": true, + "alert_events": true, + "confidential_issues_events": true, + "merge_requests_events": true, + "tag_push_events": false, + "deployment_events": false, + "note_events": true, + "confidential_note_events": true, + "pipeline_events": true, + "wiki_page_events": true, + "job_events": true, + "comment_on_event_enabled": true, + "inherited": false, + "vulnerability_events": true + }, + { + "id": 76, + "title": "Alerts endpoint", + "slug": "alerts", + "created_at": "2019-11-20T11:20:25.297Z", + "updated_at": "2019-11-20T12:24:37.498Z", + "active": true, + "commit_events": true, + "push_events": true, + "issues_events": true, + "alert_events": true, + "confidential_issues_events": true, + "merge_requests_events": true, + "tag_push_events": true, + "deployment_events": false, + "note_events": true, + "confidential_note_events": true, + "pipeline_events": true, + "wiki_page_events": true, + "job_events": true, + "comment_on_event_enabled": true, + "inherited": false, + "vulnerability_events": true + } +] +``` + +## Apple App Store Connect + +### Set up Apple App Store Connect + +Set up the Apple App Store Connect integration for a group. + +```plaintext +PUT /groups/:id/integrations/apple_app_store +``` + +Parameters: + +| Parameter | Type | Required | Description | +| --------- | ---- | -------- | ----------- | +| `app_store_issuer_id` | string | yes | Apple App Store Connect issuer ID. | +| `app_store_key_id` | string | yes | Apple App Store Connect key ID. | +| `app_store_private_key_file_name` | string | yes | Apple App Store Connect private key filename. | +| `app_store_private_key` | string | yes | Apple App Store Connect private key. | +| `app_store_protected_refs` | boolean | no | Set variables on protected branches and tags only. | +| `use_inherited_settings` | boolean | no | Indicates whether or not to inherit default settings. Defaults to `false`. | + +### Disable Apple App Store Connect + +Disable the Apple App Store Connect integration for a group. Integration settings are reset. + +```plaintext +DELETE /groups/:id/integrations/apple_app_store +``` + +### Get Apple App Store Connect settings + +Get the Apple App Store Connect integration settings for a group. + +```plaintext +GET /groups/:id/integrations/apple_app_store +``` + +## Asana + +### Set up Asana + +Set up the Asana integration for a group. + +```plaintext +PUT /groups/:id/integrations/asana +``` + +Parameters: + +| Parameter | Type | Required | Description | +| --------- | ---- | -------- | ----------- | +| `api_key` | string | yes | User API token. The user must have access to the task. All comments are attributed to this user. | +| `restrict_to_branch` | string | no | Comma-separated list of branches to be automatically inspected. Leave blank to include all branches. | +| `use_inherited_settings` | boolean | no | Indicates whether or not to inherit default settings. Defaults to `false`. | + +### Disable Asana + +Disable the Asana integration for a group. Integration settings are reset. + +```plaintext +DELETE /groups/:id/integrations/asana +``` + +### Get Asana settings + +Get the Asana integration settings for a group. + +```plaintext +GET /groups/:id/integrations/asana +``` + +## Assembla + +### Set up Assembla + +Set up the Assembla integration for a group. + +```plaintext +PUT /groups/:id/integrations/assembla +``` + +Parameters: + +| Parameter | Type | Required | Description | +| --------- | ---- | -------- | ----------- | +| `token` | string | yes | The authentication token. | +| `subdomain` | string | no | The subdomain setting. | +| `use_inherited_settings` | boolean | no | Indicates whether or not to inherit default settings. Defaults to `false`. | + +### Disable Assembla + +Disable the Assembla integration for a group. Integration settings are reset. + +```plaintext +DELETE /groups/:id/integrations/assembla +``` + +### Get Assembla settings + +Get the Assembla integration settings for a group. + +```plaintext +GET /groups/:id/integrations/assembla +``` + +## Atlassian Bamboo + +### Set up Atlassian Bamboo + +Set up the Atlassian Bamboo integration for a group. + +You must configure automatic revision labeling and a repository trigger in Bamboo. + +```plaintext +PUT /groups/:id/integrations/bamboo +``` + +Parameters: + +| Parameter | Type | Required | Description | +| --------- | ---- | -------- | ----------- | +| `bamboo_url` | string | yes | Bamboo root URL (for example, `https://bamboo.example.com`). | +| `enable_ssl_verification` | boolean | no | Enable SSL verification. Defaults to `true` (enabled). | +| `build_key` | string | yes | Bamboo build plan key (for example, `KEY`). | +| `username` | string | yes | User with API access to the Bamboo server. | +| `password` | string | yes | Password of the user. | +| `use_inherited_settings` | boolean | no | Indicates whether or not to inherit default settings. Defaults to `false`. | + +### Disable Atlassian Bamboo + +Disable the Atlassian Bamboo integration for a group. Integration settings are reset. + +```plaintext +DELETE /groups/:id/integrations/bamboo +``` + +### Get Atlassian Bamboo settings + +Get the Atlassian Bamboo integration settings for a group. + +```plaintext +GET /groups/:id/integrations/bamboo +``` + +## Bugzilla + +### Set up Bugzilla + +Set up the Bugzilla integration for a group. + +```plaintext +PUT /groups/:id/integrations/bugzilla +``` + +Parameters: + +| Parameter | Type | Required | Description | +| --------- | ---- | -------- | ----------- | +| `new_issue_url` | string | yes | URL of the new issue. | +| `issues_url` | string | yes | URL of the issue. | +| `project_url` | string | yes | URL of the project. | +| `use_inherited_settings` | boolean | no | Indicates whether or not to inherit default settings. Defaults to `false`. | + +### Disable Bugzilla + +Disable the Bugzilla integration for a group. Integration settings are reset. + +```plaintext +DELETE /groups/:id/integrations/bugzilla +``` + +### Get Bugzilla settings + +Get the Bugzilla integration settings for a group. + +```plaintext +GET /groups/:id/integrations/bugzilla +``` + +## Buildkite + +### Set up Buildkite + +Set up the Buildkite integration for a group. + +```plaintext +PUT /groups/:id/integrations/buildkite +``` + +Parameters: + +| Parameter | Type | Required | Description | +| --------- | ---- | -------- | ----------- | +| `token` | string | yes | Buildkite project GitLab token. | +| `project_url` | string | yes | Pipeline URL (for example, `https://buildkite.com/example/pipeline`). | +| `enable_ssl_verification` | boolean | no | **Deprecated:** This parameter has no effect because SSL verification is always enabled. | +| `push_events` | boolean | no | Enable notifications for push events. | +| `merge_requests_events` | boolean | no | Enable notifications for merge request events. | +| `tag_push_events` | boolean | no | Enable notifications for tag push events. | +| `use_inherited_settings` | boolean | no | Indicates whether or not to inherit default settings. Defaults to `false`. | + +### Disable Buildkite + +Disable the Buildkite integration for a group. Integration settings are reset. + +```plaintext +DELETE /groups/:id/integrations/buildkite +``` + +### Get Buildkite settings + +Get the Buildkite integration settings for a group. + +```plaintext +GET /groups/:id/integrations/buildkite +``` + +## Campfire Classic + +You can integrate with Campfire Classic. However, Campfire Classic is an old product that is +[no longer sold](https://gitlab.com/gitlab-org/gitlab/-/issues/329337) by Basecamp. + +### Set up Campfire Classic + +Set up the Campfire Classic integration for a group. + +```plaintext +PUT /groups/:id/integrations/campfire +``` + +Parameters: + +| Parameter | Type | Required | Description | +|---------------|---------|----------|---------------------------------------------------------------------------------------------| +| `token` | string | yes | API authentication token from Campfire Classic. To get the token, sign in to Campfire Classic and select **My info**. | +| `subdomain` | string | no | `.campfirenow.com` subdomain when you're signed in. | +| `room` | string | no | ID portion of the Campfire Classic room URL. | +| `use_inherited_settings` | boolean | no | Indicates whether or not to inherit default settings. Defaults to `false`. | + +### Disable Campfire Classic + +Disable the Campfire Classic integration for a group. Integration settings are reset. + +```plaintext +DELETE /groups/:id/integrations/campfire +``` + +### Get Campfire Classic settings + +Get the Campfire Classic integration settings for a group. + +```plaintext +GET /groups/:id/integrations/campfire +``` + +## ClickUp + +### Set up ClickUp + +Set up the ClickUp integration for a group. + +```plaintext +PUT /groups/:id/integrations/clickup +``` + +Parameters: + +| Parameter | Type | Required | Description | +| ------------- | ------ | -------- | -------------- | +| `issues_url` | string | yes | URL of the issue. | +| `project_url` | string | yes | URL of the project. | +| `use_inherited_settings` | boolean | no | Indicates whether or not to inherit default settings. Defaults to `false`. | + +### Disable ClickUp + +Disable the ClickUp integration for a group. Integration settings are reset. + +```plaintext +DELETE /groups/:id/integrations/clickup +``` + +### Get ClickUp settings + +Get the ClickUp integration settings for a group. + +```plaintext +GET /groups/:id/integrations/clickup +``` + +## Confluence Workspace + +### Set up Confluence Workspace + +Set up the Confluence Workspace integration for a group. + +```plaintext +PUT /groups/:id/integrations/confluence +``` + +Parameters: + +| Parameter | Type | Required | Description | +| --------- | ---- | -------- | ----------- | +| `confluence_url` | string | yes | URL of the Confluence Workspace hosted on `atlassian.net`. | +| `use_inherited_settings` | boolean | no | Indicates whether or not to inherit default settings. Defaults to `false`. | + +### Disable Confluence Workspace + +Disable the Confluence Workspace integration for a group. Integration settings are reset. + +```plaintext +DELETE /groups/:id/integrations/confluence +``` + +### Get Confluence Workspace settings + +Get the Confluence Workspace integration settings for a group. + +```plaintext +GET /groups/:id/integrations/confluence +``` + +## Custom issue tracker + +### Set up a custom issue tracker + +Set up a custom issue tracker for a group. + +```plaintext +PUT /groups/:id/integrations/custom-issue-tracker +``` + +Parameters: + +| Parameter | Type | Required | Description | +| --------- | ---- | -------- | ----------- | +| `new_issue_url` | string | yes | URL of the new issue. | +| `issues_url` | string | yes | URL of the issue. | +| `project_url` | string | yes | URL of the project. | +| `use_inherited_settings` | boolean | no | Indicates whether or not to inherit default settings. Defaults to `false`. | + +### Disable a custom issue tracker + +Disable a custom issue tracker for a group. Integration settings are reset. + +```plaintext +DELETE /groups/:id/integrations/custom-issue-tracker +``` + +### Get custom issue tracker settings + +Get the custom issue tracker settings for a group. + +```plaintext +GET /groups/:id/integrations/custom-issue-tracker +``` + +## Datadog + +### Set up Datadog + +Set up the Datadog integration for a group. + +```plaintext +PUT /groups/:id/integrations/datadog +``` + +Parameters: + +| Parameter | Type | Required | Description | +|------------------------|---------|----------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| `api_key` | string | yes | API key used for authentication with Datadog. | +| `api_url` | string | no | (Advanced) The full URL for your Datadog site. | +| `datadog_env` | string | no | For self-managed deployments, set the `env%` tag for all the data sent to Datadog. | +| `datadog_service` | string | no | Tag all data from this GitLab instance in Datadog. Can be used when managing several self-managed deployments. | +| `datadog_site` | string | no | The Datadog site to send data to. To send data to the EU site, use `datadoghq.eu`. | +| `datadog_tags` | string | no | Custom tags in Datadog. Specify one tag per line in the format `key:value\nkey2:value2` | +| `archive_trace_events` | boolean | no | When enabled, job logs are collected by Datadog and displayed along with pipeline execution traces. | +| `use_inherited_settings` | boolean | no | Indicates whether or not to inherit default settings. Defaults to `false`. | + +### Disable Datadog + +Disable the Datadog integration for a group. Integration settings are reset. + +```plaintext +DELETE /groups/:id/integrations/datadog +``` + +### Get Datadog settings + +Get the Datadog integration settings for a group. + +```plaintext +GET /groups/:id/integrations/datadog +``` + +## Diffblue Cover + +### Set up Diffblue Cover + +Set up the Diffblue Cover integration for a group. + +```plaintext +PUT /groups/:id/integrations/diffblue-cover +``` + +Parameters: + +| Parameter | Type | Required | Description | +| --------- | ---- | -------- | ----------- | +| `diffblue_license_key` | string | yes | Diffblue Cover license key. | +| `diffblue_access_token_name` | string | yes | Access token name used by Diffblue Cover in pipelines. | +| `diffblue_access_token_secret` | string | yes | Access token secret used by Diffblue Cover in pipelines. | +| `use_inherited_settings` | boolean | no | Indicates whether or not to inherit default settings. Defaults to `false`. | + +### Disable Diffblue Cover + +Disable the Diffblue Cover integration for a group. Integration settings are reset. + +```plaintext +DELETE /groups/:id/integrations/diffblue-cover +``` + +### Get Diffblue Cover settings + +Get the Diffblue Cover integration settings for a group. + +```plaintext +GET /groups/:id/integrations/diffblue-cover +``` + +## Discord Notifications + +### Set up Discord Notifications + +Set up Discord Notifications for a group. + +```plaintext +PUT /groups/:id/integrations/discord +``` + +Parameters: + +| Parameter | Type | Required | Description | +| --------- | ---- | -------- | ----------- | +| `webhook` | string | yes | Discord webhook (for example, `https://discord.com/api/webhooks/...`). | +| `branches_to_be_notified` | string | no | Branches to send notifications for. Valid options are `all`, `default`, `protected`, and `default_and_protected`. The default value is `default`. | +| `confidential_issues_events` | boolean | no | Enable notifications for confidential issue events. | +| `confidential_issue_channel` | string | no | The webhook override to receive notifications for confidential issue events. | +| `confidential_note_events` | boolean | no | Enable notifications for confidential note events. | +| `confidential_note_channel` | string | no | The webhook override to receive notifications for confidential note events. | +| `deployment_events` | boolean | no | Enable notifications for deployment events. | +| `deployment_channel` | string | no | The webhook override to receive notifications for deployment events. | +| `group_confidential_mentions_events` | boolean | no | Enable notifications for group confidential mention events. | +| `group_confidential_mentions_channel` | string | no | The webhook override to receive notifications for group confidential mention events. | +| `group_mentions_events` | boolean | no | Enable notifications for group mention events. | +| `group_mentions_channel` | string | no | The webhook override to receive notifications for group mention events. | +| `issues_events` | boolean | no | Enable notifications for issue events. | +| `issue_channel` | string | no | The webhook override to receive notifications for issue events. | +| `merge_requests_events` | boolean | no | Enable notifications for merge request events. | +| `merge_request_channel` | string | no | The webhook override to receive notifications for merge request events. | +| `note_events` | boolean | no | Enable notifications for note events. | +| `note_channel` | string | no | The webhook override to receive notifications for note events. | +| `notify_only_broken_pipelines` | boolean | no | Send notifications for broken pipelines. | +| `pipeline_events` | boolean | no | Enable notifications for pipeline events. | +| `pipeline_channel` | string | no | The webhook override to receive notifications for pipeline events. | +| `push_events` | boolean | no | Enable notifications for push events. | +| `push_channel` | string | no | The webhook override to receive notifications for push events. | +| `tag_push_events` | boolean | no | Enable notifications for tag push events. | +| `tag_push_channel` | string | no | The webhook override to receive notifications for tag push events. | +| `wiki_page_events` | boolean | no | Enable notifications for wiki page events. | +| `wiki_page_channel` | string | no | The webhook override to receive notifications for wiki page events. | +| `use_inherited_settings` | boolean | no | Indicates whether or not to inherit default settings. Defaults to `false`. | + +### Disable Discord Notifications + +Disable Discord Notifications for a group. Integration settings are reset. + +```plaintext +DELETE /groups/:id/integrations/discord +``` + +### Get Discord Notifications settings + +Get the Discord Notifications settings for a group. + +```plaintext +GET /groups/:id/integrations/discord +``` + +## Drone + +### Set up Drone + +Set up the Drone integration for a group. + +```plaintext +PUT /groups/:id/integrations/drone-ci +``` + +Parameters: + +| Parameter | Type | Required | Description | +| --------- | ---- | -------- | ----------- | +| `token` | string | yes | Drone CI project specific token. | +| `drone_url` | string | yes | `http://drone.example.com`. | +| `enable_ssl_verification` | boolean | no | Enable SSL verification. Defaults to `true` (enabled). | +| `push_events` | boolean | no | Enable notifications for push events. | +| `merge_requests_events` | boolean | no | Enable notifications for merge request events. | +| `tag_push_events` | boolean | no | Enable notifications for tag push events. | +| `use_inherited_settings` | boolean | no | Indicates whether or not to inherit default settings. Defaults to `false`. | + +### Disable Drone + +Disable the Drone integration for a group. Integration settings are reset. + +```plaintext +DELETE /groups/:id/integrations/drone-ci +``` + +### Get Drone settings + +Get the Drone integration settings for a group. + +```plaintext +GET /groups/:id/integrations/drone-ci +``` + +## Emails on push + +### Set up emails on push + +Set up the emails on push integration for a group. + +```plaintext +PUT /groups/:id/integrations/emails-on-push +``` + +Parameters: + +| Parameter | Type | Required | Description | +| --------- | ---- | -------- | ----------- | +| `recipients` | string | yes | Emails separated by whitespace. | +| `disable_diffs` | boolean | no | Disable code diffs. | +| `send_from_committer_email` | boolean | no | Send from committer. | +| `push_events` | boolean | no | Enable notifications for push events. | +| `tag_push_events` | boolean | no | Enable notifications for tag push events. | +| `branches_to_be_notified` | string | no | Branches to send notifications for. Valid options are `all`, `default`, `protected`, and `default_and_protected`. Notifications are always fired for tag pushes. The default value is `all`. | +| `use_inherited_settings` | boolean | no | Indicates whether or not to inherit default settings. Defaults to `false`. | + +### Disable emails on push + +Disable the emails on push integration for a group. Integration settings are reset. + +```plaintext +DELETE /groups/:id/integrations/emails-on-push +``` + +### Get emails on push settings + +Get the emails on push integration settings for a group. + +```plaintext +GET /groups/:id/integrations/emails-on-push +``` + +## Engineering Workflow Management (EWM) + +### Set up EWM + +Set up the EWM integration for a group. + +```plaintext +PUT /groups/:id/integrations/ewm +``` + +Parameters: + +| Parameter | Type | Required | Description | +| --------- | ---- | -------- | ----------- | +| `new_issue_url` | string | yes | URL of the new issue. | +| `project_url` | string | yes | URL of the project. | +| `issues_url` | string | yes | URL of the issue. | +| `use_inherited_settings` | boolean | no | Indicates whether or not to inherit default settings. Defaults to `false`. | + +### Disable EWM + +Disable the EWM integration for a group. Integration settings are reset. + +```plaintext +DELETE /groups/:id/integrations/ewm +``` + +### Get EWM settings + +Get the EWM integration settings for a group. + +```plaintext +GET /groups/:id/integrations/ewm +``` + +## External wiki + +### Set up an external wiki + +Set up an external wiki for a group. + +```plaintext +PUT /groups/:id/integrations/external-wiki +``` + +Parameters: + +| Parameter | Type | Required | Description | +| --------- | ---- | -------- | ----------- | +| `external_wiki_url` | string | yes | URL of the external wiki. | +| `use_inherited_settings` | boolean | no | Indicates whether or not to inherit default settings. Defaults to `false`. | + +### Disable an external wiki + +Disable an external wiki for a group. Integration settings are reset. + +```plaintext +DELETE /groups/:id/integrations/external-wiki +``` + +### Get external wiki settings + +Get the external wiki settings for a group. + +```plaintext +GET /groups/:id/integrations/external-wiki +``` + +## GitGuardian + +DETAILS: +**Tier:** Premium, Ultimate +**Offering:** Self-managed, GitLab Dedicated + +FLAG: +On self-managed GitLab, by default this feature is available. To hide the feature, ask an administrator to [disable the feature flag](../administration/feature_flags.md) named `git_guardian_integration`. +On GitLab.com, this feature is not available. On GitLab Dedicated, this feature is available. + +[GitGuardian](https://www.gitguardian.com/) is a cybersecurity service that detects sensitive data such as API keys +and passwords in source code repositories. +It scans Git repositories, alerts on policy violations, and helps organizations +fix security issues before hackers can exploit them. + +You can configure GitLab to reject commits based on GitGuardian policies. + +### Known issues + +- Pushes can be delayed or can time out. With the GitGuardian integration, pushes are sent to a third-party, and GitLab has no control over the connection with GitGuardian or the GitGuardian process. +- Due to a [GitGuardian API limitation](https://api.gitguardian.com/docs#operation/multiple_scan), the integration ignores files over the size of 1 MB. They are not scanned. +- If a pushed file has a name over 256 characters long the push won't go through. + For more information, see [GitGuardian API documentation](https://api.gitguardian.com/docs#operation/multiple_scan) . + +Troubleshooting steps on [the integration page](../user/project/integrations/git_guardian.md#troubleshooting) +show how to mitigate some of these problems. + +### Set up GitGuardian + +Set up the GitGuardian integration for a group. + +```plaintext +PUT /groups/:id/integrations/git-guardian +``` + +Parameters: + +| Parameter | Type | Required | Description | +| --------- | ---- | -------- |-----------------------------------------------| +| `token` | string | yes | GitGuardian API token with `scan` scope. | +| `use_inherited_settings` | boolean | no | Indicates whether or not to inherit default settings. Defaults to `false`. | + +### Disable GitGuardian + +Disable the GitGuardian integration for a group. Integration settings are reset. + +```plaintext +DELETE /groups/:id/integrations/git-guardian +``` + +### Get GitGuardian settings + +Get the GitGuardian integration settings for a group. + +```plaintext +GET /groups/:id/integrations/git-guardian +``` + +## GitHub + +DETAILS: +**Tier:** Premium, Ultimate +**Offering:** GitLab.com, Self-managed, GitLab Dedicated + +### Set up GitHub + +Set up the GitHub integration for a group. + +```plaintext +PUT /groups/:id/integrations/github +``` + +Parameters: + +| Parameter | Type | Required | Description | +| --------- | ---- | -------- | ----------- | +| `token` | string | yes | GitHub API token with `repo:status` OAuth scope. | +| `repository_url` | string | yes | GitHub repository URL. | +| `static_context` | boolean | no | Append the hostname of your GitLab instance to the [status check name](../user/project/integrations/github.md#static-or-dynamic-status-check-names). | +| `use_inherited_settings` | boolean | no | Indicates whether or not to inherit default settings. Defaults to `false`. | + +### Disable GitHub + +Disable the GitHub integration for a group. Integration settings are reset. + +```plaintext +DELETE /groups/:id/integrations/github +``` + +### Get GitHub settings + +Get the GitHub integration settings for a group. + +```plaintext +GET /groups/:id/integrations/github +``` + +## GitLab for Jira Cloud app + +The GitLab for Jira Cloud app integration is enabled or disabled automatically through [group linking and unlinking in Jira](../integration/jira/connect-app.md#configure-the-gitlab-for-jira-cloud-app). You cannot enable or disable the integration with the GitLab integrations form or the API. + +### Update integration for a group + +Use this API endpoint to update an integration you create with group linking in Jira. + +```plaintext +PUT /groups/:id/integrations/jira-cloud-app +``` + +Parameters: + +| Parameter | Type | Required | Description | +| --------- | ---- | -------- | ----------- | +| `jira_cloud_app_service_ids` | string | no | Jira Service Management Service IDs. Use commas (`,`) to separate multiple IDs. | +| `jira_cloud_app_enable_deployment_gating` | boolean | no | Enables deployment gating for blocked GitLab deployments from Jira Service Management. | +| `jira_cloud_app_deployment_gating_environments` | string | no | The environments (production, staging, testing, or development) to enable deployment gating. Required if deployment gating is enabled. Use commas (`,`) to separate multiple environments. | + +### Get GitLab for Jira Cloud app settings + +Get the GitLab for Jira Cloud app integration settings for a group. + +```plaintext +GET /groups/:id/integrations/jira-cloud-app +``` + +## GitLab for Slack app + +### Set up GitLab for Slack app + +Update the GitLab for Slack app integration for a group. + +You cannot create a GitLab for Slack app through the API because the integration +requires an OAuth 2.0 token that you cannot get from the GitLab API alone. +Instead, you must [install the app](../user/project/integrations/gitlab_slack_application.md#install-the-gitlab-for-slack-app) from the GitLab UI. +You can then use this API endpoint to update the integration. + +```plaintext +PUT /groups/:id/integrations/gitlab-slack-application +``` + +Parameters: + +| Parameter | Type | Required | Description | +| --------- | ---- | -------- | ----------- | +| `channel` | string | no | Default channel to use if no other channel is configured. | +| `notify_only_broken_pipelines` | boolean | no | Send notifications for broken pipelines. | +| `notify_only_default_branch` | boolean | no | **Deprecated:** This parameter has been replaced with `branches_to_be_notified`. | +| `branches_to_be_notified` | string | no | Branches to send notifications for. Valid options are `all`, `default`, `protected`, and `default_and_protected`. The default value is `default`. | +| `alert_events` | boolean | no | Enable notifications for alert events. | +| `issues_events` | boolean | no | Enable notifications for issue events. | +| `confidential_issues_events` | boolean | no | Enable notifications for confidential issue events. | +| `merge_requests_events` | boolean | no | Enable notifications for merge request events. | +| `note_events` | boolean | no | Enable notifications for note events. | +| `confidential_note_events` | boolean | no | Enable notifications for confidential note events. | +| `deployment_events` | boolean | no | Enable notifications for deployment events. | +| `incidents_events` | boolean | no | Enable notifications for incident events. | +| `pipeline_events` | boolean | no | Enable notifications for pipeline events. | +| `push_events` | boolean | no | Enable notifications for push events. | +| `tag_push_events` | boolean | no | Enable notifications for tag push events. | +| `vulnerability_events` | boolean | no | Enable notifications for vulnerability events. | +| `wiki_page_events` | boolean | no | Enable notifications for wiki page events. | +| `labels_to_be_notified` | string | no | Labels to send notifications for. If not set, receive notifications for all events. | +| `labels_to_be_notified_behavior` | string | no | Labels to be notified for. Valid options are `match_any` and `match_all`. Defaults to `match_any`. | +| `push_channel` | string | no | Name of the channel to receive notifications for push events. | +| `issue_channel` | string | no | Name of the channel to receive notifications for issue events. | +| `confidential_issue_channel` | string | no | Name of the channel to receive notifications for confidential issue events. | +| `merge_request_channel` | string | no | Name of the channel to receive notifications for merge request events. | +| `note_channel` | string | no | Name of the channel to receive notifications for note events. | +| `confidential_note_channel` | string | no | Name of the channel to receive notifications for confidential note events. | +| `tag_push_channel` | string | no | Name of the channel to receive notifications for tag push events. | +| `pipeline_channel` | string | no | Name of the channel to receive notifications for pipeline events. | +| `wiki_page_channel` | string | no | Name of the channel to receive notifications for wiki page events. | +| `deployment_channel` | string | no | Name of the channel to receive notifications for deployment events. | +| `incident_channel` | string | no | Name of the channel to receive notifications for incident events. | +| `vulnerability_channel` | string | no | Name of the channel to receive notifications for vulnerability events. | +| `alert_channel` | string | no | Name of the channel to receive notifications for alert events. | +| `use_inherited_settings` | boolean | no | Indicates whether or not to inherit default settings. Defaults to `false`. | + +### Disable GitLab for Slack app + +Disable the GitLab for Slack app integration for a group. Integration settings are reset. + +```plaintext +DELETE /groups/:id/integrations/gitlab-slack-application +``` + +### Get GitLab for Slack app settings + +Get the GitLab for Slack app integration settings for a group. + +```plaintext +GET /groups/:id/integrations/gitlab-slack-application +``` + +## Google Chat + +### Set up Google Chat + +Set up the Google Chat integration for a group. + +```plaintext +PUT /groups/:id/integrations/hangouts-chat +``` + +Parameters: + +| Parameter | Type | Required | Description | +| --------- | ---- | -------- | ----------- | +| `webhook` | string | yes | The Hangouts Chat webhook (for example, `https://chat.googleapis.com/v1/spaces...`). | +| `notify_only_broken_pipelines` | boolean | no | Send notifications for broken pipelines. | +| `notify_only_default_branch` | boolean | no | **Deprecated:** This parameter has been replaced with `branches_to_be_notified`. | +| `branches_to_be_notified` | string | no | Branches to send notifications for. Valid options are `all`, `default`, `protected`, and `default_and_protected`. The default value is `default`. | +| `push_events` | boolean | no | Enable notifications for push events. | +| `issues_events` | boolean | no | Enable notifications for issue events. | +| `confidential_issues_events` | boolean | no | Enable notifications for confidential issue events. | +| `merge_requests_events` | boolean | no | Enable notifications for merge request events. | +| `tag_push_events` | boolean | no | Enable notifications for tag push events. | +| `note_events` | boolean | no | Enable notifications for note events. | +| `confidential_note_events` | boolean | no | Enable notifications for confidential note events. | +| `pipeline_events` | boolean | no | Enable notifications for pipeline events. | +| `wiki_page_events` | boolean | no | Enable notifications for wiki page events. | +| `use_inherited_settings` | boolean | no | Indicates whether or not to inherit default settings. Defaults to `false`. | + +### Disable Google Chat + +Disable the Google Chat integration for a group. Integration settings are reset. + +```plaintext +DELETE /groups/:id/integrations/hangouts-chat +``` + +### Get Google Chat settings + +Get the Google Chat integration settings for a group. + +```plaintext +GET /groups/:id/integrations/hangouts-chat +``` + +## Google Artifact Management + +DETAILS: +**Tier:** Free, Premium, Ultimate +**Offering:** GitLab.com +**Status:** Beta + +This feature is in [beta](../policy/experiment-beta-support.md). + +### Set up Google Artifact Management + +Set up the Google Artifact Management integration for a group. + +```plaintext +PUT /groups/:id/integrations/google-cloud-platform-artifact-registry +``` + +Parameters: + +| Parameter | Type | Required | Description | +| --------- | ---- | -------- | ----------- | +| `artifact_registry_project_id` | string | yes | ID of the Google Cloud project. | +| `artifact_registry_location` | string | yes | Location of the Artifact Registry repository. | +| `artifact_registry_repositories` | string | yes | Repository of Artifact Registry. | +| `use_inherited_settings` | boolean | no | Indicates whether or not to inherit default settings. Defaults to `false`. | + +### Disable Google Artifact Management + +Disable the Google Artifact Management integration for a group. Integration settings are reset. + +```plaintext +DELETE /groups/:id/integrations/google-cloud-platform-artifact-registry +``` + +### Get Google Artifact Management settings + +Get the Google Artifact Management integration settings for a group. + +```plaintext +GET /groups/:id/integrations/google-cloud-platform-artifact-registry +``` + +## Google Cloud Identity and Access Management (IAM) + +DETAILS: +**Tier:** Free, Premium, Ultimate +**Offering:** GitLab.com +**Status:** Beta + +This feature is in [beta](../policy/experiment-beta-support.md). + +### Set up Google Cloud Identity and Access Management + +Set up the Google Cloud Identity and Access Management integration for a group. + +```plaintext +PUT /groups/:id/integrations/google-cloud-platform-workload-identity-federation +``` + +Parameters: + +| Parameter | Type | Required | Description | +| --------- | ---- | -------- | ----------- | +| `workload_identity_federation_project_id` | string | yes | Google Cloud project ID for the Workload Identity Federation. | +| `workload_identity_federation_project_number` | integer | yes | Google Cloud project number for the Workload Identity Federation. | +| `workload_identity_pool_id` | string | yes | ID of the Workload Identity Pool. | +| `workload_identity_pool_provider_id` | string | yes | ID of the Workload Identity Pool provider. | +| `use_inherited_settings` | boolean | no | Indicates whether or not to inherit default settings. Defaults to `false`. | + +### Disable Google Cloud Identity and Access Management + +Disable the Google Cloud Identity and Access Management integration for a group. Integration settings are reset. + +```plaintext +DELETE /groups/:id/integrations/google-cloud-platform-workload-identity-federation +``` + +### Get Google Cloud Identity and Access Management + +Get the settings for the Google Cloud Identity and Access Management for a group. + +```plaintext +GET /groups/:id/integration/google-cloud-platform-workload-identity-federation +``` + +## Google Play + +### Set up Google Play + +Set up the Google Play integration for a group. + +```plaintext +PUT /groups/:id/integrations/google-play +``` + +Parameters: + +| Parameter | Type | Required | Description | +| --------- | ---- | -------- | ----------- | +| `package_name` | string | yes | Package name of the app in Google Play. | +| `service_account_key` | string | yes | Google Play service account key. | +| `service_account_key_file_name` | string | yes | File name of the Google Play service account key. | +| `google_play_protected_refs` | boolean | no | Set variables on protected branches and tags only. | +| `use_inherited_settings` | boolean | no | Indicates whether or not to inherit default settings. Defaults to `false`. | + +### Disable Google Play + +Disable the Google Play integration for a group. Integration settings are reset. + +```plaintext +DELETE /groups/:id/integrations/google-play +``` + +### Get Google Play settings + +Get the Google Play integration settings for a group. + +```plaintext +GET /groups/:id/integrations/google-play +``` + +## Harbor + +### Set up Harbor + +Set up the Harbor integration for a group. + +```plaintext +PUT /groups/:id/integrations/harbor +``` + +Parameters: + +| Parameter | Type | Required | Description | +| --------- | ---- | -------- | ----------- | +| `url` | string | yes | The base URL to the Harbor instance linked to the GitLab project. For example, `https://demo.goharbor.io`. | +| `project_name` | string | yes | The name of the project in the Harbor instance. For example, `testproject`. | +| `username` | string | yes | The username created in the Harbor interface. | +| `password` | string | yes | The password of the user. | +| `use_inherited_settings` | boolean | no | Indicates whether or not to inherit default settings. Defaults to `false`. | + +### Disable Harbor + +Disable the Harbor integration for a group. Integration settings are reset. + +```plaintext +DELETE /groups/:id/integrations/harbor +``` + +### Get Harbor settings + +Get the Harbor integration settings for a group. + +```plaintext +GET /groups/:id/integrations/harbor +``` + +## irker (IRC gateway) + +### Set up irker + +Set up the irker integration for a group. + +```plaintext +PUT /groups/:id/integrations/irker +``` + +Parameters: + +| Parameter | Type | Required | Description | +| --------- | ---- | -------- | ----------- | +| `recipients` | string | yes | Recipients or channels separated by whitespaces. | +| `default_irc_uri` | string | no | `irc://irc.network.net:6697/`. | +| `server_host` | string | no | localhost. | +| `server_port` | integer | no | 6659. | +| `colorize_messages` | boolean | no | Colorize messages. | +| `use_inherited_settings` | boolean | no | Indicates whether or not to inherit default settings. Defaults to `false`. | + +### Disable irker + +Disable the irker integration for a group. Integration settings are reset. + +```plaintext +DELETE /groups/:id/integrations/irker +``` + +### Get irker settings + +Get the irker integration settings for a group. + +```plaintext +GET /groups/:id/integrations/irker +``` + +## Jenkins + +### Set up Jenkins + +Set up the Jenkins integration for a group. + +```plaintext +PUT /groups/:id/integrations/jenkins +``` + +Parameters: + +| Parameter | Type | Required | Description | +| --------- | ---- | -------- | ----------- | +| `jenkins_url` | string | yes | Jenkins URL like `http://jenkins.example.com`. | +| `enable_ssl_verification` | boolean | no | Enable SSL verification. Defaults to `true` (enabled). | +| `project_name` | string | yes | The URL-friendly project name. Example: `my_project_name`. | +| `username` | string | no | Username for authentication with the Jenkins server, if authentication is required by the server. | +| `password` | string | no | Password for authentication with the Jenkins server, if authentication is required by the server. | +| `push_events` | boolean | no | Enable notifications for push events. | +| `merge_requests_events` | boolean | no | Enable notifications for merge request events. | +| `tag_push_events` | boolean | no | Enable notifications for tag push events. | +| `use_inherited_settings` | boolean | no | Indicates whether or not to inherit default settings. Defaults to `false`. | + +### Disable Jenkins + +Disable the Jenkins integration for a group. Integration settings are reset. + +```plaintext +DELETE /groups/:id/integrations/jenkins +``` + +### Get Jenkins settings + +Get the Jenkins integration settings for a group. + +```plaintext +GET /groups/:id/integrations/jenkins +``` + +## JetBrains TeamCity + +### Set up JetBrains TeamCity + +Set up the JetBrains TeamCity integration for a group. + +The build configuration in TeamCity must use the build number format `%build.vcs.number%`. +In the advanced settings for VCS root, configure monitoring for all branches so merge requests can build. + +```plaintext +PUT /groups/:id/integrations/teamcity +``` + +Parameters: + +| Parameter | Type | Required | Description | +| --------- | ---- | -------- | ----------- | +| `teamcity_url` | string | yes | TeamCity root URL (for example, `https://teamcity.example.com`). | +| `enable_ssl_verification` | boolean | no | Enable SSL verification. Defaults to `true` (enabled). | +| `build_type` | string | yes | Build configuration ID. | +| `username` | string | yes | A user with permissions to trigger a manual build. | +| `password` | string | yes | The password of the user. | +| `push_events` | boolean | no | Enable notifications for push events. | +| `merge_requests_events` | boolean | no | Enable notifications for merge request events. | +| `use_inherited_settings` | boolean | no | Indicates whether or not to inherit default settings. Defaults to `false`. | + +### Disable JetBrains TeamCity + +Disable the JetBrains TeamCity integration for a group. Integration settings are reset. + +```plaintext +DELETE /groups/:id/integrations/teamcity +``` + +### Get JetBrains TeamCity settings + +Get the JetBrains TeamCity integration settings for a group. + +```plaintext +GET /groups/:id/integrations/teamcity +``` + +## Jira + +### Set up Jira + +Set up the Jira integration for a group. + +```plaintext +PUT /groups/:id/integrations/jira +``` + +Parameters: + +| Parameter | Type | Required | Description | +| --------- | ---- | -------- | ----------- | +| `url` | string | yes | The URL to the Jira project which is being linked to this GitLab project (for example, `https://jira.example.com`). | +| `api_url` | string | no | The base URL to the Jira instance API. Web URL value is used if not set (for example, `https://jira-api.example.com`). | +| `username` | string | no | The email or username to be used with Jira. For Jira Cloud use an email, for Jira Data Center and Jira Server use a username. Required when using Basic authentication (`jira_auth_type` is `0`). | +| `password` | string | yes | The Jira API token, password, or personal access token to be used with Jira. When your authentication method is basic (`jira_auth_type` is `0`), use an API token for Jira Cloud or a password for Jira Data Center or Jira Server. When your authentication method is a Jira personal access token (`jira_auth_type` is `1`), use the personal access token. | +| `active` | boolean | no | Activates or deactivates the integration. Defaults to `false` (deactivated). | +| `jira_auth_type`| integer | no | The authentication method to be used with Jira. `0` means Basic Authentication. `1` means Jira personal access token. Defaults to `0`. | +| `jira_issue_prefix` | string | no | Prefix to match Jira issue keys. | +| `jira_issue_regex` | string | no | Regular expression to match Jira issue keys. | +| `jira_issue_transition_automatic` | boolean | no | Enable [automatic issue transitions](../integration/jira/issues.md#automatic-issue-transitions). Takes precedence over `jira_issue_transition_id` if enabled. Defaults to `false`. | +| `jira_issue_transition_id` | string | no | The ID of one or more transitions for [custom issue transitions](../integration/jira/issues.md#custom-issue-transitions). Ignored if `jira_issue_transition_automatic` is enabled. Defaults to a blank string, which disables custom transitions. | +| `commit_events` | boolean | no | Enable notifications for commit events. | +| `merge_requests_events` | boolean | no | Enable notifications for merge request events. | +| `comment_on_event_enabled` | boolean | no | Enable comments in Jira issues on each GitLab event (commit or merge request). | +| `issues_enabled` | boolean | no | Enable viewing Jira issues in GitLab. | +| `project_keys` | array of strings | no | Keys of Jira projects. When `issues_enabled` is `true`, this setting specifies which Jira projects to view issues from in GitLab. | +| `use_inherited_settings` | boolean | no | Indicates whether or not to inherit default settings. Defaults to `false`. | + +### Disable Jira + +Disable the Jira integration for a group. Integration settings are reset. + +```plaintext +DELETE /groups/:id/integrations/jira +``` + +### Get Jira settings + +Get the Jira integration settings for a group. + +```plaintext +GET /groups/:id/integrations/jira +``` + +## Matrix notifications + +### Set up Matrix notifications + +Set up Matrix notifications for a group. + +```plaintext +PUT /groups/:id/integrations/matrix +``` + +Parameters: + +| Parameter | Type | Required | Description | +| --------- | ---- | -------- | ----------- | +| `hostname` | string | no | Custom hostname of the Matrix server. The default value is `https://matrix.org`. | +| `token` | string | yes | The Matrix access token (for example, `syt-zyx57W2v1u123ew11`). | +| `room` | string | yes | Unique identifier for the target room (in the format `!qPKKM111FFKKsfoCVy:matrix.org`). | +| `notify_only_broken_pipelines` | boolean | no | Send notifications for broken pipelines. | +| `branches_to_be_notified` | string | no | Branches to send notifications for. Valid options are `all`, `default`, `protected`, and `default_and_protected`. The default value is `default`. | +| `push_events` | boolean | no | Enable notifications for push events. | +| `issues_events` | boolean | no | Enable notifications for issue events. | +| `confidential_issues_events` | boolean | no | Enable notifications for confidential issue events. | +| `merge_requests_events` | boolean | no | Enable notifications for merge request events. | +| `tag_push_events` | boolean | no | Enable notifications for tag push events. | +| `note_events` | boolean | no | Enable notifications for note events. | +| `confidential_note_events` | boolean | no | Enable notifications for confidential note events. | +| `pipeline_events` | boolean | no | Enable notifications for pipeline events. | +| `wiki_page_events` | boolean | no | Enable notifications for wiki page events. | +| `use_inherited_settings` | boolean | no | Indicates whether or not to inherit default settings. Defaults to `false`. | + +### Disable Matrix notifications + +Disable Matrix notifications for a group. Integration settings are reset. + +```plaintext +DELETE /groups/:id/integrations/matrix +``` + +### Get Matrix notifications settings + +Get the Matrix notifications settings for a group. + +```plaintext +GET /groups/:id/integrations/matrix +``` + +## Mattermost notifications + +### Set up Mattermost notifications + +Set up Mattermost notifications for a group. + +```plaintext +PUT /groups/:id/integrations/mattermost +``` + +Parameters: + +| Parameter | Type | Required | Description | +| --------- | ---- | -------- | ----------- | +| `webhook` | string | yes | Mattermost notifications webhook (for example, `http://mattermost.example.com/hooks/...`). | +| `username` | string | no | Mattermost notifications username. | +| `channel` | string | no | Default channel to use if no other channel is configured. | +| `notify_only_broken_pipelines` | boolean | no | Send notifications for broken pipelines. | +| `notify_only_default_branch` | boolean | no | **Deprecated:** This parameter has been replaced with `branches_to_be_notified`. | +| `branches_to_be_notified` | string | no | Branches to send notifications for. Valid options are `all`, `default`, `protected`, and `default_and_protected`. The default value is `default`. | +| `labels_to_be_notified` | string | no | Labels to send notifications for. Leave blank to receive notifications for all events. | +| `labels_to_be_notified_behavior` | string | no | Labels to be notified for. Valid options are `match_any` and `match_all`. The default value is `match_any`. | +| `push_events` | boolean | no | Enable notifications for push events. | +| `issues_events` | boolean | no | Enable notifications for issue events. | +| `confidential_issues_events` | boolean | no | Enable notifications for confidential issue events. | +| `merge_requests_events` | boolean | no | Enable notifications for merge request events. | +| `tag_push_events` | boolean | no | Enable notifications for tag push events. | +| `note_events` | boolean | no | Enable notifications for note events. | +| `confidential_note_events` | boolean | no | Enable notifications for confidential note events. | +| `pipeline_events` | boolean | no | Enable notifications for pipeline events. | +| `wiki_page_events` | boolean | no | Enable notifications for wiki page events. | +| `push_channel` | string | no | The name of the channel to receive notifications for push events. | +| `issue_channel` | string | no | The name of the channel to receive notifications for issue events. | +| `confidential_issue_channel` | string | no | The name of the channel to receive notifications for confidential issue events. | +| `merge_request_channel` | string | no | The name of the channel to receive notifications for merge request events. | +| `note_channel` | string | no | The name of the channel to receive notifications for note events. | +| `confidential_note_channel` | string | no | The name of the channel to receive notifications for confidential note events. | +| `tag_push_channel` | string | no | The name of the channel to receive notifications for tag push events. | +| `pipeline_channel` | string | no | The name of the channel to receive notifications for pipeline events. | +| `wiki_page_channel` | string | no | The name of the channel to receive notifications for wiki page events. | +| `use_inherited_settings` | boolean | no | Indicates whether or not to inherit default settings. Defaults to `false`. | + +### Disable Mattermost notifications + +Disable Mattermost notifications for a group. Integration settings are reset. + +```plaintext +DELETE /groups/:id/integrations/mattermost +``` + +### Get Mattermost notifications settings + +Get the Mattermost notifications settings for a group. + +```plaintext +GET /groups/:id/integrations/mattermost +``` + +## Mattermost slash commands + +### Set up Mattermost slash commands + +Set up Mattermost slash commands for a group. + +```plaintext +PUT /groups/:id/integrations/mattermost-slash-commands +``` + +Parameters: + +| Parameter | Type | Required | Description | +| --------- | ------ | -------- | --------------------- | +| `token` | string | yes | The Mattermost token. | +| `use_inherited_settings` | boolean | no | Indicates whether or not to inherit default settings. Defaults to `false`. | + +### Disable Mattermost slash commands + +Disable Mattermost slash commands for a group. Integration settings are reset. + +```plaintext +DELETE /groups/:id/integrations/mattermost-slash-commands +``` + +### Get Mattermost slash commands settings + +Get the Mattermost slash commands settings for a group. + +```plaintext +GET /groups/:id/integrations/mattermost-slash-commands +``` + +## Microsoft Teams notifications + +### Set up Microsoft Teams notifications + +Set up Microsoft Teams notifications for a group. + +```plaintext +PUT /groups/:id/integrations/microsoft-teams +``` + +Parameters: + +| Parameter | Type | Required | Description | +| --------- | ---- | -------- | ----------- | +| `webhook` | string | yes | The Microsoft Teams webhook (for example, `https://outlook.office.com/webhook/...`). | +| `notify_only_broken_pipelines` | boolean | no | Send notifications for broken pipelines. | +| `notify_only_default_branch` | boolean | no | **Deprecated:** This parameter has been replaced with `branches_to_be_notified`. | +| `branches_to_be_notified` | string | no | Branches to send notifications for. Valid options are `all`, `default`, `protected`, and `default_and_protected`. The default value is `default`. | +| `push_events` | boolean | no | Enable notifications for push events. | +| `issues_events` | boolean | no | Enable notifications for issue events. | +| `confidential_issues_events` | boolean | no | Enable notifications for confidential issue events. | +| `merge_requests_events` | boolean | no | Enable notifications for merge request events. | +| `tag_push_events` | boolean | no | Enable notifications for tag push events. | +| `note_events` | boolean | no | Enable notifications for note events. | +| `confidential_note_events` | boolean | no | Enable notifications for confidential note events. | +| `pipeline_events` | boolean | no | Enable notifications for pipeline events. | +| `wiki_page_events` | boolean | no | Enable notifications for wiki page events. | +| `use_inherited_settings` | boolean | no | Indicates whether or not to inherit default settings. Defaults to `false`. | + +### Disable Microsoft Teams notifications + +Disable Microsoft Teams notifications for a group. Integration settings are reset. + +```plaintext +DELETE /groups/:id/integrations/microsoft-teams +``` + +### Get Microsoft Teams notifications settings + +Get the Microsoft Teams notifications settings for a group. + +```plaintext +GET /groups/:id/integrations/microsoft-teams +``` + +## Mock CI + +This integration is only available in a development environment. +For an example Mock CI server, see [`gitlab-org/gitlab-mock-ci-service`](https://gitlab.com/gitlab-org/gitlab-mock-ci-service). + +### Set up Mock CI + +Set up the Mock CI integration for a group. + +```plaintext +PUT /groups/:id/integrations/mock-ci +``` + +Parameters: + +| Parameter | Type | Required | Description | +| --------- | ---- | -------- | ----------- | +| `mock_service_url` | string | yes | URL of the Mock CI integration. | +| `enable_ssl_verification` | boolean | no | Enable SSL verification. Defaults to `true` (enabled). | +| `use_inherited_settings` | boolean | no | Indicates whether or not to inherit default settings. Defaults to `false`. | + +### Disable Mock CI + +Disable the Mock CI integration for a group. Integration settings are reset. + +```plaintext +DELETE /groups/:id/integrations/mock-ci +``` + +### Get Mock CI settings + +Get the Mock CI integration settings for a group. + +```plaintext +GET /groups/:id/integrations/mock-ci +``` + +## Packagist + +### Set up Packagist + +Set up the Packagist integration for a group. + +```plaintext +PUT /groups/:id/integrations/packagist +``` + +Parameters: + +| Parameter | Type | Required | Description | +| --------- | ---- | -------- | ----------- | +| `username` | string | yes | The username of a Packagist account. | +| `token` | string | yes | API token to the Packagist server. | +| `server` | boolean | no | URL of the Packagist server. Leave blank for the default ``. | +| `push_events` | boolean | no | Enable notifications for push events. | +| `merge_requests_events` | boolean | no | Enable notifications for merge request events. | +| `tag_push_events` | boolean | no | Enable notifications for tag push events. | +| `use_inherited_settings` | boolean | no | Indicates whether or not to inherit default settings. Defaults to `false`. | + +### Disable Packagist + +Disable the Packagist integration for a group. Integration settings are reset. + +```plaintext +DELETE /groups/:id/integrations/packagist +``` + +### Get Packagist settings + +Get the Packagist integration settings for a group. + +```plaintext +GET /groups/:id/integrations/packagist +``` + +## Phorge + +### Set up Phorge + +Set up the Phorge integration for a group. + +```plaintext +PUT /groups/:id/integrations/phorge +``` + +Parameters: + +| Parameter | Type | Required | Description | +|-----------------|--------|----------|-----------------------| +| `issues_url` | string | yes | URL of the issue. | +| `project_url` | string | yes | URL of the project. | +| `use_inherited_settings` | boolean | no | Indicates whether or not to inherit default settings. Defaults to `false`. | + +### Disable Phorge + +Disable the Phorge integration for a group. Integration settings are reset. + +```plaintext +DELETE /groups/:id/integrations/phorge +``` + +### Get Phorge settings + +Get the Phorge integration settings for a group. + +```plaintext +GET /groups/:id/integrations/phorge +``` + +## Pipeline status emails + +### Set up pipeline status emails + +Set up pipeline status emails for a group. + +```plaintext +PUT /groups/:id/integrations/pipelines-email +``` + +Parameters: + +| Parameter | Type | Required | Description | +| --------- | ---- | -------- | ----------- | +| `recipients` | string | yes | Comma-separated list of recipient email addresses. | +| `notify_only_broken_pipelines` | boolean | no | Send notifications for broken pipelines. | +| `branches_to_be_notified` | string | no | Branches to send notifications for. Valid options are `all`, `default`, `protected`, and `default_and_protected`. The default value is `default`. | +| `notify_only_default_branch` | boolean | no | Send notifications for the default branch. | +| `pipeline_events` | boolean | no | Enable notifications for pipeline events. | +| `use_inherited_settings` | boolean | no | Indicates whether or not to inherit default settings. Defaults to `false`. | + +### Disable pipeline status emails + +Disable pipeline status emails for a group. Integration settings are reset. + +```plaintext +DELETE /groups/:id/integrations/pipelines-email +``` + +### Get pipeline status emails settings + +Get the pipeline status emails settings for a group. + +```plaintext +GET /groups/:id/integrations/pipelines-email +``` + +## Pivotal Tracker + +### Set up Pivotal Tracker + +Set up the Pivotal Tracker integration for a group. + +```plaintext +PUT /groups/:id/integrations/pivotaltracker +``` + +Parameters: + +| Parameter | Type | Required | Description | +| --------- | ---- | -------- | ----------- | +| `token` | string | yes | The Pivotal Tracker token. | +| `restrict_to_branch` | boolean | no | Comma-separated list of branches to automatically inspect. Leave blank to include all branches. | +| `use_inherited_settings` | boolean | no | Indicates whether or not to inherit default settings. Defaults to `false`. | + +### Disable Pivotal Tracker + +Disable the Pivotal Tracker integration for a group. Integration settings are reset. + +```plaintext +DELETE /groups/:id/integrations/pivotaltracker +``` + +### Get Pivotal Tracker settings + +Get the Pivotal Tracker integration settings for a group. + +```plaintext +GET /groups/:id/integrations/pivotaltracker +``` + +## Pumble + +### Set up Pumble + +Set up the Pumble integration for a group. + +```plaintext +PUT /groups/:id/integrations/pumble +``` + +Parameters: + +| Parameter | Type | Required | Description | +| --------- | ---- | -------- | ----------- | +| `webhook` | string | yes | The Pumble webhook (for example, `https://api.pumble.com/workspaces/x/...`). | +| `branches_to_be_notified` | string | no | Branches to send notifications for. Valid options are `all`, `default`, `protected`, and `default_and_protected`. The default is `default`. | +| `confidential_issues_events` | boolean | no | Enable notifications for confidential issue events. | +| `confidential_note_events` | boolean | no | Enable notifications for confidential note events. | +| `issues_events` | boolean | no | Enable notifications for issue events. | +| `merge_requests_events` | boolean | no | Enable notifications for merge request events. | +| `note_events` | boolean | no | Enable notifications for note events. | +| `notify_only_broken_pipelines` | boolean | no | Send notifications for broken pipelines. | +| `pipeline_events` | boolean | no | Enable notifications for pipeline events. | +| `push_events` | boolean | no | Enable notifications for push events. | +| `tag_push_events` | boolean | no | Enable notifications for tag push events. | +| `wiki_page_events` | boolean | no | Enable notifications for wiki page events. | +| `use_inherited_settings` | boolean | no | Indicates whether or not to inherit default settings. Defaults to `false`. | + +### Disable Pumble + +Disable the Pumble integration for a group. Integration settings are reset. + +```plaintext +DELETE /groups/:id/integrations/pumble +``` + +### Get Pumble settings + +Get the Pumble integration settings for a group. + +```plaintext +GET /groups/:id/integrations/pumble +``` + +## Pushover + +### Set up Pushover + +Set up the Pushover integration for a group. + +```plaintext +PUT /groups/:id/integrations/pushover +``` + +Parameters: + +| Parameter | Type | Required | Description | +| --------- | ---- | -------- | ----------- | +| `api_key` | string | yes | Your application key. | +| `user_key` | string | yes | Your user key. | +| `priority` | string | yes | The priority. | +| `device` | string | no | Leave blank for all active devices. | +| `sound` | string | no | The sound of the notification. | +| `use_inherited_settings` | boolean | no | Indicates whether or not to inherit default settings. Defaults to `false`. | + +### Disable Pushover + +Disable the Pushover integration for a group. Integration settings are reset. + +```plaintext +DELETE /groups/:id/integrations/pushover +``` + +### Get Pushover settings + +Get the Pushover integration settings for a group. + +```plaintext +GET /groups/:id/integrations/pushover +``` + +## Redmine + +### Set up Redmine + +Set up the Redmine integration for a group. + +```plaintext +PUT /groups/:id/integrations/redmine +``` + +Parameters: + +| Parameter | Type | Required | Description | +| --------- | ---- | -------- | ----------- | +| `new_issue_url` | string | yes | URL of the new issue. | +| `project_url` | string | yes | URL of the project. | +| `issues_url` | string | yes | URL of the issue. | +| `use_inherited_settings` | boolean | no | Indicates whether or not to inherit default settings. Defaults to `false`. | + +### Disable Redmine + +Disable the Redmine integration for a group. Integration settings are reset. + +```plaintext +DELETE /groups/:id/integrations/redmine +``` + +### Get Redmine settings + +Get the Redmine integration settings for a group. + +```plaintext +GET /groups/:id/integrations/redmine +``` + +## Slack notifications + +### Set up Slack notifications + +Set up Slack notifications for a group. + +```plaintext +PUT /groups/:id/integrations/slack +``` + +Parameters: + +| Parameter | Type | Required | Description | +| --------- | ---- | -------- | ----------- | +| `webhook` | string | yes | Slack notifications webhook (for example, `https://hooks.slack.com/services/...`). | +| `username` | string | no | Slack notifications username. | +| `channel` | string | no | Default channel to use if no other channel is configured. | +| `notify_only_broken_pipelines` | boolean | no | Send notifications for broken pipelines. | +| `notify_only_default_branch` | boolean | no | **Deprecated:** This parameter has been replaced with `branches_to_be_notified`. | +| `branches_to_be_notified` | string | no | Branches to send notifications for. Valid options are `all`, `default`, `protected`, and `default_and_protected`. The default value is `default`. | +| `labels_to_be_notified` | string | no | Labels to send notifications for. Leave blank to receive notifications for all events. | +| `labels_to_be_notified_behavior` | string | no | Labels to be notified for. Valid options are `match_any` and `match_all`. The default value is `match_any`. | +| `alert_channel` | string | no | The name of the channel to receive notifications for alert events. | +| `alert_events` | boolean | no | Enable notifications for alert events. | +| `commit_events` | boolean | no | Enable notifications for commit events. | +| `confidential_issue_channel` | string | no | The name of the channel to receive notifications for confidential issue events. | +| `confidential_issues_events` | boolean | no | Enable notifications for confidential issue events. | +| `confidential_note_channel` | string | no | The name of the channel to receive notifications for confidential note events. | +| `confidential_note_events` | boolean | no | Enable notifications for confidential note events. | +| `deployment_channel` | string | no | The name of the channel to receive notifications for deployment events. | +| `deployment_events` | boolean | no | Enable notifications for deployment events. | +| `incident_channel` | string | no | The name of the channel to receive notifications for incident events. | +| `incidents_events` | boolean | no | Enable notifications for incident events. | +| `issue_channel` | string | no | The name of the channel to receive notifications for issue events. | +| `issues_events` | boolean | no | Enable notifications for issue events. | +| `job_events` | boolean | no | Enable notifications for job events. | +| `merge_request_channel` | string | no | The name of the channel to receive notifications for merge request events. | +| `merge_requests_events` | boolean | no | Enable notifications for merge request events. | +| `note_channel` | string | no | The name of the channel to receive notifications for note events. | +| `note_events` | boolean | no | Enable notifications for note events. | +| `pipeline_channel` | string | no | The name of the channel to receive notifications for pipeline events. | +| `pipeline_events` | boolean | no | Enable notifications for pipeline events. | +| `push_channel` | string | no | The name of the channel to receive notifications for push events. | +| `push_events` | boolean | no | Enable notifications for push events. | +| `tag_push_channel` | string | no | The name of the channel to receive notifications for tag push events. | +| `tag_push_events` | boolean | no | Enable notifications for tag push events. | +| `wiki_page_channel` | string | no | The name of the channel to receive notifications for wiki page events. | +| `wiki_page_events` | boolean | no | Enable notifications for wiki page events. | +| `use_inherited_settings` | boolean | no | Indicates whether or not to inherit default settings. Defaults to `false`. | + +### Disable Slack notifications + +Disable Slack notifications for a group. Integration settings are reset. + +```plaintext +DELETE /groups/:id/integrations/slack +``` + +### Get Slack notifications settings + +Get the Slack notifications settings for a group. + +```plaintext +GET /groups/:id/integrations/slack +``` + +## Slack slash commands + +### Set up Slack slash commands + +Set up Slack slash commands for a group. + +```plaintext +PUT /groups/:id/integrations/slack-slash-commands +``` + +Parameters: + +| Parameter | Type | Required | Description | +| --------- | ---- | -------- | ----------- | +| `token` | string | yes | The Slack token. | +| `use_inherited_settings` | boolean | no | Indicates whether or not to inherit default settings. Defaults to `false`. | + +### Disable Slack slash commands + +Disable Slack slash commands for a group. Integration settings are reset. + +```plaintext +DELETE /groups/:id/integrations/slack-slash-commands +``` + +### Get Slack slash commands settings + +Get the Slack slash commands settings for a group. + +```plaintext +GET /groups/:id/integrations/slack-slash-commands +``` + +Example response: + +```json +{ + "id": 4, + "title": "Slack slash commands", + "slug": "slack-slash-commands", + "created_at": "2017-06-27T05:51:39-07:00", + "updated_at": "2017-06-27T05:51:39-07:00", + "active": true, + "push_events": true, + "issues_events": true, + "confidential_issues_events": true, + "merge_requests_events": true, + "tag_push_events": true, + "note_events": true, + "job_events": true, + "pipeline_events": true, + "comment_on_event_enabled": false, + "inherited": false, + "properties": { + "token": "" + } +} +``` + +## Squash TM + +### Set up Squash TM + +Set up the Squash TM integration settings for a group. + +```plaintext +PUT /groups/:id/integrations/squash-tm +``` + +Parameters: + +| Parameter | Type | Required | Description | +|-------------------------|--------|----------|-------------------------------| +| `url` | string | yes | URL of the Squash TM webhook. | +| `token` | string | no | Secret token. | +| `use_inherited_settings` | boolean | no | Indicates whether or not to inherit default settings. Defaults to `false`. | + +### Disable Squash TM + +Disable the Squash TM integration for a group. Integration settings are preserved. + +```plaintext +DELETE /groups/:id/integrations/squash-tm +``` + +### Get Squash TM settings + +Get the Squash TM integration settings for a group. + +```plaintext +GET /groups/:id/integrations/squash-tm +``` + +## Telegram + +### Set up Telegram + +Set up the Telegram integration for a group. + +```plaintext +PUT /groups/:id/integrations/telegram +``` + +Parameters: + +| Parameter | Type | Required | Description | +| --------- | ---- | -------- | ----------- | +| `hostname` | string | no | Custom hostname of the Telegram API. The default value is `https://api.telegram.org`. | +| `token` | string | yes | The Telegram bot token (for example, `123456:ABC-DEF1234ghIkl-zyx57W2v1u123ew11`). | +| `room` | string | yes | Unique identifier for the target chat or the username of the target channel (in the format `@channelusername`). | +| `thread` | integer | no | Unique identifier for the target message thread (topic in a forum supergroup). | +| `notify_only_broken_pipelines` | boolean | no | Send notifications for broken pipelines. | +| `branches_to_be_notified` | string | no | Branches to send notifications for. Valid options are `all`, `default`, `protected`, and `default_and_protected`. The default value is `default`. | +| `push_events` | boolean | yes | Enable notifications for push events. | +| `issues_events` | boolean | yes | Enable notifications for issue events. | +| `confidential_issues_events` | boolean | yes | Enable notifications for confidential issue events. | +| `merge_requests_events` | boolean | yes | Enable notifications for merge request events. | +| `tag_push_events` | boolean | yes | Enable notifications for tag push events. | +| `note_events` | boolean | yes | Enable notifications for note events. | +| `confidential_note_events` | boolean | yes | Enable notifications for confidential note events. | +| `pipeline_events` | boolean | yes | Enable notifications for pipeline events. | +| `wiki_page_events` | boolean | yes | Enable notifications for wiki page events. | +| `use_inherited_settings` | boolean | no | Indicates whether or not to inherit default settings. Defaults to `false`. | + +### Disable Telegram + +Disable the Telegram integration for a group. Integration settings are reset. + +```plaintext +DELETE /groups/:id/integrations/telegram +``` + +### Get Telegram settings + +Get the Telegram integration settings for a group. + +```plaintext +GET /groups/:id/integrations/telegram +``` + +## Unify Circuit + +### Set up Unify Circuit + +Set up the Unify Circuit integration for a group. + +```plaintext +PUT /groups/:id/integrations/unify-circuit +``` + +Parameters: + +| Parameter | Type | Required | Description | +| --------- | ---- | -------- | ----------- | +| `webhook` | string | yes | The Unify Circuit webhook (for example, `https://circuit.com/rest/v2/webhooks/incoming/...`). | +| `notify_only_broken_pipelines` | boolean | no | Send notifications for broken pipelines. | +| `branches_to_be_notified` | string | no | Branches to send notifications for. Valid options are `all`, `default`, `protected`, and `default_and_protected`. The default value is `default`. | +| `push_events` | boolean | no | Enable notifications for push events. | +| `issues_events` | boolean | no | Enable notifications for issue events. | +| `confidential_issues_events` | boolean | no | Enable notifications for confidential issue events. | +| `merge_requests_events` | boolean | no | Enable notifications for merge request events. | +| `tag_push_events` | boolean | no | Enable notifications for tag push events. | +| `note_events` | boolean | no | Enable notifications for note events. | +| `confidential_note_events` | boolean | no | Enable notifications for confidential note events. | +| `pipeline_events` | boolean | no | Enable notifications for pipeline events. | +| `wiki_page_events` | boolean | no | Enable notifications for wiki page events. | +| `use_inherited_settings` | boolean | no | Indicates whether or not to inherit default settings. Defaults to `false`. | + +### Disable Unify Circuit + +Disable the Unify Circuit integration for a group. Integration settings are reset. + +```plaintext +DELETE /groups/:id/integrations/unify-circuit +``` + +### Get Unify Circuit settings + +Get the Unify Circuit integration settings for a group. + +```plaintext +GET /groups/:id/integrations/unify-circuit +``` + +## Webex Teams + +### Set up Webex Teams + +Set up Webex Teams for a group. + +```plaintext +PUT /groups/:id/integrations/webex-teams +``` + +Parameters: + +| Parameter | Type | Required | Description | +| --------- | ---- | -------- | ----------- | +| `webhook` | string | yes | The Webex Teams webhook (for example, `https://api.ciscospark.com/v1/webhooks/incoming/...`). | +| `notify_only_broken_pipelines` | boolean | no | Send notifications for broken pipelines. | +| `branches_to_be_notified` | string | no | Branches to send notifications for. Valid options are `all`, `default`, `protected`, and `default_and_protected`. The default value is `default`. | +| `push_events` | boolean | no | Enable notifications for push events. | +| `issues_events` | boolean | no | Enable notifications for issue events. | +| `confidential_issues_events` | boolean | no | Enable notifications for confidential issue events. | +| `merge_requests_events` | boolean | no | Enable notifications for merge request events. | +| `tag_push_events` | boolean | no | Enable notifications for tag push events. | +| `note_events` | boolean | no | Enable notifications for note events. | +| `confidential_note_events` | boolean | no | Enable notifications for confidential note events. | +| `pipeline_events` | boolean | no | Enable notifications for pipeline events. | +| `wiki_page_events` | boolean | no | Enable notifications for wiki page events. | +| `use_inherited_settings` | boolean | no | Indicates whether or not to inherit default settings. Defaults to `false`. | + +### Disable Webex Teams + +Disable Webex Teams for a group. Integration settings are reset. + +```plaintext +DELETE /groups/:id/integrations/webex-teams +``` + +### Get Webex Teams settings + +Get the Webex Teams settings for a group. + +```plaintext +GET /groups/:id/integrations/webex-teams +``` + +## YouTrack + +### Set up YouTrack + +Set up the YouTrack integration for a group. + +```plaintext +PUT /groups/:id/integrations/youtrack +``` + +Parameters: + +| Parameter | Type | Required | Description | +| --------- | ---- | -------- | ----------- | +| `issues_url` | string | yes | URL of the issue. | +| `project_url` | string | yes | URL of the project. | +| `use_inherited_settings` | boolean | no | Indicates whether or not to inherit default settings. Defaults to `false`. | + +### Disable YouTrack + +Disable the YouTrack integration for a group. Integration settings are reset. + +```plaintext +DELETE /groups/:id/integrations/youtrack +``` + +### Get YouTrack settings + +Get the YouTrack integration settings for a group. + +```plaintext +GET /groups/:id/integrations/youtrack +``` diff --git a/doc/api/integrations.md b/doc/api/integrations.md index 3473762577b5e45117ffb8fc50ee194f6b496eb9..c7cf72c676d82b136a1e12dd9b766d62294f2ea0 100644 --- a/doc/api/integrations.md +++ b/doc/api/integrations.md @@ -4,13 +4,13 @@ group: Import and Integrate info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://handbook.gitlab.com/handbook/product/ux/technical-writing/#assignments --- -# Integrations API +# Project integrations API DETAILS: **Tier:** Free, Premium, Ultimate **Offering:** GitLab.com, Self-managed, GitLab Dedicated -This API enables you to work with external services that integrate with GitLab. +Use this API to work with external services that integrate with GitLab. This API requires an access token with the Maintainer or Owner role. diff --git a/doc/development/integrations/index.md b/doc/development/integrations/index.md index d222a7d0f9ca540f6f89f833a346505587253017..f3cbfe3f2c1ddafd95ab457f7e6a4fabbafd7405 100644 --- a/doc/development/integrations/index.md +++ b/doc/development/integrations/index.md @@ -360,7 +360,7 @@ To expose the integration in the [REST API](../../api/integrations.md): 'foo-bar' => ::Integrations::FooBar.api_arguments ``` -1. Update the reference documentation in `doc/api/integrations.md`, add a new section for your integration, and document all properties. +1. Update the reference documentation in `doc/api/integrations.md` and `doc/api/group_integrations.md`, add a new section for your integration, and document all properties. You can also refer to our [REST API style guide](../api_styleguide.md). @@ -451,7 +451,7 @@ In the major milestone of intended removal (M.0), disable the integration and de - Delete the integration model's `#execute` and `#test` methods (if defined), but keep the model. - Add a post-migration to delete the integration records from PostgreSQL (see [example merge request](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/114721)). - [Mark the integration documentation as removed](../../development/documentation/styleguide/deprecations_and_removals.md#remove-a-page). -- [Update the integration API documentation](../../api/integrations.md). +- Update the [project](../../api/integrations.md) and [group](../../api/group_integrations.md) integrations API pages. In the next minor release (M.1): diff --git a/ee/lib/ee/api/entities/project_integration_basic.rb b/ee/lib/ee/api/entities/integration_basic.rb similarity index 87% rename from ee/lib/ee/api/entities/project_integration_basic.rb rename to ee/lib/ee/api/entities/integration_basic.rb index 6824962fc0080a4baa6872bcf7e8e6c8fc8edaa0..86567bfbce53b82c17a700d5cc356b820d4aec55 100644 --- a/ee/lib/ee/api/entities/project_integration_basic.rb +++ b/ee/lib/ee/api/entities/integration_basic.rb @@ -3,7 +3,7 @@ module EE module API module Entities - module ProjectIntegrationBasic + module IntegrationBasic extend ActiveSupport::Concern prepended do diff --git a/ee/spec/lib/ee/api/entities/project_integration_basic_spec.rb b/ee/spec/lib/ee/api/entities/integration_basic_spec.rb similarity index 67% rename from ee/spec/lib/ee/api/entities/project_integration_basic_spec.rb rename to ee/spec/lib/ee/api/entities/integration_basic_spec.rb index 3ef177f380549bc75ec97dc539f4e22dd8d036be..c52e6cfc1e67d4ed5ecac49bc4da7df8a7d201d3 100644 --- a/ee/spec/lib/ee/api/entities/project_integration_basic_spec.rb +++ b/ee/spec/lib/ee/api/entities/integration_basic_spec.rb @@ -2,11 +2,11 @@ require 'spec_helper' -RSpec.describe ::EE::API::Entities::ProjectIntegrationBasic, feature_category: :integrations do +RSpec.describe ::EE::API::Entities::IntegrationBasic, feature_category: :integrations do let_it_be(:integration) { create(:jenkins_integration) } let(:entity) do - API::Entities::ProjectIntegrationBasic.new(integration) + API::Entities::IntegrationBasic.new(integration) end subject(:representation) { entity.as_json } diff --git a/ee/spec/requests/api/integrations_spec.rb b/ee/spec/requests/api/integrations_spec.rb index 3e9c1c9c427d73f9dce1ebbdba9692a6467c1213..bef6823fb5e7ce4bee47f61d746c14772aecfd4c 100644 --- a/ee/spec/requests/api/integrations_spec.rb +++ b/ee/spec/requests/api/integrations_spec.rb @@ -9,6 +9,7 @@ let_it_be(:user2) { create(:user) } let_it_be_with_reload(:project) { create(:project, namespace: user.namespace) } let_it_be(:project2) { create(:project, creator_id: user.id, namespace: user.namespace) } + let_it_be(:group, reload: true) { create(:group, owners: user) } let_it_be(:available_integration_names) do Integration::EE_PROJECT_LEVEL_ONLY_INTEGRATION_NAMES.union(Integration::GOOGLE_CLOUD_PLATFORM_INTEGRATION_NAMES) @@ -50,15 +51,27 @@ integration = params[:integration] describe "PUT /projects/:id/#{endpoint}/#{integration.dasherize}" do - it_behaves_like 'set up an integration', endpoint: endpoint, integration: integration + it_behaves_like 'set up an integration', endpoint: endpoint, integration: integration, + parent_resource_name: 'project' do + let(:parent_resource) { project } + let(:integrations_map) { project_integrations_map } + end end describe "DELETE /projects/:id/#{endpoint}/#{integration.dasherize}" do - it_behaves_like 'disable an integration', endpoint: endpoint, integration: integration + it_behaves_like 'disable an integration', endpoint: endpoint, integration: integration, + parent_resource_name: 'project' do + let(:parent_resource) { project } + let(:integrations_map) { project_integrations_map } + end end describe "GET /projects/:id/#{endpoint}/#{integration.dasherize}" do - it_behaves_like 'get an integration settings', endpoint: endpoint, integration: integration + it_behaves_like 'get an integration settings', endpoint: endpoint, integration: integration, + parent_resource_name: 'project' do + let(:parent_resource) { project } + let(:integrations_map) { project_integrations_map } + end end end diff --git a/lib/api/entities/project_integration.rb b/lib/api/entities/integration.rb similarity index 64% rename from lib/api/entities/project_integration.rb rename to lib/api/entities/integration.rb index f4709ce6dabbe90676cc00c5c0e34ebdd5f62511..48ade64963ca7ed1f3907ed12e09d7959b1acbba 100644 --- a/lib/api/entities/project_integration.rb +++ b/lib/api/entities/integration.rb @@ -2,11 +2,11 @@ module API module Entities - class ProjectIntegration < Entities::ProjectIntegrationBasic + class Integration < Entities::IntegrationBasic # Expose serialized properties - expose :properties, documentation: { type: 'Hash', example: { "token" => "secr3t" } } do |integration, options| + expose :properties, documentation: { type: 'Hash', example: { "token" => "secr3t" } } do |integration, _| integration.api_field_names.index_with do |name| - integration.public_send(name) # rubocop:disable GitlabSecurity/PublicSend + integration.public_send(name) # rubocop:disable GitlabSecurity/PublicSend -- we're exposing the fields that are allowed to be exposed end end end diff --git a/lib/api/entities/project_integration_basic.rb b/lib/api/entities/integration_basic.rb similarity index 94% rename from lib/api/entities/project_integration_basic.rb rename to lib/api/entities/integration_basic.rb index e57263fafa27f19fc397cbdf8a283b59575ffe35..633687c0a6b9591de514f3ea466101b8cb80eb8d 100644 --- a/lib/api/entities/project_integration_basic.rb +++ b/lib/api/entities/integration_basic.rb @@ -2,7 +2,7 @@ module API module Entities - class ProjectIntegrationBasic < Grape::Entity + class IntegrationBasic < Grape::Entity expose :id, documentation: { type: 'integer', example: 75 } expose :title, documentation: { type: 'string', example: 'Jenkins CI' } expose :slug, documentation: { type: 'integer', example: 'jenkins' } do |integration| @@ -33,4 +33,4 @@ class ProjectIntegrationBasic < Grape::Entity end end -API::Entities::ProjectIntegrationBasic.prepend_mod +API::Entities::IntegrationBasic.prepend_mod diff --git a/lib/api/helpers.rb b/lib/api/helpers.rb index a9ce3ff68907f013f6240266a1e018a8c09e4f8a..61ba521080430448738503d1c97ba9a990a390a3 100644 --- a/lib/api/helpers.rb +++ b/lib/api/helpers.rb @@ -374,10 +374,14 @@ def authorize_admin_project authorize! :admin_project, user_project end - def authorize_admin_integrations + def authorize_admin_project_integrations authorize! :admin_integrations, user_project end + def authorize_admin_group_integrations + authorize! :admin_integrations, user_group + end + def authorize_admin_group authorize! :admin_group, user_group end diff --git a/lib/api/integrations.rb b/lib/api/integrations.rb index 0747cc8842baa4241c6a8a7172774118f19a660c..5be57fb6f1059cf6042c302764f8091c30662360 100644 --- a/lib/api/integrations.rb +++ b/lib/api/integrations.rb @@ -1,3 +1,4 @@ +# lib/api/integrations.rb # frozen_string_literal: true module API class Integrations < ::API::Base @@ -45,7 +46,7 @@ def integration_attributes(integration) end # The API officially documents only the `:id/integrations` API paths. - # We support the older `id:/services` path for backwards-compatibility in API V4. + # We support the older `id:/services` path for project integrations 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 @@ -53,144 +54,18 @@ def integration_attributes(integration) end resource :projects, requirements: API::NAMESPACE_OR_PROJECT_REQUIREMENTS do before { authenticate! } - before { authorize_admin_integrations } + before { authorize_admin_project_integrations } - desc 'List all active integrations' do - detail 'Get a list of all active project integrations.' - success Entities::ProjectIntegrationBasic - failure [ - { code: 401, message: 'Unauthorized' }, - { code: 404, message: 'Not found' } - ] - is_array true - tags INTEGRATIONS_TAGS - end - get path do - integrations = user_project.integrations.active - - present integrations, with: Entities::ProjectIntegrationBasic - end - - INTEGRATIONS.each do |slug, settings| - desc "Create/Edit #{slug.titleize} integration" do - detail "Set #{slug.titleize} integration for a project." - success Entities::ProjectIntegrationBasic - failure [ - { code: 400, message: 'Bad request' }, - { code: 401, message: 'Unauthorized' }, - { code: 404, message: 'Not found' }, - { code: 422, message: 'Unprocessable entity' } - ] - tags INTEGRATIONS_TAGS - end - params do - settings.each do |setting| - 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 - put "#{path}/#{slug}" do - if slug == "git-guardian" && Feature.disabled?(:git_guardian_integration) - render_api_error!('GitGuardian feature is disabled', 400) - end - - integration = user_project.find_or_initialize_integration(slug.underscore) - - render_api_error!('400 Integration not available', 400) if integration.nil? - - params = declared_params(include_missing: false).merge(active: true) - - unless integration.manual_activation? || integration.is_a?(::Integrations::Prometheus) - if integration.new_record? - render_api_error!("You cannot create the #{integration.class.title} integration from the API", 422) - end - - params.delete(:active) - end - - result = ::Integrations::UpdateService.new( - current_user: current_user, integration: integration, attributes: params - ).execute - - if result.success? - present integration, with: Entities::ProjectIntegration - else - render_api_error!(result.message, 400) - end - end - end - - desc "Disable an integration" do - detail "Disable the integration for a project. Integration settings are preserved." - success code: 204 - failure [ - { code: 400, message: 'Bad request' }, - { code: 401, message: 'Unauthorized' }, - { code: 404, message: 'Not found' } - ] - tags INTEGRATIONS_TAGS - end - params do - requires :slug, type: String, values: INTEGRATIONS.keys, desc: 'The name of the integration' - end - delete "#{path}/:slug" do - if params[:slug] == "git-guardian" && Feature.disabled?(:git_guardian_integration) - render_api_error!('GitGuardian feature is disabled', 400) - end - - integration = user_project.find_or_initialize_integration(params[:slug].underscore) - - not_found!('Integration') unless integration&.persisted? - - if integration.is_a?(::Integrations::JiraCloudApp) - render_api_error!("You cannot disable the #{integration.class.title} integration from the API", 422) - end - - destroy_conditionally!(integration) do - attrs = integration_attributes(integration).index_with do |attr| - column = if integration.attribute_present?(attr) - integration.column_for_attribute(attr) - elsif integration.data_fields_present? - integration.data_fields.column_for_attribute(attr) - end - - case column - when nil, ActiveRecord::ConnectionAdapters::NullColumn - nil - else - column.default - end - end.merge(active: false) - - render_api_error!('400 Bad Request', 400) unless integration.update(attrs) + helpers do + def fetch_parent_resource + user_project end end - desc "Get an integration settings" do - detail "Get the integration settings for a project." - success Entities::ProjectIntegration - failure [ - { code: 400, message: 'Bad request' }, - { code: 401, message: 'Unauthorized' }, - { code: 404, message: 'Not found' } - ] - tags INTEGRATIONS_TAGS - end - params do - requires :slug, type: String, values: INTEGRATIONS.keys, desc: 'The name of the integration' - end - get "#{path}/:slug" do - integration = user_project.find_or_initialize_integration(params[:slug].underscore) - - not_found!('Integration') unless integration&.persisted? - - present integration, with: Entities::ProjectIntegration - end + mount IntegratableOperations, with: { + path: path + } end - SLASH_COMMAND_INTEGRATIONS.each do |integration_slug, settings| helpers do def slash_command_integration(project, integration_slug, params) @@ -237,6 +112,28 @@ def slash_command_integration(project, integration_slug, params) end end + # New API endpoints should use the `:id/integrations` path exclusively. + ':id/integrations'.tap do |path| + params do + requires :id, types: [String, Integer], desc: 'The ID or URL-encoded path of the group' + end + + resource :groups, requirements: API::NAMESPACE_OR_PROJECT_REQUIREMENTS do + before { authenticate! } + before { authorize_admin_group_integrations } + + helpers do + def fetch_parent_resource + user_group + end + end + + mount IntegratableOperations, with: { + path: path + } + end + end + desc "Trigger a global slack command" do detail 'Added in GitLab 9.4' failure [ diff --git a/lib/api/integrations/integratable_operations.rb b/lib/api/integrations/integratable_operations.rb new file mode 100644 index 0000000000000000000000000000000000000000..f80044930c3da28de729d5f666ea7f5c7d64e5db --- /dev/null +++ b/lib/api/integrations/integratable_operations.rb @@ -0,0 +1,174 @@ +# frozen_string_literal: true + +module API + class Integrations + class IntegratableOperations < Grape::API # rubocop:disable API/Base -- subclassing from Grape::API is required for mounting in the main API. + INTEGRATIONS_TAGS = %w[integrations].freeze + + mounted do + helpers do + def integration_attributes(integration) + integration.fields.inject([]) do |arr, hash| + arr << hash[:name].to_sym + end + end + + def find_or_initialize_integration(slug) + parent_resource.find_or_initialize_integration(slug.underscore) + end + + def parent_resource + unless respond_to?(:fetch_parent_resource, true) + raise NotImplementedError, + "You must implement a `fetch_parent_resource` method that returns " \ + "the integratable resource in the namespace that mounts this API." + end + + @parent_resource ||= fetch_parent_resource + end + end + + desc 'List all active integrations' do + detail "Get a list of all active integrations." + success Entities::IntegrationBasic + failure [ + { code: 401, message: 'Unauthorized' }, + { code: 404, message: 'Not found' } + ] + is_array true + tags INTEGRATIONS_TAGS + end + + get(configuration[:path]) do + integrations = parent_resource.integrations.active + + present integrations, with: Entities::IntegrationBasic + end + + INTEGRATIONS.each do |slug, settings| + desc "Create/Edit #{slug.titleize} integration" do + detail "Set #{slug.titleize} integration." + success Entities::IntegrationBasic + failure [ + { code: 400, message: 'Bad request' }, + { code: 401, message: 'Unauthorized' }, + { code: 404, message: 'Not found' }, + { code: 422, message: 'Unprocessable entity' } + ] + tags INTEGRATIONS_TAGS + end + params do + settings.each do |setting| + 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 + put("#{configuration[:path]}/#{slug}") do + if slug == "git-guardian" && Feature.disabled?(:git_guardian_integration) + render_api_error!('GitGuardian feature is disabled', 400) + end + + integration = find_or_initialize_integration(slug) + + params = declared_params(include_missing: false).merge(active: true) + + render_api_error!('400 Integration not available', 400) if integration.nil? + + manual_or_special = integration.manual_activation? || integration.is_a?(::Integrations::Prometheus) + + unless manual_or_special + if integration.new_record? + render_api_error!("You cannot create the #{integration.class.title} integration from the API", 422) + end + + params.delete(:active) + end + + result = ::Integrations::UpdateService.new( + current_user: current_user, integration: integration, attributes: params + ).execute + + if result.success? + present integration, with: Entities::Integration + else + message = result.message || '400 Bad Request' + render_api_error!(message, 400) + end + end + end + + desc "Disable an integration" do + detail "Disable the integration. Integration settings are preserved." + success code: 204 + failure [ + { code: 400, message: 'Bad request' }, + { code: 401, message: 'Unauthorized' }, + { code: 404, message: 'Not found' } + ] + tags INTEGRATIONS_TAGS + end + params do + requires :slug, type: String, values: INTEGRATIONS.keys, + desc: 'The name of the integration' + end + delete("#{configuration[:path]}/:slug") do + if params[:slug] == "git-guardian" && Feature.disabled?(:git_guardian_integration) + render_api_error!('GitGuardian feature is disabled', 400) + end + + integration = find_or_initialize_integration(params[:slug]) + + not_found!('Integration') unless integration&.persisted? + + if integration.is_a?(::Integrations::JiraCloudApp) + render_api_error!("You cannot disable the #{integration.class.title} integration from the API", 422) + end + + destroy_conditionally!(integration) do + attrs = integration_attributes(integration).index_with do |attr| + column = if integration.attribute_present?(attr) + integration.column_for_attribute(attr) + elsif integration.data_fields_present? + integration.data_fields.column_for_attribute(attr) + end + + case column + when nil, ActiveRecord::ConnectionAdapters::NullColumn + nil + else + column.default + end + end.merge(active: false) + + render_api_error!('400 Bad Request', 400) unless integration.update(attrs) + end + end + + desc "Get an integration settings" do + detail "Get the integration settings." + success Entities::Integration + failure [ + { code: 400, message: 'Bad request' }, + { code: 401, message: 'Unauthorized' }, + { code: 404, message: 'Not found' } + ] + tags INTEGRATIONS_TAGS + end + params do + requires :slug, type: String, values: INTEGRATIONS.keys, + desc: 'The name of the integration' + end + get("#{configuration[:path]}/:slug") do + integration = find_or_initialize_integration(params[:slug]) + + not_found!('Integration') unless integration&.persisted? + + present integration, with: Entities::Integration + end + end + end + end +end diff --git a/spec/requests/api/integrations_spec.rb b/spec/requests/api/integrations_spec.rb index 6610a26697f7a5bba8c1f50a7f4eb7b90b20a4f0..373a98f01ea412edf5a9a1626eab316c66611c4f 100644 --- a/spec/requests/api/integrations_spec.rb +++ b/spec/requests/api/integrations_spec.rb @@ -7,7 +7,9 @@ let_it_be(:user) { create(:user) } let_it_be(:user2) { create(:user) } - let_it_be(:project, reload: true) { create(:project, creator_id: user.id, namespace: user.namespace) } + let_it_be(:project, reload: true) { create(:project, creator_id: user.id, namespace: user.namespace, owners: [user]) } + let_it_be(:user3) { create(:user) } + let_it_be(:user4) { create(:user) } let_it_be(:available_integration_names) do excluded_integrations = [Integrations::GitlabSlackApplication.to_param, Integrations::Zentao.to_param] @@ -23,6 +25,16 @@ let_it_be(:project2) { create(:project, creator_id: user.id, namespace: user.namespace) } + let_it_be(:group, reload: true) do + create(:group, owners: user) + end + + let_it_be(:group_integrations_map) do + available_integration_names.index_with do |name| + create(integration_factory(name), :group, :inactive, group: group) + end + end + %w[integrations services].each do |endpoint| describe "GET /projects/:id/#{endpoint}" do it 'returns authentication error when unauthenticated' do @@ -38,17 +50,15 @@ expect(response).to have_gitlab_http_status(:forbidden) end - context 'with integrations' do - it "returns a list of all active integrations" do - get api("/projects/#{project.id}/#{endpoint}", user) + it "returns a list of all active integrations" do + get api("/projects/#{project.id}/#{endpoint}", user) - aggregate_failures 'expect successful response with all active integrations' do - expect(response).to have_gitlab_http_status(:ok) - expect(json_response).to be_an Array - expect(json_response.count).to eq(1) - expect(json_response.first['slug']).to eq('prometheus') - expect(response).to match_response_schema('public_api/v4/integrations') - end + aggregate_failures 'expect successful response with all active integrations' do + expect(response).to have_gitlab_http_status(:ok) + expect(json_response).to be_an Array + expect(json_response.count).to eq(1) + expect(json_response.first['slug']).to eq('prometheus') + expect(response).to match_response_schema('public_api/v4/integrations') end end end @@ -70,15 +80,24 @@ integration = params[:integration] describe "PUT /projects/:id/#{endpoint}/#{integration.dasherize}" do - it_behaves_like 'set up an integration', endpoint: endpoint, integration: integration + it_behaves_like 'set up an integration', endpoint: endpoint, integration: integration, parent_resource_name: 'project' do + let(:parent_resource) { project } + let(:integrations_map) { project_integrations_map } + end end describe "DELETE /projects/:id/#{endpoint}/#{integration.dasherize}" do - it_behaves_like 'disable an integration', endpoint: endpoint, integration: integration + it_behaves_like 'disable an integration', endpoint: endpoint, integration: integration, parent_resource_name: 'project' do + let(:parent_resource) { project } + let(:integrations_map) { project_integrations_map } + end end describe "GET /projects/:id/#{endpoint}/#{integration.dasherize}" do - it_behaves_like 'get an integration settings', endpoint: endpoint, integration: integration + it_behaves_like 'get an integration settings', endpoint: endpoint, integration: integration, parent_resource_name: 'project' do + let(:parent_resource) { project } + let(:integrations_map) { project_integrations_map } + end end end @@ -438,6 +457,72 @@ def assert_secret_fields_filtered(response_keys, integration) end end + 'integrations'.tap do |endpoint| + describe "GET /groups/:id/#{endpoint}" do + it 'returns authentication error when unauthenticated' do + get api("/groups/#{group.id}/#{endpoint}") + + expect(response).to have_gitlab_http_status(:unauthorized) + end + + it "returns error when authenticated but user is not a group owner" do + group.add_developer(user4) + get api("/groups/#{group.id}/#{endpoint}", user4) + + expect(response).to have_gitlab_http_status(:forbidden) + end + + it "returns a list of all active integrations" do + get api("/groups/#{group.id}/#{endpoint}", user) + + aggregate_failures 'expect successful response with all active integrations' do + expect(response).to have_gitlab_http_status(:ok) + expect(json_response).to be_an Array + expect(json_response.count).to eq(1) + expect(json_response.first['slug']).to eq('prometheus') + expect(response).to match_response_schema('public_api/v4/integrations') + end + end + end + + where(:integration) do + # You cannot create a GitLab for Slack app. You must install the app from the GitLab UI. + unavailable_integration_names = [ + Integrations::GitlabSlackApplication.to_param, + Integrations::Zentao.to_param, + Integrations::Prometheus.to_param + ] + + names = Integration.available_integration_names(include_instance_specific: false, include_project_specific: false) + names.reject { |name| name.in?(unavailable_integration_names) } + end + + with_them do + integration = params[:integration] + + describe "PUT /groups/:id/#{endpoint}/#{integration.dasherize}" do + it_behaves_like 'set up an integration', endpoint: endpoint, integration: integration, parent_resource_name: 'group' do + let(:parent_resource) { group } + let(:integrations_map) { group_integrations_map } + end + end + + describe "DELETE /groups/:id/#{endpoint}/#{integration.dasherize}" do + it_behaves_like 'disable an integration', endpoint: endpoint, integration: integration, parent_resource_name: 'group' do + let(:parent_resource) { group } + let(:integrations_map) { group_integrations_map } + end + end + + describe "GET /groups/:id/#{endpoint}/#{integration.dasherize}" do + it_behaves_like 'get an integration settings', endpoint: endpoint, integration: integration, parent_resource_name: 'group' do + let(:parent_resource) { group } + let(:integrations_map) { group_integrations_map } + end + end + end + end + describe 'POST /slack/trigger' do before_all do create(:gitlab_slack_application_integration, project: project) diff --git a/spec/support/shared_examples/integrations_shared_examples.rb b/spec/support/shared_examples/integrations_shared_examples.rb index 4f1000f121e8d61f135202dd8fe2354312d2dfae..45b8229c50a4e004c77d84bb2a772283d0c673ab 100644 --- a/spec/support/shared_examples/integrations_shared_examples.rb +++ b/spec/support/shared_examples/integrations_shared_examples.rb @@ -1,10 +1,16 @@ # frozen_string_literal: true -RSpec.shared_examples 'set up an integration' do |endpoint:, integration:| +RSpec.shared_examples 'set up an integration' do |endpoint:, integration:, parent_resource_name:| include_context 'with integration' - let(:integration_attrs) { attributes_for(integration_factory).without(:active, :type) } - let(:url) { api("/projects/#{project.id}/#{endpoint}/#{dashed_integration}", user) } + let(:integrations_map) { raise NotImplementedError, 'Define `integrations_map` in the calling context' } + let(:parent_resource) { raise NotImplementedError, 'Define `parent_resource` in the calling context' } + + let(:integration_attrs) do + attributes_for(integration_factory).without(:active, :type) + end + + let(:url) { api("/#{parent_resource_name.pluralize}/#{parent_resource.id}/#{endpoint}/#{dashed_integration}", user) } subject(:request) { put url, params: integration_attrs } @@ -14,7 +20,7 @@ expect(response).to have_gitlab_http_status(:ok) expect(json_response['slug']).to eq(dashed_integration) - current_integration = project.integrations.by_name(integration).first + current_integration = parent_resource.integrations.by_name(integration).first expect(current_integration).to have_attributes(integration_attrs) expect(json_response['properties'].keys).to match_array(current_integration.api_field_names) @@ -32,7 +38,7 @@ put url, params: flipped_attrs expect(response).to have_gitlab_http_status(:ok) - expect(project.integrations.by_name(integration).first).to have_attributes(flipped_attrs) + expect(parent_resource.integrations.by_name(integration).first).to have_attributes(flipped_attrs) end end @@ -57,6 +63,39 @@ expect(response).to have_gitlab_http_status(expected_code) end + context 'when the integration does not exist' do + let(:fresh_parent_resource) { create(parent_resource_name.to_sym, owners: [user]) } + let(:parent_resource) { fresh_parent_resource } + + it "creates #{integration} and returns the correct fields" do + initial_count = parent_resource.integrations.by_name(integration).count + expect(initial_count).to eq(0) + + request + + current_integration = parent_resource.integrations.by_name(integration).first + manual_or_special = current_integration&.manual_activation? || + current_integration.is_a?(::Integrations::Prometheus) + delta = manual_or_special ? 1 : 0 + + expect(parent_resource.integrations.by_name(integration).count).to eq(initial_count + delta) + + if manual_or_special + expect(response).to have_gitlab_http_status(:ok) + expect(json_response['slug']).to eq(dashed_integration) + + expect(current_integration).to have_attributes(integration_attrs) + expect(json_response['properties'].keys).to match_array(current_integration.api_field_names) + + if current_integration.secret_fields.present? + expect(json_response['properties'].keys).not_to include(*current_integration.secret_fields) + end + else + expect(response).to have_gitlab_http_status(:unprocessable_entity) + end + end + end + context 'when an integration is disabled' do before do allow(Integration).to receive(:disabled_integration_names).and_return([integration.to_param]) @@ -69,48 +108,58 @@ end end - context 'when an integration is disabled at the project-level' do - before do - allow_next_found_instance_of(Project) do |project| - allow(project).to receive(:disabled_integrations).and_return([integration]) + if parent_resource_name == 'project' + context 'when an integration is disabled at the parent_resource-level' do + before do + allow_next_found_instance_of(parent_resource.class) do |instance| + allow(instance).to receive(:disabled_integrations).and_return([integration]) + end end - end - it 'returns bad request' do - put url, params: integration_attrs + it 'returns bad request' do + put url, params: integration_attrs - expect(response).to have_gitlab_http_status(:bad_request) + expect(response).to have_gitlab_http_status(:bad_request) + end end end end -RSpec.shared_examples 'disable an integration' do |endpoint:, integration:| +RSpec.shared_examples 'disable an integration' do |endpoint:, integration:, parent_resource_name:| include_context 'with integration' + let(:fresh_parent_resource) { create(parent_resource_name.to_sym, owners: [user]) } + let(:parent_resource) { fresh_parent_resource } before do - project_integrations_map[integration].activate! + integrations_map[integration].update_column(:active, true) end it "deletes #{integration}" do - delete api("/projects/#{project.id}/#{endpoint}/#{dashed_integration}", user) - + expect do + delete api("/#{parent_resource_name.pluralize}/#{parent_resource.id}/#{endpoint}/#{dashed_integration}", user) + end.to change { + parent_resource.integrations.where(type_new: integration_klass.name, active: true).count + }.from(1).to(0) expect(response).to have_gitlab_http_status(:no_content) - project.send(integration_method).reload - expect(project.send(integration_method).activated?).to be_falsey end it 'returns not found if integration does not exist' do - delete api("/projects/#{project2.id}/#{endpoint}/#{dashed_integration}", user) + delete api("/#{parent_resource_name.pluralize}/#{fresh_parent_resource.id}/#{endpoint}/#{dashed_integration}", user) expect(response).to have_gitlab_http_status(:not_found) expect(json_response['message']).to eq('404 Integration Not Found') end end -RSpec.shared_examples 'get an integration settings' do |endpoint:, integration:| +RSpec.shared_examples 'get an integration settings' do |endpoint:, integration:, parent_resource_name:| include_context 'with integration' - let(:initialized_integration) { project_integrations_map[integration] } + let(:initialized_integration) do + integrations_map[integration] + end + + let(:fresh_parent_resource) { create(parent_resource_name.to_sym, owners: [user]) } + let(:parent_resource) { fresh_parent_resource } def deactive_integration! return initialized_integration.deactivate! unless initialized_integration.is_a?(::Integrations::Prometheus) @@ -134,14 +183,14 @@ def activate_integration! end it "returns all properties of inactive integration #{integration}, except password fields" do - get api("/projects/#{project.id}/#{endpoint}/#{dashed_integration}", user) + get api("/#{parent_resource_name.pluralize}/#{parent_resource.id}/#{endpoint}/#{dashed_integration}", user) expect(initialized_integration).not_to be_active expect(response).to have_gitlab_http_status(:ok) - expect(json_response['properties'].keys).to match_array(integration_instance.api_field_names) + expect(json_response['properties'].keys).to match_array(initialized_integration.api_field_names) - unless integration_instance.secret_fields.empty? - expect(json_response['properties'].keys).not_to include(*integration_instance.secret_fields) + unless initialized_integration.secret_fields.empty? + expect(json_response['properties'].keys).not_to include(*initialized_integration.secret_fields) end end end @@ -152,44 +201,46 @@ def activate_integration! end it "returns all properties of active integration #{integration}, except password fields" do - get api("/projects/#{project.id}/#{endpoint}/#{dashed_integration}", user) + get api("/#{parent_resource_name.pluralize}/#{parent_resource.id}/#{endpoint}/#{dashed_integration}", user) expect(initialized_integration).to be_active expect(response).to have_gitlab_http_status(:ok) - expect(json_response['properties'].keys).to match_array(integration_instance.api_field_names) + expect(json_response['properties'].keys).to match_array(initialized_integration.api_field_names) - unless integration_instance.secret_fields.empty? - expect(json_response['properties'].keys).not_to include(*integration_instance.secret_fields) + unless initialized_integration.secret_fields.empty? + expect(json_response['properties'].keys).not_to include(*initialized_integration.secret_fields) end end end it 'returns authentication error when unauthenticated' do - get api("/projects/#{project.id}/#{endpoint}/#{dashed_integration}") + get api("/#{parent_resource_name.pluralize}/#{parent_resource.id}/#{endpoint}/#{dashed_integration}") expect(response).to have_gitlab_http_status(:unauthorized) end it "returns not found if integration does not exist" do - get api("/projects/#{project2.id}/#{endpoint}/#{dashed_integration}", user) + get api("/#{parent_resource_name.pluralize}/#{fresh_parent_resource.id}/#{endpoint}/#{dashed_integration}", user) expect(response).to have_gitlab_http_status(:not_found) expect(json_response['message']).to eq('404 Integration Not Found') end - it "returns not found if integration exists but is in `Project#disabled_integrations`" do - allow_next_found_instance_of(Project) do |project| - allow(project).to receive(:disabled_integrations).and_return([integration]) - end + if parent_resource_name == 'project' + it "returns not found if integration exists but is in `#{parent_resource_name}#disabled_integrations`" do + allow_next_found_instance_of(parent_resource.class) do |instance| + allow(instance).to receive(:disabled_integrations).and_return([integration]) + end - get api("/projects/#{project.id}/#{endpoint}/#{dashed_integration}", user) + get api("/#{parent_resource_name.pluralize}/#{parent_resource.id}/#{endpoint}/#{dashed_integration}", user) - expect(response).to have_gitlab_http_status(:not_found) - expect(json_response['message']).to eq('404 Integration Not Found') + expect(response).to have_gitlab_http_status(:not_found) + expect(json_response['message']).to eq('404 Integration Not Found') + end end - it "returns error when authenticated but not a project owner" do - project.add_developer(user2) - get api("/projects/#{project.id}/#{endpoint}/#{dashed_integration}", user2) + it "returns error when authenticated but not an parent_resource owner" do + parent_resource.add_developer(user2) + get api("/#{parent_resource_name.pluralize}/#{parent_resource.id}/#{endpoint}/#{dashed_integration}", user2) expect(response).to have_gitlab_http_status(:forbidden) end