Welcome to mirror list, hosted at ThFree Co, Russian Federation.

gitlab.com/gitlab-org/gitlab-foss.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGitLab Bot <gitlab-bot@gitlab.com>2020-08-25 18:10:17 +0300
committerGitLab Bot <gitlab-bot@gitlab.com>2020-08-25 18:10:17 +0300
commit11a29f1f026ecd0c466625782af00a14889a2f91 (patch)
treec4b893017684aa7ebabbefb695674f7f448038fc
parentc1892df2eb57a33cc3a751378e40cb49823fee82 (diff)
Add latest changes from gitlab-org/gitlab@master
-rw-r--r--.gitlab/CODEOWNERS3
-rw-r--r--.gitlab/ci/rails.gitlab-ci.yml3
-rw-r--r--.gitlab/ci/rules.gitlab-ci.yml10
-rw-r--r--.gitlab/ci/setup.gitlab-ci.yml11
-rw-r--r--CHANGELOG.md8
-rw-r--r--app/assets/javascripts/design_management/components/design_notes/design_note.vue12
-rw-r--r--app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_failed_to_merge.vue10
-rw-r--r--app/assets/stylesheets/framework/wells.scss4
-rw-r--r--app/graphql/types/query_type.rb10
-rw-r--r--app/views/admin/dashboard/index.html.haml10
-rw-r--r--app/views/import/fogbugz/new.html.haml5
-rw-r--r--app/views/import/fogbugz/new_user_map.html.haml5
-rw-r--r--app/views/import/fogbugz/status.html.haml5
-rw-r--r--app/views/projects/_import_project_pane.html.haml3
-rw-r--r--changelogs/unreleased/209770-design-comments-text-wrapping-behavior.yml5
-rw-r--r--changelogs/unreleased/225939-replace-fa-bugs-icons-with-gitlab-svg-bug-icon.yml5
-rw-r--r--changelogs/unreleased/229296-migrate-bootstrap-button-to-gitlab-ui-glbutton-in-app-assets-javas.yml5
-rw-r--r--changelogs/unreleased/37248-add-api-to-monitor-issue-creation.yml5
-rw-r--r--changelogs/unreleased/id-fix-nil-line-codes-for-diff-positions.yml5
-rw-r--r--doc/api/graphql/reference/gitlab_schema.graphql15
-rw-r--r--doc/api/graphql/reference/gitlab_schema.json37
-rw-r--r--doc/api/issues.md314
-rw-r--r--doc/user/project/import/github.md4
-rw-r--r--lib/api/issues.rb13
-rw-r--r--lib/gitlab/danger/helper.rb1
-rw-r--r--locale/gitlab.pot12
-rw-r--r--package.json4
-rw-r--r--qa/qa/specs/features/browser_ui/7_configure/auto_devops/create_project_with_auto_devops_spec.rb4
-rw-r--r--qa/qa/specs/features/browser_ui/7_configure/kubernetes/kubernetes_integration_spec.rb2
-rw-r--r--qa/qa/specs/features/browser_ui/8_monitor/all_monitor_core_features_spec.rb10
-rw-r--r--scripts/rspec_helpers.sh4
-rw-r--r--scripts/utils.sh4
-rwxr-xr-xscripts/verify-tff-mapping163
-rw-r--r--spec/frontend/design_management/components/design_notes/__snapshots__/design_note_spec.js.snap11
-rw-r--r--spec/frontend/design_management/components/design_notes/design_note_spec.js6
-rw-r--r--spec/frontend/vue_mr_widget/components/states/mr_widget_failed_to_merge_spec.js6
-rw-r--r--spec/graphql/types/query_type_spec.rb9
-rw-r--r--spec/requests/api/graphql/issue/issue_spec.rb126
-rw-r--r--spec/requests/api/issues/issues_spec.rb45
-rw-r--r--tests.yml54
-rwxr-xr-xtooling/bin/find_foss_tests12
-rw-r--r--yarn.lock18
42 files changed, 926 insertions, 72 deletions
diff --git a/.gitlab/CODEOWNERS b/.gitlab/CODEOWNERS
index 7a5516338e8..2cf8db04bb9 100644
--- a/.gitlab/CODEOWNERS
+++ b/.gitlab/CODEOWNERS
@@ -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]
diff --git a/.gitlab/ci/rails.gitlab-ci.yml b/.gitlab/ci/rails.gitlab-ci.yml
index 0b54626f690..6acd52382cf 100644
--- a/.gitlab/ci/rails.gitlab-ci.yml
+++ b/.gitlab/ci/rails.gitlab-ci.yml
@@ -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:
diff --git a/.gitlab/ci/rules.gitlab-ci.yml b/.gitlab/ci/rules.gitlab-ci.yml
index 49f96eeac74..b2836d2600e 100644
--- a/.gitlab/ci/rules.gitlab-ci.yml
+++ b/.gitlab/ci/rules.gitlab-ci.yml
@@ -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 #
#######################
diff --git a/.gitlab/ci/setup.gitlab-ci.yml b/.gitlab/ci/setup.gitlab-ci.yml
index 26c7a2194cc..b2b64700b18 100644
--- a/.gitlab/ci/setup.gitlab-ci.yml
+++ b/.gitlab/ci/setup.gitlab-ci.yml
@@ -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
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 99a0b061a29..d7bb4ac918d 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -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)
diff --git a/app/assets/javascripts/design_management/components/design_notes/design_note.vue b/app/assets/javascripts/design_management/components/design_notes/design_note.vue
index 172e61920ef..ab64e5c43db 100644
--- a/app/assets/javascripts/design_management/components/design_notes/design_note.vue
+++ b/app/assets/javascripts/design_management/components/design_notes/design_note.vue
@@ -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">
diff --git a/app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_failed_to_merge.vue b/app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_failed_to_merge.vue
index 9df0c045fe4..a5ec095b8ec 100644
--- a/app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_failed_to_merge.vue
+++ b/app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_failed_to_merge.vue
@@ -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>
diff --git a/app/assets/stylesheets/framework/wells.scss b/app/assets/stylesheets/framework/wells.scss
index 3eff1807403..55996a074c6 100644
--- a/app/assets/stylesheets/framework/wells.scss
+++ b/app/assets/stylesheets/framework/wells.scss
@@ -110,10 +110,6 @@
.dark-well {
background-color: $gray-normal;
-
- .btn {
- width: 100%;
- }
}
.card.card-body-centered {
diff --git a/app/graphql/types/query_type.rb b/app/graphql/types/query_type.rb
index c04f4da70cf..7709b18fb39 100644
--- a/app/graphql/types/query_type.rb
+++ b/app/graphql/types/query_type.rb
@@ -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
diff --git a/app/views/admin/dashboard/index.html.haml b/app/views/admin/dashboard/index.html.haml
index 8c9e98765aa..b6ac5db4d2d 100644
--- a/app/views/admin/dashboard/index.html.haml
+++ b/app/views/admin/dashboard/index.html.haml
@@ -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
diff --git a/app/views/import/fogbugz/new.html.haml b/app/views/import/fogbugz/new.html.haml
index 626080c284b..4daa769215f 100644
--- a/app/views/import/fogbugz/new.html.haml
+++ b/app/views/import/fogbugz/new.html.haml
@@ -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
diff --git a/app/views/import/fogbugz/new_user_map.html.haml b/app/views/import/fogbugz/new_user_map.html.haml
index cdc53520e93..fb93a3eca0d 100644
--- a/app/views/import/fogbugz/new_user_map.html.haml
+++ b/app/views/import/fogbugz/new_user_map.html.haml
@@ -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
diff --git a/app/views/import/fogbugz/status.html.haml b/app/views/import/fogbugz/status.html.haml
index f201c0e83fe..e04a412e3bc 100644
--- a/app/views/import/fogbugz/status.html.haml
+++ b/app/views/import/fogbugz/status.html.haml
@@ -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
diff --git a/app/views/projects/_import_project_pane.html.haml b/app/views/projects/_import_project_pane.html.haml
index dd7971f6db0..fe3354aefbb 100644
--- a/app/views/projects/_import_project_pane.html.haml
+++ b/app/views/projects/_import_project_pane.html.haml
@@ -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
diff --git a/changelogs/unreleased/209770-design-comments-text-wrapping-behavior.yml b/changelogs/unreleased/209770-design-comments-text-wrapping-behavior.yml
new file mode 100644
index 00000000000..10c5689eccf
--- /dev/null
+++ b/changelogs/unreleased/209770-design-comments-text-wrapping-behavior.yml
@@ -0,0 +1,5 @@
+---
+title: 'Resolve Design comments: Text wrapping behavior'
+merge_request: 40359
+author:
+type: fixed
diff --git a/changelogs/unreleased/225939-replace-fa-bugs-icons-with-gitlab-svg-bug-icon.yml b/changelogs/unreleased/225939-replace-fa-bugs-icons-with-gitlab-svg-bug-icon.yml
new file mode 100644
index 00000000000..3c47daf4e25
--- /dev/null
+++ b/changelogs/unreleased/225939-replace-fa-bugs-icons-with-gitlab-svg-bug-icon.yml
@@ -0,0 +1,5 @@
+---
+title: Replace fa-bugs icons with GitLab SVG bug icon
+merge_request: 40273
+author:
+type: changed
diff --git a/changelogs/unreleased/229296-migrate-bootstrap-button-to-gitlab-ui-glbutton-in-app-assets-javas.yml b/changelogs/unreleased/229296-migrate-bootstrap-button-to-gitlab-ui-glbutton-in-app-assets-javas.yml
new file mode 100644
index 00000000000..11de8081fee
--- /dev/null
+++ b/changelogs/unreleased/229296-migrate-bootstrap-button-to-gitlab-ui-glbutton-in-app-assets-javas.yml
@@ -0,0 +1,5 @@
+---
+title: Migrate Bootstrap button to GitLab UI GlButton in mr_widget_failed_to_merge
+merge_request: 40170
+author:
+type: other
diff --git a/changelogs/unreleased/37248-add-api-to-monitor-issue-creation.yml b/changelogs/unreleased/37248-add-api-to-monitor-issue-creation.yml
new file mode 100644
index 00000000000..10499223fb3
--- /dev/null
+++ b/changelogs/unreleased/37248-add-api-to-monitor-issue-creation.yml
@@ -0,0 +1,5 @@
+---
+title: Add ability to get an Issue using GraphQL and REST API
+merge_request: 35176
+author:
+type: added
diff --git a/changelogs/unreleased/id-fix-nil-line-codes-for-diff-positions.yml b/changelogs/unreleased/id-fix-nil-line-codes-for-diff-positions.yml
new file mode 100644
index 00000000000..1d7b495e8f0
--- /dev/null
+++ b/changelogs/unreleased/id-fix-nil-line-codes-for-diff-positions.yml
@@ -0,0 +1,5 @@
+---
+title: Avoid creating diff position when line-code is nil
+merge_request: 40089
+author:
+type: fixed
diff --git a/doc/api/graphql/reference/gitlab_schema.graphql b/doc/api/graphql/reference/gitlab_schema.graphql
index 41f85567624..eb781fc082b 100644
--- a/doc/api/graphql/reference/gitlab_schema.graphql
+++ b/doc/api/graphql/reference/gitlab_schema.graphql
@@ -7223,6 +7223,11 @@ type IssueEdge {
}
"""
+Identifier of Issue
+"""
+scalar IssueID
+
+"""
Autogenerated input type of IssueMoveList
"""
input IssueMoveListInput {
@@ -12508,6 +12513,16 @@ type Query {
instanceSecurityDashboard: InstanceSecurityDashboard
"""
+ Find an issue
+ """
+ issue(
+ """
+ The global ID of the Issue
+ """
+ id: IssueID!
+ ): Issue
+
+ """
Find an iteration
"""
iteration(
diff --git a/doc/api/graphql/reference/gitlab_schema.json b/doc/api/graphql/reference/gitlab_schema.json
index 77eeb7012b5..fa4b5620b86 100644
--- a/doc/api/graphql/reference/gitlab_schema.json
+++ b/doc/api/graphql/reference/gitlab_schema.json
@@ -19964,6 +19964,16 @@
"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",
"description": "Autogenerated input type of IssueMoveList",
@@ -36857,6 +36867,33 @@
"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",
"args": [
diff --git a/doc/api/issues.md b/doc/api/issues.md
index c9f7dd71849..93f788d62a3 100644
--- a/doc/api/issues.md
+++ b/doc/api/issues.md
@@ -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.
diff --git a/doc/user/project/import/github.md b/doc/user/project/import/github.md
index 531b308111a..274eb3baee4 100644
--- a/doc/user/project/import/github.md
+++ b/doc/user/project/import/github.md
@@ -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)**
diff --git a/lib/api/issues.rb b/lib/api/issues.rb
index 1694a967f26..0e5b0fae6e2 100644
--- a/lib/api/issues.rb
+++ b/lib/api/issues.rb
@@ -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
diff --git a/lib/gitlab/danger/helper.rb b/lib/gitlab/danger/helper.rb
index 077c71f1233..9ba5df89a35 100644
--- a/lib/gitlab/danger/helper.rb
+++ b/lib/gitlab/danger/helper.rb
@@ -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,
diff --git a/locale/gitlab.pot b/locale/gitlab.pot
index 43f3e471da8..f5bb70a8ff8 100644
--- a/locale/gitlab.pot
+++ b/locale/gitlab.pot
@@ -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 ""
diff --git a/package.json b/package.json
index cb288aece9d..f5bcb056c7d 100644
--- a/package.json
+++ b/package.json
@@ -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",
diff --git a/qa/qa/specs/features/browser_ui/7_configure/auto_devops/create_project_with_auto_devops_spec.rb b/qa/qa/specs/features/browser_ui/7_configure/auto_devops/create_project_with_auto_devops_spec.rb
index 3e25ecfd45d..f393a12844b 100644
--- a/qa/qa/specs/features/browser_ui/7_configure/auto_devops/create_project_with_auto_devops_spec.rb
+++ b/qa/qa/specs/features/browser_ui/7_configure/auto_devops/create_project_with_auto_devops_spec.rb
@@ -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)
diff --git a/qa/qa/specs/features/browser_ui/7_configure/kubernetes/kubernetes_integration_spec.rb b/qa/qa/specs/features/browser_ui/7_configure/kubernetes/kubernetes_integration_spec.rb
index 5073b715341..a9eebb80d5a 100644
--- a/qa/qa/specs/features/browser_ui/7_configure/kubernetes/kubernetes_integration_spec.rb
+++ b/qa/qa/specs/features/browser_ui/7_configure/kubernetes/kubernetes_integration_spec.rb
@@ -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
diff --git a/qa/qa/specs/features/browser_ui/8_monitor/all_monitor_core_features_spec.rb b/qa/qa/specs/features/browser_ui/8_monitor/all_monitor_core_features_spec.rb
index 7c883559574..af9c9a9e48f 100644
--- a/qa/qa/specs/features/browser_ui/8_monitor/all_monitor_core_features_spec.rb
+++ b/qa/qa/specs/features/browser_ui/8_monitor/all_monitor_core_features_spec.rb
@@ -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|
diff --git a/scripts/rspec_helpers.sh b/scripts/rspec_helpers.sh
index 1ecf9a566d7..3b0c7d973de 100644
--- a/scripts/rspec_helpers.sh
+++ b/scripts/rspec_helpers.sh
@@ -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
}
diff --git a/scripts/utils.sh b/scripts/utils.sh
index f81e5c8982a..98d9dca74c0 100644
--- a/scripts/utils.sh
+++ b/scripts/utils.sh
@@ -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)
diff --git a/scripts/verify-tff-mapping b/scripts/verify-tff-mapping
new file mode 100755
index 00000000000..9541d2468b1
--- /dev/null
+++ b/scripts/verify-tff-mapping
@@ -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.'
diff --git a/spec/frontend/design_management/components/design_notes/__snapshots__/design_note_spec.js.snap b/spec/frontend/design_management/components/design_notes/__snapshots__/design_note_spec.js.snap
index b55bacb6fc5..d20d81c5230 100644
--- a/spec/frontend/design_management/components/design_notes/__snapshots__/design_note_spec.js.snap
+++ b/spec/frontend/design_management/components/design_notes/__snapshots__/design_note_spec.js.snap
@@ -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>
diff --git a/spec/frontend/design_management/components/design_notes/design_note_spec.js b/spec/frontend/design_management/components/design_notes/design_note_spec.js
index 8b32d3022ee..8eeaa6cd5ab 100644
--- a/spec/frontend/design_management/components/design_notes/design_note_spec.js
+++ b/spec/frontend/design_management/components/design_notes/design_note_spec.js
@@ -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);
diff --git a/spec/frontend/vue_mr_widget/components/states/mr_widget_failed_to_merge_spec.js b/spec/frontend/vue_mr_widget/components/states/mr_widget_failed_to_merge_spec.js
index f591393d721..6778a8f4a1f 100644
--- a/spec/frontend/vue_mr_widget/components/states/mr_widget_failed_to_merge_spec.js
+++ b/spec/frontend/vue_mr_widget/components/states/mr_widget_failed_to_merge_spec.js
@@ -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', () => {
diff --git a/spec/graphql/types/query_type_spec.rb b/spec/graphql/types/query_type_spec.rb
index ab13162b406..d09fd34b551 100644
--- a/spec/graphql/types/query_type_spec.rb
+++ b/spec/graphql/types/query_type_spec.rb
@@ -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
diff --git a/spec/requests/api/graphql/issue/issue_spec.rb b/spec/requests/api/graphql/issue/issue_spec.rb
new file mode 100644
index 00000000000..1c9d6b25856
--- /dev/null
+++ b/spec/requests/api/graphql/issue/issue_spec.rb
@@ -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
diff --git a/spec/requests/api/issues/issues_spec.rb b/spec/requests/api/issues/issues_spec.rb
index b638a65d65e..b8cbddd9ed4 100644
--- a/spec/requests/api/issues/issues_spec.rb
+++ b/spec/requests/api/issues/issues_spec.rb
@@ -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')
diff --git a/tests.yml b/tests.yml
new file mode 100644
index 00000000000..d24cc44a403
--- /dev/null
+++ b/tests.yml
@@ -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
diff --git a/tooling/bin/find_foss_tests b/tooling/bin/find_foss_tests
index c694210ad40..9cd8a616ad0 100755
--- a/tooling/bin/find_foss_tests
+++ b/tooling/bin/find_foss_tests
@@ -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(' '))
diff --git a/yarn.lock b/yarn.lock
index aab6b97a34b..4c1ae0b398a 100644
--- a/yarn.lock
+++ b/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/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/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.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"