summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGitLab Bot <gitlab-bot@gitlab.com>2020-01-22 15:08:48 +0000
committerGitLab Bot <gitlab-bot@gitlab.com>2020-01-22 15:08:48 +0000
commit180cd023a11c0eb413ad0de124d9758ea25672bd (patch)
tree63d77be00a22dc637daa0b6d5b644e230f5f4890
parentbe3e24ea3c9f497efde85900df298ce9bc42fce8 (diff)
downloadgitlab-ce-180cd023a11c0eb413ad0de124d9758ea25672bd.tar.gz
Add latest changes from gitlab-org/gitlab@master
-rw-r--r--.gitlab/ci/reports.gitlab-ci.yml1
-rw-r--r--GITALY_SERVER_VERSION2
-rw-r--r--GITLAB_PAGES_VERSION2
-rw-r--r--app/assets/javascripts/api.js9
-rw-r--r--app/graphql/types/group_type.rb19
-rw-r--r--app/models/member.rb1
-rw-r--r--app/workers/error_tracking_issue_link_worker.rb12
-rw-r--r--changelogs/unreleased/33596-add-pipeline-metadata-to-the-package-registry-ui.yml6
-rw-r--r--changelogs/unreleased/admin_user_memberships_endpoint.yml5
-rw-r--r--changelogs/unreleased/allow-minimum-processes-in-sidekiq-cluster.yml5
-rw-r--r--changelogs/unreleased/feat-backfill-group-graphql-api.yml5
-rw-r--r--changelogs/unreleased/gitaly-version-v1-83-0.yml5
-rw-r--r--changelogs/unreleased/pages-1-14.yml5
-rw-r--r--changelogs/unreleased/sy-sync-plugin-sentry-issues.yml5
-rw-r--r--doc/administration/operations/extra_sidekiq_processes.md39
-rw-r--r--doc/api/access_requests.md2
-rw-r--r--doc/api/graphql/reference/gitlab_schema.graphql35
-rw-r--r--doc/api/graphql/reference/gitlab_schema.json98
-rw-r--r--doc/api/graphql/reference/index.md7
-rw-r--r--doc/api/users.md50
-rw-r--r--lib/api/entities.rb9
-rw-r--r--lib/api/users.rb26
-rw-r--r--lib/sentry/client.rb6
-rw-r--r--lib/sentry/client/issue_link.rb35
-rw-r--r--locale/gitlab.pot6
-rw-r--r--qa/qa/runtime/browser.rb13
-rw-r--r--spec/factories/project_error_tracking_settings.rb2
-rw-r--r--spec/features/error_tracking/user_sees_error_details_spec.rb32
-rw-r--r--spec/features/error_tracking/user_sees_error_index_spec.rb69
-rw-r--r--spec/fixtures/api/schemas/public_api/v4/membership.json10
-rw-r--r--spec/fixtures/api/schemas/public_api/v4/memberships.json4
-rw-r--r--spec/fixtures/sentry/global_integration_link_sample_response.json (renamed from spec/fixtures/sentry/issue_link_sample_response.json)0
-rw-r--r--spec/fixtures/sentry/issue_sample_response.json282
-rw-r--r--spec/fixtures/sentry/plugin_link_sample_response.json6
-rw-r--r--spec/graphql/types/group_type_spec.rb9
-rw-r--r--spec/lib/sentry/client/issue_link_spec.rb38
-rw-r--r--spec/lib/sentry/client/issue_spec.rb4
-rw-r--r--spec/requests/api/users_spec.rb77
-rw-r--r--spec/support/shared_contexts/features/error_tracking_shared_context.rb23
-rw-r--r--spec/support/shared_examples/features/error_tracking_shared_example.rb86
-rw-r--r--spec/workers/error_tracking_issue_link_worker_spec.rb13
41 files changed, 753 insertions, 310 deletions
diff --git a/.gitlab/ci/reports.gitlab-ci.yml b/.gitlab/ci/reports.gitlab-ci.yml
index 81cc3e7dd2f..4d6c02336fe 100644
--- a/.gitlab/ci/reports.gitlab-ci.yml
+++ b/.gitlab/ci/reports.gitlab-ci.yml
@@ -142,6 +142,7 @@ dependency_scanning:
variables:
DOCKER_DRIVER: overlay2
DOCKER_TLS_CERTDIR: ""
+ DS_EXCLUDED_PATHS: "qa/qa/ee/fixtures/secure_premade_reports,spec,ee/spec"
allow_failure: true
services:
- docker:stable-dind
diff --git a/GITALY_SERVER_VERSION b/GITALY_SERVER_VERSION
index dbd41264aa9..6b4de0a42b0 100644
--- a/GITALY_SERVER_VERSION
+++ b/GITALY_SERVER_VERSION
@@ -1 +1 @@
-1.81.0
+1.83.0
diff --git a/GITLAB_PAGES_VERSION b/GITLAB_PAGES_VERSION
index 0eed1a29efd..850e742404b 100644
--- a/GITLAB_PAGES_VERSION
+++ b/GITLAB_PAGES_VERSION
@@ -1 +1 @@
-1.12.0
+1.14.0
diff --git a/app/assets/javascripts/api.js b/app/assets/javascripts/api.js
index bee079c6643..6de9ab9efb3 100644
--- a/app/assets/javascripts/api.js
+++ b/app/assets/javascripts/api.js
@@ -44,6 +44,7 @@ const Api = {
releasePath: '/api/:version/projects/:id/releases/:tag_name',
mergeRequestsPipeline: '/api/:version/projects/:id/merge_requests/:merge_request_iid/pipelines',
adminStatisticsPath: '/api/:version/application/statistics',
+ pipelineSinglePath: '/api/:version/projects/:id/pipelines/:pipeline_id',
group(groupId, callback) {
const url = Api.buildUrl(Api.groupPath).replace(':id', groupId);
@@ -448,6 +449,14 @@ const Api = {
return axios.get(url);
},
+ pipelineSingle(id, pipelineId) {
+ const url = Api.buildUrl(this.pipelineSinglePath)
+ .replace(':id', encodeURIComponent(id))
+ .replace(':pipeline_id', encodeURIComponent(pipelineId));
+
+ return axios.get(url);
+ },
+
buildUrl(url) {
return joinPaths(gon.relative_url_root || '', url.replace(':version', gon.api_version));
},
diff --git a/app/graphql/types/group_type.rb b/app/graphql/types/group_type.rb
index 393948fcede..d22983f2164 100644
--- a/app/graphql/types/group_type.rb
+++ b/app/graphql/types/group_type.rb
@@ -17,6 +17,25 @@ module Types
group.avatar_url(only_path: false)
end
+ field :share_with_group_lock, GraphQL::BOOLEAN_TYPE, null: true,
+ description: 'Indicates if sharing a project with another group within this group is prevented'
+
+ field :project_creation_level, GraphQL::STRING_TYPE, null: true, method: :project_creation_level_str,
+ description: 'The permission level required to create projects in the group'
+ field :subgroup_creation_level, GraphQL::STRING_TYPE, null: true, method: :subgroup_creation_level_str,
+ description: 'The permission level required to create subgroups within the group'
+
+ field :require_two_factor_authentication, GraphQL::BOOLEAN_TYPE, null: true,
+ description: 'Indicates if all users in this group are required to set up two-factor authentication'
+ field :two_factor_grace_period, GraphQL::INT_TYPE, null: true,
+ description: 'Time before two-factor authentication is enforced'
+
+ field :auto_devops_enabled, GraphQL::BOOLEAN_TYPE, null: true,
+ description: 'Indicates whether Auto DevOps is enabled for all projects within this group'
+
+ field :emails_disabled, GraphQL::BOOLEAN_TYPE, null: true,
+ description: 'Indicates if a group has email notifications disabled'
+
field :mentions_disabled, GraphQL::BOOLEAN_TYPE, null: true,
description: 'Indicates if a group is disabled from getting mentioned'
diff --git a/app/models/member.rb b/app/models/member.rb
index 2654453cf3f..57924161b63 100644
--- a/app/models/member.rb
+++ b/app/models/member.rb
@@ -82,6 +82,7 @@ class Member < ApplicationRecord
scope :with_user, -> (user) { where(user: user) }
scope :with_source_id, ->(source_id) { where(source_id: source_id) }
+ scope :including_source, -> { includes(:source) }
scope :order_name_asc, -> { left_join_users.reorder(Gitlab::Database.nulls_last_order('users.name', 'ASC')) }
scope :order_name_desc, -> { left_join_users.reorder(Gitlab::Database.nulls_last_order('users.name', 'DESC')) }
diff --git a/app/workers/error_tracking_issue_link_worker.rb b/app/workers/error_tracking_issue_link_worker.rb
index 5048f361c31..b306ecc154b 100644
--- a/app/workers/error_tracking_issue_link_worker.rb
+++ b/app/workers/error_tracking_issue_link_worker.rb
@@ -20,17 +20,11 @@ class ErrorTrackingIssueLinkWorker
def perform(issue_id)
@issue = Issue.find_by_id(issue_id)
- return unless issue && error_tracking && sentry_issue_id
+ return unless valid?
try_obtain_lease do
logger.info("Linking Sentry issue #{sentry_issue_id} to GitLab issue #{issue.id}")
- if integration_id.nil?
- logger.info("Sentry integration unavailable for #{error_tracking.api_url}")
-
- break
- end
-
sentry_client.create_issue_link(integration_id, sentry_issue_id, issue)
rescue Sentry::Client::Error
logger.info("Failed to link Sentry issue #{sentry_issue_id} to GitLab issue #{issue.id}")
@@ -39,6 +33,10 @@ class ErrorTrackingIssueLinkWorker
private
+ def valid?
+ issue && error_tracking && sentry_issue_id
+ end
+
def error_tracking
strong_memoize(:error_tracking) do
issue.project.error_tracking_setting
diff --git a/changelogs/unreleased/33596-add-pipeline-metadata-to-the-package-registry-ui.yml b/changelogs/unreleased/33596-add-pipeline-metadata-to-the-package-registry-ui.yml
new file mode 100644
index 00000000000..6de64dc562e
--- /dev/null
+++ b/changelogs/unreleased/33596-add-pipeline-metadata-to-the-package-registry-ui.yml
@@ -0,0 +1,6 @@
+---
+title: Packages published to the package registry via CI/CD with a CI_JOB_TOKEN will
+ display pipeline information on the details page
+merge_request: 22485
+author:
+type: added
diff --git a/changelogs/unreleased/admin_user_memberships_endpoint.yml b/changelogs/unreleased/admin_user_memberships_endpoint.yml
new file mode 100644
index 00000000000..e1e3bfd144d
--- /dev/null
+++ b/changelogs/unreleased/admin_user_memberships_endpoint.yml
@@ -0,0 +1,5 @@
+---
+title: Add users memberships endpoints for admins
+merge_request: 22518
+author:
+type: added
diff --git a/changelogs/unreleased/allow-minimum-processes-in-sidekiq-cluster.yml b/changelogs/unreleased/allow-minimum-processes-in-sidekiq-cluster.yml
new file mode 100644
index 00000000000..e1e2bd21d5d
--- /dev/null
+++ b/changelogs/unreleased/allow-minimum-processes-in-sidekiq-cluster.yml
@@ -0,0 +1,5 @@
+---
+title: Allow setting minimum concurrency for sidekiq-cluster processes
+merge_request: 23408
+author:
+type: added
diff --git a/changelogs/unreleased/feat-backfill-group-graphql-api.yml b/changelogs/unreleased/feat-backfill-group-graphql-api.yml
new file mode 100644
index 00000000000..df1c1019bab
--- /dev/null
+++ b/changelogs/unreleased/feat-backfill-group-graphql-api.yml
@@ -0,0 +1,5 @@
+---
+title: Backfill missing GraphQL API Group type properties
+merge_request: 23389
+author: Fabio Huser
+type: added
diff --git a/changelogs/unreleased/gitaly-version-v1-83-0.yml b/changelogs/unreleased/gitaly-version-v1-83-0.yml
new file mode 100644
index 00000000000..c36181005f4
--- /dev/null
+++ b/changelogs/unreleased/gitaly-version-v1-83-0.yml
@@ -0,0 +1,5 @@
+---
+title: Upgrade to Gitaly v1.83.0
+merge_request: 23431
+author:
+type: changed
diff --git a/changelogs/unreleased/pages-1-14.yml b/changelogs/unreleased/pages-1-14.yml
new file mode 100644
index 00000000000..679b51da3da
--- /dev/null
+++ b/changelogs/unreleased/pages-1-14.yml
@@ -0,0 +1,5 @@
+---
+title: Upgrade pages to 1.14.0
+merge_request: 23317
+author:
+type: added
diff --git a/changelogs/unreleased/sy-sync-plugin-sentry-issues.yml b/changelogs/unreleased/sy-sync-plugin-sentry-issues.yml
new file mode 100644
index 00000000000..a1165adde8f
--- /dev/null
+++ b/changelogs/unreleased/sy-sync-plugin-sentry-issues.yml
@@ -0,0 +1,5 @@
+---
+title: Sync GitLab issues with Sentry plugin integration
+merge_request: 23355
+author:
+type: added
diff --git a/doc/administration/operations/extra_sidekiq_processes.md b/doc/administration/operations/extra_sidekiq_processes.md
index acb57debe26..8ab75da3501 100644
--- a/doc/administration/operations/extra_sidekiq_processes.md
+++ b/doc/administration/operations/extra_sidekiq_processes.md
@@ -124,9 +124,18 @@ number of threads that equals the number of queues, plus one spare thread.
For example, a process that handles the `process_commit` and `post_receive`
queues will use three threads in total.
-## Limiting concurrency
+## Managing concurrency
-To limit the concurrency of the Sidekiq process:
+When setting the maximum concurrency, keep in mind this normally should
+not exceed the number of CPU cores available. The values in the examples
+below are arbitrary and not particular recommendations.
+
+Each thread requires a Redis connection, so adding threads may increase Redis
+latency and potentially cause client timeouts. See the [Sidekiq documentation
+about Redis](https://github.com/mperham/sidekiq/wiki/Using-Redis) for more
+details.
+
+### When running a single Sidekiq process (default)
1. Edit `/etc/gitlab/gitlab.rb` and add:
@@ -140,11 +149,14 @@ To limit the concurrency of the Sidekiq process:
sudo gitlab-ctl reconfigure
```
-To limit the max concurrency of the Sidekiq cluster processes:
+This will set the concurrency (number of threads) for the Sidekiq process.
+
+### When running Sidekiq cluster
1. Edit `/etc/gitlab/gitlab.rb` and add:
```ruby
+ sidekiq_cluster['min_concurrency'] = 15
sidekiq_cluster['max_concurrency'] = 25
```
@@ -154,14 +166,21 @@ To limit the max concurrency of the Sidekiq cluster processes:
sudo gitlab-ctl reconfigure
```
-For each queue group, the concurrency factor will be set to `min(number of queues, N)`.
-Setting the value to 0 will disable the limit. Keep in mind this normally would
-not exceed the number of CPU cores available.
+`min_concurrency` and `max_concurrency` are independent; one can be set without
+the other. Setting `min_concurrency` to 0 will disable the limit.
+
+For each queue group, let N be one more than the number of queues. The
+concurrency factor will be set to:
+
+1. `N`, if it's between `min_concurrency` and `max_concurrency`.
+1. `max_concurrency`, if `N` exceeds this value.
+1. `min_concurrency`, if `N` is less than this value.
+
+If `min_concurrency` is equal to `max_concurrency`, then this value will be used
+regardless of the number of queues.
-Each thread requires a Redis connection, so adding threads may
-increase Redis latency and potentially cause client timeouts. See the [Sidekiq
-documentation about Redis](https://github.com/mperham/sidekiq/wiki/Using-Redis)
-for more details.
+When `min_concurrency` is greater than `max_concurrency`, it is treated as
+being equal to `max_concurrency`.
## Modifying the check interval
diff --git a/doc/api/access_requests.md b/doc/api/access_requests.md
index 584a4ecb89c..a9ebffbc606 100644
--- a/doc/api/access_requests.md
+++ b/doc/api/access_requests.md
@@ -2,7 +2,7 @@
>**Note:** This feature was introduced in GitLab 8.11
- **Valid access levels**
+## Valid access levels
The access levels are defined in the `Gitlab::Access` module. Currently, these levels are recognized:
diff --git a/doc/api/graphql/reference/gitlab_schema.graphql b/doc/api/graphql/reference/gitlab_schema.graphql
index f3bf45b0b3d..7d18a0abfe5 100644
--- a/doc/api/graphql/reference/gitlab_schema.graphql
+++ b/doc/api/graphql/reference/gitlab_schema.graphql
@@ -2435,6 +2435,11 @@ type GrafanaIntegration {
type Group {
"""
+ Indicates whether Auto DevOps is enabled for all projects within this group
+ """
+ autoDevopsEnabled: Boolean
+
+ """
Avatar URL of the group
"""
avatarUrl: String
@@ -2450,6 +2455,11 @@ type Group {
descriptionHtml: String
"""
+ Indicates if a group has email notifications disabled
+ """
+ emailsDisabled: Boolean
+
+ """
Find a single epic
"""
epic(
@@ -2624,6 +2634,11 @@ type Group {
path: String!
"""
+ The permission level required to create projects in the group
+ """
+ projectCreationLevel: String
+
+ """
Projects within this namespace
"""
projects(
@@ -2659,11 +2674,26 @@ type Group {
requestAccessEnabled: Boolean
"""
+ Indicates if all users in this group are required to set up two-factor authentication
+ """
+ requireTwoFactorAuthentication: Boolean
+
+ """
Aggregated storage statistics of the namespace. Only available for root namespaces
"""
rootStorageStatistics: RootStorageStatistics
"""
+ Indicates if sharing a project with another group within this group is prevented
+ """
+ shareWithGroupLock: Boolean
+
+ """
+ The permission level required to create subgroups within the group
+ """
+ subgroupCreationLevel: String
+
+ """
Time logged in issues by group members
"""
timelogs(
@@ -2699,6 +2729,11 @@ type Group {
): TimelogConnection!
"""
+ Time before two-factor authentication is enforced
+ """
+ twoFactorGracePeriod: Int
+
+ """
Permissions for the current user on the resource
"""
userPermissions: GroupPermissions!
diff --git a/doc/api/graphql/reference/gitlab_schema.json b/doc/api/graphql/reference/gitlab_schema.json
index 645df8c0184..9f888eb89c4 100644
--- a/doc/api/graphql/reference/gitlab_schema.json
+++ b/doc/api/graphql/reference/gitlab_schema.json
@@ -3045,6 +3045,20 @@
"description": null,
"fields": [
{
+ "name": "autoDevopsEnabled",
+ "description": "Indicates whether Auto DevOps is enabled for all projects within this group",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "SCALAR",
+ "name": "Boolean",
+ "ofType": null
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
"name": "avatarUrl",
"description": "Avatar URL of the group",
"args": [
@@ -3087,6 +3101,20 @@
"deprecationReason": null
},
{
+ "name": "emailsDisabled",
+ "description": "Indicates if a group has email notifications disabled",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "SCALAR",
+ "name": "Boolean",
+ "ofType": null
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
"name": "epic",
"description": "Find a single epic",
"args": [
@@ -3525,6 +3553,20 @@
"deprecationReason": null
},
{
+ "name": "projectCreationLevel",
+ "description": "The permission level required to create projects in the group",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "SCALAR",
+ "name": "String",
+ "ofType": null
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
"name": "projects",
"description": "Projects within this namespace",
"args": [
@@ -3606,6 +3648,20 @@
"deprecationReason": null
},
{
+ "name": "requireTwoFactorAuthentication",
+ "description": "Indicates if all users in this group are required to set up two-factor authentication",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "SCALAR",
+ "name": "Boolean",
+ "ofType": null
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
"name": "rootStorageStatistics",
"description": "Aggregated storage statistics of the namespace. Only available for root namespaces",
"args": [
@@ -3620,6 +3676,34 @@
"deprecationReason": null
},
{
+ "name": "shareWithGroupLock",
+ "description": "Indicates if sharing a project with another group within this group is prevented",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "SCALAR",
+ "name": "Boolean",
+ "ofType": null
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "subgroupCreationLevel",
+ "description": "The permission level required to create subgroups within the group",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "SCALAR",
+ "name": "String",
+ "ofType": null
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
"name": "timelogs",
"description": "Time logged in issues by group members",
"args": [
@@ -3705,6 +3789,20 @@
"deprecationReason": null
},
{
+ "name": "twoFactorGracePeriod",
+ "description": "Time before two-factor authentication is enforced",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "SCALAR",
+ "name": "Int",
+ "ofType": null
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
"name": "userPermissions",
"description": "Permissions for the current user on the resource",
"args": [
diff --git a/doc/api/graphql/reference/index.md b/doc/api/graphql/reference/index.md
index 6696863faff..1177ffff36c 100644
--- a/doc/api/graphql/reference/index.md
+++ b/doc/api/graphql/reference/index.md
@@ -393,6 +393,13 @@ Autogenerated return type of EpicTreeReorder
| `userPermissions` | GroupPermissions! | Permissions for the current user on the resource |
| `webUrl` | String! | Web URL of the group |
| `avatarUrl` | String | Avatar URL of the group |
+| `shareWithGroupLock` | Boolean | Indicates if sharing a project with another group within this group is prevented |
+| `projectCreationLevel` | String | The permission level required to create projects in the group |
+| `subgroupCreationLevel` | String | The permission level required to create subgroups within the group |
+| `requireTwoFactorAuthentication` | Boolean | Indicates if all users in this group are required to set up two-factor authentication |
+| `twoFactorGracePeriod` | Int | Time before two-factor authentication is enforced |
+| `autoDevopsEnabled` | Boolean | Indicates whether Auto DevOps is enabled for all projects within this group |
+| `emailsDisabled` | Boolean | Indicates if a group has email notifications disabled |
| `mentionsDisabled` | Boolean | Indicates if a group is disabled from getting mentioned |
| `parent` | Group | Parent group |
| `epicsEnabled` | Boolean | Indicates if Epics are enabled for namespace |
diff --git a/doc/api/users.md b/doc/api/users.md
index 4ba524d6d1d..7694345d08b 100644
--- a/doc/api/users.md
+++ b/doc/api/users.md
@@ -1405,3 +1405,53 @@ Example response:
```
Please note that `last_activity_at` is deprecated, please use `last_activity_on`.
+
+## User memberships (admin only)
+
+> [Introduced](https://gitlab.com/gitlab-org/gitlab/merge_requests/22518) in GitLab 12.8.
+
+Lists all projects and groups a user is a member of. This endpoint is available for admins only.
+It returns the `source_id`, `source_name`, `source_type` and `access_level` of a membership.
+Source can be of type `Namespace` (representing a group) or `Project`. The response represents only direct memberships. Inherited memberships, for example in subgroups, will not be included.
+Access levels will be represented by an integer value. Read more about the meaning of access level values [here](access_requests.md#valid-access-levels).
+
+```
+GET /users/:id/memberships
+```
+
+Parameters:
+
+| Attribute | Type | Required | Description |
+| --------- | ---- | -------- | ----------- |
+| `id` | integer | yes | The ID of a specified user |
+| `type` | string | no | Filter memberships by type. Can be either `Project` or `Namespace` |
+
+Returns:
+
+- `200 OK` on success.
+- `404 User Not Found` if user cannot be found.
+- `403 Forbidden` when not requested by an admin.
+- `400 Bad Request` when requested type is not supported.
+
+```bash
+curl --header "PRIVATE-TOKEN: <your_access_token>" https://gitlab.example.com/api/v4/users/<user_id>/memberships
+```
+
+Example response:
+
+```json
+[
+ {
+ "source_id": 1,
+ "source_name": "Project one",
+ "source_type": "Project",
+ "access_level": "20"
+ },
+ {
+ "source_id": 3,
+ "source_name": "Group three",
+ "source_type": "Namespace",
+ "access_level": "20"
+ },
+]
+```
diff --git a/lib/api/entities.rb b/lib/api/entities.rb
index 97be90030c8..899418831bf 100644
--- a/lib/api/entities.rb
+++ b/lib/api/entities.rb
@@ -2,6 +2,15 @@
module API
module Entities
+ class Membership < Grape::Entity
+ expose :source_id
+ expose :source_name do |member|
+ member.source.name
+ end
+ expose :source_type
+ expose :access_level
+ end
+
class BlameRangeCommit < Grape::Entity
expose :id
expose :parent_ids
diff --git a/lib/api/users.rb b/lib/api/users.rb
index 120f66b6a71..eba7c50435c 100644
--- a/lib/api/users.rb
+++ b/lib/api/users.rb
@@ -533,6 +533,32 @@ module API
end
# rubocop: enable CodeReuse/ActiveRecord
+ desc 'Get memberships' do
+ success Entities::Membership
+ end
+ params do
+ requires :user_id, type: Integer, desc: 'The ID of the user'
+ optional :type, type: String, values: %w[Project Namespace]
+ use :pagination
+ end
+ get ":user_id/memberships" do
+ authenticated_as_admin!
+ user = find_user_by_id(params)
+
+ members = case params[:type]
+ when 'Project'
+ user.project_members
+ when 'Namespace'
+ user.group_members
+ else
+ user.members
+ end
+
+ members = members.including_source
+
+ present paginate(members), with: Entities::Membership
+ end
+
params do
requires :user_id, type: Integer, desc: 'The ID of the user'
end
diff --git a/lib/sentry/client.rb b/lib/sentry/client.rb
index 8898960c24d..36ec1caf80c 100644
--- a/lib/sentry/client.rb
+++ b/lib/sentry/client.rb
@@ -54,6 +54,12 @@ module Sentry
end
end
+ def http_post(url, params = {})
+ http_request do
+ Gitlab::HTTP.post(url, **request_params.merge(body: params.to_json))
+ end
+ end
+
def http_request
response = handle_request_exceptions do
yield
diff --git a/lib/sentry/client/issue_link.rb b/lib/sentry/client/issue_link.rb
index 200b1a6b435..91498c19f8b 100644
--- a/lib/sentry/client/issue_link.rb
+++ b/lib/sentry/client/issue_link.rb
@@ -3,8 +3,22 @@
module Sentry
class Client
module IssueLink
- def create_issue_link(integration_id, sentry_issue_identifier, issue)
- issue_link_url = issue_link_api_url(integration_id, sentry_issue_identifier)
+ # Creates a link in Sentry corresponding to the provided
+ # Sentry issue and GitLab issue
+ # @param integration_id [Integer, nil] Representing a global
+ # GitLab integration in Sentry. Nil for plugins.
+ # @param sentry_issue_id [Integer] Id for an issue from Sentry
+ # @param issue [Issue] Issue for which the link should be created
+ def create_issue_link(integration_id, sentry_issue_id, issue)
+ return create_plugin_link(sentry_issue_id, issue) unless integration_id
+
+ create_global_integration_link(integration_id, sentry_issue_id, issue)
+ end
+
+ private
+
+ def create_global_integration_link(integration_id, sentry_issue_id, issue)
+ issue_link_url = global_integration_link_api_url(integration_id, sentry_issue_id)
params = {
project: issue.project.id,
@@ -14,11 +28,22 @@ module Sentry
http_put(issue_link_url, params)
end
- private
+ def global_integration_link_api_url(integration_id, sentry_issue_id)
+ issue_link_url = URI(url)
+ issue_link_url.path = "/api/0/groups/#{sentry_issue_id}/integrations/#{integration_id}/"
+
+ issue_link_url
+ end
+
+ def create_plugin_link(sentry_issue_id, issue)
+ issue_link_url = plugin_link_api_url(sentry_issue_id)
+
+ http_post(issue_link_url, issue_id: issue.iid)
+ end
- def issue_link_api_url(integration_id, sentry_issue_identifier)
+ def plugin_link_api_url(sentry_issue_id)
issue_link_url = URI(url)
- issue_link_url.path = "/api/0/groups/#{sentry_issue_identifier}/integrations/#{integration_id}/"
+ issue_link_url.path = "/api/0/issues/#{sentry_issue_id}/plugins/gitlab/link/"
issue_link_url
end
diff --git a/locale/gitlab.pot b/locale/gitlab.pot
index aad7e54b9db..788d4d43b70 100644
--- a/locale/gitlab.pot
+++ b/locale/gitlab.pot
@@ -13026,6 +13026,12 @@ msgstr ""
msgid "PackageRegistry|There was a problem fetching the details for this package."
msgstr ""
+msgid "PackageRegistry|There was an error fetching the pipeline information."
+msgstr ""
+
+msgid "PackageRegistry|Unable to fetch pipeline information"
+msgstr ""
+
msgid "PackageRegistry|Unable to load package"
msgstr ""
diff --git a/qa/qa/runtime/browser.rb b/qa/qa/runtime/browser.rb
index 340f6dc0356..ec78759f6c8 100644
--- a/qa/qa/runtime/browser.rb
+++ b/qa/qa/runtime/browser.rb
@@ -66,14 +66,23 @@ module QA
metadata[:type] = :feature
end
- config.before do
+ config.before(:suite) do
unless browser.rspec_configured
browser.rspec_configured = true
##
# Perform before hooks, which are different for CE and EE
#
- Runtime::Release.perform_before_hooks
+ begin
+ Runtime::Release.perform_before_hooks
+ rescue
+ saved = Capybara::Screenshot.screenshot_and_save_page
+
+ QA::Runtime::Logger.error("Screenshot: #{saved[:image]}") if saved&.key?(:image)
+ QA::Runtime::Logger.error("HTML capture: #{saved[:html]}") if saved&.key?(:html)
+
+ raise
+ end
end
end
end
diff --git a/spec/factories/project_error_tracking_settings.rb b/spec/factories/project_error_tracking_settings.rb
index 5d3fb284eef..7af881f4214 100644
--- a/spec/factories/project_error_tracking_settings.rb
+++ b/spec/factories/project_error_tracking_settings.rb
@@ -3,7 +3,7 @@
FactoryBot.define do
factory :project_error_tracking_setting, class: 'ErrorTracking::ProjectErrorTrackingSetting' do
project
- api_url { 'https://sentrytest.gitlab.com/api/0/projects/sentry-org/sentry-project' }
+ api_url { 'https://gitlab.com/api/0/projects/sentry-org/sentry-project' }
enabled { true }
token { 'access_token_123' }
project_name { 'Sentry Project' }
diff --git a/spec/features/error_tracking/user_sees_error_details_spec.rb b/spec/features/error_tracking/user_sees_error_details_spec.rb
deleted file mode 100644
index 6f72c44c689..00000000000
--- a/spec/features/error_tracking/user_sees_error_details_spec.rb
+++ /dev/null
@@ -1,32 +0,0 @@
-# frozen_string_literal: true
-
-require 'spec_helper'
-
-describe 'View error details page', :js, :use_clean_rails_memory_store_caching, :sidekiq_inline do
- include_context 'sentry error tracking context feature'
-
- context 'with current user as project owner' do
- before do
- sign_in(project.owner)
-
- visit details_project_error_tracking_index_path(project, issue_id: issue_id)
- end
-
- it_behaves_like 'error tracking show page'
- end
-
- context 'with current user as project guest' do
- let_it_be(:user) { create(:user) }
-
- before do
- project.add_guest(user)
- sign_in(user)
-
- visit details_project_error_tracking_index_path(project, issue_id: issue_id)
- end
-
- it 'renders not found' do
- expect(page).to have_content('Page Not Found')
- end
- end
-end
diff --git a/spec/features/error_tracking/user_sees_error_index_spec.rb b/spec/features/error_tracking/user_sees_error_index_spec.rb
deleted file mode 100644
index 0d23df31e29..00000000000
--- a/spec/features/error_tracking/user_sees_error_index_spec.rb
+++ /dev/null
@@ -1,69 +0,0 @@
-# frozen_string_literal: true
-
-require 'spec_helper'
-
-describe 'View error details page', :js, :use_clean_rails_memory_store_caching, :sidekiq_inline do
- include_context 'sentry error tracking context feature'
-
- let_it_be(:issues_response_body) { fixture_file('sentry/issues_sample_response.json') }
- let_it_be(:issues_response) { JSON.parse(issues_response_body) }
- let(:issues_api_url) { "#{sentry_api_urls.issues_url}?limit=20&query=is:unresolved" }
-
- before do
- stub_request(:get, issues_api_url).with(
- headers: { 'Authorization' => 'Bearer access_token_123' }
- ).to_return(status: 200, body: issues_response_body, headers: { 'Content-Type' => 'application/json' })
- end
-
- context 'with current user as project owner' do
- before do
- sign_in(project.owner)
-
- visit project_error_tracking_index_path(project)
- end
-
- it_behaves_like 'error tracking index page'
- end
-
- # A bug caused the detail link to be broken for all users but the project owner
- context 'with current user as project maintainer' do
- let_it_be(:user) { create(:user) }
-
- before do
- project.add_maintainer(user)
- sign_in(user)
-
- visit project_error_tracking_index_path(project)
- end
-
- it_behaves_like 'error tracking index page'
- end
-
- context 'with error tracking settings disabled' do
- before do
- project_error_tracking_settings.update(enabled: false)
- sign_in(project.owner)
-
- visit project_error_tracking_index_path(project)
- end
-
- it 'renders call to action' do
- expect(page).to have_content('Enable error tracking')
- end
- end
-
- context 'with current user as project guest' do
- let_it_be(:user) { create(:user) }
-
- before do
- project.add_guest(user)
- sign_in(user)
-
- visit project_error_tracking_index_path(project)
- end
-
- it 'renders not found' do
- expect(page).to have_content('Page Not Found')
- end
- end
-end
diff --git a/spec/fixtures/api/schemas/public_api/v4/membership.json b/spec/fixtures/api/schemas/public_api/v4/membership.json
new file mode 100644
index 00000000000..3412076f84a
--- /dev/null
+++ b/spec/fixtures/api/schemas/public_api/v4/membership.json
@@ -0,0 +1,10 @@
+{
+ "type": "object",
+ "properties" : {
+ "source_id": { "type": "integer" },
+ "source_name": { "type": "string" },
+ "source_type": { "type": "string" },
+ "access_level": { "type": "integer" }
+ },
+ "additionalProperties": false
+}
diff --git a/spec/fixtures/api/schemas/public_api/v4/memberships.json b/spec/fixtures/api/schemas/public_api/v4/memberships.json
new file mode 100644
index 00000000000..54c98b9cb99
--- /dev/null
+++ b/spec/fixtures/api/schemas/public_api/v4/memberships.json
@@ -0,0 +1,4 @@
+{
+ "type": "array",
+ "items": { "$ref": "membership.json" }
+}
diff --git a/spec/fixtures/sentry/issue_link_sample_response.json b/spec/fixtures/sentry/global_integration_link_sample_response.json
index f7f3220e83d..f7f3220e83d 100644
--- a/spec/fixtures/sentry/issue_link_sample_response.json
+++ b/spec/fixtures/sentry/global_integration_link_sample_response.json
diff --git a/spec/fixtures/sentry/issue_sample_response.json b/spec/fixtures/sentry/issue_sample_response.json
index 43d55f584b8..a320a21de34 100644
--- a/spec/fixtures/sentry/issue_sample_response.json
+++ b/spec/fixtures/sentry/issue_sample_response.json
@@ -38,7 +38,7 @@
},
"firstSeen": "2018-11-06T21:19:55Z",
"hasSeen": false,
- "id": "11",
+ "id": "503504",
"isBookmarked": false,
"isPublic": false,
"isSubscribed": true,
@@ -72,64 +72,232 @@
"shortId": "PUMP-STATION-1",
"stats": {
"24h": [
- [1541451600.0, 557],
- [1541455200.0, 473],
- [1541458800.0, 914],
- [1541462400.0, 991],
- [1541466000.0, 925],
- [1541469600.0, 881],
- [1541473200.0, 182],
- [1541476800.0, 490],
- [1541480400.0, 820],
- [1541484000.0, 322],
- [1541487600.0, 836],
- [1541491200.0, 565],
- [1541494800.0, 758],
- [1541498400.0, 880],
- [1541502000.0, 677],
- [1541505600.0, 381],
- [1541509200.0, 814],
- [1541512800.0, 329],
- [1541516400.0, 446],
- [1541520000.0, 731],
- [1541523600.0, 111],
- [1541527200.0, 926],
- [1541530800.0, 772],
- [1541534400.0, 400],
- [1541538000.0, 943]
+ [
+ 1541451600.0,
+ 557
+ ],
+ [
+ 1541455200.0,
+ 473
+ ],
+ [
+ 1541458800.0,
+ 914
+ ],
+ [
+ 1541462400.0,
+ 991
+ ],
+ [
+ 1541466000.0,
+ 925
+ ],
+ [
+ 1541469600.0,
+ 881
+ ],
+ [
+ 1541473200.0,
+ 182
+ ],
+ [
+ 1541476800.0,
+ 490
+ ],
+ [
+ 1541480400.0,
+ 820
+ ],
+ [
+ 1541484000.0,
+ 322
+ ],
+ [
+ 1541487600.0,
+ 836
+ ],
+ [
+ 1541491200.0,
+ 565
+ ],
+ [
+ 1541494800.0,
+ 758
+ ],
+ [
+ 1541498400.0,
+ 880
+ ],
+ [
+ 1541502000.0,
+ 677
+ ],
+ [
+ 1541505600.0,
+ 381
+ ],
+ [
+ 1541509200.0,
+ 814
+ ],
+ [
+ 1541512800.0,
+ 329
+ ],
+ [
+ 1541516400.0,
+ 446
+ ],
+ [
+ 1541520000.0,
+ 731
+ ],
+ [
+ 1541523600.0,
+ 111
+ ],
+ [
+ 1541527200.0,
+ 926
+ ],
+ [
+ 1541530800.0,
+ 772
+ ],
+ [
+ 1541534400.0,
+ 400
+ ],
+ [
+ 1541538000.0,
+ 943
+ ]
],
"30d": [
- [1538870400.0, 565],
- [1538956800.0, 12862],
- [1539043200.0, 15617],
- [1539129600.0, 10809],
- [1539216000.0, 15065],
- [1539302400.0, 12927],
- [1539388800.0, 12994],
- [1539475200.0, 13139],
- [1539561600.0, 11838],
- [1539648000.0, 12088],
- [1539734400.0, 12338],
- [1539820800.0, 12768],
- [1539907200.0, 12816],
- [1539993600.0, 15356],
- [1540080000.0, 10910],
- [1540166400.0, 12306],
- [1540252800.0, 12912],
- [1540339200.0, 14700],
- [1540425600.0, 11890],
- [1540512000.0, 11684],
- [1540598400.0, 13510],
- [1540684800.0, 12625],
- [1540771200.0, 12811],
- [1540857600.0, 13180],
- [1540944000.0, 14651],
- [1541030400.0, 14161],
- [1541116800.0, 12612],
- [1541203200.0, 14316],
- [1541289600.0, 14742],
- [1541376000.0, 12505],
- [1541462400.0, 14180]
+ [
+ 1538870400.0,
+ 565
+ ],
+ [
+ 1538956800.0,
+ 12862
+ ],
+ [
+ 1539043200.0,
+ 15617
+ ],
+ [
+ 1539129600.0,
+ 10809
+ ],
+ [
+ 1539216000.0,
+ 15065
+ ],
+ [
+ 1539302400.0,
+ 12927
+ ],
+ [
+ 1539388800.0,
+ 12994
+ ],
+ [
+ 1539475200.0,
+ 13139
+ ],
+ [
+ 1539561600.0,
+ 11838
+ ],
+ [
+ 1539648000.0,
+ 12088
+ ],
+ [
+ 1539734400.0,
+ 12338
+ ],
+ [
+ 1539820800.0,
+ 12768
+ ],
+ [
+ 1539907200.0,
+ 12816
+ ],
+ [
+ 1539993600.0,
+ 15356
+ ],
+ [
+ 1540080000.0,
+ 10910
+ ],
+ [
+ 1540166400.0,
+ 12306
+ ],
+ [
+ 1540252800.0,
+ 12912
+ ],
+ [
+ 1540339200.0,
+ 14700
+ ],
+ [
+ 1540425600.0,
+ 11890
+ ],
+ [
+ 1540512000.0,
+ 11684
+ ],
+ [
+ 1540598400.0,
+ 13510
+ ],
+ [
+ 1540684800.0,
+ 12625
+ ],
+ [
+ 1540771200.0,
+ 12811
+ ],
+ [
+ 1540857600.0,
+ 13180
+ ],
+ [
+ 1540944000.0,
+ 14651
+ ],
+ [
+ 1541030400.0,
+ 14161
+ ],
+ [
+ 1541116800.0,
+ 12612
+ ],
+ [
+ 1541203200.0,
+ 14316
+ ],
+ [
+ 1541289600.0,
+ 14742
+ ],
+ [
+ 1541376000.0,
+ 12505
+ ],
+ [
+ 1541462400.0,
+ 14180
+ ]
]
},
"status": "unresolved",
diff --git a/spec/fixtures/sentry/plugin_link_sample_response.json b/spec/fixtures/sentry/plugin_link_sample_response.json
new file mode 100644
index 00000000000..2e07e412844
--- /dev/null
+++ b/spec/fixtures/sentry/plugin_link_sample_response.json
@@ -0,0 +1,6 @@
+{
+ "message": "Successfully linked issue.",
+ "link": "https://gitlab.com/test/tanuki-inc/issues/3",
+ "id": 3,
+ "label": "GL-3"
+}
diff --git a/spec/graphql/types/group_type_spec.rb b/spec/graphql/types/group_type_spec.rb
index de11bad0723..6a0028f6529 100644
--- a/spec/graphql/types/group_type_spec.rb
+++ b/spec/graphql/types/group_type_spec.rb
@@ -10,7 +10,14 @@ describe GitlabSchema.types['Group'] do
it { expect(described_class).to require_graphql_authorizations(:read_group) }
it 'has the expected fields' do
- expected_fields = %w[web_url avatar_url mentions_disabled parent]
+ expected_fields = %w[
+ id name path full_name full_path description description_html visibility
+ lfs_enabled request_access_enabled projects root_storage_statistics
+ web_url avatar_url share_with_group_lock project_creation_level
+ subgroup_creation_level require_two_factor_authentication
+ two_factor_grace_period auto_devops_enabled emails_disabled
+ mentions_disabled parent
+ ]
is_expected.to include_graphql_fields(*expected_fields)
end
diff --git a/spec/lib/sentry/client/issue_link_spec.rb b/spec/lib/sentry/client/issue_link_spec.rb
index 35a69be6de5..3434e93365e 100644
--- a/spec/lib/sentry/client/issue_link_spec.rb
+++ b/spec/lib/sentry/client/issue_link_spec.rb
@@ -5,18 +5,18 @@ require 'spec_helper'
describe Sentry::Client::IssueLink do
include SentryClientHelpers
- let(:error_tracking_setting) { create(:project_error_tracking_setting, api_url: sentry_url) }
- let(:sentry_url) { 'https://sentrytest.gitlab.com/api/0/projects/sentry-org/sentry-project' }
- let(:client) { error_tracking_setting.sentry_client }
+ let_it_be(:sentry_url) { 'https://sentrytest.gitlab.com/api/0/projects/sentry-org/sentry-project' }
+ let_it_be(:error_tracking_setting) { create(:project_error_tracking_setting, api_url: sentry_url) }
+ let_it_be(:issue) { create(:issue, project: error_tracking_setting.project) }
- let(:issue_link_sample_response) { JSON.parse(fixture_file('sentry/issue_link_sample_response.json')) }
+ let(:client) { error_tracking_setting.sentry_client }
+ let(:sentry_issue_id) { 11111111 }
describe '#create_issue_link' do
+ let(:sentry_issue_link_url) { "https://sentrytest.gitlab.com/api/0/groups/#{sentry_issue_id}/integrations/#{integration_id}/" }
let(:integration_id) { 44444 }
- let(:sentry_issue_id) { 11111111 }
- let(:issue) { create(:issue, project: error_tracking_setting.project) }
- let(:sentry_issue_link_url) { "https://sentrytest.gitlab.com/api/0/groups/#{sentry_issue_id}/integrations/#{integration_id}/" }
+ let(:issue_link_sample_response) { JSON.parse(fixture_file('sentry/global_integration_link_sample_response.json')) }
let(:sentry_api_response) { issue_link_sample_response }
let!(:sentry_api_request) { stub_sentry_request(sentry_issue_link_url, :put, body: sentry_api_response, status: 201) }
@@ -37,5 +37,29 @@ describe Sentry::Client::IssueLink do
it_behaves_like 'maps Sentry exceptions', :put
end
+
+ context 'when integration_id is not provided' do
+ let(:sentry_issue_link_url) { "https://sentrytest.gitlab.com/api/0/issues/#{sentry_issue_id}/plugins/gitlab/link/" }
+ let(:integration_id) { nil }
+
+ let(:issue_link_sample_response) { JSON.parse(fixture_file('sentry/plugin_link_sample_response.json')) }
+ let!(:sentry_api_request) { stub_sentry_request(sentry_issue_link_url, :post, body: sentry_api_response) }
+
+ it_behaves_like 'calls sentry api'
+
+ it { is_expected.to be_present }
+
+ context 'redirects' do
+ let(:sentry_api_url) { sentry_issue_link_url }
+
+ it_behaves_like 'no Sentry redirects', :post
+ end
+
+ context 'when exception is raised' do
+ let(:sentry_request_url) { sentry_issue_link_url }
+
+ it_behaves_like 'maps Sentry exceptions', :post
+ end
+ end
end
end
diff --git a/spec/lib/sentry/client/issue_spec.rb b/spec/lib/sentry/client/issue_spec.rb
index 2762c5b5cb9..061ebcfdc06 100644
--- a/spec/lib/sentry/client/issue_spec.rb
+++ b/spec/lib/sentry/client/issue_spec.rb
@@ -8,7 +8,7 @@ describe Sentry::Client::Issue do
let(:token) { 'test-token' }
let(:sentry_url) { 'https://sentrytest.gitlab.com/api/0' }
let(:client) { Sentry::Client.new(sentry_url, token) }
- let(:issue_id) { 11 }
+ let(:issue_id) { 503504 }
describe '#list_issues' do
shared_examples 'issues have correct return type' do |klass|
@@ -243,7 +243,7 @@ describe Sentry::Client::Issue do
end
it 'has a correct external URL' do
- expect(subject.external_url).to eq('https://sentrytest.gitlab.com/api/0/issues/11')
+ expect(subject.external_url).to eq('https://sentrytest.gitlab.com/api/0/issues/503504')
end
it 'issue has a correct external base url' do
diff --git a/spec/requests/api/users_spec.rb b/spec/requests/api/users_spec.rb
index 5af56aa6f75..4438d3aab82 100644
--- a/spec/requests/api/users_spec.rb
+++ b/spec/requests/api/users_spec.rb
@@ -2100,6 +2100,83 @@ describe API::Users do
end
end
+ describe "GET /users/:id/memberships" do
+ let_it_be(:user) { create(:user) }
+ let_it_be(:project) { create(:project) }
+ let_it_be(:group) { create(:group) }
+ let(:requesting_user) { create(:user) }
+
+ before_all do
+ project.add_guest(user)
+ group.add_guest(user)
+ end
+
+ it "responses with 403" do
+ get api("/users/#{user.id}/memberships", requesting_user)
+
+ expect(response).to have_gitlab_http_status(:forbidden)
+ end
+
+ context 'requested by admin user' do
+ let(:requesting_user) { create(:user, :admin) }
+
+ it "responses successfully" do
+ get api("/users/#{user.id}/memberships", requesting_user)
+
+ aggregate_failures 'expect successful response including groups and projects' do
+ expect(response).to have_gitlab_http_status(:ok)
+ expect(response).to match_response_schema('public_api/v4/memberships')
+ expect(response).to include_pagination_headers
+ expect(json_response).to contain_exactly(
+ a_hash_including('source_type' => 'Project'),
+ a_hash_including('source_type' => 'Namespace')
+ )
+ end
+ end
+
+ it 'does not submit N+1 DB queries' do
+ # Avoid setup queries
+ get api("/users/#{user.id}/memberships", requesting_user)
+
+ control = ActiveRecord::QueryRecorder.new do
+ get api("/users/#{user.id}/memberships", requesting_user)
+ end
+
+ create_list(:project, 5).map { |project| project.add_guest(user) }
+
+ expect do
+ get api("/users/#{user.id}/memberships", requesting_user)
+ end.not_to exceed_query_limit(control)
+ end
+
+ context 'with type filter' do
+ it "only returns project memberships" do
+ get api("/users/#{user.id}/memberships?type=Project", requesting_user)
+
+ aggregate_failures do
+ expect(json_response).to contain_exactly(a_hash_including('source_type' => 'Project'))
+ expect(json_response).not_to include(a_hash_including('source_type' => 'Namespace'))
+ end
+ end
+
+ it "only returns group memberships" do
+ get api("/users/#{user.id}/memberships?type=Namespace", requesting_user)
+
+ aggregate_failures do
+ expect(json_response).to contain_exactly(a_hash_including('source_type' => 'Namespace'))
+ expect(json_response).not_to include(a_hash_including('source_type' => 'Project'))
+ end
+ end
+
+ it "recognizes unsupported types" do
+ get api("/users/#{user.id}/memberships?type=foo", requesting_user)
+
+ expect(response).to have_gitlab_http_status(:bad_request)
+ end
+ end
+ end
+ end
+
context "user activities", :clean_gitlab_redis_shared_state do
let!(:old_active_user) { create(:user, last_activity_on: Time.utc(2000, 1, 1)) }
let!(:newly_active_user) { create(:user, last_activity_on: 2.days.ago.midday) }
diff --git a/spec/support/shared_contexts/features/error_tracking_shared_context.rb b/spec/support/shared_contexts/features/error_tracking_shared_context.rb
deleted file mode 100644
index 230554ce7ac..00000000000
--- a/spec/support/shared_contexts/features/error_tracking_shared_context.rb
+++ /dev/null
@@ -1,23 +0,0 @@
-# frozen_string_literal: true
-
-shared_context 'sentry error tracking context feature' do
- include ReactiveCachingHelpers
-
- let_it_be(:project) { create(:project) }
- let_it_be(:project_error_tracking_settings) { create(:project_error_tracking_setting, project: project) }
- let_it_be(:issue_response_body) { fixture_file('sentry/issue_sample_response.json') }
- let_it_be(:issue_response) { JSON.parse(issue_response_body) }
- let_it_be(:event_response_body) { fixture_file('sentry/issue_latest_event_sample_response.json') }
- let_it_be(:event_response) { JSON.parse(event_response_body) }
- let(:sentry_api_urls) { Sentry::ApiUrls.new(project_error_tracking_settings.api_url) }
- let(:issue_id) { issue_response['id'] }
-
- before do
- stub_request(:get, sentry_api_urls.issue_url(issue_id)).with(
- headers: { 'Authorization' => 'Bearer access_token_123' }
- ).to_return(status: 200, body: issue_response_body, headers: { 'Content-Type' => 'application/json' })
- stub_request(:get, sentry_api_urls.issue_latest_event_url(issue_id)).with(
- headers: { 'Authorization' => 'Bearer access_token_123' }
- ).to_return(status: 200, body: event_response_body, headers: { 'Content-Type' => 'application/json' })
- end
-end
diff --git a/spec/support/shared_examples/features/error_tracking_shared_example.rb b/spec/support/shared_examples/features/error_tracking_shared_example.rb
deleted file mode 100644
index 4343ffe9255..00000000000
--- a/spec/support/shared_examples/features/error_tracking_shared_example.rb
+++ /dev/null
@@ -1,86 +0,0 @@
-# frozen_string_literal: true
-
-shared_examples 'error tracking index page' do
- it 'renders the error index page' do
- within('div.js-title-container') do
- expect(page).to have_content(project.namespace.name)
- expect(page).to have_content(project.name)
- end
-
- within('div.error-list') do
- expect(page).to have_content('Error')
- expect(page).to have_content('Events')
- expect(page).to have_content('Users')
- expect(page).to have_content('Last Seen')
- end
- end
-
- it 'renders the error index data' do
- Timecop.freeze(2020, 01, 01, 12, 0, 0) do
- within('div.error-list') do
- expect(page).to have_content(issues_response[0]['title'])
- expect(page).to have_content(issues_response[0]['count'].to_s)
- expect(page).to have_content(issues_response[0]['last_seen'])
- expect(page).to have_content('1 year ago')
- end
- end
- end
-
- context 'when error is clicked' do
- before do
- click_on issues_response[0]['title']
- end
-
- it 'loads the error page' do
- expect(page).to have_content('Error details')
- end
- end
-end
-
-shared_examples 'expanded stack trace context' do |selected_line: nil, expected_line: 1|
- it 'expands the stack trace context' do
- within('div.stacktrace') do
- find("div.file-holder:nth-child(#{selected_line}) svg.ic-chevron-right").click if selected_line
-
- expanded_line = find("div.file-holder:nth-child(#{expected_line})")
- expect(expanded_line).to have_css('svg.ic-chevron-down')
-
- event_response['entries'][0]['data']['values'][0]['stacktrace']['frames'][-expected_line]['context'].each do |context|
- expect(page).to have_content(context[0])
- end
- end
- end
-end
-
-shared_examples 'error tracking show page' do
- it 'renders the error details' do
- release_short_version = issue_response['firstRelease']['shortVersion']
-
- Timecop.freeze(2020, 01, 01, 12, 0, 0) do
- expect(page).to have_content('1 month ago by raven.scripts.runner in main')
- expect(page).to have_content(issue_response['metadata']['title'])
- expect(page).to have_content('level: error')
- expect(page).to have_content('Error details')
- expect(page).to have_content('GitLab Issue: https://gitlab.com/gitlab-org/gitlab/issues/1')
- expect(page).to have_content("Sentry event: https://sentrytest.gitlab.com/sentry-org/sentry-project/issues/#{issue_id}")
- expect(page).to have_content("First seen: 1 year ago (2018-11-06 9:19:55PM UTC) Release: #{release_short_version}")
- expect(page).to have_content('Events: 1')
- expect(page).to have_content('Users: 0')
- end
- end
-
- it 'renders the stack trace heading' do
- expect(page).to have_content('Stack trace')
- end
-
- it 'renders the stack trace' do
- event_response['entries'][0]['data']['values'][0]['stacktrace']['frames'].each do |frame|
- expect(frame['filename']).not_to be_nil
- expect(page).to have_content(frame['filename'])
- end
- end
-
- # The first line is expanded by default if no line is selected
- it_behaves_like 'expanded stack trace context', selected_line: nil, expected_line: 1
- it_behaves_like 'expanded stack trace context', selected_line: 8, expected_line: 8
-end
diff --git a/spec/workers/error_tracking_issue_link_worker_spec.rb b/spec/workers/error_tracking_issue_link_worker_spec.rb
index cf16e4a0803..b9206e7e12c 100644
--- a/spec/workers/error_tracking_issue_link_worker_spec.rb
+++ b/spec/workers/error_tracking_issue_link_worker_spec.rb
@@ -40,14 +40,17 @@ describe ErrorTrackingIssueLinkWorker do
end
end
- shared_examples_for 'terminates after one API request' do
+ shared_examples_for 'attempts to create a link via plugin' do
it 'takes no action' do
expect_next_instance_of(Sentry::Client) do |client|
expect(client).to receive(:repos).with('sentry-org').and_return([repo])
+ expect(client)
+ .to receive(:create_issue_link)
+ .with(nil, sentry_issue.sentry_issue_identifier, issue)
+ .and_return(true)
end
- expect_any_instance_of(Sentry::Client).not_to receive(:create_issue_link)
- expect(subject).to be nil
+ expect(subject).to be true
end
end
@@ -78,7 +81,7 @@ describe ErrorTrackingIssueLinkWorker do
)
end
- it_behaves_like 'terminates after one API request'
+ it_behaves_like 'attempts to create a link via plugin'
end
context 'when Sentry the GitLab integration is for another project' do
@@ -90,7 +93,7 @@ describe ErrorTrackingIssueLinkWorker do
)
end
- it_behaves_like 'terminates after one API request'
+ it_behaves_like 'attempts to create a link via plugin'
end
end
end