summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGitLab Bot <gitlab-bot@gitlab.com>2019-09-26 09:06:04 +0000
committerGitLab Bot <gitlab-bot@gitlab.com>2019-09-26 09:06:04 +0000
commit759cd6c2985088d187ed519f2a881c2c690b34ec (patch)
tree183e291c0404bf9b3ac7638be6fa1fe94b7d2d14
parent9735395f94088df7e6470e3e8a2638385ede36b6 (diff)
downloadgitlab-ce-759cd6c2985088d187ed519f2a881c2c690b34ec.tar.gz
Add latest changes from gitlab-org/gitlab@master
-rw-r--r--.eslintrc.yml1
-rw-r--r--.rubocop_todo.yml13
-rw-r--r--app/assets/javascripts/jobs/store/utils.js31
-rw-r--r--app/models/audit_event.rb9
-rw-r--r--app/models/ci/pipeline.rb6
-rw-r--r--app/models/concerns/mentionable.rb2
-rw-r--r--app/models/project_services/hipchat_service.rb2
-rw-r--r--app/models/project_services/irker_service.rb4
-rw-r--r--app/models/project_services/jira_service.rb2
-rw-r--r--app/models/project_services/packagist_service.rb2
-rw-r--r--app/models/wiki_page.rb6
-rw-r--r--app/views/projects/diffs/_stats.html.haml4
-rw-r--r--changelogs/unreleased/13426-add-user-and-timestamps-to-design-management-version.yml5
-rw-r--r--changelogs/unreleased/29284-video-preview-not-working.yml5
-rw-r--r--changelogs/unreleased/31118-do-not-use-blob-for-file-path.yml5
-rw-r--r--changelogs/unreleased/5582-add-missing-actions-and-data-to-environments-and-deployments-apis.yml5
-rw-r--r--db/migrate/20190918025618_add_user_and_timestamps_to_design_management_versions.rb16
-rw-r--r--db/migrate/20190926041216_add_user_indexes_to_design_management_versions.rb19
-rw-r--r--db/schema.rb6
-rw-r--r--doc/api/api_resources.md1
-rw-r--r--doc/api/audit_events.md115
-rw-r--r--doc/api/environments.md14
-rw-r--r--lib/api/entities.rb2
-rw-r--r--lib/banzai/filter/video_link_filter.rb22
-rw-r--r--lib/gitlab/diff/file.rb2
-rw-r--r--lib/gitlab/github_import/importer/releases_importer.rb6
-rw-r--r--spec/features/projects/commits/user_browses_commits_spec.rb4
-rw-r--r--spec/fixtures/api/schemas/deployment.json3
-rw-r--r--spec/fixtures/api/schemas/public_api/v4/deployment.json3
-rw-r--r--spec/fixtures/api/schemas/public_api/v4/environment.json3
-rw-r--r--spec/frontend/jobs/store/utils_spec.js86
-rw-r--r--spec/lib/banzai/filter/video_link_filter_spec.rb35
32 files changed, 359 insertions, 80 deletions
diff --git a/.eslintrc.yml b/.eslintrc.yml
index 37499eff807..8000bcd4361 100644
--- a/.eslintrc.yml
+++ b/.eslintrc.yml
@@ -46,7 +46,6 @@ rules:
promise/always-return: off
promise/no-callback-in-promise: off
promise/no-nesting: off
- promise/valid-params: off
overrides:
files:
- '**/spec/**/*'
diff --git a/.rubocop_todo.yml b/.rubocop_todo.yml
index 48b840b4af2..81bb28dacab 100644
--- a/.rubocop_todo.yml
+++ b/.rubocop_todo.yml
@@ -442,19 +442,6 @@ Rails/LinkToBlank:
- 'ee/app/helpers/ee/user_callouts_helper.rb'
- 'ee/app/helpers/license_helper.rb'
-# Offense count: 11
-# Cop supports --auto-correct.
-Rails/Presence:
- Exclude:
- - 'app/models/ci/pipeline.rb'
- - 'app/models/concerns/mentionable.rb'
- - 'app/models/project_services/hipchat_service.rb'
- - 'app/models/project_services/irker_service.rb'
- - 'app/models/project_services/jira_service.rb'
- - 'app/models/project_services/packagist_service.rb'
- - 'app/models/wiki_page.rb'
- - 'lib/gitlab/github_import/importer/releases_importer.rb'
-
# Offense count: 1
# Cop supports --auto-correct.
# Configuration parameters: Include.
diff --git a/app/assets/javascripts/jobs/store/utils.js b/app/assets/javascripts/jobs/store/utils.js
index 3838c759354..fd2af0e421b 100644
--- a/app/assets/javascripts/jobs/store/utils.js
+++ b/app/assets/javascripts/jobs/store/utils.js
@@ -56,6 +56,37 @@ export const logLinesParser = (lines = [], lineNumberStart) =>
}, []);
/**
+ * Finds the repeated offset, removes the old one
+ *
+ * Returns a new array with the updated log without
+ * the repeated offset
+ *
+ * @param Array newLog
+ * @param Array oldParsed
+ * @returns Array
+ *
+ */
+export const findOffsetAndRemove = (newLog, oldParsed) => {
+ const cloneOldLog = [...oldParsed];
+ const lastIndex = cloneOldLog.length - 1;
+ const last = cloneOldLog[lastIndex];
+
+ const firstNew = newLog[0];
+
+ if (last.offset === firstNew.offset || (last.line && last.line.offset === firstNew.offset)) {
+ cloneOldLog.splice(lastIndex);
+ } else if (last.lines && last.lines.length) {
+ const lastNestedIndex = last.lines.length - 1;
+ const lastNested = last.lines[lastNestedIndex];
+ if (lastNested.offset === firstNew.offset) {
+ last.lines.splice(lastNestedIndex);
+ }
+ }
+
+ return cloneOldLog;
+};
+
+/**
* When the trace is not complete, backend may send the last received line
* in the new response.
*
diff --git a/app/models/audit_event.rb b/app/models/audit_event.rb
index c2eef500fb0..06a607b75a4 100644
--- a/app/models/audit_event.rb
+++ b/app/models/audit_event.rb
@@ -1,6 +1,8 @@
# frozen_string_literal: true
class AuditEvent < ApplicationRecord
+ include CreatedAtFilterable
+
serialize :details, Hash # rubocop:disable Cop/ActiveRecordSerialize
belongs_to :user, foreign_key: :author_id
@@ -9,6 +11,9 @@ class AuditEvent < ApplicationRecord
validates :entity_id, presence: true
validates :entity_type, presence: true
+ scope :by_entity_type, -> (entity_type) { where(entity_type: entity_type) }
+ scope :by_entity_id, -> (entity_id) { where(entity_id: entity_id) }
+
after_initialize :initialize_details
def initialize_details
@@ -18,6 +23,10 @@ class AuditEvent < ApplicationRecord
def author_name
self.user.name
end
+
+ def formatted_details
+ details.merge(details.slice(:from, :to).transform_values(&:to_s))
+ end
end
AuditEvent.prepend_if_ee('EE::AuditEvent')
diff --git a/app/models/ci/pipeline.rb b/app/models/ci/pipeline.rb
index 49656a32c03..12295c0457d 100644
--- a/app/models/ci/pipeline.rb
+++ b/app/models/ci/pipeline.rb
@@ -584,11 +584,7 @@ module Ci
def ci_yaml_file_path
return unless repository_source? || unknown_source?
- if project.ci_config_path.blank?
- '.gitlab-ci.yml'
- else
- project.ci_config_path
- end
+ project.ci_config_path.presence || '.gitlab-ci.yml'
end
def ci_yaml_file
diff --git a/app/models/concerns/mentionable.rb b/app/models/concerns/mentionable.rb
index 377600ef6e5..9b6c57261d8 100644
--- a/app/models/concerns/mentionable.rb
+++ b/app/models/concerns/mentionable.rb
@@ -150,7 +150,7 @@ module Mentionable
#
# Returns a Hash.
def detect_mentionable_changes
- source = (changes.present? ? changes : previous_changes).dup
+ source = (changes.presence || previous_changes).dup
mentionable = self.class.mentionable_attrs.map { |attr, options| attr }
diff --git a/app/models/project_services/hipchat_service.rb b/app/models/project_services/hipchat_service.rb
index 3320405e9e9..1d0b37abf72 100644
--- a/app/models/project_services/hipchat_service.rb
+++ b/app/models/project_services/hipchat_service.rb
@@ -73,7 +73,7 @@ class HipchatService < Service
private
def gate
- options = { api_version: api_version.present? ? api_version : 'v2' }
+ options = { api_version: api_version.presence || 'v2' }
options[:server_url] = server unless server.blank?
@gate ||= HipChat::Client.new(token, options)
end
diff --git a/app/models/project_services/irker_service.rb b/app/models/project_services/irker_service.rb
index fb76bc89c98..4a6c8339625 100644
--- a/app/models/project_services/irker_service.rb
+++ b/app/models/project_services/irker_service.rb
@@ -36,8 +36,8 @@ class IrkerService < Service
def settings
{
- server_host: server_host.present? ? server_host : 'localhost',
- server_port: server_port.present? ? server_port : 6659
+ server_host: server_host.presence || 'localhost',
+ server_port: server_port.presence || 6659
}
end
diff --git a/app/models/project_services/jira_service.rb b/app/models/project_services/jira_service.rb
index 4a02da975f2..cfdf55b5155 100644
--- a/app/models/project_services/jira_service.rb
+++ b/app/models/project_services/jira_service.rb
@@ -337,7 +337,7 @@ class JiraService < IssueTrackerService
end
def client_url
- api_url.present? ? api_url : url
+ api_url.presence || url
end
def reset_password?
diff --git a/app/models/project_services/packagist_service.rb b/app/models/project_services/packagist_service.rb
index 003884bb7ac..35dbedd1341 100644
--- a/app/models/project_services/packagist_service.rb
+++ b/app/models/project_services/packagist_service.rb
@@ -59,7 +59,7 @@ class PackagistService < Service
end
def hook_url
- base_url = server.present? ? server : 'https://packagist.org'
+ base_url = server.presence || 'https://packagist.org'
"#{base_url}/api/update-package?username=#{username}&apiToken=#{token}"
end
end
diff --git a/app/models/wiki_page.rb b/app/models/wiki_page.rb
index cd4c7895587..1fa29e5b933 100644
--- a/app/models/wiki_page.rb
+++ b/app/models/wiki_page.rb
@@ -77,11 +77,7 @@ class WikiPage
# The escaped URL path of this page.
def slug
- if @attributes[:slug].present?
- @attributes[:slug]
- else
- wiki.wiki.preview_slug(title, format)
- end
+ @attributes[:slug].presence || wiki.wiki.preview_slug(title, format)
end
alias_method :to_param, :slug
diff --git a/app/views/projects/diffs/_stats.html.haml b/app/views/projects/diffs/_stats.html.haml
index c9057f385da..86e6e732610 100644
--- a/app/views/projects/diffs/_stats.html.haml
+++ b/app/views/projects/diffs/_stats.html.haml
@@ -24,9 +24,9 @@
%a.diff-changed-file{ href: "##{hexdigest(diff_file.file_path)}", title: diff_file.new_path }
= sprite_icon(diff_file_changed_icon(diff_file), size: 16, css_class: "#{diff_file_changed_icon_color(diff_file)} diff-file-changed-icon append-right-8")
%span.diff-changed-file-content.append-right-8
- - if diff_file.blob&.name
+ - if diff_file.file_path
%strong.diff-changed-file-name
- = diff_file.blob.name
+ = diff_file.file_path
- else
%strong.diff-changed-blank-file-name
= s_('Diffs|No file name available')
diff --git a/changelogs/unreleased/13426-add-user-and-timestamps-to-design-management-version.yml b/changelogs/unreleased/13426-add-user-and-timestamps-to-design-management-version.yml
new file mode 100644
index 00000000000..2f56de32b2d
--- /dev/null
+++ b/changelogs/unreleased/13426-add-user-and-timestamps-to-design-management-version.yml
@@ -0,0 +1,5 @@
+---
+title: Add user_id and created_at columns to design_management_versions table
+merge_request: 17316
+author:
+type: added
diff --git a/changelogs/unreleased/29284-video-preview-not-working.yml b/changelogs/unreleased/29284-video-preview-not-working.yml
new file mode 100644
index 00000000000..304700dea30
--- /dev/null
+++ b/changelogs/unreleased/29284-video-preview-not-working.yml
@@ -0,0 +1,5 @@
+---
+title: Fix inline rendering of videos for uploads with uppercase file extensions
+merge_request: 17581
+author:
+type: fixed
diff --git a/changelogs/unreleased/31118-do-not-use-blob-for-file-path.yml b/changelogs/unreleased/31118-do-not-use-blob-for-file-path.yml
new file mode 100644
index 00000000000..454ad15ee46
--- /dev/null
+++ b/changelogs/unreleased/31118-do-not-use-blob-for-file-path.yml
@@ -0,0 +1,5 @@
+---
+title: Reduce Gitaly calls when viewing a commit
+merge_request: 17095
+author:
+type: performance
diff --git a/changelogs/unreleased/5582-add-missing-actions-and-data-to-environments-and-deployments-apis.yml b/changelogs/unreleased/5582-add-missing-actions-and-data-to-environments-and-deployments-apis.yml
new file mode 100644
index 00000000000..7c90834385f
--- /dev/null
+++ b/changelogs/unreleased/5582-add-missing-actions-and-data-to-environments-and-deployments-apis.yml
@@ -0,0 +1,5 @@
+---
+title: Add status to deployments and state to environments in API responses
+merge_request: 16242
+author:
+type: changed
diff --git a/db/migrate/20190918025618_add_user_and_timestamps_to_design_management_versions.rb b/db/migrate/20190918025618_add_user_and_timestamps_to_design_management_versions.rb
new file mode 100644
index 00000000000..3daca8a8e97
--- /dev/null
+++ b/db/migrate/20190918025618_add_user_and_timestamps_to_design_management_versions.rb
@@ -0,0 +1,16 @@
+# frozen_string_literal: true
+
+class AddUserAndTimestampsToDesignManagementVersions < ActiveRecord::Migration[5.2]
+ include Gitlab::Database::MigrationHelpers
+
+ DOWNTIME = false
+
+ def up
+ add_column :design_management_versions, :user_id, :integer
+ add_column :design_management_versions, :created_at, :datetime_with_timezone
+ end
+
+ def down
+ remove_columns :design_management_versions, :user_id, :created_at
+ end
+end
diff --git a/db/migrate/20190926041216_add_user_indexes_to_design_management_versions.rb b/db/migrate/20190926041216_add_user_indexes_to_design_management_versions.rb
new file mode 100644
index 00000000000..6eb9fdbbcaa
--- /dev/null
+++ b/db/migrate/20190926041216_add_user_indexes_to_design_management_versions.rb
@@ -0,0 +1,19 @@
+# frozen_string_literal: true
+
+class AddUserIndexesToDesignManagementVersions < ActiveRecord::Migration[5.2]
+ include Gitlab::Database::MigrationHelpers
+
+ DOWNTIME = false
+
+ disable_ddl_transaction!
+
+ def up
+ add_concurrent_foreign_key :design_management_versions, :users, column: :user_id, on_delete: :nullify
+ add_concurrent_index :design_management_versions, :user_id, where: 'user_id IS NOT NULL'
+ end
+
+ def down
+ remove_concurrent_index :design_management_versions, :user_id
+ remove_foreign_key :design_management_versions, column: :user_id
+ end
+end
diff --git a/db/schema.rb b/db/schema.rb
index 6674e00950a..aff672919c1 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: 2019_09_19_162036) do
+ActiveRecord::Schema.define(version: 2019_09_26_041216) do
# These are extensions that must be enabled in order to support this database
enable_extension "pg_trgm"
@@ -1232,8 +1232,11 @@ ActiveRecord::Schema.define(version: 2019_09_19_162036) do
create_table "design_management_versions", force: :cascade do |t|
t.binary "sha", null: false
t.bigint "issue_id"
+ t.integer "user_id"
+ t.datetime_with_timezone "created_at"
t.index ["issue_id"], name: "index_design_management_versions_on_issue_id"
t.index ["sha", "issue_id"], name: "index_design_management_versions_on_sha_and_issue_id", unique: true
+ t.index ["user_id"], name: "index_design_management_versions_on_user_id", where: "(user_id IS NOT NULL)"
end
create_table "draft_notes", force: :cascade do |t|
@@ -3930,6 +3933,7 @@ ActiveRecord::Schema.define(version: 2019_09_19_162036) do
add_foreign_key "design_management_designs_versions", "design_management_designs", column: "design_id", name: "fk_03c671965c", on_delete: :cascade
add_foreign_key "design_management_designs_versions", "design_management_versions", column: "version_id", name: "fk_f4d25ba00c", on_delete: :cascade
add_foreign_key "design_management_versions", "issues", on_delete: :cascade
+ add_foreign_key "design_management_versions", "users", name: "fk_ee16b939e5", on_delete: :nullify
add_foreign_key "draft_notes", "merge_requests", on_delete: :cascade
add_foreign_key "draft_notes", "users", column: "author_id", on_delete: :cascade
add_foreign_key "elasticsearch_indexed_namespaces", "namespaces", on_delete: :cascade
diff --git a/doc/api/api_resources.md b/doc/api/api_resources.md
index e2ddc2cbc18..232a9825691 100644
--- a/doc/api/api_resources.md
+++ b/doc/api/api_resources.md
@@ -104,6 +104,7 @@ The following API resources are available outside of project and group contexts
| Resource | Available endpoints |
|:--------------------------------------------------|:------------------------------------------------------------------------|
| [Applications](applications.md) | `/applications` |
+| [Audit Events](audit_events.md) **(PREMIUM ONLY)** | `/audit_events` |
| [Avatar](avatar.md) | `/avatar` |
| [Broadcast messages](broadcast_messages.md) | `/broadcast_messages` |
| [Code snippets](snippets.md) | `/snippets` |
diff --git a/doc/api/audit_events.md b/doc/api/audit_events.md
new file mode 100644
index 00000000000..aca221cf990
--- /dev/null
+++ b/doc/api/audit_events.md
@@ -0,0 +1,115 @@
+# Audit Events API **(PREMIUM ONLY)**
+
+The Audit Events API allows you to retrieve [instance audit events](../administration/audit_events.md#instance-events-premium-only).
+
+To retrieve audit events using the API, you must [authenticate yourself](README.html#authentication) as an Administrator.
+
+## Retrieve all instance audit events
+
+```
+GET /audit_events
+```
+
+| Attribute | Type | Required | Description |
+| --------- | ---- | -------- | ----------- |
+| `created_after` | string | no | Return audit events created on or after the given time. Format: ISO 8601 YYYY-MM-DDTHH:MM:SSZ |
+| `created_before` | string | no | Return audit events created on or before the given time. Format: ISO 8601 YYYY-MM-DDTHH:MM:SSZ |
+| `entity_type` | string | no | Return audit events for the given entity type. Valid values are: `User`, `Group`, or `Project`. |
+| `entity_id` | boolean | no | Return audit events for the given entity ID. Requires `entity_type` attribute to be present. |
+
+By default, `GET` requests return 20 results at a time because the API results
+are paginated.
+
+Read more on [pagination](README.md#pagination).
+
+```bash
+curl --header "PRIVATE-TOKEN: <your_access_token>" https://primary.example.com/api/v4/audit_events
+```
+
+Example response:
+
+```json
+[
+ {
+ "id": 1,
+ "author_id": 1,
+ "entity_id": 6,
+ "entity_type": "Project",
+ "details": {
+ "custom_message": "Project archived",
+ "author_name": "Administrator",
+ "target_id": "flightjs/flight",
+ "target_type": "Project",
+ "target_details": "flightjs/flight",
+ "ip_address": "127.0.0.1",
+ "entity_path": "flightjs/flight"
+ },
+ "created_at": "2019-08-30T07:00:41.885Z"
+ },
+ {
+ "id": 2,
+ "author_id": 1,
+ "entity_id": 60,
+ "entity_type": "Group",
+ "details": {
+ "add": "group",
+ "author_name": "Administrator",
+ "target_id": "flightjs",
+ "target_type": "Group",
+ "target_details": "flightjs",
+ "ip_address": "127.0.0.1",
+ "entity_path": "flightjs"
+ },
+ "created_at": "2019-08-27T18:36:44.162Z"
+ },
+ {
+ "id": 3,
+ "author_id": 51,
+ "entity_id": 51,
+ "entity_type": "User",
+ "details": {
+ "change": "email address",
+ "from": "hello@flightjs.com",
+ "to": "maintainer@flightjs.com",
+ "author_name": "Andreas",
+ "target_id": 51,
+ "target_type": "User",
+ "target_details": "Andreas",
+ "ip_address": null,
+ "entity_path": "Andreas"
+ },
+ "created_at": "2019-08-22T16:34:25.639Z"
+ }
+]
+```
+
+## Retrieve single instance audit event
+
+```
+GET /audit_events/:id
+```
+
+```bash
+curl --header "PRIVATE-TOKEN: <your_access_token>" https://primary.example.com/api/v4/audit_events/1
+```
+
+Example response:
+
+```json
+{
+ "id": 1,
+ "author_id": 1,
+ "entity_id": 6,
+ "entity_type": "Project",
+ "details": {
+ "custom_message": "Project archived",
+ "author_name": "Administrator",
+ "target_id": "flightjs/flight",
+ "target_type": "Project",
+ "target_details": "flightjs/flight",
+ "ip_address": "127.0.0.1",
+ "entity_path": "flightjs/flight"
+ },
+ "created_at": "2019-08-30T07:00:41.885Z"
+}
+```
diff --git a/doc/api/environments.md b/doc/api/environments.md
index 26ee075c921..3f46c11ed69 100644
--- a/doc/api/environments.md
+++ b/doc/api/environments.md
@@ -26,7 +26,8 @@ Example response:
"id": 1,
"name": "review/fix-foo",
"slug": "review-fix-foo-dfjre3",
- "external_url": "https://review-fix-foo-dfjre3.example.gitlab.com"
+ "external_url": "https://review-fix-foo-dfjre3.example.gitlab.com",
+ "state": "available"
}
]
```
@@ -54,12 +55,14 @@ Example of response
"name": "review/fix-foo",
"slug": "review-fix-foo-dfjre3",
"external_url": "https://review-fix-foo-dfjre3.example.gitlab.com"
+ "state": "available",
"last_deployment": {
"id": 100,
"iid": 34,
"ref": "fdroid",
"sha": "416d8ea11849050d3d1f5104cf8cf51053e790ab",
"created_at": "2019-03-25T18:55:13.252Z",
+ "status": "success",
"user": {
"id": 1,
"name": "Administrator",
@@ -163,7 +166,8 @@ Example response:
"id": 1,
"name": "deploy",
"slug": "deploy",
- "external_url": "https://deploy.example.gitlab.com"
+ "external_url": "https://deploy.example.gitlab.com",
+ "state": "available"
}
```
@@ -195,7 +199,8 @@ Example response:
"id": 1,
"name": "staging",
"slug": "staging",
- "external_url": "https://staging.example.gitlab.com"
+ "external_url": "https://staging.example.gitlab.com",
+ "state": "available"
}
```
@@ -240,6 +245,7 @@ Example response:
"id": 1,
"name": "deploy",
"slug": "deploy",
- "external_url": "https://deploy.example.gitlab.com"
+ "external_url": "https://deploy.example.gitlab.com",
+ "state": "stopped"
}
```
diff --git a/lib/api/entities.rb b/lib/api/entities.rb
index 9d393f0217b..72bbba8065e 100644
--- a/lib/api/entities.rb
+++ b/lib/api/entities.rb
@@ -1470,11 +1470,13 @@ module API
expose :user, using: Entities::UserBasic
expose :environment, using: Entities::EnvironmentBasic
expose :deployable, using: Entities::Job
+ expose :status
end
class Environment < EnvironmentBasic
expose :project, using: Entities::BasicProjectDetails
expose :last_deployment, using: Entities::Deployment, if: { last_deployment: true }
+ expose :state
end
class LicenseBasic < Grape::Entity
diff --git a/lib/banzai/filter/video_link_filter.rb b/lib/banzai/filter/video_link_filter.rb
index 58006cc6c13..bdd257a5e67 100644
--- a/lib/banzai/filter/video_link_filter.rb
+++ b/lib/banzai/filter/video_link_filter.rb
@@ -8,8 +8,8 @@ module Banzai
# a "Download" link in the case the video cannot be played.
class VideoLinkFilter < HTML::Pipeline::Filter
def call
- doc.xpath(query).each do |el|
- el.replace(video_node(doc, el))
+ doc.xpath('descendant-or-self::img[not(ancestor::a)]').each do |el|
+ el.replace(video_node(doc, el)) if has_video_extension?(el)
end
doc
@@ -17,22 +17,10 @@ module Banzai
private
- def query
- @query ||= begin
- src_query = UploaderHelper::SAFE_VIDEO_EXT.map do |ext|
- "'.#{ext}' = substring(@src, string-length(@src) - #{ext.size})"
- end
+ def has_video_extension?(element)
+ src_attr = context[:asset_proxy_enabled] ? 'data-canonical-src' : 'src'
- if context[:asset_proxy_enabled].present?
- src_query.concat(
- UploaderHelper::SAFE_VIDEO_EXT.map do |ext|
- "'.#{ext}' = substring(@data-canonical-src, string-length(@data-canonical-src) - #{ext.size})"
- end
- )
- end
-
- "descendant-or-self::img[not(ancestor::a) and (#{src_query.join(' or ')})]"
- end
+ element.attr(src_attr).downcase.end_with?(*UploaderHelper::SAFE_VIDEO_EXT)
end
def video_node(doc, element)
diff --git a/lib/gitlab/diff/file.rb b/lib/gitlab/diff/file.rb
index c46087e65de..30fe7440148 100644
--- a/lib/gitlab/diff/file.rb
+++ b/lib/gitlab/diff/file.rb
@@ -428,8 +428,8 @@ module Gitlab
def viewer_class_from(classes)
return unless diffable?
- return if different_type? || external_storage_error?
return unless new_file? || deleted_file? || content_changed?
+ return if different_type? || external_storage_error?
verify_binary = !stored_externally?
diff --git a/lib/gitlab/github_import/importer/releases_importer.rb b/lib/gitlab/github_import/importer/releases_importer.rb
index fe3a8d4aea5..1881f715c99 100644
--- a/lib/gitlab/github_import/importer/releases_importer.rb
+++ b/lib/gitlab/github_import/importer/releases_importer.rb
@@ -47,11 +47,7 @@ module Gitlab
end
def description_for(release)
- if release.body.present?
- release.body
- else
- "Release for tag #{release.tag_name}"
- end
+ release.body.presence || "Release for tag #{release.tag_name}"
end
end
end
diff --git a/spec/features/projects/commits/user_browses_commits_spec.rb b/spec/features/projects/commits/user_browses_commits_spec.rb
index 085d8d63d52..131d9097f48 100644
--- a/spec/features/projects/commits/user_browses_commits_spec.rb
+++ b/spec/features/projects/commits/user_browses_commits_spec.rb
@@ -93,13 +93,13 @@ describe 'User browses commits' do
context 'when the blob does not exist' do
let(:commit) { create(:commit, project: project) }
- it 'shows a blank label' do
+ it 'renders successfully' do
allow_any_instance_of(Gitlab::Diff::File).to receive(:blob).and_return(nil)
allow_any_instance_of(Gitlab::Diff::File).to receive(:binary?).and_return(true)
visit(project_commit_path(project, commit))
- expect(find('.diff-file-changes', visible: false)).to have_content('No file name available')
+ expect(find('.diff-file-changes', visible: false)).to have_content('files/ruby/popen.rb')
end
end
diff --git a/spec/fixtures/api/schemas/deployment.json b/spec/fixtures/api/schemas/deployment.json
index 81c2d1ef5ab..b1e3c000ddf 100644
--- a/spec/fixtures/api/schemas/deployment.json
+++ b/spec/fixtures/api/schemas/deployment.json
@@ -60,7 +60,8 @@
"scheduled_actions": {
"type": "array",
"items": { "$ref": "job/job.json" }
- }
+ },
+ "status": { "type": "string" }
},
"additionalProperties": false
}
diff --git a/spec/fixtures/api/schemas/public_api/v4/deployment.json b/spec/fixtures/api/schemas/public_api/v4/deployment.json
index 3af2dc27d55..13b10eac625 100644
--- a/spec/fixtures/api/schemas/public_api/v4/deployment.json
+++ b/spec/fixtures/api/schemas/public_api/v4/deployment.json
@@ -26,7 +26,8 @@
{ "type": "null" },
{ "$ref": "job.json" }
]
- }
+ },
+ "status": { "type": "string" }
},
"additionalProperties": false
}
diff --git a/spec/fixtures/api/schemas/public_api/v4/environment.json b/spec/fixtures/api/schemas/public_api/v4/environment.json
index 242e90fb7ac..57352017f03 100644
--- a/spec/fixtures/api/schemas/public_api/v4/environment.json
+++ b/spec/fixtures/api/schemas/public_api/v4/environment.json
@@ -17,7 +17,8 @@
{ "type": "null" },
{ "$ref": "deployment.json" }
]
- }
+ },
+ "state": { "type": "string" }
},
"additionalProperties": false
}
diff --git a/spec/frontend/jobs/store/utils_spec.js b/spec/frontend/jobs/store/utils_spec.js
index 1e885b6b788..bb45fcb7435 100644
--- a/spec/frontend/jobs/store/utils_spec.js
+++ b/spec/frontend/jobs/store/utils_spec.js
@@ -3,6 +3,7 @@ import {
updateIncrementalTrace,
parseHeaderLine,
parseLine,
+ findOffsetAndRemove,
} from '~/jobs/store/utils';
import {
utilsMockData,
@@ -83,6 +84,91 @@ describe('Jobs Store Utils', () => {
});
});
+ describe('findOffsetAndRemove', () => {
+ describe('when last item is header', () => {
+ const existingLog = [
+ {
+ isHeader: true,
+ isClosed: true,
+ line: { content: [{ text: 'bar' }], offset: 10, lineNumber: 1 },
+ },
+ ];
+
+ describe('and matches the offset', () => {
+ it('returns an array with the item removed', () => {
+ const newData = [{ offset: 10, content: [{ text: 'foobar' }] }];
+ const result = findOffsetAndRemove(newData, existingLog);
+
+ expect(result).toEqual([]);
+ });
+ });
+
+ describe('and does not match the offset', () => {
+ it('returns the provided existing log', () => {
+ const newData = [{ offset: 110, content: [{ text: 'foobar' }] }];
+ const result = findOffsetAndRemove(newData, existingLog);
+
+ expect(result).toEqual(existingLog);
+ });
+ });
+ });
+
+ describe('when last item is a regular line', () => {
+ const existingLog = [{ content: [{ text: 'bar' }], offset: 10, lineNumber: 1 }];
+
+ describe('and matches the offset', () => {
+ it('returns an array with the item removed', () => {
+ const newData = [{ offset: 10, content: [{ text: 'foobar' }] }];
+ const result = findOffsetAndRemove(newData, existingLog);
+
+ expect(result).toEqual([]);
+ });
+ });
+
+ describe('and does not match the fofset', () => {
+ it('returns the provided old log', () => {
+ const newData = [{ offset: 101, content: [{ text: 'foobar' }] }];
+ const result = findOffsetAndRemove(newData, existingLog);
+
+ expect(result).toEqual(existingLog);
+ });
+ });
+ });
+
+ describe('when last item is nested', () => {
+ const existingLog = [
+ {
+ isHeader: true,
+ isClosed: true,
+ lines: [{ offset: 101, content: [{ text: 'foobar' }], lineNumber: 2 }],
+ line: {
+ offset: 10,
+ lineNumber: 1,
+ section_duration: '10:00',
+ },
+ },
+ ];
+
+ describe('and matches the offset', () => {
+ it('returns an array with the last nested line item removed', () => {
+ const newData = [{ offset: 101, content: [{ text: 'foobar' }] }];
+
+ const result = findOffsetAndRemove(newData, existingLog);
+ expect(result[0].lines).toEqual([]);
+ });
+ });
+
+ describe('and does not match the offset', () => {
+ it('returns the provided old log', () => {
+ const newData = [{ offset: 120, content: [{ text: 'foobar' }] }];
+
+ const result = findOffsetAndRemove(newData, existingLog);
+ expect(result).toEqual(existingLog);
+ });
+ });
+ });
+ });
+
describe('updateIncrementalTrace', () => {
describe('without repeated section', () => {
it('concats and parses both arrays', () => {
diff --git a/spec/lib/banzai/filter/video_link_filter_spec.rb b/spec/lib/banzai/filter/video_link_filter_spec.rb
index b5be204d680..afcc846ba05 100644
--- a/spec/lib/banzai/filter/video_link_filter_spec.rb
+++ b/spec/lib/banzai/filter/video_link_filter_spec.rb
@@ -17,27 +17,32 @@ describe Banzai::Filter::VideoLinkFilter do
let(:project) { create(:project, :repository) }
- context 'when the element src has a video extension' do
- UploaderHelper::SAFE_VIDEO_EXT.each do |ext|
- it "replaces the image tag 'path/video.#{ext}' with a video tag" do
- container = filter(link_to_image("/path/video.#{ext}")).children.first
+ shared_examples 'replaces the image tag with a video tag' do |ext|
+ it "replaces the image tag 'path/video.#{ext}' with a video tag" do
+ container = filter(link_to_image("/path/video.#{ext}")).children.first
- expect(container.name).to eq 'div'
- expect(container['class']).to eq 'video-container'
+ expect(container.name).to eq 'div'
+ expect(container['class']).to eq 'video-container'
+
+ video, paragraph = container.children
- video, paragraph = container.children
+ expect(video.name).to eq 'video'
+ expect(video['src']).to eq "/path/video.#{ext}"
- expect(video.name).to eq 'video'
- expect(video['src']).to eq "/path/video.#{ext}"
+ expect(paragraph.name).to eq 'p'
- expect(paragraph.name).to eq 'p'
+ link = paragraph.children.first
- link = paragraph.children.first
+ expect(link.name).to eq 'a'
+ expect(link['href']).to eq "/path/video.#{ext}"
+ expect(link['target']).to eq '_blank'
+ end
+ end
- expect(link.name).to eq 'a'
- expect(link['href']).to eq "/path/video.#{ext}"
- expect(link['target']).to eq '_blank'
- end
+ context 'when the element src has a video extension' do
+ UploaderHelper::SAFE_VIDEO_EXT.each do |ext|
+ it_behaves_like 'replaces the image tag with a video tag', ext
+ it_behaves_like 'replaces the image tag with a video tag', ext.upcase
end
end