summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorFilipa Lacerda <filipa@gitlab.com>2018-05-16 11:25:50 +0100
committerFilipa Lacerda <filipa@gitlab.com>2018-05-16 11:25:50 +0100
commita55da0a95a7d38caed4070006f611e9eaea3e387 (patch)
treed0771c25194dfce8bb17eb02a0e820d415ae9bc0
parent3593b83a0279bab40f8ba97dc339b32c56f6e0df (diff)
parent75f94fc39bedbc635bd4bc52cdf145d1e81752dd (diff)
downloadgitlab-ce-a55da0a95a7d38caed4070006f611e9eaea3e387.tar.gz
[ci skip] Merge branch 'master' into 46381-dropdown-mr-widget
* master: (31 commits) Remove docker pull prefix from registry clipboard feature Document the 3h timeout for GitLab.com shared Runners Fix bug with long strings in issue boards Fix setting Gitlab metrics content types Add documentation for bulk editing of issues and merge requests Remove authentication for readonly endpoints in issues API Improve testing best practices guidelines Add a unique and not null constraint on the project_features.project_id column fix typos Frontend Guide, development_process.md Add index on runner_type for ci_runners Update docs describing `fast_spec_helper` best practices Display help text below auto devops domain with nip.io domain name (#45561) Add CHANGELOG Does not log failed sign-in attempts when database is in read-only mode Simplified priority, performance impact should be severity Ref contains oid check done by Gitaly code example formatting more typos typo in `endpoint` clarify that the function export should be default ...
-rw-r--r--CONTRIBUTING.md34
-rw-r--r--app/assets/javascripts/registry/components/collapsible_container.vue7
-rw-r--r--app/assets/javascripts/registry/components/table_registry.vue6
-rw-r--r--app/assets/stylesheets/framework/mixins.scss12
-rw-r--r--app/assets/stylesheets/pages/boards.scss8
-rw-r--r--app/helpers/auto_devops_helper.rb9
-rw-r--r--app/models/project.rb1
-rw-r--r--app/models/user.rb3
-rw-r--r--app/views/projects/settings/ci_cd/_autodevops_form.html.haml4
-rw-r--r--changelogs/unreleased/40855_remove_authentication_in_readonly_issue_api.yml5
-rw-r--r--changelogs/unreleased/43367-fix-board-long-strings.yml5
-rw-r--r--changelogs/unreleased/45584-add-nip-io-domain-suggestion-in-auto-devops.yml5
-rw-r--r--changelogs/unreleased/46010-add-index-to-runner-type.yml5
-rw-r--r--changelogs/unreleased/46361-does-not-log-failed-sign-in-attempts-when-the-database-is-in-read-only-mode.yml5
-rw-r--r--changelogs/unreleased/fix-metrics-content-types.yml5
-rw-r--r--changelogs/unreleased/registry-ux-improvements-remove-clipboard-prefix.yml5
-rw-r--r--changelogs/unreleased/sh-enforce-unique-and-not-null-project-ids-project-features.yml5
-rw-r--r--changelogs/unreleased/zj-ref-contains-sha-mandatory.yml5
-rw-r--r--db/migrate/20180511090724_add_index_on_ci_runners_runner_type.rb15
-rw-r--r--db/post_migrate/20180511174224_add_unique_constraint_to_project_features_project_id.rb43
-rw-r--r--db/post_migrate/20180512061621_add_not_null_constraint_to_project_features_project_id.rb21
-rw-r--r--db/schema.rb7
-rw-r--r--doc/administration/high_availability/nfs.md2
-rw-r--r--doc/ci/quick_start/README.md4
-rw-r--r--doc/development/fe_guide/development_process.md6
-rw-r--r--doc/development/fe_guide/vuex.md36
-rw-r--r--doc/development/query_recorder.md2
-rw-r--r--doc/development/testing_guide/best_practices.md23
-rw-r--r--doc/user/gitlab_com/index.md7
-rw-r--r--doc/user/project/bulk_editing.md17
-rw-r--r--doc/user/project/issues/index.md4
-rw-r--r--doc/user/project/merge_requests/index.md4
-rw-r--r--doc/user/project/web_ide/img/commit_changes.pngbin672321 -> 244172 bytes
-rw-r--r--doc/user/project/web_ide/index.md23
-rw-r--r--lib/api/issues.rb3
-rw-r--r--lib/gitlab/git/repository.rb39
-rw-r--r--lib/gitlab/import_export/relation_factory.rb2
-rw-r--r--lib/gitlab/metrics/web_transaction.rb14
-rw-r--r--locale/gitlab.pot13
-rw-r--r--spec/fast_spec_helper.rb12
-rw-r--r--spec/features/projects/settings/pipelines_settings_spec.rb23
-rw-r--r--spec/lib/gitlab/git/repository_spec.rb32
-rw-r--r--spec/lib/gitlab/import_export/all_models.yml1
-rw-r--r--spec/lib/gitlab/metrics/web_transaction_spec.rb6
-rw-r--r--spec/migrations/add_unique_constraint_to_project_features_project_id_spec.rb59
-rw-r--r--spec/models/guest_spec.rb6
-rw-r--r--spec/models/user_spec.rb14
-rw-r--r--spec/requests/api/issues_spec.rb300
-rw-r--r--spec/requests/openid_connect_spec.rb4
49 files changed, 590 insertions, 281 deletions
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index d82f21fe795..5447ebbdd8c 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -31,8 +31,8 @@ _This notice should stay as the first item in the CONTRIBUTING.md file._
- [Subject labels (~wiki, ~"container registry", ~ldap, ~api, etc.)](#subject-labels-wiki-container-registry-ldap-api-etc)
- [Team labels (~"CI/CD", ~Discussion, ~Quality, ~Platform, etc.)](#team-labels-cicd-discussion-quality-platform-etc)
- [Milestone labels (~Deliverable, ~Stretch, ~"Next Patch Release")](#milestone-labels-deliverable-stretch-next-patch-release)
- - [Priority labels (~Deliverable, ~Stretch, ~"Next Patch Release")](#bug-priority-labels-p1-p2-p3-etc)
- - [Severity labels (~Deliverable, ~Stretch, ~"Next Patch Release")](#bug-severity-labels-s1-s2-s3-etc)
+ - [Priority labels (~P1, ~P2, ~P3 , ~P4)](#bug-priority-labels-p1-p2-p3-p4)
+ - [Severity labels (~S1, ~S2, ~S3 , ~S4)](#bug-severity-labels-s1-s2-s3-s4)
- [Label for community contributors (~"Accepting Merge Requests")](#label-for-community-contributors-accepting-merge-requests)
- [Implement design & UI elements](#implement-design--ui-elements)
- [Issue tracker](#issue-tracker)
@@ -211,9 +211,10 @@ Each issue scheduled for the current milestone should be labeled ~Deliverable
or ~"Stretch". Any open issue for a previous milestone should be labeled
~"Next Patch Release", or otherwise rescheduled to a different milestone.
-### Bug Priority labels (~P1, ~P2, ~P3 & etc.)
+### Bug Priority labels (~P1, ~P2, ~P3, ~P4)
-Bug Priority labels help us define the time a ~bug fix should be completed. Priority determines how quickly the defect turnaround time must be. If there are multiple defects, the priority decides which defect has to be fixed immediately versus later.
+Bug Priority labels help us define the time a ~bug fix should be completed. Priority determines how quickly the defect turnaround time must be.
+If there are multiple defects, the priority decides which defect has to be fixed immediately versus later.
This label documents the planned timeline & urgency which is used to measure against our actual SLA on delivering ~bug fixes.
| Label | Meaning | Estimate time to fix | Guidance |
@@ -223,16 +224,7 @@ This label documents the planned timeline & urgency which is used to measure aga
| ~P3 | Medium Priority | Within the next 3 releases (approx one quarter) | |
| ~P4 | Low Priority | Anything outside the next 3 releases (approx beyond one quarter) | The issue is prominent but does not impact user workflow and a workaround is documented |
-#### Specific Priority guidance
-
-| Label | Availability / Performance |
-|-------|--------------------------------------------------------------|
-| ~P1 | |
-| ~P2 | The issue is (almost) guaranteed to occur in the near future |
-| ~P3 | The issue is likely to occur in the near future |
-| ~P4 | The issue _may_ occur but it's not likely |
-
-### Bug Severity labels (~S1, ~S2, ~S3 & etc.)
+### Bug Severity labels (~S1, ~S2, ~S3, ~S4)
Severity labels help us clearly communicate the impact of a ~bug on users.
@@ -243,14 +235,14 @@ Severity labels help us clearly communicate the impact of a ~bug on users.
| ~S3 | Major Severity | Broken Feature, workaround acceptable | Can create merge requests only from the Merge Requests page, not through the Issue. |
| ~S4 | Low Severity | Functionality inconvenience or cosmetic issue | Label colors are incorrect / not being displayed. |
-#### Specific Severity guidance
+#### Severity impact guidance
-| Label | Security Impact |
-|-------|-------------------------------------------------------------------|
-| ~S1 | >50% customers impacted (possible company extinction level event) |
-| ~S2 | Multiple customers impacted (but not apocalyptic) |
-| ~S3 | A single customer impacted |
-| ~S4 | No customer impact, or expected impact within 30 days |
+| Label | Security Impact | Availability / Performance Impact |
+|-------|---------------------------------------------------------------------|--------------------------------------------------------------|
+| ~S1 | >50% users impacted (possible company extinction level event) | |
+| ~S2 | Many users or multiple paid customers impacted (but not apocalyptic)| The issue is (almost) guaranteed to occur in the near future |
+| ~S3 | A few users or a single paid customer impacted | The issue is likely to occur in the near future |
+| ~S4 | No paid users/customer impacted, or expected impact within 30 days | The issue _may_ occur but it's not likely |
### Label for community contributors (~"Accepting Merge Requests")
diff --git a/app/assets/javascripts/registry/components/collapsible_container.vue b/app/assets/javascripts/registry/components/collapsible_container.vue
index a03180e80e6..2ce43ef0125 100644
--- a/app/assets/javascripts/registry/components/collapsible_container.vue
+++ b/app/assets/javascripts/registry/components/collapsible_container.vue
@@ -28,11 +28,6 @@
isOpen: false,
};
},
- computed: {
- clipboardText() {
- return `docker pull ${this.repo.location}`;
- },
- },
methods: {
...mapActions([
'fetchRepos',
@@ -84,7 +79,7 @@
<clipboard-button
v-if="repo.location"
- :text="clipboardText"
+ :text="repo.location"
:title="repo.location"
css-class="btn-default btn-transparent btn-clipboard"
/>
diff --git a/app/assets/javascripts/registry/components/table_registry.vue b/app/assets/javascripts/registry/components/table_registry.vue
index a2227b2f554..673b1db6769 100644
--- a/app/assets/javascripts/registry/components/table_registry.vue
+++ b/app/assets/javascripts/registry/components/table_registry.vue
@@ -56,10 +56,6 @@
.catch(() => this.showError(errorMessagesTypes.FETCH_REGISTRY));
},
- clipboardText(text) {
- return `docker pull ${text}`;
- },
-
showError(message) {
Flash(errorMessages[message]);
},
@@ -89,7 +85,7 @@
<clipboard-button
v-if="item.location"
:title="item.location"
- :text="clipboardText(item.location)"
+ :text="item.location"
css-class="btn-default btn-transparent btn-clipboard"
/>
</td>
diff --git a/app/assets/stylesheets/framework/mixins.scss b/app/assets/stylesheets/framework/mixins.scss
index 9ff24ebc127..0ea0b65b95f 100644
--- a/app/assets/stylesheets/framework/mixins.scss
+++ b/app/assets/stylesheets/framework/mixins.scss
@@ -210,3 +210,15 @@
margin-left: -$size;
}
}
+
+/*
+ * Mixin that fixes wrapping issues with long strings (e.g. URLs)
+ *
+ * Note: the width needs to be set for it to work in Firefox
+ */
+@mixin overflow-break-word {
+ overflow-wrap: break-word;
+ word-wrap: break-word;
+ word-break: break-word;
+ max-width: 100%;
+}
diff --git a/app/assets/stylesheets/pages/boards.scss b/app/assets/stylesheets/pages/boards.scss
index 681242f8d85..011d38532b4 100644
--- a/app/assets/stylesheets/pages/boards.scss
+++ b/app/assets/stylesheets/pages/boards.scss
@@ -284,6 +284,9 @@
box-shadow: 0 1px 2px $issue-boards-card-shadow;
list-style: none;
+ // as a fallback, hide overflow content so that dragging and dropping still works
+ overflow: hidden;
+
&:not(:last-child) {
margin-bottom: 5px;
}
@@ -310,14 +313,13 @@
}
.card-title {
+ @include overflow-break-word();
margin: 0 30px 0 0;
font-size: 1em;
line-height: inherit;
a {
color: $gl-text-color;
- word-wrap: break-word;
- word-break: break-word;
margin-right: 2px;
}
}
@@ -462,8 +464,8 @@
}
.issuable-header-text {
+ @include overflow-break-word();
padding-right: 35px;
- word-break: break-word;
> strong {
font-weight: $gl-font-weight-bold;
diff --git a/app/helpers/auto_devops_helper.rb b/app/helpers/auto_devops_helper.rb
index 16451993e93..7b076728685 100644
--- a/app/helpers/auto_devops_helper.rb
+++ b/app/helpers/auto_devops_helper.rb
@@ -24,6 +24,15 @@ module AutoDevopsHelper
end
end
+ def cluster_ingress_ip(project)
+ project
+ .cluster_ingresses
+ .where("external_ip is not null")
+ .limit(1)
+ .pluck(:external_ip)
+ .first
+ end
+
private
def missing_auto_devops_domain?(project)
diff --git a/app/models/project.rb b/app/models/project.rb
index 32d34f5e9b8..534a0e630af 100644
--- a/app/models/project.rb
+++ b/app/models/project.rb
@@ -217,6 +217,7 @@ class Project < ActiveRecord::Base
has_one :cluster_project, class_name: 'Clusters::Project'
has_many :clusters, through: :cluster_project, class_name: 'Clusters::Cluster'
+ has_many :cluster_ingresses, through: :clusters, source: :application_ingress, class_name: 'Clusters::Applications::Ingress'
# Container repositories need to remove data from the container registry,
# which is not managed by the DB. Hence we're still using dependent: :destroy
diff --git a/app/models/user.rb b/app/models/user.rb
index dfef065f094..173ab38e20c 100644
--- a/app/models/user.rb
+++ b/app/models/user.rb
@@ -1097,8 +1097,11 @@ class User < ActiveRecord::Base
# <https://github.com/plataformatec/devise/blob/v4.0.0/lib/devise/models/lockable.rb#L92>
#
def increment_failed_attempts!
+ return if ::Gitlab::Database.read_only?
+
self.failed_attempts ||= 0
self.failed_attempts += 1
+
if attempts_exceeded?
lock_access! unless access_locked?
else
diff --git a/app/views/projects/settings/ci_cd/_autodevops_form.html.haml b/app/views/projects/settings/ci_cd/_autodevops_form.html.haml
index 71e77dae69e..8cb6c446e18 100644
--- a/app/views/projects/settings/ci_cd/_autodevops_form.html.haml
+++ b/app/views/projects/settings/ci_cd/_autodevops_form.html.haml
@@ -35,7 +35,9 @@
= _('Domain')
= form.text_field :domain, class: 'form-control', placeholder: 'domain.com'
.help-block
- = s_('CICD|You need to specify a domain if you want to use Auto Review Apps and Auto Deploy stages.')
+ = s_('CICD|A domain is required to use Auto Review Apps and Auto Deploy Stages.')
+ - if cluster_ingress_ip = cluster_ingress_ip(@project)
+ = s_('%{nip_domain} can be used as an alternative to a custom domain.').html_safe % { nip_domain: "<code>#{cluster_ingress_ip}.nip.io</code>".html_safe }
= link_to icon('question-circle'), help_page_path('topics/autodevops/index.md', anchor: 'auto-devops-base-domain'), target: '_blank'
= f.submit 'Save changes', class: "btn btn-success prepend-top-15"
diff --git a/changelogs/unreleased/40855_remove_authentication_in_readonly_issue_api.yml b/changelogs/unreleased/40855_remove_authentication_in_readonly_issue_api.yml
new file mode 100644
index 00000000000..58686639594
--- /dev/null
+++ b/changelogs/unreleased/40855_remove_authentication_in_readonly_issue_api.yml
@@ -0,0 +1,5 @@
+---
+title: made listing and showing public issue apis available without authentication
+merge_request: 18638
+author: haseebeqx
+type: changed
diff --git a/changelogs/unreleased/43367-fix-board-long-strings.yml b/changelogs/unreleased/43367-fix-board-long-strings.yml
new file mode 100644
index 00000000000..6228741601e
--- /dev/null
+++ b/changelogs/unreleased/43367-fix-board-long-strings.yml
@@ -0,0 +1,5 @@
+---
+title: Fix issue board bug with long strings in titles
+merge_request: 18924
+author:
+type: fixed
diff --git a/changelogs/unreleased/45584-add-nip-io-domain-suggestion-in-auto-devops.yml b/changelogs/unreleased/45584-add-nip-io-domain-suggestion-in-auto-devops.yml
new file mode 100644
index 00000000000..31b4c29e03d
--- /dev/null
+++ b/changelogs/unreleased/45584-add-nip-io-domain-suggestion-in-auto-devops.yml
@@ -0,0 +1,5 @@
+---
+title: Display help text below auto devops domain with nip.io domain name (#45561)
+merge_request: 18496
+author:
+type: added
diff --git a/changelogs/unreleased/46010-add-index-to-runner-type.yml b/changelogs/unreleased/46010-add-index-to-runner-type.yml
new file mode 100644
index 00000000000..fb8340e37b2
--- /dev/null
+++ b/changelogs/unreleased/46010-add-index-to-runner-type.yml
@@ -0,0 +1,5 @@
+---
+title: Add index on runner_type for ci_runners
+merge_request: 18897
+author:
+type: performance
diff --git a/changelogs/unreleased/46361-does-not-log-failed-sign-in-attempts-when-the-database-is-in-read-only-mode.yml b/changelogs/unreleased/46361-does-not-log-failed-sign-in-attempts-when-the-database-is-in-read-only-mode.yml
new file mode 100644
index 00000000000..e4255f11ecf
--- /dev/null
+++ b/changelogs/unreleased/46361-does-not-log-failed-sign-in-attempts-when-the-database-is-in-read-only-mode.yml
@@ -0,0 +1,5 @@
+---
+title: Does not log failed sign-in attempts when the database is in read-only mode
+merge_request: 18957
+author:
+type: fixed
diff --git a/changelogs/unreleased/fix-metrics-content-types.yml b/changelogs/unreleased/fix-metrics-content-types.yml
new file mode 100644
index 00000000000..a418dccffc3
--- /dev/null
+++ b/changelogs/unreleased/fix-metrics-content-types.yml
@@ -0,0 +1,5 @@
+---
+title: Fix setting Gitlab metrics content types
+merge_request:
+author:
+type: fixed
diff --git a/changelogs/unreleased/registry-ux-improvements-remove-clipboard-prefix.yml b/changelogs/unreleased/registry-ux-improvements-remove-clipboard-prefix.yml
new file mode 100644
index 00000000000..ddf7f51aa5e
--- /dev/null
+++ b/changelogs/unreleased/registry-ux-improvements-remove-clipboard-prefix.yml
@@ -0,0 +1,5 @@
+---
+title: Remove docker pull prefix from registry clipboard feature
+merge_request: 18933
+author: Lars Greiss
+type: changed
diff --git a/changelogs/unreleased/sh-enforce-unique-and-not-null-project-ids-project-features.yml b/changelogs/unreleased/sh-enforce-unique-and-not-null-project-ids-project-features.yml
new file mode 100644
index 00000000000..aae42b66c84
--- /dev/null
+++ b/changelogs/unreleased/sh-enforce-unique-and-not-null-project-ids-project-features.yml
@@ -0,0 +1,5 @@
+---
+title: Add a unique and not null constraint on the project_features.project_id column
+merge_request:
+author:
+type: fixed
diff --git a/changelogs/unreleased/zj-ref-contains-sha-mandatory.yml b/changelogs/unreleased/zj-ref-contains-sha-mandatory.yml
new file mode 100644
index 00000000000..61bdce43c0e
--- /dev/null
+++ b/changelogs/unreleased/zj-ref-contains-sha-mandatory.yml
@@ -0,0 +1,5 @@
+---
+title: Refs containting sha checks are done by Gitaly
+merge_request:
+author:
+type: other
diff --git a/db/migrate/20180511090724_add_index_on_ci_runners_runner_type.rb b/db/migrate/20180511090724_add_index_on_ci_runners_runner_type.rb
new file mode 100644
index 00000000000..580f56007c7
--- /dev/null
+++ b/db/migrate/20180511090724_add_index_on_ci_runners_runner_type.rb
@@ -0,0 +1,15 @@
+class AddIndexOnCiRunnersRunnerType < ActiveRecord::Migration
+ include Gitlab::Database::MigrationHelpers
+
+ DOWNTIME = false
+
+ disable_ddl_transaction!
+
+ def up
+ add_concurrent_index :ci_runners, :runner_type
+ end
+
+ def down
+ remove_index :ci_runners, :runner_type
+ end
+end
diff --git a/db/post_migrate/20180511174224_add_unique_constraint_to_project_features_project_id.rb b/db/post_migrate/20180511174224_add_unique_constraint_to_project_features_project_id.rb
new file mode 100644
index 00000000000..88a9f5f8256
--- /dev/null
+++ b/db/post_migrate/20180511174224_add_unique_constraint_to_project_features_project_id.rb
@@ -0,0 +1,43 @@
+class AddUniqueConstraintToProjectFeaturesProjectId < ActiveRecord::Migration
+ include Gitlab::Database::MigrationHelpers
+
+ DOWNTIME = false
+
+ disable_ddl_transaction!
+
+ class ProjectFeature < ActiveRecord::Base
+ self.table_name = 'project_features'
+
+ include EachBatch
+ end
+
+ def up
+ remove_duplicates
+
+ add_concurrent_index :project_features, :project_id, unique: true, name: 'index_project_features_on_project_id_unique'
+ remove_concurrent_index_by_name :project_features, 'index_project_features_on_project_id'
+ rename_index :project_features, 'index_project_features_on_project_id_unique', 'index_project_features_on_project_id'
+ end
+
+ def down
+ rename_index :project_features, 'index_project_features_on_project_id', 'index_project_features_on_project_id_old'
+ add_concurrent_index :project_features, :project_id
+ remove_concurrent_index_by_name :project_features, 'index_project_features_on_project_id_old'
+ end
+
+ private
+
+ def remove_duplicates
+ features = ProjectFeature
+ .select('MAX(id) AS max, COUNT(id), project_id')
+ .group(:project_id)
+ .having('COUNT(id) > 1')
+
+ features.each do |feature|
+ ProjectFeature
+ .where(project_id: feature['project_id'])
+ .where('id <> ?', feature['max'])
+ .each_batch { |batch| batch.delete_all }
+ end
+ end
+end
diff --git a/db/post_migrate/20180512061621_add_not_null_constraint_to_project_features_project_id.rb b/db/post_migrate/20180512061621_add_not_null_constraint_to_project_features_project_id.rb
new file mode 100644
index 00000000000..5a6d6ff4a10
--- /dev/null
+++ b/db/post_migrate/20180512061621_add_not_null_constraint_to_project_features_project_id.rb
@@ -0,0 +1,21 @@
+class AddNotNullConstraintToProjectFeaturesProjectId < ActiveRecord::Migration
+ include Gitlab::Database::MigrationHelpers
+
+ DOWNTIME = false
+
+ class ProjectFeature < ActiveRecord::Base
+ include EachBatch
+
+ self.table_name = 'project_features'
+ end
+
+ def up
+ ProjectFeature.where(project_id: nil).delete_all
+
+ change_column_null :project_features, :project_id, false
+ end
+
+ def down
+ change_column_null :project_features, :project_id, true
+ end
+end
diff --git a/db/schema.rb b/db/schema.rb
index 95adccf0d5c..ed29d202f91 100644
--- a/db/schema.rb
+++ b/db/schema.rb
@@ -11,7 +11,7 @@
#
# It's strongly recommended that you check this file into your version control system.
-ActiveRecord::Schema.define(version: 20180508135515) do
+ActiveRecord::Schema.define(version: 20180512061621) do
# These are extensions that must be enabled in order to support this database
enable_extension "plpgsql"
@@ -503,6 +503,7 @@ ActiveRecord::Schema.define(version: 20180508135515) do
add_index "ci_runners", ["contacted_at"], name: "index_ci_runners_on_contacted_at", using: :btree
add_index "ci_runners", ["is_shared"], name: "index_ci_runners_on_is_shared", using: :btree
add_index "ci_runners", ["locked"], name: "index_ci_runners_on_locked", using: :btree
+ add_index "ci_runners", ["runner_type"], name: "index_ci_runners_on_runner_type", using: :btree
add_index "ci_runners", ["token"], name: "index_ci_runners_on_token", using: :btree
create_table "ci_stages", force: :cascade do |t|
@@ -1493,7 +1494,7 @@ ActiveRecord::Schema.define(version: 20180508135515) do
add_index "project_deploy_tokens", ["project_id", "deploy_token_id"], name: "index_project_deploy_tokens_on_project_id_and_deploy_token_id", unique: true, using: :btree
create_table "project_features", force: :cascade do |t|
- t.integer "project_id"
+ t.integer "project_id", null: false
t.integer "merge_requests_access_level"
t.integer "issues_access_level"
t.integer "wiki_access_level"
@@ -1504,7 +1505,7 @@ ActiveRecord::Schema.define(version: 20180508135515) do
t.integer "repository_access_level", default: 20, null: false
end
- add_index "project_features", ["project_id"], name: "index_project_features_on_project_id", using: :btree
+ add_index "project_features", ["project_id"], name: "index_project_features_on_project_id", unique: true, using: :btree
create_table "project_group_links", force: :cascade do |t|
t.integer "project_id", null: false
diff --git a/doc/administration/high_availability/nfs.md b/doc/administration/high_availability/nfs.md
index ad8ffc46559..957f17e3ea3 100644
--- a/doc/administration/high_availability/nfs.md
+++ b/doc/administration/high_availability/nfs.md
@@ -1,7 +1,7 @@
# NFS
You can view information and options set for each of the mounted NFS file
-systems by running `sudo nfsstat -m`.
+systems by running `nfsstat -m` and `cat /etc/fstab`.
## NFS Server features
diff --git a/doc/ci/quick_start/README.md b/doc/ci/quick_start/README.md
index fec0ff87326..47e658f610e 100644
--- a/doc/ci/quick_start/README.md
+++ b/doc/ci/quick_start/README.md
@@ -151,7 +151,8 @@ The next step is to configure a Runner so that it picks the pending jobs.
In GitLab, Runners run the jobs that you define in `.gitlab-ci.yml`. A Runner
can be a virtual machine, a VPS, a bare-metal machine, a docker container or
even a cluster of containers. GitLab and the Runners communicate through an API,
-so the only requirement is that the Runner's machine has [Internet] access.
+so the only requirement is that the Runner's machine has network access to the
+GitLab server.
A Runner can be specific to a certain project or serve multiple projects in
GitLab. If it serves all projects it's called a _Shared Runner_.
@@ -226,4 +227,3 @@ CI with various languages.
[enabled]: ../enable_or_disable_ci.md
[stages]: ../yaml/README.md#stages
[pipeline]: ../pipelines.md
-[internet]: https://about.gitlab.com/images/theinternet.png
diff --git a/doc/development/fe_guide/development_process.md b/doc/development/fe_guide/development_process.md
index 5504a6421d5..d240dbe8b02 100644
--- a/doc/development/fe_guide/development_process.md
+++ b/doc/development/fe_guide/development_process.md
@@ -22,9 +22,9 @@ Please use your best judgement when to use it and please contribute new points t
- [ ] Are all [departments](https://about.gitlab.com/handbook/engineering/#engineering-teams) that are needed from your perspective already involved in the issue? (For example is UX missing?)
- [ ] Is the specification complete? Are you missing decisions? How about error handling/defaults/edge cases? Take your time to understand the needed implementation and go through its flow.
- [ ] Are all necessary UX specifications available that you will need in order to implement? Are there new UX components/patterns in the designs? Then contact the UI component team early on. How should error messages or validation be handled?
-- [ ] **Library usage** Use Vuex as soon as you have even a medium state to manage, use Vue router if you need to have different views internally and want to link from the outside. Check what libraries we already have for which occassions.
+- [ ] **Library usage** Use Vuex as soon as you have even a medium state to manage, use Vue router if you need to have different views internally and want to link from the outside. Check what libraries we already have for which occasions.
- [ ] **Plan your implementation:**
- - [ ] **Architecture plan:** Create a plan aligned with GitLab's architecture, how you are going to do the implementation, for example Vue application setup and its components (through [onion skinning](https://gitlab.com/gitlab-org/gitlab-ce/issues/35873#note_39994091)), Store structure and data flow, which existing Vue components can you reuse. Its a good idea to go through your plan with another engineer to refine it.
+ - [ ] **Architecture plan:** Create a plan aligned with GitLab's architecture, how you are going to do the implementation, for example Vue application setup and its components (through [onion skinning](https://gitlab.com/gitlab-org/gitlab-ce/issues/35873#note_39994091)), Store structure and data flow, which existing Vue components can you reuse. It's a good idea to go through your plan with another engineer to refine it.
- [ ] **Backend:** The best way is to kickoff the implementation in a call and discuss with the assigned Backend engineer what you will need from the backend and also when. Can you reuse existing API's? How is the performance with the planned architecture? Maybe create together a JSON mock object to already start with development.
- [ ] **Communication:** It also makes sense to have for bigger features an own slack channel (normally called #f_{feature_name}) and even weekly demo calls with all people involved.
- [ ] **Dependency Plan:** Are there big dependencies in the plan between you and others, then maybe create an execution diagram to show what is blocking which part and the order of the different parts.
@@ -56,7 +56,7 @@ Please use your best judgement when to use it and please contribute new points t
- [ ] If you have multiple MR's then also smoke test against the final merge.
- [ ] Are there any big changes on how and especially how frequently we use the API then let production know about it
- [ ] Smoke test of the RC on dev., staging., canary deployments and .com
-- [ ] Follow up on issues that came out of the review. Create isssues for discovered edge cases that should be covered in future iterations.
+- [ ] Follow up on issues that came out of the review. Create issues for discovered edge cases that should be covered in future iterations.
---
diff --git a/doc/development/fe_guide/vuex.md b/doc/development/fe_guide/vuex.md
index 6a89bfc7721..8997a5889dc 100644
--- a/doc/development/fe_guide/vuex.md
+++ b/doc/development/fe_guide/vuex.md
@@ -68,10 +68,10 @@ Often we need to provide data from haml to our Vue application. Let's store it i
You can use `mapState` to access state properties in the components.
### `actions.js`
-An action is a playload of information to send data from our application to our store.
+An action is a payload of information to send data from our application to our store.
An action is usually composed by a `type` and a `payload` and they describe what happened.
-Enforcing that every change is described as an action lets us have a clear understanting of what is going on in the app.
+Enforcing that every change is described as an action lets us have a clear understanding of what is going on in the app.
In this file, we will write the actions that will call the respective mutations:
@@ -87,7 +87,7 @@ In this file, we will write the actions that will call the respective mutations:
export const fetchUsers = ({ state, dispatch }) => {
dispatch('requestUsers');
- axios.get(state.endoint)
+ axios.get(state.endpoint)
.then(({ data }) => dispatch('receiveUsersSuccess', data))
.catch((error) => {
dispatch('receiveUsersError', error)
@@ -102,7 +102,7 @@ In this file, we will write the actions that will call the respective mutations:
export const addUser = ({ state, dispatch }, user) => {
dispatch('requestAddUser');
- axios.post(state.endoint, user)
+ axios.post(state.endpoint, user)
.then(({ data }) => dispatch('receiveAddUserSuccess', data))
.catch((error) => dispatch('receiveAddUserError', error));
}
@@ -126,7 +126,7 @@ The component MUST only dispatch the `fetchNamespace` action. Actions namespaced
The `fetch` action will be responsible to dispatch `requestNamespace`, `receiveNamespaceSuccess` and `receiveNamespaceError`
By following this pattern we guarantee:
-1. All aplications follow the same pattern, making it easier for anyone to maintain the code
+1. All applications follow the same pattern, making it easier for anyone to maintain the code
1. All data in the application follows the same lifecycle pattern
1. Actions are contained and human friendly
1. Unit tests are easier
@@ -149,7 +149,7 @@ import { mapActions } from 'vuex';
};
```
-#### `mutations.js`
+### `mutations.js`
The mutations specify how the application state changes in response to actions sent to the store.
The only way to change state in a Vuex store should be by committing a mutation.
@@ -175,7 +175,7 @@ Remember that actions only describe that something happened, they don't describe
state.isLoading = false;
},
[types.REQUEST_ADD_USER](state, user) {
- state.isAddingUser = true;
+ state.isAddingUser = true;
},
[types.RECEIVE_ADD_USER_SUCCESS](state, user) {
state.isAddingUser = false;
@@ -183,12 +183,12 @@ Remember that actions only describe that something happened, they don't describe
},
[types.REQUEST_ADD_USER_ERROR](state, error) {
state.isAddingUser = true;
- state.errorAddingUser = error∂;
+ state.errorAddingUser = error;
},
};
```
-#### `getters.js`
+### `getters.js`
Sometimes we may need to get derived state based on store state, like filtering for a specific prop.
Using a getter will also cache the result based on dependencies due to [how computed props work](https://vuejs.org/v2/guide/computed.html#Computed-Caching-vs-Methods)
This can be done through the `getters`:
@@ -213,7 +213,7 @@ import { mapGetters } from 'vuex';
};
```
-#### `mutations_types.js`
+### `mutations_types.js`
From [vuex mutations docs][vuex-mutations]:
> It is a commonly seen pattern to use constants for mutation types in various Flux implementations. This allows the code to take advantage of tooling like linters, and putting all constants in a single file allows your collaborators to get an at-a-glance view of what mutations are possible in the entire application.
@@ -289,7 +289,7 @@ export default {
```
### Vuex Gotchas
-1. Do not call a mutation directly. Always use an action to commit a mutation. Doing so will keep consistency through out the application. From Vuex docs:
+1. Do not call a mutation directly. Always use an action to commit a mutation. Doing so will keep consistency throughout the application. From Vuex docs:
> why don't we just call store.commit('action') directly? Well, remember that mutations must be synchronous? Actions aren't. We can perform asynchronous operations inside an action.
@@ -342,7 +342,7 @@ describe('component', () => {
};
// populate the store
- store.dipatch('addUser', user);
+ store.dispatch('addUser', user);
vm = new Component({
store,
@@ -352,6 +352,18 @@ describe('component', () => {
});
```
+#### Testing Vuex actions and getters
+Because we're currently using [`babel-plugin-rewire`](https://github.com/speedskater/babel-plugin-rewire), you may encounter the following error when testing your Vuex actions and getters:
+`[vuex] actions should be function or object with "handler" function`
+
+To prevent this error from happening, you need to export an empty function as `default`:
+```
+// getters.js or actions.js
+
+// prevent babel-plugin-rewire from generating an invalid default during karma tests
+export default () => {};
+```
+
[vuex-docs]: https://vuex.vuejs.org
[vuex-structure]: https://vuex.vuejs.org/en/structure.html
[vuex-mutations]: https://vuex.vuejs.org/en/mutations.html
diff --git a/doc/development/query_recorder.md b/doc/development/query_recorder.md
index 12e90101139..26d3355e94d 100644
--- a/doc/development/query_recorder.md
+++ b/doc/development/query_recorder.md
@@ -2,7 +2,7 @@
QueryRecorder is a tool for detecting the [N+1 queries problem](http://guides.rubyonrails.org/active_record_querying.html#eager-loading-associations) from tests.
-> Implemented in [spec/support/query_recorder.rb](https://gitlab.com/gitlab-org/gitlab-ce/blob/master/spec/support/query_recorder.rb) via [9c623e3e](https://gitlab.com/gitlab-org/gitlab-ce/commit/9c623e3e5d7434f2e30f7c389d13e5af4ede770a)
+> Implemented in [spec/support/query_recorder.rb](https://gitlab.com/gitlab-org/gitlab-ce/blob/master/spec/support/helpers/query_recorder.rb) via [9c623e3e](https://gitlab.com/gitlab-org/gitlab-ce/commit/9c623e3e5d7434f2e30f7c389d13e5af4ede770a)
As a rule, merge requests [should not increase query counts](merge_request_performance_guidelines.md#query-counts). If you find yourself adding something like `.includes(:author, :assignee)` to avoid having `N+1` queries, consider using QueryRecorder to enforce this with a test. Without this, a new feature which causes an additional model to be accessed will silently reintroduce the problem.
diff --git a/doc/development/testing_guide/best_practices.md b/doc/development/testing_guide/best_practices.md
index 9d3f2935127..a76a5096b69 100644
--- a/doc/development/testing_guide/best_practices.md
+++ b/doc/development/testing_guide/best_practices.md
@@ -133,11 +133,24 @@ really fast since:
- gitlab-shell and Gitaly setup are skipped
- Test repositories setup are skipped
-Note that in some cases, you might have to add some `require_dependency 'foo'`
-in your file under test since Rails autoloading is not available in these cases.
-
-This shouldn't be a problem since explicitely listing dependencies should be
-considered a good practice anyway.
+`fast_spec_helper` also support autoloading classes that are located inside the
+`lib/` directory. It means that as long as your class / module is using only
+code from the `lib/` directory you will not need to explicitly load any
+dependencies. `fast_spec_helper` also loads all ActiveSupport extensions,
+including core extensions that are commonly used in the Rails environment.
+
+Note that in some cases, you might still have to load some dependencies using
+`require_dependency` when a code is using gems or a dependency is not located
+in `lib/`.
+
+For example, if you want to test your code that is calling the
+`Gitlab::UntrustedRegexp` class, which under the hood uses `re2` library, you
+should either add `require_dependency 're2'` to files in your library that
+need `re2` gem, to make this requirement explicit, or you can add it to the
+spec itself, but the former is preferred.
+
+It takes around one second to load tests that are using `fast_spec_helper`
+instead of 30+ seconds in case of a regular `spec_helper`.
### `let` variables
diff --git a/doc/user/gitlab_com/index.md b/doc/user/gitlab_com/index.md
index 7baccb796c6..0c1cd113686 100644
--- a/doc/user/gitlab_com/index.md
+++ b/doc/user/gitlab_com/index.md
@@ -75,7 +75,6 @@ Shared Runners on GitLab.com run in [autoscale mode] and powered by
Google Cloud Platform and DigitalOcean. Autoscaling means reduced
waiting times to spin up CI/CD jobs, and isolated VMs for each project,
thus maximizing security.
-
They're free to use for public open source projects and limited to 2000 CI
minutes per month per group for private projects. Read about all
[GitLab.com plans](https://about.gitlab.com/pricing/).
@@ -90,6 +89,10 @@ ephemeral instances with 3.75GB of RAM, CoreOS and the latest Docker Engine
installed. Instances provide 1 vCPU and 25GB of HDD disk space. The default
region of the VMs is US East1.
+Jobs handled by the shared Runners on GitLab.com (`shared-runners-manager-X.gitlab.com`),
+**will be timed out after 3 hours**, regardless of the timeout configured in a
+project. Check the issues [4010] and [4070] for the reference.
+
Below are the shared Runners settings.
| Setting | GitLab.com | Default |
@@ -340,3 +343,5 @@ High Performance TCP/HTTP Load Balancer:
[mailgun]: https://www.mailgun.com/ "Mailgun website"
[sidekiq]: http://sidekiq.org/ "Sidekiq website"
[unicorn-worker-killer]: https://rubygems.org/gems/unicorn-worker-killer "unicorn-worker-killer"
+[4010]: https://gitlab.com/gitlab-com/infrastructure/issues/4010 "Find a good value for maximum timeout for Shared Runners"
+[4070]: https://gitlab.com/gitlab-com/infrastructure/issues/4070 "Configure per-runner timeout for shared-runners-manager-X on GitLab.com"
diff --git a/doc/user/project/bulk_editing.md b/doc/user/project/bulk_editing.md
new file mode 100644
index 00000000000..324a7fa6603
--- /dev/null
+++ b/doc/user/project/bulk_editing.md
@@ -0,0 +1,17 @@
+# Bulk Editing
+
+>**Note:**
+- A permission level of `Reporter` or higher is required in order to manage
+issues.
+- A permission level of `Developer` or higher is required in order to manage
+merge requests.
+
+Fields across multiple issues or merge requests can be updated simutaneously by using the bulk edit feature.
+
+>**Note:**
+- Bulk editing of issues and merge requests is only available at the project level.
+
+To access the feature, navigate to either the issue or merge request list for the project and click 'Edit Issues' or 'Edit Merge Requests'. This will cause a sidebar to be shown on the right-hand side of the screen, where the available, editable fields are displayed. Checkboxes will also appear to the left-hand side of each issue or merge request, ready to be selected.
+
+Once all items have been selected, choose the appropriate fields and their values from the sidebar and click 'Update All' to apply these changes.
+
diff --git a/doc/user/project/issues/index.md b/doc/user/project/issues/index.md
index be4436749f9..bf17731c523 100644
--- a/doc/user/project/issues/index.md
+++ b/doc/user/project/issues/index.md
@@ -151,3 +151,7 @@ or Bugzilla.
### Issue's API
Read through the [API documentation](../../../api/issues.md).
+
+### Bulk editing issues
+
+Find out about [bulk editing issues](../../project/bulk_editing.md).
diff --git a/doc/user/project/merge_requests/index.md b/doc/user/project/merge_requests/index.md
index a6c0fd49c45..5932f5a2bc1 100644
--- a/doc/user/project/merge_requests/index.md
+++ b/doc/user/project/merge_requests/index.md
@@ -233,6 +233,10 @@ all your changes will be available to preview by anyone with the Review Apps lin
[Read more about Review Apps.](../../../ci/review_apps/index.md)
+## Bulk editing merge requests
+
+Find out about [bulk editing merge requests](../../project/bulk_editing.md).
+
## Tips
Here are some tips that will help you be more efficient with merge requests in
diff --git a/doc/user/project/web_ide/img/commit_changes.png b/doc/user/project/web_ide/img/commit_changes.png
index b6fcbf699aa..a5364c12760 100644
--- a/doc/user/project/web_ide/img/commit_changes.png
+++ b/doc/user/project/web_ide/img/commit_changes.png
Binary files differ
diff --git a/doc/user/project/web_ide/index.md b/doc/user/project/web_ide/index.md
index b7064b83c4e..105d8a6ab61 100644
--- a/doc/user/project/web_ide/index.md
+++ b/doc/user/project/web_ide/index.md
@@ -13,15 +13,27 @@ and from merge requests.
![Open Web IDE](img/open_web_ide.png)
-## Commit changes
+## File finder
-Changed files are shown on the right in the commit panel. All changes are
-automatically staged. To commit your changes, add a commit message and click
-the 'Commit Button'.
+> [Introduced in](https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/18323) [GitLab Core][ce] 10.8.
+
+The file finder allows you to quickly open files in the current branch by
+searching. The file finder is launched using the keyboard shortcut `Command-p`,
+`Control-p`, or `t` (when editor is not in focus). Type the filename or
+file path fragments to start seeing results.
+
+## Stage and commit changes
+
+After making your changes, click the Commit button in the bottom left to
+review the list of changed files. Click on each file to review the changes and
+click the tick icon to stage the file.
+
+Once you have staged some changes, you can add a commit message and commit the
+staged changes. Unstaged changes will not be commited.
![Commit changes](img/commit_changes.png)
-## Comparing changes
+## Reviewing changes
Before you commit your changes, you can compare them with the previous commit
by switching to the review mode or selecting the file from the staged files
@@ -30,4 +42,5 @@ list.
An additional review mode is available when you open a merge request, which
shows you a preview of the merge request diff if you commit your changes.
+[ce]: https://about.gitlab.com/pricing/
[ee]: https://about.gitlab.com/pricing/
diff --git a/lib/api/issues.rb b/lib/api/issues.rb
index 12ff2a1398b..2f50f94c897 100644
--- a/lib/api/issues.rb
+++ b/lib/api/issues.rb
@@ -2,7 +2,7 @@ module API
class Issues < Grape::API
include PaginationParams
- before { authenticate! }
+ before { authenticate_non_get! }
helpers ::Gitlab::IssuableMetadata
@@ -70,6 +70,7 @@ module API
desc: 'Return issues for the given scope: `created-by-me`, `assigned-to-me` or `all`'
end
get do
+ authenticate! unless params[:scope] == 'all'
issues = paginate(find_issues)
options = {
diff --git a/lib/gitlab/git/repository.rb b/lib/gitlab/git/repository.rb
index 29a3a35812c..25487f53999 100644
--- a/lib/gitlab/git/repository.rb
+++ b/lib/gitlab/git/repository.rb
@@ -1467,25 +1467,11 @@ module Gitlab
end
def branch_names_contains_sha(sha)
- gitaly_migrate(:branch_names_contains_sha,
- status: Gitlab::GitalyClient::MigrationStatus::OPT_OUT) do |is_enabled|
- if is_enabled
- gitaly_ref_client.branch_names_contains_sha(sha)
- else
- refs_contains_sha('refs/heads/', sha)
- end
- end
+ gitaly_ref_client.branch_names_contains_sha(sha)
end
def tag_names_contains_sha(sha)
- gitaly_migrate(:tag_names_contains_sha,
- status: Gitlab::GitalyClient::MigrationStatus::OPT_OUT) do |is_enabled|
- if is_enabled
- gitaly_ref_client.tag_names_contains_sha(sha)
- else
- refs_contains_sha('refs/tags/', sha)
- end
- end
+ gitaly_ref_client.tag_names_contains_sha(sha)
end
def search_files_by_content(query, ref)
@@ -1620,27 +1606,6 @@ module Gitlab
end
end
- def refs_contains_sha(refs_prefix, sha)
- refs_prefix << "/" unless refs_prefix.ends_with?('/')
-
- # By forcing the output to %(refname) each line wiht a ref will start with
- # the ref prefix. All other lines can be discarded.
- args = %W(for-each-ref --contains=#{sha} --format=%(refname) #{refs_prefix})
- names, code = run_git(args)
-
- return [] unless code.zero?
-
- refs = []
- left_slice_count = refs_prefix.length
- names.lines.each do |line|
- next unless line.start_with?(refs_prefix)
-
- refs << encode_utf8(line.rstrip[left_slice_count..-1])
- end
-
- refs
- end
-
def rugged_write_config(full_path:)
rugged.config['gitlab.fullpath'] = full_path
end
diff --git a/lib/gitlab/import_export/relation_factory.rb b/lib/gitlab/import_export/relation_factory.rb
index e3e9f156fb4..4a41a69840b 100644
--- a/lib/gitlab/import_export/relation_factory.rb
+++ b/lib/gitlab/import_export/relation_factory.rb
@@ -28,7 +28,7 @@ module Gitlab
IMPORTED_OBJECT_MAX_RETRIES = 5.freeze
- EXISTING_OBJECT_CHECK = %i[milestone milestones label labels project_label project_labels group_label group_labels].freeze
+ EXISTING_OBJECT_CHECK = %i[milestone milestones label labels project_label project_labels group_label group_labels project_feature].freeze
TOKEN_RESET_MODELS = %w[Ci::Trigger Ci::Build ProjectHook].freeze
diff --git a/lib/gitlab/metrics/web_transaction.rb b/lib/gitlab/metrics/web_transaction.rb
index 89ff02a96d6..7cf33ca9e8a 100644
--- a/lib/gitlab/metrics/web_transaction.rb
+++ b/lib/gitlab/metrics/web_transaction.rb
@@ -4,18 +4,6 @@ module Gitlab
CONTROLLER_KEY = 'action_controller.instance'.freeze
ENDPOINT_KEY = 'api.endpoint'.freeze
- CONTENT_TYPES = {
- 'text/html' => :html,
- 'text/plain' => :txt,
- 'application/json' => :json,
- 'text/js' => :js,
- 'application/atom+xml' => :atom,
- 'image/png' => :png,
- 'image/jpeg' => :jpeg,
- 'image/gif' => :gif,
- 'image/svg+xml' => :svg
- }.freeze
-
def initialize(env)
super()
@env = env
@@ -40,7 +28,7 @@ module Gitlab
controller = @env[CONTROLLER_KEY]
action = "#{controller.action_name}"
- suffix = CONTENT_TYPES[controller.content_type]
+ suffix = controller.request_format
if suffix && suffix != :html
action += ".#{suffix}"
diff --git a/locale/gitlab.pot b/locale/gitlab.pot
index 20377dc81b2..1179f71353a 100644
--- a/locale/gitlab.pot
+++ b/locale/gitlab.pot
@@ -8,8 +8,8 @@ msgid ""
msgstr ""
"Project-Id-Version: gitlab 1.0.0\n"
"Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2018-05-09 09:24+0200\n"
-"PO-Revision-Date: 2018-05-09 09:24+0200\n"
+"POT-Creation-Date: 2018-05-14 10:49+0200\n"
+"PO-Revision-Date: 2018-05-14 10:49+0200\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n"
"Language: \n"
@@ -72,6 +72,9 @@ msgstr[1] ""
msgid "%{loadingIcon} Started"
msgstr ""
+msgid "%{nip_domain} can be used as an alternative to a custom domain."
+msgstr ""
+
msgid "%{number_commits_behind} commits behind %{default_branch}, %{number_commits_ahead} commits ahead"
msgstr ""
@@ -737,6 +740,9 @@ msgstr ""
msgid "CI/CD settings"
msgstr ""
+msgid "CICD|A domain is required to use Auto Review Apps and Auto Deploy Stages."
+msgstr ""
+
msgid "CICD|An explicit %{ci_file} needs to be specified before you can begin using Continuous Integration and Delivery."
msgstr ""
@@ -767,9 +773,6 @@ msgstr ""
msgid "CICD|The Auto DevOps pipeline configuration will be used when there is no %{ci_file} in the project."
msgstr ""
-msgid "CICD|You need to specify a domain if you want to use Auto Review Apps and Auto Deploy stages."
-msgstr ""
-
msgid "Can run untagged jobs"
msgstr ""
diff --git a/spec/fast_spec_helper.rb b/spec/fast_spec_helper.rb
index 978113a08a4..134eb25e4b1 100644
--- a/spec/fast_spec_helper.rb
+++ b/spec/fast_spec_helper.rb
@@ -3,14 +3,8 @@ require 'bundler/setup'
ENV['GITLAB_ENV'] = 'test'
ENV['IN_MEMORY_APPLICATION_SETTINGS'] = 'true'
-unless Object.respond_to?(:require_dependency)
- class Object
- alias_method :require_dependency, :require
- end
-end
-
-# Defines Settings and Gitlab.config which are at the center of the app
require_relative '../config/settings'
-require_relative '../lib/gitlab' unless defined?(Gitlab.config)
-
require_relative 'support/rspec'
+require 'active_support/all'
+
+ActiveSupport::Dependencies.autoload_paths << 'lib'
diff --git a/spec/features/projects/settings/pipelines_settings_spec.rb b/spec/features/projects/settings/pipelines_settings_spec.rb
index e875a88a52b..cfdae246c09 100644
--- a/spec/features/projects/settings/pipelines_settings_spec.rb
+++ b/spec/features/projects/settings/pipelines_settings_spec.rb
@@ -75,6 +75,29 @@ describe "Projects > Settings > Pipelines settings" do
expect(project.auto_devops).not_to be_enabled
expect(project.auto_devops.domain).to eq('test.com')
end
+
+ context 'when there is a cluster with ingress and external_ip' do
+ before do
+ cluster = create(:cluster, projects: [project])
+ cluster.create_application_ingress!(external_ip: '192.168.1.100')
+ end
+
+ it 'shows the help text with the nip.io domain as an alternative to custom domain' do
+ visit project_settings_ci_cd_path(project)
+ expect(page).to have_content('192.168.1.100.nip.io can be used as an alternative to a custom domain')
+ end
+ end
+
+ context 'when there is no ingress' do
+ before do
+ create(:cluster, projects: [project])
+ end
+
+ it 'alternative to custom domain is not shown' do
+ visit project_settings_ci_cd_path(project)
+ expect(page).not_to have_content('can be used as an alternative to a custom domain')
+ end
+ end
end
end
end
diff --git a/spec/lib/gitlab/git/repository_spec.rb b/spec/lib/gitlab/git/repository_spec.rb
index cce84276fe3..fcb690d8aa3 100644
--- a/spec/lib/gitlab/git/repository_spec.rb
+++ b/spec/lib/gitlab/git/repository_spec.rb
@@ -615,32 +615,22 @@ describe Gitlab::Git::Repository, seed_helper: true do
end
describe '#branch_names_contains_sha' do
- shared_examples 'returning the right branches' do
- let(:head_id) { repository.rugged.head.target.oid }
- let(:new_branch) { head_id }
- let(:utf8_branch) { 'branch-é' }
+ let(:head_id) { repository.rugged.head.target.oid }
+ let(:new_branch) { head_id }
+ let(:utf8_branch) { 'branch-é' }
- before do
- repository.create_branch(new_branch, 'master')
- repository.create_branch(utf8_branch, 'master')
- end
-
- after do
- repository.delete_branch(new_branch)
- repository.delete_branch(utf8_branch)
- end
-
- it 'displays that branch' do
- expect(repository.branch_names_contains_sha(head_id)).to include('master', new_branch, utf8_branch)
- end
+ before do
+ repository.create_branch(new_branch, 'master')
+ repository.create_branch(utf8_branch, 'master')
end
- context 'when Gitaly is enabled' do
- it_behaves_like 'returning the right branches'
+ after do
+ repository.delete_branch(new_branch)
+ repository.delete_branch(utf8_branch)
end
- context 'when Gitaly is disabled', :disable_gitaly do
- it_behaves_like 'returning the right branches'
+ it 'displays that branch' do
+ expect(repository.branch_names_contains_sha(head_id)).to include('master', new_branch, utf8_branch)
end
end
diff --git a/spec/lib/gitlab/import_export/all_models.yml b/spec/lib/gitlab/import_export/all_models.yml
index ad76adcc2e5..8b46b04b8b5 100644
--- a/spec/lib/gitlab/import_export/all_models.yml
+++ b/spec/lib/gitlab/import_export/all_models.yml
@@ -185,6 +185,7 @@ project:
- cluster
- clusters
- cluster_project
+- cluster_ingresses
- creator
- group
- namespace
diff --git a/spec/lib/gitlab/metrics/web_transaction_spec.rb b/spec/lib/gitlab/metrics/web_transaction_spec.rb
index 1d162f53a13..c07b33a039a 100644
--- a/spec/lib/gitlab/metrics/web_transaction_spec.rb
+++ b/spec/lib/gitlab/metrics/web_transaction_spec.rb
@@ -180,11 +180,11 @@ describe Gitlab::Metrics::WebTransaction do
end
context 'when request goes to ActionController' do
- let(:content_type) { 'text/html' }
+ let(:request_format) { :html }
before do
klass = double(:klass, name: 'TestController')
- controller = double(:controller, class: klass, action_name: 'show', content_type: content_type)
+ controller = double(:controller, class: klass, action_name: 'show', request_format: request_format)
env['action_controller.instance'] = controller
end
@@ -195,7 +195,7 @@ describe Gitlab::Metrics::WebTransaction do
end
context 'when the response content type is not :html' do
- let(:content_type) { 'application/json' }
+ let(:request_format) { :json }
it 'appends the mime type to the transaction action' do
expect(transaction.labels).to eq({ controller: 'TestController', action: 'show.json' })
diff --git a/spec/migrations/add_unique_constraint_to_project_features_project_id_spec.rb b/spec/migrations/add_unique_constraint_to_project_features_project_id_spec.rb
new file mode 100644
index 00000000000..bf299b70a29
--- /dev/null
+++ b/spec/migrations/add_unique_constraint_to_project_features_project_id_spec.rb
@@ -0,0 +1,59 @@
+require 'spec_helper'
+require Rails.root.join('db', 'post_migrate', '20180511174224_add_unique_constraint_to_project_features_project_id.rb')
+
+describe AddUniqueConstraintToProjectFeaturesProjectId, :migration do
+ let(:namespaces) { table(:namespaces) }
+ let(:projects) { table(:projects) }
+ let(:features) { table(:project_features) }
+ let(:migration) { described_class.new }
+
+ describe '#up' do
+ before do
+ (1..3).each do |i|
+ namespaces.create(id: i, name: "ns-test-#{i}", path: "ns-test-i#{i}")
+ projects.create!(id: i, name: "test-#{i}", path: "test-#{i}", namespace_id: i)
+ end
+
+ features.create!(id: 1, project_id: 1)
+ features.create!(id: 2, project_id: 1)
+ features.create!(id: 3, project_id: 2)
+ features.create!(id: 4, project_id: 2)
+ features.create!(id: 5, project_id: 2)
+ features.create!(id: 6, project_id: 3)
+ end
+
+ it 'creates a unique index and removes duplicates' do
+ expect(migration.index_exists?(:project_features, :project_id, unique: false, name: 'index_project_features_on_project_id')).to be true
+
+ expect { migration.up }.to change { features.count }.from(6).to(3)
+
+ expect(migration.index_exists?(:project_features, :project_id, unique: true, name: 'index_project_features_on_project_id')).to be true
+ expect(migration.index_exists?(:project_features, :project_id, name: 'index_project_features_on_project_id_unique')).to be false
+
+ project_1_features = features.where(project_id: 1)
+ expect(project_1_features.count).to eq(1)
+ expect(project_1_features.first.id).to eq(2)
+
+ project_2_features = features.where(project_id: 2)
+ expect(project_2_features.count).to eq(1)
+ expect(project_2_features.first.id).to eq(5)
+
+ project_3_features = features.where(project_id: 3)
+ expect(project_3_features.count).to eq(1)
+ expect(project_3_features.first.id).to eq(6)
+ end
+ end
+
+ describe '#down' do
+ it 'restores the original index' do
+ migration.up
+
+ expect(migration.index_exists?(:project_features, :project_id, unique: true, name: 'index_project_features_on_project_id')).to be true
+
+ migration.down
+
+ expect(migration.index_exists?(:project_features, :project_id, unique: false, name: 'index_project_features_on_project_id')).to be true
+ expect(migration.index_exists?(:project_features, :project_id, name: 'index_project_features_on_project_id_old')).to be false
+ end
+ end
+end
diff --git a/spec/models/guest_spec.rb b/spec/models/guest_spec.rb
index 2afdd6751a4..fc30f3056e5 100644
--- a/spec/models/guest_spec.rb
+++ b/spec/models/guest_spec.rb
@@ -1,9 +1,9 @@
require 'spec_helper'
describe Guest do
- let(:public_project) { build_stubbed(:project, :public) }
- let(:private_project) { build_stubbed(:project, :private) }
- let(:internal_project) { build_stubbed(:project, :internal) }
+ set(:public_project) { create(:project, :public) }
+ set(:private_project) { create(:project, :private) }
+ set(:internal_project) { create(:project, :internal) }
describe '.can_pull?' do
context 'when project is private' do
diff --git a/spec/models/user_spec.rb b/spec/models/user_spec.rb
index ad094b3ed48..bb5308221f0 100644
--- a/spec/models/user_spec.rb
+++ b/spec/models/user_spec.rb
@@ -2755,4 +2755,18 @@ describe User do
it { is_expected.to be_truthy }
end
end
+
+ describe '#increment_failed_attempts!' do
+ subject(:user) { create(:user, failed_attempts: 0) }
+
+ it 'logs failed sign-in attempts' do
+ expect { user.increment_failed_attempts! }.to change(user, :failed_attempts).from(0).to(1)
+ end
+
+ it 'does not log failed sign-in attempts when in a GitLab read-only instance' do
+ allow(Gitlab::Database).to receive(:read_only?) { true }
+
+ expect { user.increment_failed_attempts! }.not_to change(user, :failed_attempts)
+ end
+ end
end
diff --git a/spec/requests/api/issues_spec.rb b/spec/requests/api/issues_spec.rb
index 90f9c4ad214..60e174ff92a 100644
--- a/spec/requests/api/issues_spec.rb
+++ b/spec/requests/api/issues_spec.rb
@@ -64,12 +64,32 @@ describe API::Issues do
describe "GET /issues" do
context "when unauthenticated" do
- it "returns authentication error" do
+ it "returns an array of all issues" do
+ get api("/issues"), scope: 'all'
+
+ expect(response).to have_http_status(200)
+ expect(json_response).to be_an Array
+ end
+
+ it "returns authentication error without any scope" do
get api("/issues")
- expect(response).to have_gitlab_http_status(401)
+ expect(response).to have_http_status(401)
+ end
+
+ it "returns authentication error when scope is assigned-to-me" do
+ get api("/issues"), scope: 'assigned-to-me'
+
+ expect(response).to have_http_status(401)
+ end
+
+ it "returns authentication error when scope is created-by-me" do
+ get api("/issues"), scope: 'created-by-me'
+
+ expect(response).to have_http_status(401)
end
end
+
context "when authenticated" do
let(:first_issue) { json_response.first }
@@ -379,9 +399,6 @@ describe API::Issues do
end
let!(:group_note) { create(:note_on_issue, author: user, project: group_project, noteable: group_issue) }
- before do
- group_project.add_reporter(user)
- end
let(:base_url) { "/groups/#{group.id}/issues" }
context 'when group has subgroups', :nested_groups do
@@ -408,178 +425,201 @@ describe API::Issues do
end
end
- it 'returns all group issues (including opened and closed)' do
- get api(base_url, admin)
+ context 'when user is unauthenticated' do
+ it 'lists all issues in public projects' do
+ get api(base_url)
- expect_paginated_array_response(size: 3)
+ expect_paginated_array_response(size: 2)
+ end
end
- it 'returns group issues without confidential issues for non project members' do
- get api("#{base_url}?state=opened", non_member)
+ context 'when user is a group member' do
+ before do
+ group_project.add_reporter(user)
+ end
- expect_paginated_array_response(size: 1)
- expect(json_response.first['title']).to eq(group_issue.title)
- end
+ it 'returns all group issues (including opened and closed)' do
+ get api(base_url, admin)
- it 'returns group confidential issues for author' do
- get api("#{base_url}?state=opened", author)
+ expect_paginated_array_response(size: 3)
+ end
- expect_paginated_array_response(size: 2)
- end
+ it 'returns group issues without confidential issues for non project members' do
+ get api("#{base_url}?state=opened", non_member)
- it 'returns group confidential issues for assignee' do
- get api("#{base_url}?state=opened", assignee)
+ expect_paginated_array_response(size: 1)
+ expect(json_response.first['title']).to eq(group_issue.title)
+ end
- expect_paginated_array_response(size: 2)
- end
+ it 'returns group confidential issues for author' do
+ get api("#{base_url}?state=opened", author)
- it 'returns group issues with confidential issues for project members' do
- get api("#{base_url}?state=opened", user)
+ expect_paginated_array_response(size: 2)
+ end
- expect_paginated_array_response(size: 2)
- end
+ it 'returns group confidential issues for assignee' do
+ get api("#{base_url}?state=opened", assignee)
- it 'returns group confidential issues for admin' do
- get api("#{base_url}?state=opened", admin)
+ expect_paginated_array_response(size: 2)
+ end
- expect_paginated_array_response(size: 2)
- end
+ it 'returns group issues with confidential issues for project members' do
+ get api("#{base_url}?state=opened", user)
- it 'returns an array of labeled group issues' do
- get api("#{base_url}?labels=#{group_label.title}", user)
+ expect_paginated_array_response(size: 2)
+ end
- expect_paginated_array_response(size: 1)
- expect(json_response.first['labels']).to eq([group_label.title])
- end
+ it 'returns group confidential issues for admin' do
+ get api("#{base_url}?state=opened", admin)
- it 'returns an array of labeled group issues where all labels match' do
- get api("#{base_url}?labels=#{group_label.title},foo,bar", user)
+ expect_paginated_array_response(size: 2)
+ end
- expect_paginated_array_response(size: 0)
- end
+ it 'returns an array of labeled group issues' do
+ get api("#{base_url}?labels=#{group_label.title}", user)
- it 'returns issues matching given search string for title' do
- get api("#{base_url}?search=#{group_issue.title}", user)
+ expect_paginated_array_response(size: 1)
+ expect(json_response.first['labels']).to eq([group_label.title])
+ end
- expect_paginated_array_response(size: 1)
- expect(json_response.first['id']).to eq(group_issue.id)
- end
+ it 'returns an array of labeled group issues where all labels match' do
+ get api("#{base_url}?labels=#{group_label.title},foo,bar", user)
- it 'returns issues matching given search string for description' do
- get api("#{base_url}?search=#{group_issue.description}", user)
+ expect_paginated_array_response(size: 0)
+ end
- expect_paginated_array_response(size: 1)
- expect(json_response.first['id']).to eq(group_issue.id)
- end
+ it 'returns issues matching given search string for title' do
+ get api("#{base_url}?search=#{group_issue.title}", user)
- it 'returns an array of labeled issues when all labels matches' do
- label_b = create(:label, title: 'foo', project: group_project)
- label_c = create(:label, title: 'bar', project: group_project)
+ expect_paginated_array_response(size: 1)
+ expect(json_response.first['id']).to eq(group_issue.id)
+ end
- create(:label_link, label: label_b, target: group_issue)
- create(:label_link, label: label_c, target: group_issue)
+ it 'returns issues matching given search string for description' do
+ get api("#{base_url}?search=#{group_issue.description}", user)
- get api("#{base_url}", user), labels: "#{group_label.title},#{label_b.title},#{label_c.title}"
+ expect_paginated_array_response(size: 1)
+ expect(json_response.first['id']).to eq(group_issue.id)
+ end
- expect_paginated_array_response(size: 1)
- expect(json_response.first['labels']).to eq([label_c.title, label_b.title, group_label.title])
- end
+ it 'returns an array of labeled issues when all labels matches' do
+ label_b = create(:label, title: 'foo', project: group_project)
+ label_c = create(:label, title: 'bar', project: group_project)
- it 'returns an array of issues found by iids' do
- get api(base_url, user), iids: [group_issue.iid]
+ create(:label_link, label: label_b, target: group_issue)
+ create(:label_link, label: label_c, target: group_issue)
- expect_paginated_array_response(size: 1)
- expect(json_response.first['id']).to eq(group_issue.id)
- end
+ get api("#{base_url}", user), labels: "#{group_label.title},#{label_b.title},#{label_c.title}"
- it 'returns an empty array if iid does not exist' do
- get api(base_url, user), iids: [99999]
+ expect_paginated_array_response(size: 1)
+ expect(json_response.first['labels']).to eq([label_c.title, label_b.title, group_label.title])
+ end
- expect_paginated_array_response(size: 0)
- end
+ it 'returns an array of issues found by iids' do
+ get api(base_url, user), iids: [group_issue.iid]
- it 'returns an empty array if no group issue matches labels' do
- get api("#{base_url}?labels=foo,bar", user)
+ expect_paginated_array_response(size: 1)
+ expect(json_response.first['id']).to eq(group_issue.id)
+ end
- expect_paginated_array_response(size: 0)
- end
+ it 'returns an empty array if iid does not exist' do
+ get api(base_url, user), iids: [99999]
- it 'returns an empty array if no issue matches milestone' do
- get api("#{base_url}?milestone=#{group_empty_milestone.title}", user)
+ expect_paginated_array_response(size: 0)
+ end
- expect_paginated_array_response(size: 0)
- end
+ it 'returns an empty array if no group issue matches labels' do
+ get api("#{base_url}?labels=foo,bar", user)
- it 'returns an empty array if milestone does not exist' do
- get api("#{base_url}?milestone=foo", user)
+ expect_paginated_array_response(size: 0)
+ end
- expect_paginated_array_response(size: 0)
- end
+ it 'returns an empty array if no issue matches milestone' do
+ get api("#{base_url}?milestone=#{group_empty_milestone.title}", user)
- it 'returns an array of issues in given milestone' do
- get api("#{base_url}?state=opened&milestone=#{group_milestone.title}", user)
+ expect_paginated_array_response(size: 0)
+ end
- expect_paginated_array_response(size: 1)
- expect(json_response.first['id']).to eq(group_issue.id)
- end
+ it 'returns an empty array if milestone does not exist' do
+ get api("#{base_url}?milestone=foo", user)
- it 'returns an array of issues matching state in milestone' do
- get api("#{base_url}?milestone=#{group_milestone.title}"\
- '&state=closed', user)
+ expect_paginated_array_response(size: 0)
+ end
- expect_paginated_array_response(size: 1)
- expect(json_response.first['id']).to eq(group_closed_issue.id)
- end
+ it 'returns an array of issues in given milestone' do
+ get api("#{base_url}?state=opened&milestone=#{group_milestone.title}", user)
- it 'returns an array of issues with no milestone' do
- get api("#{base_url}?milestone=#{no_milestone_title}", user)
+ expect_paginated_array_response(size: 1)
+ expect(json_response.first['id']).to eq(group_issue.id)
+ end
- expect(response).to have_gitlab_http_status(200)
+ it 'returns an array of issues matching state in milestone' do
+ get api("#{base_url}?milestone=#{group_milestone.title}"\
+ '&state=closed', user)
- expect_paginated_array_response(size: 1)
- expect(json_response.first['id']).to eq(group_confidential_issue.id)
- end
+ expect_paginated_array_response(size: 1)
+ expect(json_response.first['id']).to eq(group_closed_issue.id)
+ end
- it 'sorts by created_at descending by default' do
- get api(base_url, user)
+ it 'returns an array of issues with no milestone' do
+ get api("#{base_url}?milestone=#{no_milestone_title}", user)
- response_dates = json_response.map { |issue| issue['created_at'] }
+ expect(response).to have_gitlab_http_status(200)
- expect_paginated_array_response(size: 3)
- expect(response_dates).to eq(response_dates.sort.reverse)
- end
+ expect_paginated_array_response(size: 1)
+ expect(json_response.first['id']).to eq(group_confidential_issue.id)
+ end
- it 'sorts ascending when requested' do
- get api("#{base_url}?sort=asc", user)
+ it 'sorts by created_at descending by default' do
+ get api(base_url, user)
- response_dates = json_response.map { |issue| issue['created_at'] }
+ response_dates = json_response.map { |issue| issue['created_at'] }
- expect_paginated_array_response(size: 3)
- expect(response_dates).to eq(response_dates.sort)
- end
+ expect_paginated_array_response(size: 3)
+ expect(response_dates).to eq(response_dates.sort.reverse)
+ end
- it 'sorts by updated_at descending when requested' do
- get api("#{base_url}?order_by=updated_at", user)
+ it 'sorts ascending when requested' do
+ get api("#{base_url}?sort=asc", user)
- response_dates = json_response.map { |issue| issue['updated_at'] }
+ response_dates = json_response.map { |issue| issue['created_at'] }
- expect_paginated_array_response(size: 3)
- expect(response_dates).to eq(response_dates.sort.reverse)
- end
+ expect_paginated_array_response(size: 3)
+ expect(response_dates).to eq(response_dates.sort)
+ end
- it 'sorts by updated_at ascending when requested' do
- get api("#{base_url}?order_by=updated_at&sort=asc", user)
+ it 'sorts by updated_at descending when requested' do
+ get api("#{base_url}?order_by=updated_at", user)
- response_dates = json_response.map { |issue| issue['updated_at'] }
+ response_dates = json_response.map { |issue| issue['updated_at'] }
- expect_paginated_array_response(size: 3)
- expect(response_dates).to eq(response_dates.sort)
+ expect_paginated_array_response(size: 3)
+ expect(response_dates).to eq(response_dates.sort.reverse)
+ end
+
+ it 'sorts by updated_at ascending when requested' do
+ get api("#{base_url}?order_by=updated_at&sort=asc", user)
+
+ response_dates = json_response.map { |issue| issue['updated_at'] }
+
+ expect_paginated_array_response(size: 3)
+ expect(response_dates).to eq(response_dates.sort)
+ end
end
end
describe "GET /projects/:id/issues" do
let(:base_url) { "/projects/#{project.id}" }
+ context 'when unauthenticated' do
+ it 'returns public project issues' do
+ get api("/projects/#{project.id}/issues")
+
+ expect_paginated_array_response(size: 2)
+ expect(json_response.first['title']).to eq(issue.title)
+ end
+ end
+
it 'avoids N+1 queries' do
control_count = ActiveRecord::QueryRecorder.new do
get api("/projects/#{project.id}/issues", user)
@@ -789,6 +829,14 @@ describe API::Issues do
end
describe "GET /projects/:id/issues/:issue_iid" do
+ context 'when unauthenticated' do
+ it 'returns public issues' do
+ get api("/projects/#{project.id}/issues/#{issue.iid}")
+
+ expect(response).to have_gitlab_http_status(200)
+ end
+ end
+
it 'exposes known attributes' do
get api("/projects/#{project.id}/issues/#{issue.iid}", user)
@@ -1581,6 +1629,14 @@ describe API::Issues do
create(:merge_requests_closing_issues, issue: issue, merge_request: merge_request)
end
+ context 'when unauthenticated' do
+ it 'return public project issues' do
+ get api("/projects/#{project.id}/issues/#{issue.iid}/closed_by")
+
+ expect_paginated_array_response(size: 1)
+ end
+ end
+
it 'returns merge requests that will close issue on merge' do
get api("/projects/#{project.id}/issues/#{issue.iid}/closed_by", user)
@@ -1605,6 +1661,14 @@ describe API::Issues do
describe "GET /projects/:id/issues/:issue_iid/user_agent_detail" do
let!(:user_agent_detail) { create(:user_agent_detail, subject: issue) }
+ context 'when unauthenticated' do
+ it "returns unautorized" do
+ get api("/projects/#{project.id}/issues/#{issue.iid}/user_agent_detail")
+
+ expect(response).to have_gitlab_http_status(401)
+ end
+ end
+
it 'exposes known attributes' do
get api("/projects/#{project.id}/issues/#{issue.iid}/user_agent_detail", admin)
diff --git a/spec/requests/openid_connect_spec.rb b/spec/requests/openid_connect_spec.rb
index cd1a6cfc427..be286c490fe 100644
--- a/spec/requests/openid_connect_spec.rb
+++ b/spec/requests/openid_connect_spec.rb
@@ -159,7 +159,9 @@ describe 'OpenID Connect requests' do
get '/.well-known/openid-configuration'
expect(response).to have_gitlab_http_status(200)
- expect(json_response).to have_key('issuer')
+ expect(json_response['issuer']).to eq('http://localhost')
+ expect(json_response['jwks_uri']).to eq('http://www.example.com/oauth/discovery/keys')
+ expect(json_response['scopes_supported']).to eq(%w[api read_user sudo read_repository openid])
end
end
end