Add latest changes from gitlab-org/gitlab@master
This commit is contained in:
parent
c1892df2eb
commit
11a29f1f02
|
|
@ -165,12 +165,15 @@
|
|||
/.gitlab/ci/ @gl-quality/eng-prod
|
||||
/.gitlab/ci/docs.gitlab-ci.yml @gl-quality/eng-prod @gl-docsteam
|
||||
/.gitlab/ci/releases.gitlab-ci.yml @gl-quality/eng-prod @gitlab-org/delivery
|
||||
/.gitlab/ci/dast.gitlab-ci.yml @dappelt @ngeorge1 @gl-quality/eng-prod
|
||||
/.gitlab/ci/reports.gitlab-ci.yml @gitlab-com/gl-security/appsec @gl-quality/eng-prod
|
||||
/.gitlab/CODEOWNERS @gl-quality/eng-prod
|
||||
Dangerfile @gl-quality/eng-prod
|
||||
/danger/ @gl-quality/eng-prod
|
||||
/lib/gitlab/danger/ @gl-quality/eng-prod
|
||||
/scripts/ @gl-quality/eng-prod
|
||||
/scripts/frontend/ @gl-quality/eng-prod @gitlab-org/maintainers/frontend
|
||||
/scripts/review_apps/seed-dast-test-data.sh @dappelt @ngeorge1 @gl-quality/eng-prod
|
||||
.editorconfig @gl-quality/eng-prod
|
||||
|
||||
[End-to-end]
|
||||
|
|
|
|||
|
|
@ -496,11 +496,12 @@ rspec foss-impact:
|
|||
- .rails:rules:ee-mr-only
|
||||
script:
|
||||
- install_gitlab_gem
|
||||
- install_tff_gem
|
||||
- run_timed_command "scripts/gitaly-test-build"
|
||||
- run_timed_command "scripts/gitaly-test-spawn"
|
||||
- source scripts/rspec_helpers.sh
|
||||
- tooling/bin/find_foss_tests tmp/matching_foss_tests.txt
|
||||
- rspec_matched_tests tmp/matching_foss_tests.txt "--tag ~quarantine"
|
||||
- rspec_matched_foss_tests tmp/matching_foss_tests.txt "--tag ~quarantine"
|
||||
artifacts:
|
||||
expire_in: 7d
|
||||
paths:
|
||||
|
|
|
|||
|
|
@ -149,6 +149,7 @@
|
|||
- "*_VERSION"
|
||||
- "Gemfile{,.lock}"
|
||||
- "Rakefile"
|
||||
- "tests.yml"
|
||||
- "config.ru"
|
||||
- "{,ee/}{app,bin,config,db,haml_lint,lib,locale,public,scripts,symbol,vendor}/**/*"
|
||||
- "doc/api/graphql/reference/*" # Files in this folder are auto-generated
|
||||
|
|
@ -170,6 +171,7 @@
|
|||
- "*_VERSION"
|
||||
- "Gemfile{,.lock}"
|
||||
- "Rakefile"
|
||||
- "tests.yml"
|
||||
- "config.ru"
|
||||
- "{,ee/}{app,bin,config,db,haml_lint,lib,locale,public,scripts,symbol,vendor}/**/*"
|
||||
- "doc/api/graphql/reference/*" # Files in this folder are auto-generated
|
||||
|
|
@ -193,6 +195,7 @@
|
|||
- "*_VERSION"
|
||||
- "Gemfile{,.lock}"
|
||||
- "Rakefile"
|
||||
- "tests.yml"
|
||||
- "config.ru"
|
||||
- "{,ee/}{app,bin,config,db,haml_lint,lib,locale,public,scripts,symbol,vendor}/**/*"
|
||||
- "doc/api/graphql/reference/*" # Files in this folder are auto-generated
|
||||
|
|
@ -213,6 +216,7 @@
|
|||
- "*_VERSION"
|
||||
- "Gemfile{,.lock}"
|
||||
- "Rakefile"
|
||||
- "tests.yml"
|
||||
- "config.ru"
|
||||
- "{,ee/}{app,bin,config,db,haml_lint,lib,locale,public,scripts,symbol,vendor}/**/*"
|
||||
- "doc/api/graphql/reference/*" # Files in this folder are auto-generated
|
||||
|
|
@ -762,6 +766,12 @@
|
|||
changes: *code-backstage-patterns
|
||||
when: on_success
|
||||
|
||||
.setup:rules:verify-tests-yml:
|
||||
rules:
|
||||
- <<: *if-default-refs
|
||||
changes: *code-backstage-patterns
|
||||
when: on_success
|
||||
|
||||
#######################
|
||||
# Test metadata rules #
|
||||
#######################
|
||||
|
|
|
|||
|
|
@ -48,3 +48,14 @@ no_ee_check:
|
|||
stage: test
|
||||
script:
|
||||
- scripts/no-ee-check
|
||||
|
||||
verify-tests-yml:
|
||||
extends:
|
||||
- .setup:rules:verify-tests-yml
|
||||
image: ruby:2.6-alpine
|
||||
stage: test
|
||||
needs: []
|
||||
script:
|
||||
- source scripts/utils.sh
|
||||
- install_tff_gem
|
||||
- scripts/verify-tff-mapping
|
||||
|
|
|
|||
|
|
@ -2,14 +2,6 @@
|
|||
documentation](doc/development/changelog.md) for instructions on adding your own
|
||||
entry.
|
||||
|
||||
## 13.3.1 (2020-08-25)
|
||||
|
||||
### Fixed (2 changes)
|
||||
|
||||
- Fix bug when promoting an Issue with attachments to an Epic. !39654
|
||||
- Avoid creating diff position when line-code is nil. !40089
|
||||
|
||||
|
||||
## 13.3.0 (2020-08-22)
|
||||
|
||||
### Security (2 changes)
|
||||
|
|
|
|||
|
|
@ -102,12 +102,12 @@ export default {
|
|||
</a>
|
||||
<span class="note-headline-light note-headline-meta">
|
||||
<span class="system-note-message"> <slot></slot> </span>
|
||||
<template v-if="note.createdAt">
|
||||
<span class="system-note-separator"></span>
|
||||
<a class="note-timestamp system-note-separator" :href="`#note_${noteAnchorId}`">
|
||||
<time-ago-tooltip :time="note.createdAt" tooltip-placement="bottom" />
|
||||
</a>
|
||||
</template>
|
||||
<a
|
||||
class="note-timestamp system-note-separator gl-display-block gl-mb-2"
|
||||
:href="`#note_${noteAnchorId}`"
|
||||
>
|
||||
<time-ago-tooltip :time="note.createdAt" tooltip-placement="bottom" />
|
||||
</a>
|
||||
</span>
|
||||
</div>
|
||||
<div class="gl-display-flex">
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
<script>
|
||||
import { GlButton } from '@gitlab/ui';
|
||||
import { n__ } from '~/locale';
|
||||
import { stripHtml } from '~/lib/utils/text_utility';
|
||||
import statusIcon from '../mr_widget_status_icon.vue';
|
||||
|
|
@ -8,6 +9,7 @@ export default {
|
|||
name: 'MRWidgetFailedToMerge',
|
||||
|
||||
components: {
|
||||
GlButton,
|
||||
statusIcon,
|
||||
},
|
||||
|
||||
|
|
@ -84,14 +86,14 @@ export default {
|
|||
<span v-else> {{ s__('mrWidget|Merge failed.') }} </span>
|
||||
<span :class="{ 'has-custom-error': mr.mergeError }"> {{ timerText }} </span>
|
||||
</span>
|
||||
<button
|
||||
class="btn btn-default btn-sm js-refresh-button"
|
||||
<gl-button
|
||||
size="small"
|
||||
data-testid="merge-request-failed-refresh-button"
|
||||
data-qa-selector="merge_request_error_content"
|
||||
type="button"
|
||||
@click="refresh"
|
||||
>
|
||||
{{ s__('mrWidget|Refresh now') }}
|
||||
</button>
|
||||
</gl-button>
|
||||
</div>
|
||||
</template>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -110,10 +110,6 @@
|
|||
|
||||
.dark-well {
|
||||
background-color: $gray-normal;
|
||||
|
||||
.btn {
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
.card.card-body-centered {
|
||||
|
|
|
|||
|
|
@ -70,9 +70,19 @@ module Types
|
|||
description: 'Text to echo back',
|
||||
resolver: Resolvers::EchoResolver
|
||||
|
||||
field :issue, Types::IssueType,
|
||||
null: true,
|
||||
description: 'Find an issue' do
|
||||
argument :id, ::Types::GlobalIDType[::Issue], required: true, description: 'The global ID of the Issue'
|
||||
end
|
||||
|
||||
def design_management
|
||||
DesignManagementObject.new(nil)
|
||||
end
|
||||
|
||||
def issue(id:)
|
||||
GitlabSchema.object_from_id(id, expected_type: ::Issue)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
|||
|
|
@ -13,14 +13,14 @@
|
|||
.admin-dashboard.gl-mt-3
|
||||
.row
|
||||
.col-sm-4
|
||||
.info-well.dark-well
|
||||
.info-well.dark-well.flex-fill
|
||||
.well-segment.well-centered
|
||||
= link_to admin_projects_path do
|
||||
%h3.text-center
|
||||
Projects:
|
||||
= approximate_count_with_delimiters(@counts, Project)
|
||||
%hr
|
||||
= link_to('New project', new_project_path, class: "btn btn-success")
|
||||
= link_to('New project', new_project_path, class: "btn btn-success gl-w-full")
|
||||
.col-sm-4
|
||||
.info-well.dark-well
|
||||
.well-segment.well-centered
|
||||
|
|
@ -30,8 +30,8 @@
|
|||
= approximate_count_with_delimiters(@counts, User)
|
||||
%hr
|
||||
.btn-group.d-flex{ role: 'group' }
|
||||
= link_to 'New user', new_admin_user_path, class: "btn btn-success"
|
||||
= link_to s_('AdminArea|Users statistics'), admin_dashboard_stats_path, class: 'btn btn-primary'
|
||||
= link_to 'New user', new_admin_user_path, class: "btn btn-success gl-w-full"
|
||||
= link_to s_('AdminArea|Users statistics'), admin_dashboard_stats_path, class: 'btn btn-primary gl-w-full'
|
||||
.col-sm-4
|
||||
.info-well.dark-well
|
||||
.well-segment.well-centered
|
||||
|
|
@ -40,7 +40,7 @@
|
|||
Groups:
|
||||
= approximate_count_with_delimiters(@counts, Group)
|
||||
%hr
|
||||
= link_to 'New group', new_admin_group_path, class: "btn btn-success"
|
||||
= link_to 'New group', new_admin_group_path, class: "btn btn-success gl-w-full"
|
||||
.row
|
||||
.col-md-4
|
||||
#js-admin-statistics-container
|
||||
|
|
|
|||
|
|
@ -1,7 +1,8 @@
|
|||
- page_title _("FogBugz Import")
|
||||
- header_title _("Projects"), root_path
|
||||
%h3.page-title
|
||||
%i.fa.fa-bug
|
||||
%h3.page-title.d-flex
|
||||
.gl-display-flex.gl-align-items-center.gl-justify-content-center
|
||||
= sprite_icon('bug', css_class: 'gl-mr-2')
|
||||
= _('Import projects from FogBugz')
|
||||
%hr
|
||||
|
||||
|
|
|
|||
|
|
@ -1,7 +1,8 @@
|
|||
- page_title _('User map'), _('FogBugz import')
|
||||
- header_title _("Projects"), root_path
|
||||
%h3.page-title
|
||||
%i.fa.fa-bug
|
||||
%h3.page-title.d-flex
|
||||
.gl-display-flex.gl-align-items-center.gl-justify-content-center
|
||||
= sprite_icon('bug', css_class: 'gl-mr-2')
|
||||
= _('Import projects from FogBugz')
|
||||
%hr
|
||||
|
||||
|
|
|
|||
|
|
@ -1,7 +1,8 @@
|
|||
- page_title _("FogBugz import")
|
||||
- header_title _("Projects"), root_path
|
||||
%h3.page-title
|
||||
%i.fa.fa-bug
|
||||
%h3.page-title.d-flex
|
||||
.gl-display-flex.gl-align-items-center.gl-justify-content-center
|
||||
= sprite_icon('bug', css_class: 'gl-mr-2')
|
||||
= _('Import projects from FogBugz')
|
||||
|
||||
%p.light
|
||||
|
|
|
|||
|
|
@ -46,7 +46,8 @@
|
|||
- if fogbugz_import_enabled?
|
||||
%div
|
||||
= link_to new_import_fogbugz_path, class: 'btn import_fogbugz', **tracking_attrs(track_label, 'click_button', 'fogbugz') do
|
||||
= icon('bug', text: 'FogBugz')
|
||||
= sprite_icon('bug')
|
||||
FogBugz
|
||||
|
||||
- if gitea_import_enabled?
|
||||
%div
|
||||
|
|
|
|||
|
|
@ -0,0 +1,5 @@
|
|||
---
|
||||
title: 'Resolve Design comments: Text wrapping behavior'
|
||||
merge_request: 40359
|
||||
author:
|
||||
type: fixed
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
---
|
||||
title: Replace fa-bugs icons with GitLab SVG bug icon
|
||||
merge_request: 40273
|
||||
author:
|
||||
type: changed
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
---
|
||||
title: Migrate Bootstrap button to GitLab UI GlButton in mr_widget_failed_to_merge
|
||||
merge_request: 40170
|
||||
author:
|
||||
type: other
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
---
|
||||
title: Add ability to get an Issue using GraphQL and REST API
|
||||
merge_request: 35176
|
||||
author:
|
||||
type: added
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
---
|
||||
title: Avoid creating diff position when line-code is nil
|
||||
merge_request: 40089
|
||||
author:
|
||||
type: fixed
|
||||
|
|
@ -7222,6 +7222,11 @@ type IssueEdge {
|
|||
node: Issue
|
||||
}
|
||||
|
||||
"""
|
||||
Identifier of Issue
|
||||
"""
|
||||
scalar IssueID
|
||||
|
||||
"""
|
||||
Autogenerated input type of IssueMoveList
|
||||
"""
|
||||
|
|
@ -12507,6 +12512,16 @@ type Query {
|
|||
"""
|
||||
instanceSecurityDashboard: InstanceSecurityDashboard
|
||||
|
||||
"""
|
||||
Find an issue
|
||||
"""
|
||||
issue(
|
||||
"""
|
||||
The global ID of the Issue
|
||||
"""
|
||||
id: IssueID!
|
||||
): Issue
|
||||
|
||||
"""
|
||||
Find an iteration
|
||||
"""
|
||||
|
|
|
|||
|
|
@ -19963,6 +19963,16 @@
|
|||
"enumValues": null,
|
||||
"possibleTypes": null
|
||||
},
|
||||
{
|
||||
"kind": "SCALAR",
|
||||
"name": "IssueID",
|
||||
"description": "Identifier of Issue",
|
||||
"fields": null,
|
||||
"inputFields": null,
|
||||
"interfaces": null,
|
||||
"enumValues": null,
|
||||
"possibleTypes": null
|
||||
},
|
||||
{
|
||||
"kind": "INPUT_OBJECT",
|
||||
"name": "IssueMoveListInput",
|
||||
|
|
@ -36856,6 +36866,33 @@
|
|||
"isDeprecated": false,
|
||||
"deprecationReason": null
|
||||
},
|
||||
{
|
||||
"name": "issue",
|
||||
"description": "Find an issue",
|
||||
"args": [
|
||||
{
|
||||
"name": "id",
|
||||
"description": "The global ID of the Issue",
|
||||
"type": {
|
||||
"kind": "NON_NULL",
|
||||
"name": null,
|
||||
"ofType": {
|
||||
"kind": "SCALAR",
|
||||
"name": "IssueID",
|
||||
"ofType": null
|
||||
}
|
||||
},
|
||||
"defaultValue": null
|
||||
}
|
||||
],
|
||||
"type": {
|
||||
"kind": "OBJECT",
|
||||
"name": "Issue",
|
||||
"ofType": null
|
||||
},
|
||||
"isDeprecated": false,
|
||||
"deprecationReason": null
|
||||
},
|
||||
{
|
||||
"name": "iteration",
|
||||
"description": "Find an iteration",
|
||||
|
|
|
|||
|
|
@ -564,6 +564,320 @@ the issue still exists.
|
|||
|
||||
## Single issue
|
||||
|
||||
Only for administrators. Get a single issue.
|
||||
|
||||
The preferred way to do this is by using [personal access tokens](../user/profile/personal_access_tokens.md).
|
||||
|
||||
```plaintext
|
||||
GET /issues/:id
|
||||
```
|
||||
|
||||
| Attribute | Type | Required | Description |
|
||||
|-------------|---------|----------|--------------------------------------|
|
||||
| `id` | integer | yes | The ID of the issue |
|
||||
|
||||
```shell
|
||||
curl --header "PRIVATE-TOKEN: <your_access_token>" "https://gitlab.example.com/api/v4/issues/41"
|
||||
```
|
||||
|
||||
Example response:
|
||||
|
||||
```json
|
||||
{
|
||||
"id" : 1,
|
||||
"milestone" : {
|
||||
"due_date" : null,
|
||||
"project_id" : 4,
|
||||
"state" : "closed",
|
||||
"description" : "Rerum est voluptatem provident consequuntur molestias similique ipsum dolor.",
|
||||
"iid" : 3,
|
||||
"id" : 11,
|
||||
"title" : "v3.0",
|
||||
"created_at" : "2016-01-04T15:31:39.788Z",
|
||||
"updated_at" : "2016-01-04T15:31:39.788Z",
|
||||
"closed_at" : "2016-01-05T15:31:46.176Z"
|
||||
},
|
||||
"author" : {
|
||||
"state" : "active",
|
||||
"web_url" : "https://gitlab.example.com/root",
|
||||
"avatar_url" : null,
|
||||
"username" : "root",
|
||||
"id" : 1,
|
||||
"name" : "Administrator"
|
||||
},
|
||||
"description" : "Omnis vero earum sunt corporis dolor et placeat.",
|
||||
"state" : "closed",
|
||||
"iid" : 1,
|
||||
"assignees" : [{
|
||||
"avatar_url" : null,
|
||||
"web_url" : "https://gitlab.example.com/lennie",
|
||||
"state" : "active",
|
||||
"username" : "lennie",
|
||||
"id" : 9,
|
||||
"name" : "Dr. Luella Kovacek"
|
||||
}],
|
||||
"assignee" : {
|
||||
"avatar_url" : null,
|
||||
"web_url" : "https://gitlab.example.com/lennie",
|
||||
"state" : "active",
|
||||
"username" : "lennie",
|
||||
"id" : 9,
|
||||
"name" : "Dr. Luella Kovacek"
|
||||
},
|
||||
"labels" : [],
|
||||
"upvotes": 4,
|
||||
"downvotes": 0,
|
||||
"merge_requests_count": 0,
|
||||
"title" : "Ut commodi ullam eos dolores perferendis nihil sunt.",
|
||||
"updated_at" : "2016-01-04T15:31:46.176Z",
|
||||
"created_at" : "2016-01-04T15:31:46.176Z",
|
||||
"closed_at" : null,
|
||||
"closed_by" : null,
|
||||
"subscribed": false,
|
||||
"user_notes_count": 1,
|
||||
"due_date": null,
|
||||
"web_url": "http://example.com/my-group/my-project/issues/1",
|
||||
"references": {
|
||||
"short": "#1",
|
||||
"relative": "#1",
|
||||
"full": "my-group/my-project#1"
|
||||
},
|
||||
"time_stats": {
|
||||
"time_estimate": 0,
|
||||
"total_time_spent": 0,
|
||||
"human_time_estimate": null,
|
||||
"human_total_time_spent": null
|
||||
},
|
||||
"confidential": false,
|
||||
"discussion_locked": false,
|
||||
"_links": {
|
||||
"self": "http://example.com/api/v4/projects/1/issues/2",
|
||||
"notes": "http://example.com/api/v4/projects/1/issues/2/notes",
|
||||
"award_emoji": "http://example.com/api/v4/projects/1/issues/2/award_emoji",
|
||||
"project": "http://example.com/api/v4/projects/1"
|
||||
},
|
||||
"task_completion_status":{
|
||||
"count":0,
|
||||
"completed_count":0
|
||||
},
|
||||
"weight": null,
|
||||
"has_tasks": false,
|
||||
"_links": {
|
||||
"self": "http://gitlab.dummy:3000/api/v4/projects/1/issues/1",
|
||||
"notes": "http://gitlab.dummy:3000/api/v4/projects/1/issues/1/notes",
|
||||
"award_emoji": "http://gitlab.dummy:3000/api/v4/projects/1/issues/1/award_emoji",
|
||||
"project": "http://gitlab.dummy:3000/api/v4/projects/1"
|
||||
},
|
||||
"references": {
|
||||
"short": "#1",
|
||||
"relative": "#1",
|
||||
"full": "gitlab-org/gitlab-test#1"
|
||||
},
|
||||
"subscribed": true,
|
||||
"moved_to_id": null,
|
||||
"epic_iid": null,
|
||||
"epic": null
|
||||
}
|
||||
```
|
||||
|
||||
Users on GitLab [Starter, Bronze, or higher](https://about.gitlab.com/pricing/) will also see
|
||||
the `weight` parameter:
|
||||
|
||||
```json
|
||||
{
|
||||
"project_id" : 4,
|
||||
"description" : "Omnis vero earum sunt corporis dolor et placeat.",
|
||||
"weight": null,
|
||||
...
|
||||
}
|
||||
```
|
||||
|
||||
Users on GitLab [Ultimate](https://about.gitlab.com/pricing/) will additionally see
|
||||
the `epic` property:
|
||||
|
||||
```javascript
|
||||
{
|
||||
"project_id" : 4,
|
||||
"description" : "Omnis vero earum sunt corporis dolor et placeat.",
|
||||
"epic": {
|
||||
"epic_iid" : 5, //deprecated, use `iid` of the `epic` attribute
|
||||
"epic": {
|
||||
"id" : 42,
|
||||
"iid" : 5,
|
||||
"title": "My epic epic",
|
||||
"url" : "/groups/h5bp/-/epics/5",
|
||||
"group_id": 8
|
||||
},
|
||||
// ...
|
||||
}
|
||||
```
|
||||
|
||||
**Note**: `assignee` column is deprecated, now we show it as a single-sized array `assignees` to conform to the GitLab EE API.
|
||||
|
||||
**Note**: The `closed_by` attribute was [introduced in GitLab 10.6](https://gitlab.com/gitlab-org/gitlab-foss/-/merge_requests/17042). This value will only be present for issues which were closed after GitLab 10.6 and when the user account that closed the issue still exists.
|
||||
|
||||
**Note**: The `epic_iid` attribute is deprecated and [will be removed in version 5](https://gitlab.com/gitlab-org/gitlab/-/issues/35157).
|
||||
Please use `iid` of the `epic` attribute instead.
|
||||
|
||||
## Single Issue
|
||||
|
||||
Only for administrators. Get a single issue.
|
||||
|
||||
The preferred way to do this is by using [personal access tokens](../user/profile/personal_access_tokens.md).
|
||||
|
||||
```plaintext
|
||||
GET /issues/:id
|
||||
```
|
||||
|
||||
| Attribute | Type | Required | Description |
|
||||
|-------------|---------|----------|--------------------------------------|
|
||||
| `id` | integer | yes | The ID of the issue |
|
||||
|
||||
```shell
|
||||
curl --header "PRIVATE-TOKEN: <your_access_token>" "https://gitlab.example.com/api/v4/issues/41"
|
||||
```
|
||||
|
||||
Example response:
|
||||
|
||||
```json
|
||||
{
|
||||
"id" : 1,
|
||||
"milestone" : {
|
||||
"due_date" : null,
|
||||
"project_id" : 4,
|
||||
"state" : "closed",
|
||||
"description" : "Rerum est voluptatem provident consequuntur molestias similique ipsum dolor.",
|
||||
"iid" : 3,
|
||||
"id" : 11,
|
||||
"title" : "v3.0",
|
||||
"created_at" : "2016-01-04T15:31:39.788Z",
|
||||
"updated_at" : "2016-01-04T15:31:39.788Z",
|
||||
"closed_at" : "2016-01-05T15:31:46.176Z"
|
||||
},
|
||||
"author" : {
|
||||
"state" : "active",
|
||||
"web_url" : "https://gitlab.example.com/root",
|
||||
"avatar_url" : null,
|
||||
"username" : "root",
|
||||
"id" : 1,
|
||||
"name" : "Administrator"
|
||||
},
|
||||
"description" : "Omnis vero earum sunt corporis dolor et placeat.",
|
||||
"state" : "closed",
|
||||
"iid" : 1,
|
||||
"assignees" : [{
|
||||
"avatar_url" : null,
|
||||
"web_url" : "https://gitlab.example.com/lennie",
|
||||
"state" : "active",
|
||||
"username" : "lennie",
|
||||
"id" : 9,
|
||||
"name" : "Dr. Luella Kovacek"
|
||||
}],
|
||||
"assignee" : {
|
||||
"avatar_url" : null,
|
||||
"web_url" : "https://gitlab.example.com/lennie",
|
||||
"state" : "active",
|
||||
"username" : "lennie",
|
||||
"id" : 9,
|
||||
"name" : "Dr. Luella Kovacek"
|
||||
},
|
||||
"labels" : [],
|
||||
"upvotes": 4,
|
||||
"downvotes": 0,
|
||||
"merge_requests_count": 0,
|
||||
"title" : "Ut commodi ullam eos dolores perferendis nihil sunt.",
|
||||
"updated_at" : "2016-01-04T15:31:46.176Z",
|
||||
"created_at" : "2016-01-04T15:31:46.176Z",
|
||||
"closed_at" : null,
|
||||
"closed_by" : null,
|
||||
"subscribed": false,
|
||||
"user_notes_count": 1,
|
||||
"due_date": null,
|
||||
"web_url": "http://example.com/my-group/my-project/issues/1",
|
||||
"references": {
|
||||
"short": "#1",
|
||||
"relative": "#1",
|
||||
"full": "my-group/my-project#1"
|
||||
},
|
||||
"time_stats": {
|
||||
"time_estimate": 0,
|
||||
"total_time_spent": 0,
|
||||
"human_time_estimate": null,
|
||||
"human_total_time_spent": null
|
||||
},
|
||||
"confidential": false,
|
||||
"discussion_locked": false,
|
||||
"_links": {
|
||||
"self": "http://example.com/api/v4/projects/1/issues/2",
|
||||
"notes": "http://example.com/api/v4/projects/1/issues/2/notes",
|
||||
"award_emoji": "http://example.com/api/v4/projects/1/issues/2/award_emoji",
|
||||
"project": "http://example.com/api/v4/projects/1"
|
||||
},
|
||||
"task_completion_status":{
|
||||
"count":0,
|
||||
"completed_count":0
|
||||
},
|
||||
"weight": null,
|
||||
"has_tasks": false,
|
||||
"_links": {
|
||||
"self": "http://gitlab.dummy:3000/api/v4/projects/1/issues/1",
|
||||
"notes": "http://gitlab.dummy:3000/api/v4/projects/1/issues/1/notes",
|
||||
"award_emoji": "http://gitlab.dummy:3000/api/v4/projects/1/issues/1/award_emoji",
|
||||
"project": "http://gitlab.dummy:3000/api/v4/projects/1"
|
||||
},
|
||||
"references": {
|
||||
"short": "#1",
|
||||
"relative": "#1",
|
||||
"full": "gitlab-org/gitlab-test#1"
|
||||
},
|
||||
"subscribed": true,
|
||||
"moved_to_id": null,
|
||||
"epic_iid": null,
|
||||
"epic": null
|
||||
}
|
||||
```
|
||||
|
||||
Users on GitLab [Starter, Bronze, or higher](https://about.gitlab.com/pricing/) will also see
|
||||
the `weight` parameter:
|
||||
|
||||
```json
|
||||
{
|
||||
"project_id" : 4,
|
||||
"description" : "Omnis vero earum sunt corporis dolor et placeat.",
|
||||
"weight": null,
|
||||
...
|
||||
}
|
||||
```
|
||||
|
||||
Users on GitLab [Ultimate](https://about.gitlab.com/pricing/) will additionally see
|
||||
the `epic` property:
|
||||
|
||||
```javascript
|
||||
{
|
||||
"project_id" : 4,
|
||||
"description" : "Omnis vero earum sunt corporis dolor et placeat.",
|
||||
"epic": {
|
||||
"epic_iid" : 5, //deprecated, use `iid` of the `epic` attribute
|
||||
"epic": {
|
||||
"id" : 42,
|
||||
"iid" : 5,
|
||||
"title": "My epic epic",
|
||||
"url" : "/groups/h5bp/-/epics/5",
|
||||
"group_id": 8
|
||||
},
|
||||
// ...
|
||||
}
|
||||
```
|
||||
|
||||
**Note**: `assignee` column is deprecated, now we show it as a single-sized array `assignees` to conform to the GitLab EE API.
|
||||
|
||||
**Note**: The `closed_by` attribute was [introduced in GitLab 10.6](https://gitlab.com/gitlab-org/gitlab-foss/-/merge_requests/17042). This value will only be present for issues which were closed after GitLab 10.6 and when the user account that closed the issue still exists.
|
||||
|
||||
**Note**: The `epic_iid` attribute is deprecated and [will be removed in version 5](https://gitlab.com/gitlab-org/gitlab/-/issues/35157).
|
||||
Please use `iid` of the `epic` attribute instead.
|
||||
|
||||
## Single Project Issue
|
||||
|
||||
Get a single project issue.
|
||||
|
||||
If the project is private or the issue is confidential, you need to provide credentials to authorize.
|
||||
|
|
|
|||
|
|
@ -135,8 +135,8 @@ your GitHub repositories are listed.
|
|||
|
||||
## Mirroring and pipeline status sharing
|
||||
|
||||
Depending your GitLab tier, [project mirroring](../repository/repository_mirroring.md) can be set up to keep
|
||||
your imported project in sync with its GitHub copy.
|
||||
Depending on your GitLab tier, [repository mirroring](../repository/repository_mirroring.md) can be set up to keep
|
||||
your imported repository in sync with its GitHub copy.
|
||||
|
||||
Additionally, you can configure GitLab to send pipeline status updates back GitHub with the
|
||||
[GitHub Project Integration](../integrations/github.md). **(PREMIUM)**
|
||||
|
|
|
|||
|
|
@ -114,6 +114,19 @@ module API
|
|||
|
||||
present issues, options
|
||||
end
|
||||
|
||||
desc "Get specified issue (admin only)" do
|
||||
success Entities::Issue
|
||||
end
|
||||
params do
|
||||
requires :id, type: String, desc: 'The ID of the Issue'
|
||||
end
|
||||
get ":id" do
|
||||
authenticated_as_admin!
|
||||
issue = Issue.find(params['id'])
|
||||
|
||||
present issue, with: Entities::Issue, current_user: current_user, project: issue.project
|
||||
end
|
||||
end
|
||||
|
||||
params do
|
||||
|
|
|
|||
|
|
@ -171,6 +171,7 @@ module Gitlab
|
|||
%r{\A(ee/)?scripts/} => :engineering_productivity,
|
||||
%r{\Atooling/} => :engineering_productivity,
|
||||
%r{(CODEOWNERS)} => :engineering_productivity,
|
||||
%r{(tests.yml)} => :engineering_productivity,
|
||||
|
||||
%r{\A(ee/)?spec/features/} => :test,
|
||||
%r{\A(ee/)?spec/support/shared_examples/features/} => :test,
|
||||
|
|
|
|||
|
|
@ -3328,6 +3328,9 @@ msgstr ""
|
|||
msgid "As U2F devices are only supported by a few browsers, we require that you set up a two-factor authentication app before a U2F device. That way you'll always be able to log in - even when you're using an unsupported browser."
|
||||
msgstr ""
|
||||
|
||||
msgid "As we continue to build more features for SAST, we'd love your feedback on the SAST configuration feature in %{linkStart}this issue%{linkEnd}."
|
||||
msgstr ""
|
||||
|
||||
msgid "AsanaService|%{user} pushed to branch %{branch} of %{project_name} ( %{commit_url} ):"
|
||||
msgstr ""
|
||||
|
||||
|
|
@ -14283,6 +14286,9 @@ msgstr ""
|
|||
msgid "License ID:"
|
||||
msgstr ""
|
||||
|
||||
msgid "License overview"
|
||||
msgstr ""
|
||||
|
||||
msgid "License-Check"
|
||||
msgstr ""
|
||||
|
||||
|
|
@ -14409,6 +14415,9 @@ msgstr ""
|
|||
msgid "Licensed to"
|
||||
msgstr ""
|
||||
|
||||
msgid "Licensed to:"
|
||||
msgstr ""
|
||||
|
||||
msgid "Licenses"
|
||||
msgstr ""
|
||||
|
||||
|
|
@ -26979,6 +26988,9 @@ msgstr ""
|
|||
msgid "Users were successfully added."
|
||||
msgstr ""
|
||||
|
||||
msgid "Users with a Guest role or those who don't belong to a Project or Group will not use a seat from your license."
|
||||
msgstr ""
|
||||
|
||||
msgid "Users with a Guest role or those who don't belong to any projects or groups don't count towards seats in use."
|
||||
msgstr ""
|
||||
|
||||
|
|
|
|||
|
|
@ -42,8 +42,8 @@
|
|||
"@babel/plugin-syntax-import-meta": "^7.10.1",
|
||||
"@babel/preset-env": "^7.10.1",
|
||||
"@gitlab/at.js": "1.5.5",
|
||||
"@gitlab/svgs": "1.160.0",
|
||||
"@gitlab/ui": "20.6.0",
|
||||
"@gitlab/svgs": "1.161.0",
|
||||
"@gitlab/ui": "20.8.0",
|
||||
"@gitlab/visual-review-tools": "1.6.1",
|
||||
"@rails/actioncable": "^6.0.3-1",
|
||||
"@sentry/browser": "^5.10.2",
|
||||
|
|
|
|||
|
|
@ -23,7 +23,7 @@ module QA
|
|||
cluster&.remove!
|
||||
end
|
||||
|
||||
it 'runs auto devops' do
|
||||
it 'runs auto devops', status_issue: 'https://gitlab.com/gitlab-org/quality/testcases/-/issues/702' do
|
||||
Flow::Login.sign_in
|
||||
|
||||
# Set an application secret CI variable (prefixed with K8S_SECRET_)
|
||||
|
|
@ -116,7 +116,7 @@ module QA
|
|||
end
|
||||
end
|
||||
|
||||
it 'runs an AutoDevOps pipeline' do
|
||||
it 'runs an AutoDevOps pipeline', status_issue: 'https://gitlab.com/gitlab-org/quality/testcases/-/issues/444' do
|
||||
Page::Project::Menu.perform(&:click_ci_cd_pipelines)
|
||||
Page::Project::Pipeline::Index.perform(&:click_on_latest_pipeline)
|
||||
|
||||
|
|
|
|||
|
|
@ -20,7 +20,7 @@ module QA
|
|||
cluster.remove!
|
||||
end
|
||||
|
||||
it 'can create and associate a project cluster', :smoke do
|
||||
it 'can create and associate a project cluster', :smoke, status_issue: 'https://gitlab.com/gitlab-org/quality/testcases/-/issues/707' do
|
||||
Resource::KubernetesCluster::ProjectCluster.fabricate_via_browser_ui! do |k8s_cluster|
|
||||
k8s_cluster.project = project
|
||||
k8s_cluster.cluster = cluster
|
||||
|
|
|
|||
|
|
@ -10,13 +10,13 @@ module QA
|
|||
@project.visit!
|
||||
end
|
||||
|
||||
it 'configures custom metrics' do
|
||||
it 'configures custom metrics', status_issue: 'https://gitlab.com/gitlab-org/quality/testcases/-/issues/872' do
|
||||
verify_add_custom_metric
|
||||
verify_edit_custom_metric
|
||||
verify_delete_custom_metric
|
||||
end
|
||||
|
||||
it 'duplicates to create dashboard to custom' do
|
||||
it 'duplicates to create dashboard to custom', status_issue: 'https://gitlab.com/gitlab-org/quality/testcases/-/issues/871' do
|
||||
Page::Project::Menu.perform(&:go_to_operations_metrics)
|
||||
|
||||
Page::Project::Operations::Metrics::Show.perform do |on_dashboard|
|
||||
|
|
@ -27,7 +27,7 @@ module QA
|
|||
end
|
||||
end
|
||||
|
||||
it 'verifies data on filtered deployed environment' do
|
||||
it 'verifies data on filtered deployed environment', status_issue: 'https://gitlab.com/gitlab-org/quality/testcases/-/issues/874' do
|
||||
Page::Project::Menu.perform(&:go_to_operations_metrics)
|
||||
|
||||
Page::Project::Operations::Metrics::Show.perform do |on_dashboard|
|
||||
|
|
@ -37,7 +37,7 @@ module QA
|
|||
end
|
||||
end
|
||||
|
||||
it 'filters using the quick range' do
|
||||
it 'filters using the quick range', status_issue: 'https://gitlab.com/gitlab-org/quality/testcases/-/issues/873' do
|
||||
Page::Project::Menu.perform(&:go_to_operations_metrics)
|
||||
|
||||
Page::Project::Operations::Metrics::Show.perform do |on_dashboard|
|
||||
|
|
@ -52,7 +52,7 @@ module QA
|
|||
end
|
||||
end
|
||||
|
||||
it 'observes cluster health graph' do
|
||||
it 'observes cluster health graph', status_issue: 'https://gitlab.com/gitlab-org/quality/testcases/-/issues/920' do
|
||||
Page::Project::Menu.perform(&:go_to_operations_kubernetes)
|
||||
|
||||
Page::Project::Operations::Kubernetes::Index.perform do |cluster_list|
|
||||
|
|
|
|||
|
|
@ -111,7 +111,7 @@ function rspec_paralellized_job() {
|
|||
date
|
||||
}
|
||||
|
||||
function rspec_matched_tests() {
|
||||
function rspec_matched_foss_tests() {
|
||||
local test_file_count_threshold=20
|
||||
local matching_tests_file=${1}
|
||||
local rspec_opts=${2}
|
||||
|
|
@ -131,6 +131,6 @@ function rspec_matched_tests() {
|
|||
if [[ -n $test_files ]]; then
|
||||
rspec_simple_job "${rspec_opts} ${test_files}"
|
||||
else
|
||||
echo "No test files to run"
|
||||
echo "No FOSS test files to run"
|
||||
fi
|
||||
}
|
||||
|
|
|
|||
|
|
@ -35,6 +35,10 @@ function install_gitlab_gem() {
|
|||
gem install gitlab --no-document --version 4.13.0
|
||||
}
|
||||
|
||||
function install_tff_gem() {
|
||||
gem install test_file_finder --version 0.1.0
|
||||
}
|
||||
|
||||
function run_timed_command() {
|
||||
local cmd="${1}"
|
||||
local start=$(date +%s)
|
||||
|
|
|
|||
|
|
@ -0,0 +1,163 @@
|
|||
#!/usr/bin/env ruby
|
||||
|
||||
require 'set'
|
||||
|
||||
# These tests run a sanity check on the mapping file `tests.yml`
|
||||
# used with the `test_file_finder` gem (`tff`) to identify matching test files.
|
||||
# The verification depend on the presence of actual test files,
|
||||
# so they would fail if one of the test files mentioned here is deleted.
|
||||
# To minimize the chance of this test failing due to unrelated changes,
|
||||
# the test files are chosen to be critical files that are unlikely to be deleted in a typical Merge Request
|
||||
tests = [
|
||||
{
|
||||
explanation: 'EE code should map to respective spec',
|
||||
source: 'ee/app/controllers/admin/licenses_controller.rb',
|
||||
expected: ['ee/spec/controllers/admin/licenses_controller_spec.rb']
|
||||
},
|
||||
|
||||
{
|
||||
explanation: 'FOSS code should map to respective spec',
|
||||
source: 'app/finders/admin/projects_finder.rb',
|
||||
expected: ['spec/finders/admin/projects_finder_spec.rb']
|
||||
},
|
||||
|
||||
{
|
||||
explanation: 'EE extension should map to its EE extension spec and its FOSS class spec',
|
||||
source: 'ee/app/finders/ee/projects_finder.rb',
|
||||
expected: ['ee/spec/finders/ee/projects_finder_spec.rb', 'spec/finders/projects_finder_spec.rb']
|
||||
},
|
||||
|
||||
{
|
||||
explanation: 'Some EE extensions also map to its EE class spec, but this is not recommended: https://docs.gitlab.com/ee/development/ee_features.html#testing-ee-features-based-on-ce-features',
|
||||
source: 'ee/app/models/ee/user.rb',
|
||||
expected: ['ee/spec/models/user_spec.rb', 'spec/models/user_spec.rb']
|
||||
},
|
||||
|
||||
{
|
||||
explanation: 'FOSS lib should map to respective spec',
|
||||
source: 'lib/gitaly/server.rb',
|
||||
expected: ['spec/lib/gitaly/server_spec.rb']
|
||||
},
|
||||
|
||||
{
|
||||
explanation: 'EE lib should map to respective spec',
|
||||
source: 'ee/lib/flipper_session.rb',
|
||||
expected: ['ee/spec/lib/flipper_session_spec.rb']
|
||||
},
|
||||
|
||||
{
|
||||
explanation: 'Tooling should map to respective spec',
|
||||
source: 'tooling/lib/tooling/test_file_finder.rb',
|
||||
expected: ['spec/tooling/lib/tooling/test_file_finder_spec.rb']
|
||||
},
|
||||
|
||||
{
|
||||
explanation: 'FOSS spec code should map to itself',
|
||||
source: 'spec/models/issue_spec.rb',
|
||||
expected: ['spec/models/issue_spec.rb']
|
||||
},
|
||||
|
||||
{
|
||||
explanation: 'EE spec code should map to itself',
|
||||
source: 'ee/spec/models/user_spec.rb',
|
||||
expected: ['ee/spec/models/user_spec.rb']
|
||||
},
|
||||
|
||||
{
|
||||
explanation: 'EE extension spec should map to itself and the FOSS class spec',
|
||||
source: 'ee/spec/services/ee/notification_service_spec.rb',
|
||||
expected: ['ee/spec/services/ee/notification_service_spec.rb', 'spec/services/notification_service_spec.rb']
|
||||
},
|
||||
|
||||
{
|
||||
explanation: 'FOSS factory should map to factories spec',
|
||||
source: 'spec/factories/users.rb',
|
||||
expected: ['spec/factories_spec.rb']
|
||||
},
|
||||
|
||||
{
|
||||
explanation: 'EE factory should map to factories spec',
|
||||
source: 'ee/spec/factories/users.rb',
|
||||
expected: ['spec/factories_spec.rb']
|
||||
},
|
||||
|
||||
{
|
||||
explanation: 'Initializers should map to respective spec',
|
||||
source: 'config/initializers/action_mailer_hooks.rb',
|
||||
expected: ['spec/initializers/action_mailer_hooks_spec.rb']
|
||||
},
|
||||
|
||||
{
|
||||
explanation: 'FOSS views should map to respective spec',
|
||||
source: 'app/views/admin/users/_user.html.haml',
|
||||
expected: ['spec/views/admin/users/_user.html.haml_spec.rb']
|
||||
},
|
||||
|
||||
{
|
||||
explanation: 'EE views should map to respective spec',
|
||||
source: 'ee/app/views/admin/licenses/show.html.haml',
|
||||
expected: ['ee/spec/views/admin/licenses/show.html.haml_spec.rb']
|
||||
},
|
||||
|
||||
{
|
||||
explanation: 'DB structure should map to schema spec',
|
||||
source: 'db/structure.sql',
|
||||
expected: ['spec/db/schema_spec.rb']
|
||||
},
|
||||
|
||||
{
|
||||
explanation: 'Migration should map to its non-timestamped spec',
|
||||
source: 'db/migrate/20191023152913_add_default_and_free_plans.rb',
|
||||
expected: ['spec/migrations/add_default_and_free_plans_spec.rb']
|
||||
},
|
||||
|
||||
{
|
||||
explanation: 'Migration should map to its timestamped spec',
|
||||
source: 'db/post_migrate/20190924152703_migrate_issue_trackers_data.rb',
|
||||
expected: ['spec/migrations/20190924152703_migrate_issue_trackers_data_spec.rb']
|
||||
}
|
||||
]
|
||||
|
||||
class MappingTest
|
||||
def initialize(explanation:, source:, expected:, mapping: 'tests.yml')
|
||||
@explanation = explanation
|
||||
@source = source
|
||||
@mapping = mapping
|
||||
@expected_set = Set.new(expected)
|
||||
@actual_set = Set.new(actual)
|
||||
end
|
||||
|
||||
def passed?
|
||||
expected_set.eql?(actual_set)
|
||||
end
|
||||
|
||||
def failed?
|
||||
!passed?
|
||||
end
|
||||
|
||||
def failure_message
|
||||
"#{explanation}: #{source}: Expected #{expected_set.to_a}, got #{actual_set.to_a}."
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
attr_reader :explanation, :source, :expected_set, :actual_set, :mapping
|
||||
|
||||
def actual
|
||||
`tff -f #{mapping} #{source}`.split(' ')
|
||||
end
|
||||
end
|
||||
|
||||
results = tests.map { |test| MappingTest.new(test) }
|
||||
|
||||
failed_tests = results.select(&:failed?)
|
||||
if failed_tests.any?
|
||||
puts <<~MESSAGE
|
||||
tff mapping verification failed:
|
||||
#{failed_tests.map(&:failure_message).join("\n")}
|
||||
MESSAGE
|
||||
|
||||
exit 1
|
||||
end
|
||||
|
||||
puts 'tff mapping verification passed.'
|
||||
|
|
@ -46,7 +46,16 @@ exports[`Design note component should match the snapshot 1`] = `
|
|||
class="system-note-message"
|
||||
/>
|
||||
|
||||
<!---->
|
||||
<a
|
||||
class="note-timestamp system-note-separator gl-display-block gl-mb-2"
|
||||
href="#note_123"
|
||||
>
|
||||
<time-ago-tooltip-stub
|
||||
cssclass=""
|
||||
time="2019-07-26T15:02:20Z"
|
||||
tooltipplacement="bottom"
|
||||
/>
|
||||
</a>
|
||||
</span>
|
||||
</div>
|
||||
|
||||
|
|
|
|||
|
|
@ -15,6 +15,7 @@ const note = {
|
|||
userPermissions: {
|
||||
adminNote: false,
|
||||
},
|
||||
createdAt: '2019-07-26T15:02:20Z',
|
||||
};
|
||||
HTMLElement.prototype.scrollIntoView = scrollIntoViewMock;
|
||||
|
||||
|
|
@ -79,10 +80,7 @@ describe('Design note component', () => {
|
|||
|
||||
it('should render a time ago tooltip if note has createdAt property', () => {
|
||||
createComponent({
|
||||
note: {
|
||||
...note,
|
||||
createdAt: '2019-07-26T15:02:20Z',
|
||||
},
|
||||
note,
|
||||
});
|
||||
|
||||
expect(wrapper.find(TimeAgoTooltip).exists()).toBe(true);
|
||||
|
|
|
|||
|
|
@ -125,7 +125,11 @@ describe('MRWidgetFailedToMerge', () => {
|
|||
});
|
||||
|
||||
it('renders refresh button', () => {
|
||||
expect(vm.$el.querySelector('.js-refresh-button').textContent.trim()).toEqual('Refresh now');
|
||||
expect(
|
||||
vm.$el
|
||||
.querySelector('[data-testid="merge-request-failed-refresh-button"]')
|
||||
.textContent.trim(),
|
||||
).toEqual('Refresh now');
|
||||
});
|
||||
|
||||
it('renders remaining time', () => {
|
||||
|
|
|
|||
|
|
@ -20,6 +20,7 @@ RSpec.describe GitlabSchema.types['Query'] do
|
|||
milestone
|
||||
user
|
||||
users
|
||||
issue
|
||||
]
|
||||
|
||||
expect(described_class).to have_graphql_fields(*expected_fields).at_least
|
||||
|
|
@ -53,4 +54,12 @@ RSpec.describe GitlabSchema.types['Query'] do
|
|||
is_expected.to have_graphql_resolver(Resolvers::MetadataResolver)
|
||||
end
|
||||
end
|
||||
|
||||
describe 'issue field' do
|
||||
subject { described_class.fields['issue'] }
|
||||
|
||||
it 'returns issue' do
|
||||
is_expected.to have_graphql_type(Types::IssueType)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -0,0 +1,126 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
require 'spec_helper'
|
||||
|
||||
RSpec.describe 'Query.issue(id)' do
|
||||
include GraphqlHelpers
|
||||
|
||||
let_it_be(:project) { create(:project) }
|
||||
let_it_be(:issue) { create(:issue, project: project) }
|
||||
let_it_be(:current_user) { create(:user) }
|
||||
|
||||
let(:issue_data) { graphql_data['issue'] }
|
||||
|
||||
let_it_be(:issue_params) { { 'id' => issue.to_global_id.to_s } }
|
||||
let(:issue_fields) { all_graphql_fields_for('Issue'.classify) }
|
||||
|
||||
let(:query) do
|
||||
graphql_query_for('issue', issue_params, issue_fields)
|
||||
end
|
||||
|
||||
it_behaves_like 'a working graphql query' do
|
||||
before do
|
||||
post_graphql(query, current_user: current_user)
|
||||
end
|
||||
end
|
||||
|
||||
context 'when the user does not have access to the issue' do
|
||||
it 'returns nil' do
|
||||
project.project_feature.update!(issues_access_level: ProjectFeature::PRIVATE)
|
||||
|
||||
post_graphql(query)
|
||||
|
||||
expect(issue_data).to be nil
|
||||
end
|
||||
end
|
||||
|
||||
context 'when the user does have access' do
|
||||
before do
|
||||
project.add_guest(current_user)
|
||||
end
|
||||
|
||||
it 'returns the issue' do
|
||||
post_graphql(query, current_user: current_user)
|
||||
|
||||
expect(issue_data).to include(
|
||||
'title' => issue.title,
|
||||
'description' => issue.description
|
||||
)
|
||||
end
|
||||
|
||||
context 'selecting any single field' do
|
||||
where(:field) do
|
||||
scalar_fields_of('Issue').map { |name| [name] }
|
||||
end
|
||||
|
||||
with_them do
|
||||
it_behaves_like 'a working graphql query' do
|
||||
let(:issue_fields) do
|
||||
field
|
||||
end
|
||||
|
||||
before do
|
||||
post_graphql(query, current_user: current_user)
|
||||
end
|
||||
|
||||
it "returns the Issue and field #{params['field']}" do
|
||||
expect(issue_data.keys).to eq([field])
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context 'selecting multiple fields' do
|
||||
let(:issue_fields) { %w(title description) }
|
||||
|
||||
it 'returns the Issue with the specified fields' do
|
||||
post_graphql(query, current_user: current_user)
|
||||
|
||||
expect(issue_data.keys).to eq( %w(title description) )
|
||||
expect(issue_data['title']).to eq(issue.title)
|
||||
expect(issue_data['description']).to eq(issue.description)
|
||||
end
|
||||
end
|
||||
|
||||
context 'when passed a non-Issue gid' do
|
||||
let(:mr) {create(:merge_request)}
|
||||
|
||||
it 'returns an error' do
|
||||
gid = mr.to_global_id.to_s
|
||||
issue_params['id'] = gid
|
||||
|
||||
post_graphql(query, current_user: current_user)
|
||||
|
||||
expect(graphql_errors).not_to be nil
|
||||
expect(graphql_errors.first['message']).to eq("\"#{gid}\" does not represent an instance of Issue")
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context 'when there is a confidential issue' do
|
||||
let!(:confidential_issue) do
|
||||
create(:issue, :confidential, project: project)
|
||||
end
|
||||
|
||||
let(:issue_params) { { 'id' => confidential_issue.to_global_id.to_s } }
|
||||
|
||||
context 'when the user cannot see confidential issues' do
|
||||
it 'returns nil ' do
|
||||
post_graphql(query, current_user: current_user)
|
||||
|
||||
expect(issue_data).to be nil
|
||||
end
|
||||
end
|
||||
|
||||
context 'when the user can see confidential issues' do
|
||||
it 'returns the confidential issue' do
|
||||
project.add_developer(current_user)
|
||||
|
||||
post_graphql(query, current_user: current_user)
|
||||
|
||||
expect(graphql_data.count).to eq(1)
|
||||
expect(issue_data['confidential']).to be(true)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
@ -87,6 +87,46 @@ RSpec.describe API::Issues do
|
|||
end
|
||||
end
|
||||
|
||||
describe 'GET /issues/:id' do
|
||||
context 'when unauthorized' do
|
||||
it 'returns unauthorized' do
|
||||
get api("/issues/#{issue.id}" )
|
||||
|
||||
expect(response).to have_gitlab_http_status(:unauthorized)
|
||||
end
|
||||
end
|
||||
|
||||
context 'when authorized' do
|
||||
context 'as a normal user' do
|
||||
it 'returns forbidden' do
|
||||
get api("/issues/#{issue.id}", user )
|
||||
|
||||
expect(response).to have_gitlab_http_status(:forbidden)
|
||||
end
|
||||
end
|
||||
|
||||
context 'as an admin' do
|
||||
context 'when issue exists' do
|
||||
it 'returns the issue' do
|
||||
get api("/issues/#{issue.id}", admin)
|
||||
|
||||
expect(response).to have_gitlab_http_status(:ok)
|
||||
expect(json_response.dig('author', 'id')).to eq(issue.author.id)
|
||||
expect(json_response['description']).to eq(issue.description)
|
||||
end
|
||||
end
|
||||
|
||||
context 'when issue does not exist' do
|
||||
it 'returns 404' do
|
||||
get api("/issues/0", admin)
|
||||
|
||||
expect(response).to have_gitlab_http_status(:not_found)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe 'GET /issues' do
|
||||
context 'when unauthenticated' do
|
||||
it 'returns an array of all issues' do
|
||||
|
|
@ -128,6 +168,11 @@ RSpec.describe API::Issues do
|
|||
expect_paginated_array_response([issue.id, closed_issue.id])
|
||||
end
|
||||
|
||||
it 'responds with a 401 instead of the specified issue' do
|
||||
get api("/issues/#{issue.id}")
|
||||
expect(response).to have_gitlab_http_status(:unauthorized)
|
||||
end
|
||||
|
||||
context 'issues_statistics' do
|
||||
it 'returns authentication error without any scope' do
|
||||
get api('/issues_statistics')
|
||||
|
|
|
|||
|
|
@ -0,0 +1,54 @@
|
|||
mapping:
|
||||
# EE code should map to respective spec
|
||||
- source: ee/app/(.+)\.rb
|
||||
test: ee/spec/%s_spec.rb
|
||||
# FOSS code should map to respective spec
|
||||
- source: app/(.+)\.rb
|
||||
test: spec/%s_spec.rb
|
||||
|
||||
# EE extension should also map to its FOSS class spec
|
||||
- source: ee/app/(.*/)ee/(.+)\.rb
|
||||
test: spec/%s%s_spec.rb
|
||||
|
||||
# Some EE extensions also map to its EE class spec, but this is not recommended:
|
||||
# https://docs.gitlab.com/ee/development/ee_features.html#testing-ee-features-based-on-ce-features
|
||||
- source: ee/app/(.*/)ee/(.+)\.rb
|
||||
test: ee/spec/%s%s_spec.rb
|
||||
|
||||
# EE lib should map to respective spec
|
||||
- source: ee/lib/(.+)\.rb
|
||||
test: ee/spec/lib/%s_spec.rb
|
||||
|
||||
# FOSS lib & tooling should map to respective spec
|
||||
- source: (tooling/)?lib/(.+)\.rb
|
||||
test: spec/%slib/%s_spec.rb
|
||||
|
||||
# Initializers should map to respective spec
|
||||
- source: config/initializers/(.+)\.rb
|
||||
test: spec/initializers/%s_spec.rb
|
||||
|
||||
# DB structure should map to schema spec
|
||||
- source: db/structure.sql
|
||||
test: spec/db/schema_spec.rb
|
||||
|
||||
# Migration should map to either timestamped or non-timestamped spec
|
||||
- source: db/(?:post_)?migrate/(?:[0-9]+)_(.+)\.rb
|
||||
test: spec/migrations/%s_spec.rb
|
||||
- source: db/(?:post_)?migrate/([0-9]+)_(.+)\.rb
|
||||
test: spec/migrations/%s_%s_spec.rb
|
||||
|
||||
# EE/FOSS views should map to respective spec
|
||||
- source: (ee/)?app/views/(.+)\.haml
|
||||
test: '%sspec/views/%s.haml_spec.rb'
|
||||
|
||||
# EE/FOSS spec code should map to itself
|
||||
- source: (ee/)?spec/(.+)_spec\.rb
|
||||
test: '%sspec/%s_spec.rb'
|
||||
|
||||
# EE extension spec should map to its FOSS class spec
|
||||
- source: ee/spec/(.*/)ee/(.+)\.rb
|
||||
test: spec/%s%s.rb
|
||||
|
||||
# EE/FOSS factory should map to factories spec
|
||||
- source: (ee/)?spec/factories/.+\.rb
|
||||
test: spec/factories_spec.rb
|
||||
|
|
@ -1,10 +1,8 @@
|
|||
#!/usr/bin/env ruby
|
||||
# frozen_string_literal: true
|
||||
|
||||
require_relative '../../lib/gitlab/popen'
|
||||
require_relative '../lib/tooling/test_file_finder'
|
||||
|
||||
require 'gitlab'
|
||||
require 'test_file_finder'
|
||||
|
||||
gitlab_token = ENV.fetch('DANGER_GITLAB_API_TOKEN', '')
|
||||
|
||||
|
|
@ -21,9 +19,7 @@ mr_iid = ENV.fetch('CI_MERGE_REQUEST_IID')
|
|||
mr_changes = Gitlab.merge_request_changes(mr_project_path, mr_iid)
|
||||
changed_files = mr_changes.changes.map { |change| change['new_path'] }
|
||||
|
||||
tests_to_run = changed_files.flat_map do |file|
|
||||
test_files = Tooling::TestFileFinder.new(file, foss_test_only: true).test_files
|
||||
test_files.select { |f| File.exist?(f) }
|
||||
end
|
||||
mapping = TestFileFinder::Mapping.load('tests.yml')
|
||||
test_files = TestFileFinder::FileFinder.new(paths: changed_files, mapping: mapping).test_files
|
||||
|
||||
File.write(output_file, tests_to_run.uniq.join(' '))
|
||||
File.write(output_file, test_files.uniq.join(' '))
|
||||
|
|
|
|||
16
yarn.lock
16
yarn.lock
|
|
@ -843,15 +843,15 @@
|
|||
eslint-plugin-vue "^6.2.1"
|
||||
vue-eslint-parser "^7.0.0"
|
||||
|
||||
"@gitlab/svgs@1.160.0":
|
||||
version "1.160.0"
|
||||
resolved "https://registry.yarnpkg.com/@gitlab/svgs/-/svgs-1.160.0.tgz#1f6b3c9f587b7847be32b5a4ddc397fa5add8829"
|
||||
integrity sha512-oBGeuQAdgd0UAha+YweeHiBsiukKX1fatzPFxD2f2UJodMJXZh/I8e+1yL68cLT/Sn0pmZBiYF2dzaDQHBbWkg==
|
||||
"@gitlab/svgs@1.161.0":
|
||||
version "1.161.0"
|
||||
resolved "https://registry.yarnpkg.com/@gitlab/svgs/-/svgs-1.161.0.tgz#661e8d19862dfba0e4c558e2eb6d64b402c1453e"
|
||||
integrity sha512-qsbboEICn08ZoEoAX/TuYygsFaXlzsCY+CfmdOzqvJbOdfHhVXmrJBxd2hP2qqjTZm2PkbRRmn+03+ce1jvatQ==
|
||||
|
||||
"@gitlab/ui@20.6.0":
|
||||
version "20.6.0"
|
||||
resolved "https://registry.yarnpkg.com/@gitlab/ui/-/ui-20.6.0.tgz#54ca0dd156d807564fcefd5583cb730fde09b3c9"
|
||||
integrity sha512-1QW9nXAD6HXCH/a+mj3qdiLX8sHtD5tOTqJeCluqL0b0y6pPs9uXkQv0AV0zvruggQ36tHQeer8SiU2Op+EOtQ==
|
||||
"@gitlab/ui@20.8.0":
|
||||
version "20.8.0"
|
||||
resolved "https://registry.yarnpkg.com/@gitlab/ui/-/ui-20.8.0.tgz#00ecc698d2ed003f87fd59ea408f999c804d7dda"
|
||||
integrity sha512-BHXDFtY1Zw6rIkUopAJQMoDpWlAKyDZiHR13U6Tv+Ot0G6p6tW6PVVHb12m+fycNxBDKdYisdLJwH8MKNjWRrA==
|
||||
dependencies:
|
||||
"@babel/standalone" "^7.0.0"
|
||||
"@gitlab/vue-toasted" "^1.3.0"
|
||||
|
|
|
|||
Loading…
Reference in New Issue