diff options
author | GitLab Bot <gitlab-bot@gitlab.com> | 2020-03-04 12:07:52 +0000 |
---|---|---|
committer | GitLab Bot <gitlab-bot@gitlab.com> | 2020-03-04 12:07:52 +0000 |
commit | c6c7437861bff9572747674095c4dfbdfbea4988 (patch) | |
tree | 237d1ed922193f19ae326923457344c082003788 | |
parent | d80f3cd75e700b6e62910865bfd36734644ffa89 (diff) | |
download | gitlab-ce-c6c7437861bff9572747674095c4dfbdfbea4988.tar.gz |
Add latest changes from gitlab-org/gitlab@master
59 files changed, 595 insertions, 186 deletions
diff --git a/app/controllers/concerns/invisible_captcha.rb b/app/controllers/concerns/invisible_captcha_on_signup.rb index 45c0a5c58ef..9bea6145ff3 100644 --- a/app/controllers/concerns/invisible_captcha.rb +++ b/app/controllers/concerns/invisible_captcha_on_signup.rb @@ -1,6 +1,6 @@ # frozen_string_literal: true -module InvisibleCaptcha +module InvisibleCaptchaOnSignup extend ActiveSupport::Concern included do diff --git a/app/controllers/projects/releases_controller.rb b/app/controllers/projects/releases_controller.rb index 7ad841d645d..d5f93c4baf6 100644 --- a/app/controllers/projects/releases_controller.rb +++ b/app/controllers/projects/releases_controller.rb @@ -3,7 +3,7 @@ class Projects::ReleasesController < Projects::ApplicationController # Authorize before_action :require_non_empty_project, except: [:index] - before_action :release, only: %i[edit show update] + before_action :release, only: %i[edit show update downloads] before_action :authorize_read_release! before_action do push_frontend_feature_flag(:release_issue_summary, project) @@ -40,6 +40,10 @@ class Projects::ReleasesController < Projects::ApplicationController end end + def downloads + redirect_to link.url + end + protected def releases @@ -69,6 +73,14 @@ class Projects::ReleasesController < Projects::ApplicationController @release ||= project.releases.find_by_tag!(sanitized_tag_name) end + def link + release.links.find_by_filepath!(sanitized_filepath) + end + + def sanitized_filepath + CGI.unescape(params[:filepath]) + end + def sanitized_tag_name CGI.unescape(params[:tag]) end diff --git a/app/controllers/registrations_controller.rb b/app/controllers/registrations_controller.rb index 1c6cbf72cfa..855f69a0f98 100644 --- a/app/controllers/registrations_controller.rb +++ b/app/controllers/registrations_controller.rb @@ -4,7 +4,7 @@ class RegistrationsController < Devise::RegistrationsController include Recaptcha::Verify include AcceptsPendingInvitations include RecaptchaExperimentHelper - include InvisibleCaptcha + include InvisibleCaptchaOnSignup layout :choose_layout diff --git a/app/graphql/mutations/issues/update.rb b/app/graphql/mutations/issues/update.rb index 4a21df98898..3710144fff5 100644 --- a/app/graphql/mutations/issues/update.rb +++ b/app/graphql/mutations/issues/update.rb @@ -17,12 +17,12 @@ module Mutations argument :due_date, Types::TimeType, - required: true, + required: false, description: copy_field_description(Types::IssueType, :due_date) argument :confidential, GraphQL::BOOLEAN_TYPE, - required: true, + required: false, description: copy_field_description(Types::IssueType, :confidential) def resolve(project_path:, iid:, **args) diff --git a/app/models/merge_request_diff_commit.rb b/app/models/merge_request_diff_commit.rb index 7310aa4f580..2819ea7ce1e 100644 --- a/app/models/merge_request_diff_commit.rb +++ b/app/models/merge_request_diff_commit.rb @@ -10,8 +10,9 @@ class MergeRequestDiffCommit < ApplicationRecord sha_attribute :sha alias_attribute :id, :sha + # Deprecated; use `bulk_insert!` from `BulkInsertSafe` mixin instead. + # cf. https://gitlab.com/gitlab-org/gitlab/issues/207989 for progress def self.create_bulk(merge_request_diff_id, commits) - warn 'Deprecated; use `bulk_insert` from `BulkInsertSafe` mixin instead' rows = commits.map.with_index do |commit, index| # See #parent_ids. commit_hash = commit.to_hash.except(:parent_ids) diff --git a/app/presenters/hooks/project_hook_presenter.rb b/app/presenters/project_hook_presenter.rb index a65c7221b5a..a65c7221b5a 100644 --- a/app/presenters/hooks/project_hook_presenter.rb +++ b/app/presenters/project_hook_presenter.rb diff --git a/app/presenters/hooks/service_hook_presenter.rb b/app/presenters/service_hook_presenter.rb index bc20d5b1a3b..bc20d5b1a3b 100644 --- a/app/presenters/hooks/service_hook_presenter.rb +++ b/app/presenters/service_hook_presenter.rb diff --git a/app/services/post_receive_service.rb b/app/services/post_receive_service.rb index e3818e76c4c..bc5ec22e77f 100644 --- a/app/services/post_receive_service.rb +++ b/app/services/post_receive_service.rb @@ -28,7 +28,7 @@ class PostReceiveService response.add_alert_message(message) end - broadcast_message = BroadcastMessage.current&.last&.message + broadcast_message = BroadcastMessage.current_banner_messages&.last&.message response.add_alert_message(broadcast_message) response.add_merge_request_urls(merge_request_urls) diff --git a/app/views/snippets/notes/_actions.html.haml b/app/views/snippets/notes/_actions.html.haml index 6e20890a47f..28fbeaa25f0 100644 --- a/app/views/snippets/notes/_actions.html.haml +++ b/app/views/snippets/notes/_actions.html.haml @@ -2,7 +2,6 @@ - if note.emoji_awardable? .note-actions-item = link_to '#', title: _('Add reaction'), class: "note-action-button note-emoji-button js-add-award js-note-emoji has-tooltip", data: { position: 'right' } do - = icon('spinner spin') %span{ class: 'link-highlight award-control-icon-neutral' }= sprite_icon('slight-smile') %span{ class: 'link-highlight award-control-icon-positive' }= sprite_icon('smiley') %span{ class: 'link-highlight award-control-icon-super-positive' }= sprite_icon('smile') diff --git a/changelogs/unreleased/199220-snippet-index-desc.yml b/changelogs/unreleased/199220-snippet-index-desc.yml new file mode 100644 index 00000000000..c1a1063eef5 --- /dev/null +++ b/changelogs/unreleased/199220-snippet-index-desc.yml @@ -0,0 +1,5 @@ +--- +title: Add trigram index on snippet description +merge_request: 26341 +author: +type: performance diff --git a/changelogs/unreleased/27300-add-filepath-redirect-url.yml b/changelogs/unreleased/27300-add-filepath-redirect-url.yml new file mode 100644 index 00000000000..31645ba3050 --- /dev/null +++ b/changelogs/unreleased/27300-add-filepath-redirect-url.yml @@ -0,0 +1,5 @@ +--- +title: Add filepath redirect url +merge_request: 25541 +author: +type: added diff --git a/changelogs/unreleased/Resolve-Migrate--fa-spinner-app-views-snippets-notes.yml b/changelogs/unreleased/Resolve-Migrate--fa-spinner-app-views-snippets-notes.yml new file mode 100644 index 00000000000..4f28db06eab --- /dev/null +++ b/changelogs/unreleased/Resolve-Migrate--fa-spinner-app-views-snippets-notes.yml @@ -0,0 +1,5 @@ +--- +title: Remove .fa-spinner from app/views/snippets/notes +merge_request: 25036 +author: nuwe1 +type: other diff --git a/changelogs/unreleased/limit-broadcast-notifications-to-ui.yml b/changelogs/unreleased/limit-broadcast-notifications-to-ui.yml new file mode 100644 index 00000000000..f10b3b4fb95 --- /dev/null +++ b/changelogs/unreleased/limit-broadcast-notifications-to-ui.yml @@ -0,0 +1,5 @@ +--- +title: Limit notification-type broadcast display to web interface +merge_request: 26236 +author: Aleksandrs Ļedovskis +type: changed diff --git a/changelogs/unreleased/sha-params-validator.yml b/changelogs/unreleased/sha-params-validator.yml new file mode 100644 index 00000000000..ff8717bd3a1 --- /dev/null +++ b/changelogs/unreleased/sha-params-validator.yml @@ -0,0 +1,5 @@ +--- +title: Add grape custom validator for sha params +merge_request: 26220 +author: Rajendra Kadam +type: added diff --git a/config/routes/project.rb b/config/routes/project.rb index 72dda11435c..809c1386f2c 100644 --- a/config/routes/project.rb +++ b/config/routes/project.rb @@ -171,6 +171,7 @@ constraints(::Constraints::ProjectUrlConstrainer.new) do resources :releases, only: [:index, :show, :edit], param: :tag, constraints: { tag: %r{[^/]+} } do member do get :evidence + get :downloads, path: 'downloads/*filepath', format: false end end diff --git a/db/migrate/20200303074328_add_index_on_snippet_description.rb b/db/migrate/20200303074328_add_index_on_snippet_description.rb new file mode 100644 index 00000000000..f23e5f8bf8e --- /dev/null +++ b/db/migrate/20200303074328_add_index_on_snippet_description.rb @@ -0,0 +1,18 @@ +# frozen_string_literal: true + +class AddIndexOnSnippetDescription < ActiveRecord::Migration[6.0] + include Gitlab::Database::MigrationHelpers + + DOWNTIME = false + INDEX_NAME = 'index_snippets_on_description_trigram' + + disable_ddl_transaction! + + def up + add_concurrent_index :snippets, :description, name: INDEX_NAME, using: :gin, opclass: { description: :gin_trgm_ops } + end + + def down + remove_concurrent_index_by_name :snippets, INDEX_NAME + end +end diff --git a/db/schema.rb b/db/schema.rb index cb632d983f9..32fab15182c 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -10,7 +10,7 @@ # # It's strongly recommended that you check this file into your version control system. -ActiveRecord::Schema.define(version: 2020_02_27_165129) do +ActiveRecord::Schema.define(version: 2020_03_03_074328) do # These are extensions that must be enabled in order to support this database enable_extension "pg_trgm" @@ -3964,6 +3964,7 @@ ActiveRecord::Schema.define(version: 2020_02_27_165129) do t.index ["author_id"], name: "index_snippets_on_author_id" t.index ["content"], name: "index_snippets_on_content_trigram", opclass: :gin_trgm_ops, using: :gin t.index ["created_at"], name: "index_snippets_on_created_at" + t.index ["description"], name: "index_snippets_on_description_trigram", opclass: :gin_trgm_ops, using: :gin t.index ["file_name"], name: "index_snippets_on_file_name_trigram", opclass: :gin_trgm_ops, using: :gin t.index ["project_id", "visibility_level"], name: "index_snippets_on_project_id_and_visibility_level" t.index ["title"], name: "index_snippets_on_title_trigram", opclass: :gin_trgm_ops, using: :gin diff --git a/doc/administration/audit_events.md b/doc/administration/audit_events.md index 5b3052789e4..cc8135a86c4 100644 --- a/doc/administration/audit_events.md +++ b/doc/administration/audit_events.md @@ -107,6 +107,7 @@ recorded: - User was deleted ([introduced](https://gitlab.com/gitlab-org/gitlab/issues/251) in GitLab 12.8) - User was added ([introduced](https://gitlab.com/gitlab-org/gitlab/issues/251) in GitLab 12.8) - User was blocked via Admin Area ([introduced](https://gitlab.com/gitlab-org/gitlab/issues/251) in GitLab 12.8) +- User was blocked via API ([introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/25872) in GitLab 12.9) It's possible to filter particular actions by choosing an audit data type from the filter dropdown box. You can further filter by specific group, project, or user diff --git a/doc/api/graphql/reference/gitlab_schema.graphql b/doc/api/graphql/reference/gitlab_schema.graphql index eae3626515e..7dda073d8ae 100644 --- a/doc/api/graphql/reference/gitlab_schema.graphql +++ b/doc/api/graphql/reference/gitlab_schema.graphql @@ -8011,7 +8011,7 @@ input UpdateIssueInput { """ Indicates the issue is confidential """ - confidential: Boolean! + confidential: Boolean """ Description of the issue @@ -8021,7 +8021,7 @@ input UpdateIssueInput { """ Due date of the issue """ - dueDate: Time! + dueDate: Time """ The desired health status diff --git a/doc/api/graphql/reference/gitlab_schema.json b/doc/api/graphql/reference/gitlab_schema.json index bf59c94f6cc..83b098dc73d 100644 --- a/doc/api/graphql/reference/gitlab_schema.json +++ b/doc/api/graphql/reference/gitlab_schema.json @@ -21114,13 +21114,9 @@ "name": "dueDate", "description": "Due date of the issue", "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "Time", - "ofType": null - } + "kind": "SCALAR", + "name": "Time", + "ofType": null }, "defaultValue": null }, @@ -21128,13 +21124,9 @@ "name": "confidential", "description": "Indicates the issue is confidential", "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "Boolean", - "ofType": null - } + "kind": "SCALAR", + "name": "Boolean", + "ofType": null }, "defaultValue": null }, diff --git a/doc/api/users.md b/doc/api/users.md index 49bd090f294..1eed5d08d38 100644 --- a/doc/api/users.md +++ b/doc/api/users.md @@ -1168,8 +1168,11 @@ Parameters: - `id` (required) - id of specified user -Will return `201 OK` on success, `404 User Not Found` is user cannot be found or -`403 Forbidden` when trying to block an already blocked user by LDAP synchronization. +Returns: + +- `201 OK` on success. +- `404 User Not Found` if user cannot be found. +- `403 Forbidden` when trying to block an already blocked user by LDAP synchronization. ## Unblock user diff --git a/lib/api/helpers/custom_validators.rb b/lib/api/helpers/custom_validators.rb index dab4ca1d1f1..4c15c1d01cd 100644 --- a/lib/api/helpers/custom_validators.rb +++ b/lib/api/helpers/custom_validators.rb @@ -14,6 +14,17 @@ module API end end + class GitSha < Grape::Validations::Base + def validate_param!(attr_name, params) + sha = params[attr_name] + + return if Commit::EXACT_COMMIT_SHA_PATTERN.match?(sha) + + raise Grape::Exceptions::Validation, params: [@scope.full_name(attr_name)], + message: "should be a valid sha" + end + end + class Absence < Grape::Validations::Base def validate_param!(attr_name, params) return if params.respond_to?(:key?) && !params.key?(attr_name) @@ -50,6 +61,7 @@ module API end Grape::Validations.register_validator(:file_path, ::API::Helpers::CustomValidators::FilePath) +Grape::Validations.register_validator(:git_sha, ::API::Helpers::CustomValidators::GitSha) Grape::Validations.register_validator(:absence, ::API::Helpers::CustomValidators::Absence) Grape::Validations.register_validator(:integer_none_any, ::API::Helpers::CustomValidators::IntegerNoneAny) Grape::Validations.register_validator(:array_none_any, ::API::Helpers::CustomValidators::ArrayNoneAny) diff --git a/lib/api/users.rb b/lib/api/users.rb index c6dc7c08b11..5b51f114fb4 100644 --- a/lib/api/users.rb +++ b/lib/api/users.rb @@ -528,11 +528,18 @@ module API user = User.find_by(id: params[:id]) not_found!('User') unless user - if !user.ldap_blocked? - user.block - else + if user.ldap_blocked? forbidden!('LDAP blocked users cannot be modified by the API') end + + break if user.blocked? + + result = ::Users::BlockService.new(current_user).execute(user) + if result[:status] == :success + true + else + render_api_error!(result[:message], result[:http_status]) + end end # rubocop: enable CodeReuse/ActiveRecord diff --git a/lib/declarative_policy.rb b/lib/declarative_policy.rb index 9e9df88373a..e51f30af581 100644 --- a/lib/declarative_policy.rb +++ b/lib/declarative_policy.rb @@ -13,6 +13,8 @@ require_dependency 'declarative_policy/step' require_dependency 'declarative_policy/base' module DeclarativePolicy + extend PreferredScope + CLASS_CACHE_MUTEX = Mutex.new CLASS_CACHE_IVAR = :@__DeclarativePolicy_CLASS_CACHE diff --git a/lib/declarative_policy/preferred_scope.rb b/lib/declarative_policy/preferred_scope.rb index 9b7d1548056..d653a0ec1e1 100644 --- a/lib/declarative_policy/preferred_scope.rb +++ b/lib/declarative_policy/preferred_scope.rb @@ -1,9 +1,9 @@ # frozen_string_literal: true module DeclarativePolicy - PREFERRED_SCOPE_KEY = :"DeclarativePolicy.preferred_scope" + module PreferredScope + PREFERRED_SCOPE_KEY = :"DeclarativePolicy.preferred_scope" - class << self def with_preferred_scope(scope) Thread.current[PREFERRED_SCOPE_KEY], old_scope = scope, Thread.current[PREFERRED_SCOPE_KEY] yield diff --git a/lib/gitlab/background_migration/user_mentions/models/concerns/isolated_mentionable.rb b/lib/gitlab/background_migration/user_mentions/models/concerns/isolated_mentionable.rb index 1fac4b230ca..69ba3f9132b 100644 --- a/lib/gitlab/background_migration/user_mentions/models/concerns/isolated_mentionable.rb +++ b/lib/gitlab/background_migration/user_mentions/models/concerns/isolated_mentionable.rb @@ -4,95 +4,97 @@ module Gitlab module BackgroundMigration module UserMentions module Models - # == IsolatedMentionable concern - # - # Shortcutted for isolation version of Mentionable to be used in mentions migrations - # - module IsolatedMentionable - extend ::ActiveSupport::Concern - - class_methods do - # Indicate which attributes of the Mentionable to search for GFM references. - def attr_mentionable(attr, options = {}) - attr = attr.to_s - mentionable_attrs << [attr, options] + module Concerns + # == IsolatedMentionable concern + # + # Shortcutted for isolation version of Mentionable to be used in mentions migrations + # + module IsolatedMentionable + extend ::ActiveSupport::Concern + + class_methods do + # Indicate which attributes of the Mentionable to search for GFM references. + def attr_mentionable(attr, options = {}) + attr = attr.to_s + mentionable_attrs << [attr, options] + end end - end - included do - # Accessor for attributes marked mentionable. - cattr_accessor :mentionable_attrs, instance_accessor: false do - [] - end + included do + # Accessor for attributes marked mentionable. + cattr_accessor :mentionable_attrs, instance_accessor: false do + [] + end - if self < Participable - participant -> (user, ext) { all_references(user, extractor: ext) } + if self < Participable + participant -> (user, ext) { all_references(user, extractor: ext) } + end end - end - def all_references(current_user = nil, extractor: nil) - # Use custom extractor if it's passed in the function parameters. - if extractor - extractors[current_user] = extractor - else - extractor = extractors[current_user] ||= ::Gitlab::ReferenceExtractor.new(project, current_user) + def all_references(current_user = nil, extractor: nil) + # Use custom extractor if it's passed in the function parameters. + if extractor + extractors[current_user] = extractor + else + extractor = extractors[current_user] ||= ::Gitlab::ReferenceExtractor.new(project, current_user) - extractor.reset_memoized_values - end + extractor.reset_memoized_values + end - self.class.mentionable_attrs.each do |attr, options| - text = __send__(attr) # rubocop:disable GitlabSecurity/PublicSend - options = options.merge( - cache_key: [self, attr], - author: author, - skip_project_check: skip_project_check? - ).merge(mentionable_params) + self.class.mentionable_attrs.each do |attr, options| + text = __send__(attr) # rubocop:disable GitlabSecurity/PublicSend + options = options.merge( + cache_key: [self, attr], + author: author, + skip_project_check: skip_project_check? + ).merge(mentionable_params) - cached_html = self.try(:updated_cached_html_for, attr.to_sym) - options[:rendered] = cached_html if cached_html + cached_html = self.try(:updated_cached_html_for, attr.to_sym) + options[:rendered] = cached_html if cached_html - extractor.analyze(text, options) - end + extractor.analyze(text, options) + end - extractor - end + extractor + end - def extractors - @extractors ||= {} - end + def extractors + @extractors ||= {} + end - def skip_project_check? - false - end + def skip_project_check? + false + end - def build_mention_values(resource_foreign_key) - refs = all_references(author) + def build_mention_values(resource_foreign_key) + refs = all_references(author) - mentioned_users_ids = array_to_sql(refs.mentioned_users.pluck(:id)) - mentioned_projects_ids = array_to_sql(refs.mentioned_projects.pluck(:id)) - mentioned_groups_ids = array_to_sql(refs.mentioned_groups.pluck(:id)) + mentioned_users_ids = array_to_sql(refs.mentioned_users.pluck(:id)) + mentioned_projects_ids = array_to_sql(refs.mentioned_projects.pluck(:id)) + mentioned_groups_ids = array_to_sql(refs.mentioned_groups.pluck(:id)) - return if mentioned_users_ids.blank? && mentioned_projects_ids.blank? && mentioned_groups_ids.blank? + return if mentioned_users_ids.blank? && mentioned_projects_ids.blank? && mentioned_groups_ids.blank? - { - "#{resource_foreign_key}": user_mention_resource_id, - note_id: user_mention_note_id, - mentioned_users_ids: mentioned_users_ids, - mentioned_projects_ids: mentioned_projects_ids, - mentioned_groups_ids: mentioned_groups_ids - } - end + { + "#{resource_foreign_key}": user_mention_resource_id, + note_id: user_mention_note_id, + mentioned_users_ids: mentioned_users_ids, + mentioned_projects_ids: mentioned_projects_ids, + mentioned_groups_ids: mentioned_groups_ids + } + end - def array_to_sql(ids_array) - return unless ids_array.present? + def array_to_sql(ids_array) + return unless ids_array.present? - '{' + ids_array.join(", ") + '}' - end + '{' + ids_array.join(", ") + '}' + end - private + private - def mentionable_params - {} + def mentionable_params + {} + end end end end diff --git a/lib/gitlab/background_migration/user_mentions/models/concerns/mentionable_migration_methods.rb b/lib/gitlab/background_migration/user_mentions/models/concerns/mentionable_migration_methods.rb index fa479cb0ed3..efb08d44100 100644 --- a/lib/gitlab/background_migration/user_mentions/models/concerns/mentionable_migration_methods.rb +++ b/lib/gitlab/background_migration/user_mentions/models/concerns/mentionable_migration_methods.rb @@ -4,17 +4,19 @@ module Gitlab module BackgroundMigration module UserMentions module Models - # Extract common no_quote_columns method used in determining the columns that do not need - # to be quoted for corresponding models - module MentionableMigrationMethods - extend ::ActiveSupport::Concern + module Concerns + # Extract common no_quote_columns method used in determining the columns that do not need + # to be quoted for corresponding models + module MentionableMigrationMethods + extend ::ActiveSupport::Concern - class_methods do - def no_quote_columns - [ - :note_id, - user_mention_model.resource_foreign_key - ] + class_methods do + def no_quote_columns + [ + :note_id, + user_mention_model.resource_foreign_key + ] + end end end end diff --git a/lib/gitlab/background_migration/user_mentions/models/design.rb b/lib/gitlab/background_migration/user_mentions/models/design_management/design.rb index 66cff561bcb..0cdfc6447c7 100644 --- a/lib/gitlab/background_migration/user_mentions/models/design.rb +++ b/lib/gitlab/background_migration/user_mentions/models/design_management/design.rb @@ -7,7 +7,7 @@ module Gitlab module Models module DesignManagement class Design < ActiveRecord::Base - include MentionableMigrationMethods + include Concerns::MentionableMigrationMethods def self.user_mention_model Gitlab::BackgroundMigration::UserMentions::Models::DesignUserMention diff --git a/lib/gitlab/background_migration/user_mentions/models/epic.rb b/lib/gitlab/background_migration/user_mentions/models/epic.rb index ad1d904cde7..a76391d64bb 100644 --- a/lib/gitlab/background_migration/user_mentions/models/epic.rb +++ b/lib/gitlab/background_migration/user_mentions/models/epic.rb @@ -6,9 +6,9 @@ module Gitlab module UserMentions module Models class Epic < ActiveRecord::Base - include IsolatedMentionable + include Concerns::IsolatedMentionable + include Concerns::MentionableMigrationMethods include CacheMarkdownField - include MentionableMigrationMethods attr_mentionable :title, pipeline: :single_line attr_mentionable :description diff --git a/lib/gitlab/background_migration/user_mentions/models/note.rb b/lib/gitlab/background_migration/user_mentions/models/note.rb index dc364d7af5a..fb61de638a8 100644 --- a/lib/gitlab/background_migration/user_mentions/models/note.rb +++ b/lib/gitlab/background_migration/user_mentions/models/note.rb @@ -6,7 +6,7 @@ module Gitlab module UserMentions module Models class Note < ActiveRecord::Base - include IsolatedMentionable + include Concerns::IsolatedMentionable include CacheMarkdownField self.table_name = 'notes' diff --git a/lib/gitlab/background_migration/user_mentions/models/snippet.rb b/lib/gitlab/background_migration/user_mentions/models/snippet.rb index 1481cfcc562..cdbada76429 100644 --- a/lib/gitlab/background_migration/user_mentions/models/snippet.rb +++ b/lib/gitlab/background_migration/user_mentions/models/snippet.rb @@ -6,9 +6,9 @@ module Gitlab module UserMentions module Models class Snippet < ActiveRecord::Base - include IsolatedMentionable + include Concerns::IsolatedMentionable + include Concerns::MentionableMigrationMethods include CacheMarkdownField - include MentionableMigrationMethods attr_mentionable :title, pipeline: :single_line attr_mentionable :description diff --git a/lib/gitlab/ci/config/entry/artifacts.rb b/lib/gitlab/ci/config/entry/artifacts.rb index aebc1675bec..241c73db3bb 100644 --- a/lib/gitlab/ci/config/entry/artifacts.rb +++ b/lib/gitlab/ci/config/entry/artifacts.rb @@ -44,8 +44,6 @@ module Gitlab end end - helpers :reports - def value @config[:reports] = reports_value if @config.key?(:reports) @config diff --git a/lib/gitlab/ci/config/entry/bridge.rb b/lib/gitlab/ci/config/entry/bridge.rb index 721c7c8b6d7..6fdaa373170 100644 --- a/lib/gitlab/ci/config/entry/bridge.rb +++ b/lib/gitlab/ci/config/entry/bridge.rb @@ -49,8 +49,6 @@ module Gitlab description: 'Environment variables available for this job.', inherit: false - helpers :trigger, :needs, :variables - attributes :when, :allow_failure def self.matching?(name, config) diff --git a/lib/gitlab/ci/config/entry/cache.rb b/lib/gitlab/ci/config/entry/cache.rb index ef07c319ce4..a304d9b724f 100644 --- a/lib/gitlab/ci/config/entry/cache.rb +++ b/lib/gitlab/ci/config/entry/cache.rb @@ -28,8 +28,6 @@ module Gitlab entry :paths, Entry::Paths, description: 'Specify which paths should be cached across builds.' - helpers :key - attributes :policy def value diff --git a/lib/gitlab/ci/config/entry/default.rb b/lib/gitlab/ci/config/entry/default.rb index 88db17a75da..ab493ff7d78 100644 --- a/lib/gitlab/ci/config/entry/default.rb +++ b/lib/gitlab/ci/config/entry/default.rb @@ -61,8 +61,6 @@ module Gitlab description: 'Default artifacts.', inherit: false - helpers :before_script, :image, :services, :after_script, :cache - private def overwrite_entry(deps, key, current_entry) diff --git a/lib/gitlab/ci/config/entry/job.rb b/lib/gitlab/ci/config/entry/job.rb index 931f769e920..8db21b116eb 100644 --- a/lib/gitlab/ci/config/entry/job.rb +++ b/lib/gitlab/ci/config/entry/job.rb @@ -128,11 +128,6 @@ module Gitlab description: 'This job will produce a release.', inherit: false - helpers :before_script, :script, :type, :after_script, - :cache, :image, :services, :variables, - :artifacts, :environment, :coverage, :retry, - :needs, :interruptible, :release, :tags - attributes :script, :tags, :allow_failure, :when, :dependencies, :needs, :retry, :parallel, :start_in, :interruptible, :timeout, :resource_group, :release diff --git a/lib/gitlab/ci/config/entry/processable.rb b/lib/gitlab/ci/config/entry/processable.rb index 19e6601e31f..bfa2905ed77 100644 --- a/lib/gitlab/ci/config/entry/processable.rb +++ b/lib/gitlab/ci/config/entry/processable.rb @@ -54,8 +54,6 @@ module Gitlab allowed_when: %w[on_success on_failure always never manual delayed].freeze } - helpers :stage, :only, :except, :rules - attributes :extends, :rules end diff --git a/lib/gitlab/ci/config/entry/release.rb b/lib/gitlab/ci/config/entry/release.rb index 3eceaa0ccd9..b4e4c149730 100644 --- a/lib/gitlab/ci/config/entry/release.rb +++ b/lib/gitlab/ci/config/entry/release.rb @@ -33,8 +33,6 @@ module Gitlab validates :description, type: String, presence: true end - helpers :assets - def value @config[:assets] = assets_value if @config.key?(:assets) @config diff --git a/lib/gitlab/ci/config/entry/release/assets.rb b/lib/gitlab/ci/config/entry/release/assets.rb index 82ed39f51e0..1f7057d1bf6 100644 --- a/lib/gitlab/ci/config/entry/release/assets.rb +++ b/lib/gitlab/ci/config/entry/release/assets.rb @@ -23,8 +23,6 @@ module Gitlab validates :links, array_of_hashes: true, presence: true end - helpers :links - def value @config[:links] = links_value if @config.key?(:links) @config diff --git a/lib/gitlab/ci/config/entry/root.rb b/lib/gitlab/ci/config/entry/root.rb index 620f6a95e9d..caa0725c4bd 100644 --- a/lib/gitlab/ci/config/entry/root.rb +++ b/lib/gitlab/ci/config/entry/root.rb @@ -67,9 +67,7 @@ module Gitlab entry :workflow, Entry::Workflow, description: 'List of evaluable rules to determine Pipeline status' - helpers :default, :stages, :types, :variables, :workflow - - helpers :jobs, dynamic: true + dynamic_helpers :jobs delegate :before_script_value, :image_value, diff --git a/lib/gitlab/ci/config/entry/service.rb b/lib/gitlab/ci/config/entry/service.rb index 8d16371e857..247bf930d3b 100644 --- a/lib/gitlab/ci/config/entry/service.rb +++ b/lib/gitlab/ci/config/entry/service.rb @@ -7,8 +7,13 @@ module Gitlab ## # Entry that represents a configuration of Docker service. # - class Service < Image + # TODO: remove duplication with Image superclass by defining a common + # Imageable concern. + # https://gitlab.com/gitlab-org/gitlab/issues/208774 + class Service < ::Gitlab::Config::Entry::Node include ::Gitlab::Config::Entry::Validatable + include ::Gitlab::Config::Entry::Attributable + include ::Gitlab::Config::Entry::Configurable ALLOWED_KEYS = %i[name entrypoint command alias ports].freeze @@ -16,9 +21,9 @@ module Gitlab validates :config, hash_or_string: true validates :config, allowed_keys: ALLOWED_KEYS validates :config, disallowed_keys: %i[ports], unless: :with_image_ports? - validates :name, type: String, presence: true validates :entrypoint, array_of_strings: true, allow_nil: true + validates :command, array_of_strings: true, allow_nil: true validates :alias, type: String, allow_nil: true validates :alias, type: String, presence: true, unless: ->(record) { record.ports.blank? } @@ -27,6 +32,8 @@ module Gitlab entry :ports, Entry::Ports, description: 'Ports used to expose the service' + attributes :ports + def alias value[:alias] end @@ -34,6 +41,29 @@ module Gitlab def command value[:command] end + + def name + value[:name] + end + + def entrypoint + value[:entrypoint] + end + + def value + return { name: @config } if string? + return @config if hash? + + {} + end + + def with_image_ports? + opt(:with_image_ports) + end + + def skip_config_hash_validation? + true + end end end end diff --git a/lib/gitlab/config/entry/configurable.rb b/lib/gitlab/config/entry/configurable.rb index 75e15cd8cb1..3fd562c2904 100644 --- a/lib/gitlab/config/entry/configurable.rb +++ b/lib/gitlab/config/entry/configurable.rb @@ -75,7 +75,8 @@ module Gitlab # rubocop: disable CodeReuse/ActiveRecord def entry(key, entry, description: nil, default: nil, inherit: nil, reserved: nil, metadata: {}) - raise ArgumentError, "Entry #{key} already defined" if @nodes.to_h[key.to_sym] + entry_name = key.to_sym + raise ArgumentError, "Entry #{key} already defined" if @nodes.to_h[entry_name] factory = ::Gitlab::Config::Entry::Factory.new(entry) .with(description: description) @@ -84,10 +85,17 @@ module Gitlab .with(reserved: reserved) .metadata(metadata) - (@nodes ||= {}).merge!(key.to_sym => factory) + @nodes ||= {} + @nodes[entry_name] = factory + + helpers(entry_name) end # rubocop: enable CodeReuse/ActiveRecord + def dynamic_helpers(*nodes) + helpers(*nodes, dynamic: true) + end + def helpers(*nodes, dynamic: false) nodes.each do |symbol| if method_defined?("#{symbol}_defined?") || method_defined?("#{symbol}_value") diff --git a/lib/gitlab/email.rb b/lib/gitlab/email.rb new file mode 100644 index 00000000000..5f935880764 --- /dev/null +++ b/lib/gitlab/email.rb @@ -0,0 +1,22 @@ +# frozen_string_literal: true + +module Gitlab + module Email + ProcessingError = Class.new(StandardError) + EmailUnparsableError = Class.new(ProcessingError) + SentNotificationNotFoundError = Class.new(ProcessingError) + ProjectNotFound = Class.new(ProcessingError) + EmptyEmailError = Class.new(ProcessingError) + AutoGeneratedEmailError = Class.new(ProcessingError) + UserNotFoundError = Class.new(ProcessingError) + UserBlockedError = Class.new(ProcessingError) + UserNotAuthorizedError = Class.new(ProcessingError) + NoteableNotFoundError = Class.new(ProcessingError) + InvalidRecordError = Class.new(ProcessingError) + InvalidNoteError = Class.new(InvalidRecordError) + InvalidIssueError = Class.new(InvalidRecordError) + InvalidMergeRequestError = Class.new(InvalidRecordError) + UnknownIncomingEmail = Class.new(ProcessingError) + InvalidAttachment = Class.new(ProcessingError) + end +end diff --git a/lib/gitlab/email/receiver.rb b/lib/gitlab/email/receiver.rb index b7b9288517d..bf6c28b9f90 100644 --- a/lib/gitlab/email/receiver.rb +++ b/lib/gitlab/email/receiver.rb @@ -5,23 +5,6 @@ require_dependency 'gitlab/email/handler' # Inspired in great part by Discourse's Email::Receiver module Gitlab module Email - ProcessingError = Class.new(StandardError) - EmailUnparsableError = Class.new(ProcessingError) - SentNotificationNotFoundError = Class.new(ProcessingError) - ProjectNotFound = Class.new(ProcessingError) - EmptyEmailError = Class.new(ProcessingError) - AutoGeneratedEmailError = Class.new(ProcessingError) - UserNotFoundError = Class.new(ProcessingError) - UserBlockedError = Class.new(ProcessingError) - UserNotAuthorizedError = Class.new(ProcessingError) - NoteableNotFoundError = Class.new(ProcessingError) - InvalidRecordError = Class.new(ProcessingError) - InvalidNoteError = Class.new(InvalidRecordError) - InvalidIssueError = Class.new(InvalidRecordError) - InvalidMergeRequestError = Class.new(InvalidRecordError) - UnknownIncomingEmail = Class.new(ProcessingError) - InvalidAttachment = Class.new(ProcessingError) - class Receiver def initialize(raw) @raw = raw diff --git a/lib/gitlab/sidekiq_queue.rb b/lib/gitlab/sidekiq_queue.rb index 9e9ad3107f3..807c27a71ff 100644 --- a/lib/gitlab/sidekiq_queue.rb +++ b/lib/gitlab/sidekiq_queue.rb @@ -14,7 +14,8 @@ module Gitlab end def drop_jobs!(search_metadata, timeout:) - completed = false + start_time = Gitlab::Metrics::System.monotonic_time + completed = true deleted_jobs = 0 job_search_metadata = @@ -27,18 +28,16 @@ module Gitlab raise NoMetadataError if job_search_metadata.empty? raise InvalidQueueError unless queue - begin - Timeout.timeout(timeout) do - queue.each do |job| - next unless job_matches?(job, job_search_metadata) + queue.each do |job| + if timeout_exceeded?(start_time, timeout) + completed = false + break + end - job.delete - deleted_jobs += 1 - end + next unless job_matches?(job, job_search_metadata) - completed = true - end - rescue Timeout::Error + job.delete + deleted_jobs += 1 end { @@ -48,6 +47,8 @@ module Gitlab } end + private + def queue strong_memoize(:queue) do # Sidekiq::Queue.new always returns a queue, even if it doesn't @@ -59,5 +60,9 @@ module Gitlab def job_matches?(job, job_search_metadata) job_search_metadata.all? { |key, value| job[key] == value } end + + def timeout_exceeded?(start_time, timeout) + (Gitlab::Metrics::System.monotonic_time - start_time) > timeout + end end end diff --git a/lib/gitlab/utils/json_size_estimator.rb b/lib/gitlab/utils/json_size_estimator.rb new file mode 100644 index 00000000000..9f8ea3e61f9 --- /dev/null +++ b/lib/gitlab/utils/json_size_estimator.rb @@ -0,0 +1,104 @@ +# frozen_string_literal: true + +module Gitlab + module Utils + # This class estimates the JSON blob byte size of a ruby object using as + # little allocations as possible. + # The estimation should be quite accurate when using simple objects. + # + # Example: + # + # Gitlab::Utils::JsonSizeEstimator.estimate(["a", { b: 12, c: nil }]) + class JsonSizeEstimator + ARRAY_BRACKETS_SIZE = 2 # [] + OBJECT_BRACKETS_SIZE = 2 # {} + DOUBLEQUOTE_SIZE = 2 # "" + COLON_SIZE = 1 # : character size from {"a": 1} + MINUS_SIGN_SIZE = 1 # - character size from -1 + NULL_SIZE = 4 # null + + class << self + # Returns: integer (number of bytes) + def estimate(object) + case object + when Hash + estimate_hash(object) + when Array + estimate_array(object) + when String + estimate_string(object) + when Integer + estimate_integer(object) + when Float + estimate_float(object) + when DateTime, Time + estimate_time(object) + when NilClass + NULL_SIZE + else + # might be incorrect, but #to_s is safe, #to_json might be disabled for some objects: User + estimate_string(object.to_s) + end + end + + private + + def estimate_hash(hash) + size = 0 + item_count = 0 + + hash.each do |key, value| + item_count += 1 + + size += estimate(key.to_s) + COLON_SIZE + estimate(value) + end + + size + OBJECT_BRACKETS_SIZE + comma_count(item_count) + end + + def estimate_array(array) + size = 0 + item_count = 0 + + array.each do |item| + item_count += 1 + + size += estimate(item) + end + + size + ARRAY_BRACKETS_SIZE + comma_count(item_count) + end + + def estimate_string(string) + string.bytesize + DOUBLEQUOTE_SIZE + end + + def estimate_float(float) + float.to_s.bytesize + end + + def estimate_integer(integer) + if integer > 0 + integer_string_size(integer) + elsif integer < 0 + integer_string_size(integer.abs) + MINUS_SIGN_SIZE + else # 0 + 1 + end + end + + def estimate_time(time) + time.to_json.size + end + + def integer_string_size(integer) + Math.log10(integer).floor + 1 + end + + def comma_count(item_count) + item_count == 0 ? 0 : item_count - 1 + end + end + end + end +end diff --git a/lib/gitlab/utils/log_limited_array.rb b/lib/gitlab/utils/log_limited_array.rb index 9c207758580..e0589c3df4c 100644 --- a/lib/gitlab/utils/log_limited_array.rb +++ b/lib/gitlab/utils/log_limited_array.rb @@ -13,7 +13,7 @@ module Gitlab total_length = 0 limited_array = array.take_while do |arg| - total_length += arg.to_json.length + total_length += JsonSizeEstimator.estimate(arg) total_length <= MAXIMUM_ARRAY_LENGTH end diff --git a/qa/qa/specs/features/browser_ui/6_release/deploy_key/add_deploy_key_spec.rb b/qa/qa/specs/features/browser_ui/6_release/deploy_key/add_deploy_key_spec.rb index 89aba112407..10dd684546f 100644 --- a/qa/qa/specs/features/browser_ui/6_release/deploy_key/add_deploy_key_spec.rb +++ b/qa/qa/specs/features/browser_ui/6_release/deploy_key/add_deploy_key_spec.rb @@ -3,7 +3,7 @@ module QA context 'Release' do describe 'Deploy key creation' do - it 'user adds a deploy key' do + it 'user adds a deploy key', quarantine: 'https://gitlab.com/gitlab-org/gitlab/issues/208761' do Flow::Login.sign_in key = Runtime::Key::RSA.new diff --git a/qa/qa/specs/features/browser_ui/6_release/deploy_key/clone_using_deploy_key_spec.rb b/qa/qa/specs/features/browser_ui/6_release/deploy_key/clone_using_deploy_key_spec.rb index 581e6b8299e..ca32d5a84f0 100644 --- a/qa/qa/specs/features/browser_ui/6_release/deploy_key/clone_using_deploy_key_spec.rb +++ b/qa/qa/specs/features/browser_ui/6_release/deploy_key/clone_using_deploy_key_spec.rb @@ -35,7 +35,7 @@ module QA ] keys.each do |(key_class, bits)| - it "user sets up a deploy key with #{key_class}(#{bits}) to clone code using pipelines" do + it "user sets up a deploy key with #{key_class}(#{bits}) to clone code using pipelines", quarantine: 'https://gitlab.com/gitlab-org/gitlab/issues/208761' do key = key_class.new(*bits) Resource::DeployKey.fabricate_via_browser_ui! do |resource| diff --git a/spec/controllers/projects/releases_controller_spec.rb b/spec/controllers/projects/releases_controller_spec.rb index a03fabad2de..58fb2a95ce6 100644 --- a/spec/controllers/projects/releases_controller_spec.rb +++ b/spec/controllers/projects/releases_controller_spec.rb @@ -198,6 +198,63 @@ describe Projects::ReleasesController do end end + context 'GET #downloads' do + subject do + get :downloads, params: { + namespace_id: project.namespace, + project_id: project, + tag: tag, + filepath: filepath + } + end + + before do + sign_in(user) + end + + let(:release) { create(:release, project: project, tag: tag ) } + let(:tag) { 'v11.9.0-rc2' } + let(:db_filepath) { '/binaries/linux-amd64' } + let!(:link) do + create :release_link, + release: release, + name: 'linux-amd64 binaries', + filepath: db_filepath, + url: 'https://downloads.example.com/bin/gitlab-linux-amd64' + end + + context 'valid filepath' do + let(:filepath) { CGI.escape('/binaries/linux-amd64') } + + it 'redirects to the asset direct link' do + subject + + expect(response).to redirect_to(link.url) + end + end + + context 'invalid filepath' do + let(:filepath) { CGI.escape('/binaries/win32') } + + it 'is not found' do + subject + + expect(response).to have_gitlab_http_status(:not_found) + end + end + + context 'ignores filepath extension' do + let(:db_filepath) { '/binaries/linux-amd64.json' } + let(:filepath) { CGI.escape(db_filepath) } + + it 'redirects to the asset direct link' do + subject + + expect(response).to redirect_to(link.url) + end + end + end + describe 'GET #evidence' do let_it_be(:tag_name) { "v1.1.0-evidence" } let!(:release) { create(:release, :with_evidence, project: project, tag: tag_name) } diff --git a/spec/factories/broadcast_messages.rb b/spec/factories/broadcast_messages.rb index ed6e267e7c4..fa8d255ae79 100644 --- a/spec/factories/broadcast_messages.rb +++ b/spec/factories/broadcast_messages.rb @@ -6,6 +6,8 @@ FactoryBot.define do starts_at { 1.day.ago } ends_at { 1.day.from_now } + broadcast_type { :banner } + trait :expired do starts_at { 5.days.ago } ends_at { 3.days.ago } @@ -15,5 +17,9 @@ FactoryBot.define do starts_at { 5.days.from_now } ends_at { 6.days.from_now } end + + trait :notification do + broadcast_type { :notification } + end end end diff --git a/spec/lib/api/helpers/custom_validators_spec.rb b/spec/lib/api/helpers/custom_validators_spec.rb index 10505210e65..66b86d0a055 100644 --- a/spec/lib/api/helpers/custom_validators_spec.rb +++ b/spec/lib/api/helpers/custom_validators_spec.rb @@ -29,6 +29,38 @@ describe API::Helpers::CustomValidators do end end + describe API::Helpers::CustomValidators::GitSha do + let(:sha) { RepoHelpers.sample_commit.id } + let(:short_sha) { sha[0, Gitlab::Git::Commit::MIN_SHA_LENGTH] } + let(:too_short_sha) { sha[0, Gitlab::Git::Commit::MIN_SHA_LENGTH - 1] } + + subject do + described_class.new(['test'], {}, false, scope.new) + end + + context 'valid sha' do + it 'does not raise a validation error' do + expect_no_validation_error('test' => sha) + expect_no_validation_error('test' => short_sha) + end + end + + context 'empty params' do + it 'raises a validation error' do + expect_validation_error('test' => nil) + expect_validation_error('test' => '') + end + end + + context 'invalid sha' do + it 'raises a validation error' do + expect_validation_error('test' => "#{sha}2") # Sha length > 40 + expect_validation_error('test' => 'somestring') + expect_validation_error('test' => too_short_sha) # sha length < MIN_SHA_LENGTH (7) + end + end + end + describe API::Helpers::CustomValidators::FilePath do subject do described_class.new(['test'], {}, false, scope.new) diff --git a/spec/lib/gitlab/lograge/custom_options_spec.rb b/spec/lib/gitlab/lograge/custom_options_spec.rb new file mode 100644 index 00000000000..48d06283b7a --- /dev/null +++ b/spec/lib/gitlab/lograge/custom_options_spec.rb @@ -0,0 +1,50 @@ +# frozen_string_literal: true + +require 'spec_helper' + +describe Gitlab::Lograge::CustomOptions do + describe '.call' do + let(:params) do + { + 'controller' => 'ApplicationController', + 'action' => 'show', + 'format' => 'html', + 'a' => 'b' + } + end + + let(:event) do + ActiveSupport::Notifications::Event.new( + 'test', + 1, + 2, + 'transaction_id', + { params: params, user_id: 'test' } + ) + end + + subject { described_class.call(event) } + + it 'ignores some parameters' do + param_keys = subject[:params].map { |param| param[:key] } + + expect(param_keys).not_to include(*described_class::IGNORE_PARAMS) + end + + it 'formats the parameters' do + expect(subject[:params]).to eq([{ key: 'a', value: 'b' }]) + end + + it 'adds the current time' do + travel_to(5.days.ago) do + expected_time = Time.now.utc.iso8601(3) + + expect(subject[:time]).to eq(expected_time) + end + end + + it 'adds the user id' do + expect(subject[:user_id]).to eq('test') + end + end +end diff --git a/spec/lib/gitlab/sidekiq_queue_spec.rb b/spec/lib/gitlab/sidekiq_queue_spec.rb index 7a4d47563b6..9516ea10511 100644 --- a/spec/lib/gitlab/sidekiq_queue_spec.rb +++ b/spec/lib/gitlab/sidekiq_queue_spec.rb @@ -31,14 +31,7 @@ describe Gitlab::SidekiqQueue do context 'when the queue is not processed in time' do before do - calls = 0 - - allow(sidekiq_queue).to receive(:job_matches?).and_wrap_original do |m, *args| - raise Timeout::Error if calls > 0 - - calls += 1 - m.call(*args) - end + allow(Gitlab::Metrics::System).to receive(:monotonic_time).and_return(1, 2, 12) end it 'returns a non-completion flag, the number of jobs deleted, and the remaining queue size' do diff --git a/spec/lib/gitlab/utils/json_size_estimator_spec.rb b/spec/lib/gitlab/utils/json_size_estimator_spec.rb new file mode 100644 index 00000000000..ae24e25558a --- /dev/null +++ b/spec/lib/gitlab/utils/json_size_estimator_spec.rb @@ -0,0 +1,39 @@ +# frozen_string_literal: true + +require 'spec_helper' + +describe Gitlab::Utils::JsonSizeEstimator do + RSpec::Matchers.define :match_json_bytesize_of do |expected| + match do |actual| + actual == expected.to_json.bytesize + end + end + + def estimate(object) + described_class.estimate(object) + end + + [ + [], + [[[[]]]], + [1, "str", 3.14, ["str", { a: -1 }]], + {}, + { a: {} }, + { a: { b: { c: [1, 2, 3], e: Time.now, f: nil } } }, + { 100 => 500 }, + { '狸' => '狸' }, + nil + ].each do |example| + it { expect(estimate(example)).to match_json_bytesize_of(example) } + end + + it 'calls #to_s on unknown object' do + klass = Class.new do + def to_s + 'hello' + end + end + + expect(estimate(klass.new)).to match_json_bytesize_of(klass.new.to_s) # "hello" + end +end diff --git a/spec/presenters/hooks/project_hook_presenter_spec.rb b/spec/presenters/project_hook_presenter_spec.rb index 773e8ccf51e..773e8ccf51e 100644 --- a/spec/presenters/hooks/project_hook_presenter_spec.rb +++ b/spec/presenters/project_hook_presenter_spec.rb diff --git a/spec/presenters/hooks/service_hook_presenter_spec.rb b/spec/presenters/service_hook_presenter_spec.rb index bea57768e3e..bea57768e3e 100644 --- a/spec/presenters/hooks/service_hook_presenter_spec.rb +++ b/spec/presenters/service_hook_presenter_spec.rb diff --git a/spec/requests/api/users_spec.rb b/spec/requests/api/users_spec.rb index 8b9d0391b79..4a89069cbec 100644 --- a/spec/requests/api/users_spec.rb +++ b/spec/requests/api/users_spec.rb @@ -2165,14 +2165,20 @@ describe API::Users, :do_not_mock_admin_mode do end describe 'POST /users/:id/block' do + let(:blocked_user) { create(:user, state: 'blocked') } + before do admin end it 'blocks existing user' do post api("/users/#{user.id}/block", admin) - expect(response).to have_gitlab_http_status(:created) - expect(user.reload.state).to eq('blocked') + + aggregate_failures do + expect(response).to have_gitlab_http_status(:created) + expect(response.body).to eq('true') + expect(user.reload.state).to eq('blocked') + end end it 'does not re-block ldap blocked users' do @@ -2192,6 +2198,15 @@ describe API::Users, :do_not_mock_admin_mode do expect(response).to have_gitlab_http_status(:not_found) expect(json_response['message']).to eq('404 User Not Found') end + + it 'returns a 201 if user is already blocked' do + post api("/users/#{blocked_user.id}/block", admin) + + aggregate_failures do + expect(response).to have_gitlab_http_status(:created) + expect(response.body).to eq('null') + end + end end describe 'POST /users/:id/unblock' do diff --git a/spec/services/post_receive_service_spec.rb b/spec/services/post_receive_service_spec.rb index 9b9200fd33e..64b4a1125e8 100644 --- a/spec/services/post_receive_service_spec.rb +++ b/spec/services/post_receive_service_spec.rb @@ -130,14 +130,22 @@ describe PostReceiveService do end end - context 'broadcast message exists' do + context 'broadcast message banner exists' do it 'outputs a broadcast message' do - broadcast_message = create(:broadcast_message, starts_at: 1.day.ago, ends_at: 1.day.from_now) + broadcast_message = create(:broadcast_message) expect(subject).to include(build_alert_message(broadcast_message.message)) end end + context 'broadcast message notification exists' do + it 'does not output a broadcast message' do + create(:broadcast_message, :notification) + + expect(has_alert_messages?(subject)).to be_falsey + end + end + context 'broadcast message does not exist' do it 'does not output a broadcast message' do expect(has_alert_messages?(subject)).to be_falsey |