Commit 96781283 authored by GitLab Bot's avatar GitLab Bot

Add latest changes from gitlab-org/gitlab@master

parent 074d013e
...@@ -58,6 +58,9 @@ export default { ...@@ -58,6 +58,9 @@ export default {
hasDiff() { hasDiff() {
return hasDiff(this.file); return hasDiff(this.file);
}, },
isActive() {
return this.currentDiffFileId === this.file.file_hash;
},
isFileTooLarge() { isFileTooLarge() {
return this.file.viewer.error === diffViewerErrors.too_large; return this.file.viewer.error === diffViewerErrors.too_large;
}, },
...@@ -143,7 +146,7 @@ export default { ...@@ -143,7 +146,7 @@ export default {
<div <div
:id="file.file_hash" :id="file.file_hash"
:class="{ :class="{
'is-active': currentDiffFileId === file.file_hash, 'is-active': isActive,
}" }"
class="diff-file file-holder" class="diff-file file-holder"
> >
...@@ -153,6 +156,7 @@ export default { ...@@ -153,6 +156,7 @@ export default {
:collapsible="true" :collapsible="true"
:expanded="!isCollapsed" :expanded="!isCollapsed"
:add-merge-request-buttons="true" :add-merge-request-buttons="true"
:is-active="isActive"
class="js-file-title file-title" class="js-file-title file-title"
@toggleFile="handleToggle" @toggleFile="handleToggle"
@showForkMessage="showForkMessage" @showForkMessage="showForkMessage"
......
...@@ -55,6 +55,11 @@ export default { ...@@ -55,6 +55,11 @@ export default {
type: Boolean, type: Boolean,
required: true, required: true,
}, },
isActive: {
type: Boolean,
required: false,
default: false,
},
}, },
computed: { computed: {
...mapGetters('diffs', ['diffHasExpandedDiscussions', 'diffHasDiscussions']), ...mapGetters('diffs', ['diffHasExpandedDiscussions', 'diffHasDiscussions']),
...@@ -158,6 +163,9 @@ export default { ...@@ -158,6 +163,9 @@ export default {
<div <div
ref="header" ref="header"
class="js-file-title file-title file-title-flex-parent" class="js-file-title file-title file-title-flex-parent"
:class="{
'is-active': isActive,
}"
@click.self="handleToggleFile" @click.self="handleToggleFile"
> >
<div class="file-header-content"> <div class="file-header-content">
......
...@@ -26,7 +26,7 @@ export default { ...@@ -26,7 +26,7 @@ export default {
}; };
}, },
computed: { computed: {
...mapState('diffs', ['tree', 'renderTreeList']), ...mapState('diffs', ['tree', 'renderTreeList', 'currentDiffFileId', 'viewedDiffFileIds']),
...mapGetters('diffs', ['allBlobs']), ...mapGetters('diffs', ['allBlobs']),
filteredTreeList() { filteredTreeList() {
const search = this.search.toLowerCase().trim(); const search = this.search.toLowerCase().trim();
...@@ -96,6 +96,8 @@ export default { ...@@ -96,6 +96,8 @@ export default {
:level="0" :level="0"
:hide-file-stats="hideFileStats" :hide-file-stats="hideFileStats"
:file-row-component="$options.DiffFileRow" :file-row-component="$options.DiffFileRow"
:active-file="currentDiffFileId"
:viewed-files="viewedDiffFileIds"
@toggleTreeOpen="toggleTreeOpen" @toggleTreeOpen="toggleTreeOpen"
@clickFile="scrollToFile" @clickFile="scrollToFile"
/> />
......
...@@ -26,6 +26,7 @@ export default () => ({ ...@@ -26,6 +26,7 @@ export default () => ({
showTreeList: true, showTreeList: true,
currentDiffFileId: '', currentDiffFileId: '',
projectPath: '', projectPath: '',
viewedDiffFileIds: [],
commentForms: [], commentForms: [],
highlightedRow: null, highlightedRow: null,
renderTreeList: true, renderTreeList: true,
......
...@@ -284,6 +284,9 @@ export default { ...@@ -284,6 +284,9 @@ export default {
}, },
[types.UPDATE_CURRENT_DIFF_FILE_ID](state, fileId) { [types.UPDATE_CURRENT_DIFF_FILE_ID](state, fileId) {
state.currentDiffFileId = fileId; state.currentDiffFileId = fileId;
if (!state.viewedDiffFileIds.includes(fileId)) {
state.viewedDiffFileIds = [fileId, ...state.viewedDiffFileIds];
}
}, },
[types.OPEN_DIFF_FILE_COMMENT_FORM](state, formData) { [types.OPEN_DIFF_FILE_COMMENT_FORM](state, formData) {
state.commentForms.push({ state.commentForms.push({
......
...@@ -18,6 +18,16 @@ export default { ...@@ -18,6 +18,16 @@ export default {
type: Number, type: Number,
required: true, required: true,
}, },
activeFile: {
type: String,
required: false,
default: '',
},
viewedFiles: {
type: Array,
required: false,
default: () => [],
},
}, },
computed: { computed: {
isTree() { isTree() {
...@@ -34,8 +44,8 @@ export default { ...@@ -34,8 +44,8 @@ export default {
fileClass() { fileClass() {
return { return {
'file-open': this.isBlob && this.file.opened, 'file-open': this.isBlob && this.file.opened,
'is-active': this.isBlob && this.file.active, 'is-active': this.isBlob && (this.file.active || this.activeFile === this.file.fileHash),
folder: this.isTree, 'is-viewed': this.isBlob && this.viewedFiles.includes(this.file.fileHash),
'is-open': this.file.opened, 'is-open': this.file.opened,
}; };
}, },
...@@ -107,15 +117,23 @@ export default { ...@@ -107,15 +117,23 @@ export default {
v-else v-else
:class="fileClass" :class="fileClass"
:title="file.name" :title="file.name"
class="file-row" class="file-row text-left px-1 py-2 ml-n2 d-flex align-items-center"
role="button" role="button"
@click="clickFile" @click="clickFile"
@mouseleave="$emit('mouseleave', $event)" @mouseleave="$emit('mouseleave', $event)"
> >
<div class="file-row-name-container"> <div class="file-row-name-container w-100 d-flex align-items-center">
<span ref="textOutput" :style="levelIndentation" class="file-row-name str-truncated"> <span
ref="textOutput"
:style="levelIndentation"
class="file-row-name str-truncated d-inline-block"
:class="[
{ 'folder font-weight-normal': isTree },
fileClass['is-viewed'] ? 'font-weight-normal' : 'font-weight-bold',
]"
>
<file-icon <file-icon
class="file-row-icon" class="file-row-icon align-middle mr-1"
:class="{ 'text-secondary': file.type === 'tree' }" :class="{ 'text-secondary': file.type === 'tree' }"
:file-name="file.name" :file-name="file.name"
:loading="file.loading" :loading="file.loading"
...@@ -132,14 +150,8 @@ export default { ...@@ -132,14 +150,8 @@ export default {
<style> <style>
.file-row { .file-row {
display: flex;
align-items: center;
height: 32px; height: 32px;
padding: 4px 8px;
margin-left: -8px;
margin-right: -8px;
border-radius: 3px; border-radius: 3px;
text-align: left;
cursor: pointer; cursor: pointer;
} }
...@@ -157,24 +169,15 @@ export default { ...@@ -157,24 +169,15 @@ export default {
} }
.file-row-name-container { .file-row-name-container {
display: flex;
width: 100%;
align-items: center;
overflow: visible; overflow: visible;
} }
.file-row-name { .file-row-name {
display: inline-block;
flex: 1; flex: 1;
max-width: inherit; max-width: inherit;
height: 19px; height: 20px;
line-height: 16px; line-height: 16px;
text-overflow: ellipsis; text-overflow: ellipsis;
white-space: nowrap; white-space: nowrap;
} }
.file-row-name .file-row-icon {
margin-right: 2px;
vertical-align: middle;
}
</style> </style>
...@@ -69,6 +69,11 @@ ...@@ -69,6 +69,11 @@
} }
} }
.file-title.is-active,
.file-title-flex-parent.is-active {
background-color: $gray-200;
}
@media (min-width: map-get($grid-breakpoints, md)) { @media (min-width: map-get($grid-breakpoints, md)) {
&.conflict .file-title, &.conflict .file-title,
&.conflict .file-title-flex-parent { &.conflict .file-title-flex-parent {
......
...@@ -86,7 +86,11 @@ class TeamcityService < CiService ...@@ -86,7 +86,11 @@ class TeamcityService < CiService
def calculate_reactive_cache(sha, ref) def calculate_reactive_cache(sha, ref)
response = get_path("httpAuth/app/rest/builds/branch:unspecified:any,revision:#{sha}") response = get_path("httpAuth/app/rest/builds/branch:unspecified:any,revision:#{sha}")
{ build_page: read_build_page(response), commit_status: read_commit_status(response) } if response
{ build_page: read_build_page(response), commit_status: read_commit_status(response) }
else
{ build_page: teamcity_url, commit_status: :error }
end
end end
def execute(data) def execute(data)
...@@ -149,7 +153,7 @@ class TeamcityService < CiService ...@@ -149,7 +153,7 @@ class TeamcityService < CiService
end end
def get_path(path) def get_path(path)
Gitlab::HTTP.get(build_url(path), verify: false, basic_auth: basic_auth) Gitlab::HTTP.try_get(build_url(path), verify: false, basic_auth: basic_auth, extra_log_info: { project_id: project_id })
end end
def post_to_build_queue(data, branch) def post_to_build_queue(data, branch)
......
...@@ -4,14 +4,12 @@ ...@@ -4,14 +4,12 @@
module Projects module Projects
module LfsPointers module LfsPointers
class LfsListService < BaseService class LfsListService < BaseService
REV = 'HEAD'
# Retrieve all lfs blob pointers and returns a hash # Retrieve all lfs blob pointers and returns a hash
# with the structure { lfs_file_oid => lfs_file_size } # with the structure { lfs_file_oid => lfs_file_size }
def execute def execute
return {} unless project&.lfs_enabled? return {} unless project&.lfs_enabled?
Gitlab::Git::LfsChanges.new(project.repository, REV) Gitlab::Git::LfsChanges.new(project.repository)
.all_pointers .all_pointers
.map! { |blob| [blob.lfs_oid, blob.lfs_size] } .map! { |blob| [blob.lfs_oid, blob.lfs_size] }
.to_h .to_h
......
...@@ -3,7 +3,7 @@ ...@@ -3,7 +3,7 @@
class AuthorizedKeysWorker class AuthorizedKeysWorker
include ApplicationWorker include ApplicationWorker
PERMITTED_ACTIONS = [:add_key, :remove_key].freeze PERMITTED_ACTIONS = %w[add_key remove_key].freeze
feature_category :source_code_management feature_category :source_code_management
urgency :high urgency :high
...@@ -13,11 +13,13 @@ class AuthorizedKeysWorker ...@@ -13,11 +13,13 @@ class AuthorizedKeysWorker
def perform(action, *args) def perform(action, *args)
return unless Gitlab::CurrentSettings.authorized_keys_enabled? return unless Gitlab::CurrentSettings.authorized_keys_enabled?
case action case action.to_s
when :add_key when 'add_key'
authorized_keys.add_key(*args) authorized_keys.add_key(*args)
when :remove_key when 'remove_key'
authorized_keys.remove_key(*args) authorized_keys.remove_key(*args)
else
raise "Unknown action: #{action.inspect}"
end end
end end
......
...@@ -13,7 +13,7 @@ class GitlabShellWorker # rubocop:disable Scalability/IdempotentWorker ...@@ -13,7 +13,7 @@ class GitlabShellWorker # rubocop:disable Scalability/IdempotentWorker
# enqueued in the previous release, so handle them here. # enqueued in the previous release, so handle them here.
# #
# See https://gitlab.com/gitlab-org/gitlab/-/issues/25095 for more details # See https://gitlab.com/gitlab-org/gitlab/-/issues/25095 for more details
if AuthorizedKeysWorker::PERMITTED_ACTIONS.include?(action) if AuthorizedKeysWorker::PERMITTED_ACTIONS.include?(action.to_s)
AuthorizedKeysWorker.new.perform(action, *arg) AuthorizedKeysWorker.new.perform(action, *arg)
return return
......
---
title: Optimize template_repositories query by using batch counting
merge_request: 27352
author:
type: performance
---
title: Fix updating the authorized_keys file
merge_request: 27798
author:
type: fixed
---
title: Highlight currently focused/viewed file in file tree
merge_request: 27703
author:
type: changed
---
title: Set commit status to failed if the TeamCity connection is refused
merge_request: 27395
author:
type: fixed
# frozen_string_literal: true
class AddIndexOnNamespaceIdAndIdToProjects < ActiveRecord::Migration[6.0]
include Gitlab::Database::MigrationHelpers
DOWNTIME = false
disable_ddl_transaction!
def up
add_concurrent_index :projects, [:namespace_id, :id]
remove_concurrent_index :projects, :namespace_id
end
def down
add_concurrent_index :projects, :namespace_id
remove_concurrent_index :projects, [:namespace_id, :id]
end
end
# frozen_string_literal: true
class AddMaxPersonalAccessTokenLifetimeToNamespaces < ActiveRecord::Migration[6.0]
include Gitlab::Database::MigrationHelpers
DOWNTIME = false
def up
with_lock_retries do
add_column :namespaces, :max_personal_access_token_lifetime, :integer
end
end
def down
with_lock_retries do
remove_column :namespaces, :max_personal_access_token_lifetime
end
end
end
...@@ -3944,7 +3944,8 @@ CREATE TABLE public.namespaces ( ...@@ -3944,7 +3944,8 @@ CREATE TABLE public.namespaces (
max_artifacts_size integer, max_artifacts_size integer,
mentions_disabled boolean, mentions_disabled boolean,
default_branch_protection smallint, default_branch_protection smallint,
unlock_membership_to_ldap boolean unlock_membership_to_ldap boolean,
max_personal_access_token_lifetime integer
); );
CREATE SEQUENCE public.namespaces_id_seq CREATE SEQUENCE public.namespaces_id_seq
...@@ -9656,7 +9657,7 @@ CREATE INDEX index_projects_on_name_and_id ON public.projects USING btree (name, ...@@ -9656,7 +9657,7 @@ CREATE INDEX index_projects_on_name_and_id ON public.projects USING btree (name,
CREATE INDEX index_projects_on_name_trigram ON public.projects USING gin (name public.gin_trgm_ops); CREATE INDEX index_projects_on_name_trigram ON public.projects USING gin (name public.gin_trgm_ops);
CREATE INDEX index_projects_on_namespace_id ON public.projects USING btree (namespace_id); CREATE INDEX index_projects_on_namespace_id_and_id ON public.projects USING btree (namespace_id, id);
CREATE INDEX index_projects_on_path_and_id ON public.projects USING btree (path, id); CREATE INDEX index_projects_on_path_and_id ON public.projects USING btree (path, id);
...@@ -12701,6 +12702,7 @@ INSERT INTO "schema_migrations" (version) VALUES ...@@ -12701,6 +12702,7 @@ INSERT INTO "schema_migrations" (version) VALUES
('20200313101649'), ('20200313101649'),
('20200313123934'), ('20200313123934'),
('20200316111759'), ('20200316111759'),
('20200316162648'),
('20200316173312'), ('20200316173312'),
('20200317142110'), ('20200317142110'),
('20200318152134'), ('20200318152134'),
...@@ -12708,5 +12710,6 @@ INSERT INTO "schema_migrations" (version) VALUES ...@@ -12708,5 +12710,6 @@ INSERT INTO "schema_migrations" (version) VALUES
('20200318163148'), ('20200318163148'),
('20200318164448'), ('20200318164448'),
('20200318165448'), ('20200318165448'),
('20200319203901'); ('20200319203901'),
('20200323075043');
...@@ -73,6 +73,9 @@ from teams other than your own. ...@@ -73,6 +73,9 @@ from teams other than your own.
**approved by a [UX lead](https://about.gitlab.com/company/team/)**. **approved by a [UX lead](https://about.gitlab.com/company/team/)**.
1. If your merge request includes a new dependency or a filesystem change, it must be 1. If your merge request includes a new dependency or a filesystem change, it must be
**approved by a [Distribution team member](https://about.gitlab.com/company/team/)**. See how to work with the [Distribution team](https://about.gitlab.com/handbook/engineering/development/enablement/distribution/#how-to-work-with-distribution) for more details. **approved by a [Distribution team member](https://about.gitlab.com/company/team/)**. See how to work with the [Distribution team](https://about.gitlab.com/handbook/engineering/development/enablement/distribution/#how-to-work-with-distribution) for more details.
1. If your merge request includes documentation changes, it must be **approved
by a [Technical writer](https://about.gitlab.com/handbook/engineering/ux/technical-writing/#designated-technical-writers)**, based on
the appropriate [product category](https://about.gitlab.com/handbook/product/categories/).
#### Security requirements #### Security requirements
...@@ -84,12 +87,17 @@ The responsibility to find the best solution and implement it lies with the ...@@ -84,12 +87,17 @@ The responsibility to find the best solution and implement it lies with the
merge request author. merge request author.
Before assigning a merge request to a maintainer for approval and merge, they Before assigning a merge request to a maintainer for approval and merge, they
should be confident that it actually solves the problem it was meant to solve, should be confident that:
that it does so in the most appropriate way, that it satisfies all requirements,
and that there are no remaining bugs, logical problems, uncovered edge cases, - It actually solves the problem it was meant to solve.
or known vulnerabilities. The best way to do this, and to avoid unnecessary - It does so in the most appropriate way.
back-and-forth with reviewers, is to perform a self-review of your own merge - It satisfies all requirements.
request, following the [Code Review](#reviewing-a-merge-request) guidelines. - There are no remaining bugs, logical problems, uncovered edge cases,
or known vulnerabilities.
The best way to do this, and to avoid unnecessary back-and-forth with reviewers,
is to perform a self-review of your own merge request, following the
[Code Review](#reviewing-a-merge-request) guidelines.
To reach the required level of confidence in their solution, an author is expected To reach the required level of confidence in their solution, an author is expected
to involve other people in the investigation and implementation processes as to involve other people in the investigation and implementation processes as
...@@ -110,11 +118,11 @@ request diff alerting the reviewer to anything important as well as for anything ...@@ -110,11 +118,11 @@ request diff alerting the reviewer to anything important as well as for anything
that demands further explanation or attention. Examples of content that may that demands further explanation or attention. Examples of content that may
warrant a comment could be: warrant a comment could be:
- The addition of a linting rule (Rubocop, JS etc) - The addition of a linting rule (Rubocop, JS etc).
- The addition of a library (Ruby gem, JS lib etc) - The addition of a library (Ruby gem, JS lib etc).
- Where not obvious, a link to the parent class or method - Where not obvious, a link to the parent class or method.
- Any benchmarking performed to complement the change - Any benchmarking performed to complement the change.
- Potentially insecure code - Potentially insecure code.
Avoid: Avoid:
...@@ -233,6 +241,11 @@ first time. ...@@ -233,6 +241,11 @@ first time.
addressed. If there's an open reply, an open thread, a suggestion, addressed. If there's an open reply, an open thread, a suggestion,
a question, or anything else, the thread should be left to be resolved a question, or anything else, the thread should be left to be resolved
by the reviewer. by the reviewer.
- It should not be assumed that all feedback requires their recommended changes
to be incorporated into the MR before it is merged. It is a judgment call by
the MR author and the reviewer as to if this is required, or if a follow-up
issue should be created to address the feedback in the future after the MR in
question is merged.
- Push commits based on earlier rounds of feedback as isolated commits to the - Push commits based on earlier rounds of feedback as isolated commits to the
branch. Do not squash until the branch is ready to merge. Reviewers should be branch. Do not squash until the branch is ready to merge. Reviewers should be
able to read individual updates based on their earlier feedback. able to read individual updates based on their earlier feedback.
......
...@@ -48,13 +48,8 @@ request is as follows: ...@@ -48,13 +48,8 @@ request is as follows:
but do not change the commit history if you're working on shared branches though. but do not change the commit history if you're working on shared branches though.
1. Push the commit(s) to your working branch in your fork. 1. Push the commit(s) to your working branch in your fork.
1. Submit a merge request (MR) to the `master` branch in the main GitLab project. 1. Submit a merge request (MR) to the `master` branch in the main GitLab project.
1. Your merge request needs at least 1 approval, but feel free to require more. 1. Your merge request needs at least 1 approval, but depending on your changes
For instance if you're touching both backend and frontend code, it's a good idea you might need additional approvals. Refer to the [Approval guidelines](../code_review.md#approval-guidelines).
to require 2 approvals: 1 from a backend maintainer and 1 from a frontend
maintainer.
1. If you're submitting changes to documentation, you'll need approval from a technical
writer, based on the appropriate [product category](https://about.gitlab.com/handbook/product/categories/).
Only assign the MR to them when it's ready for docs review.
1. You don't have to select any specific approvers, but you can if you really want 1. You don't have to select any specific approvers, but you can if you really want
specific people to approve your merge request. specific people to approve your merge request.
1. The MR title should describe the change you want to make. 1. The MR title should describe the change you want to make.
...@@ -66,18 +61,12 @@ request is as follows: ...@@ -66,18 +61,12 @@ request is as follows:
1. Mention the issue(s) your merge request solves, using the `Solves #XXX` or 1. Mention the issue(s) your merge request solves, using the `Solves #XXX` or
`Closes #XXX` syntax to [auto-close](../../user/project/issues/managing_issues.md#closing-issues-automatically) `Closes #XXX` syntax to [auto-close](../../user/project/issues/managing_issues.md#closing-issues-automatically)
the issue(s) once the merge request is merged. the issue(s) once the merge request is merged.
1. If you're allowed to (Core team members, for example), set a relevant milestone 1. If you're allowed to, set a relevant milestone and [labels](issue_workflow.md).
and [labels](issue_workflow.md). 1. UI changes should use available components from the GitLab Design System,
1. If the MR changes the UI, you'll need approval from a Product Designer (UX), based on the appropriate [product category](https://about.gitlab.com/handbook/product/categories/). UI changes should use available components from the GitLab Design System, [Pajamas](https://design.gitlab.com/). The MR must include *Before* and *After* screenshots. [Pajamas](https://design.gitlab.com/). The MR must include *Before* and
*After* screenshots.
1. If the MR changes CSS classes, please include the list of affected pages, which 1. If the MR changes CSS classes, please include the list of affected pages, which
can be found by running `grep css-class ./app -R`. can be found by running `grep css-class ./app -R`.
1. Be prepared to answer questions and incorporate feedback into your MR with new
commits. Once you have fully addressed a suggestion from a reviewer, click the
"Resolve thread" button beneath it to mark it resolved.
1. The merge request author resolves only the threads they have fully addressed.
If there's an open reply or thread, a suggestion, a question, or anything else,
the thread should be left to be resolved by the reviewer.
1. It should not be assumed that all feedback requires their recommended changes to be incorporated into the MR before it is merged. It is a judgment call by the MR author and the reviewer as to if this is required, or if a follow-up issue should be created to address the feedback in the future after the MR in question is merged.
1. If your MR touches code that executes shell commands, reads or opens files, or 1. If your MR touches code that executes shell commands, reads or opens files, or
handles paths to files on disk, make sure it adheres to the handles paths to files on disk, make sure it adheres to the
[shell command guidelines](../shell_commands.md) [shell command guidelines](../shell_commands.md)
...@@ -98,6 +87,10 @@ request is as follows: ...@@ -98,6 +87,10 @@ request is as follows:
`doc/update/upgrading_from_source.md` in the same merge request. If these `doc/update/upgrading_from_source.md` in the same merge request. If these
instructions are specific to a version, add them to the "Version specific instructions are specific to a version, add them to the "Version specific
upgrading instructions" section. upgrading instructions" section.
1. Read and adhere to
[The responsibility of the merge request author](../code_review.md#the-responsibility-of-the-merge-request-author).
1. Read and follow
[Having your merge request reviewed](../code_review.md#having-your-merge-request-reviewed).
If you would like quick feedback on your merge request feel free to mention someone If you would like quick feedback on your merge request feel free to mention someone
from the [core team](https://about.gitlab.com/community/core-team/) or one of the from the [core team](https://about.gitlab.com/community/core-team/) or one of the
......
...@@ -589,7 +589,7 @@ When viewing a custom dashboard of a project, you can view the original ...@@ -589,7 +589,7 @@ When viewing a custom dashboard of a project, you can view the original
From each of the panels in the dashboard, you can access the context menu by clicking the **{ellipsis_v}** **More actions** dropdown box above the upper right corner of the panel to take actions related to the chart's data. From each of the panels in the dashboard, you can access the context menu by clicking the **{ellipsis_v}** **More actions** dropdown box above the upper right corner of the panel to take actions related to the chart's data.
![Context Menu](img/panel_context_menu_v12_8.png) ![Context Menu](img/panel_context_menu_v12_10.png)
The options are: The options are:
......
...@@ -3,7 +3,7 @@ ...@@ -3,7 +3,7 @@
module Gitlab module Gitlab
module Git module Git
class LfsChanges class LfsChanges
def initialize(repository, newrev) def initialize(repository, newrev = nil)
@repository = repository @repository = repository
@newrev = newrev @newrev = newrev
end end
......
...@@ -25,5 +25,17 @@ module Gitlab ...@@ -25,5 +25,17 @@ module Gitlab
rescue HTTParty::RedirectionTooDeep rescue HTTParty::RedirectionTooDeep
raise RedirectionTooDeep raise RedirectionTooDeep
end end
def self.try_get(path, options = {}, &block)
log_info = options.delete(:extra_log_info)
self.get(path, options, &block)
rescue *HTTP_ERRORS => e
extra_info = log_info || {}
extra_info = log_info.call(e, path, options) if log_info.respond_to?(:call)
Gitlab::ErrorTracking.log_exception(e, extra_info)
nil
end
end end
end end
import Vue from 'vue'; import Vue from 'vue';
import mountComponent from 'spec/helpers/vue_mount_component_helper'; import mountComponent from 'helpers/vue_mount_component_helper';
import banner from '~/cycle_analytics/components/banner.vue'; import banner from '~/cycle_analytics/components/banner.vue';
describe('Cycle analytics banner', () => { describe('Cycle analytics banner', () => {
...@@ -36,7 +36,7 @@ describe('Cycle analytics banner', () => { ...@@ -36,7 +36,7 @@ describe('Cycle analytics banner', () => {
}); });
it('should emit an event when close button is clicked', () => { it('should emit an event when close button is clicked', () => {
spyOn(vm, '$emit'); jest.spyOn(vm, '$emit').mockImplementation(() => {});
vm.$el.querySelector('.js-ca-dismiss-button').click(); vm.$el.querySelector('.js-ca-dismiss-button').click();
......
import Vue from 'vue'; import Vue from 'vue';
import mountComponent from 'spec/helpers/vue_mount_component_helper'; import mountComponent from 'helpers/vue_mount_component_helper';
import component from '~/cycle_analytics/components/total_time_component.vue'; import component from '~/cycle_analytics/components/total_time_component.vue';
describe('Total time component', () => { describe('Total time component', () => {
......
...@@ -61,6 +61,7 @@ describe('DiffFileHeader component', () => { ...@@ -61,6 +61,7 @@ describe('DiffFileHeader component', () => {
const findTitleLink = () => wrapper.find({ ref: 'titleWrapper' }); const findTitleLink = () => wrapper.find({ ref: 'titleWrapper' });
const findExpandButton = () => wrapper.find({ ref: 'expandDiffToFullFileButton' }); const findExpandButton = () => wrapper.find({ ref: 'expandDiffToFullFileButton' });
const findFileActions = () => wrapper.find('.file-actions'); const findFileActions = () => wrapper.find('.file-actions');
const findActiveHeader = () => wrapper.find('.is-active');
const findModeChangedLine = () => wrapper.find({ ref: 'fileMode' }); const findModeChangedLine = () => wrapper.find({ ref: 'fileMode' });
const findLfsLabel = () => wrapper.find('.label-lfs'); const findLfsLabel = () => wrapper.find('.label-lfs');
const findToggleDiscussionsButton = () => wrapper.find({ ref: 'toggleDiscussionsButton' }); const findToggleDiscussionsButton = () => wrapper.find({ ref: 'toggleDiscussionsButton' });
...@@ -143,6 +144,11 @@ describe('DiffFileHeader component', () => { ...@@ -143,6 +144,11 @@ describe('DiffFileHeader component', () => {
expect(wrapper.find(ClipboardButton).exists()).toBe(true); expect(wrapper.find(ClipboardButton).exists()).toBe(true);
}); });
it('contains a active header class if this is the active file header', () => {
createComponent({ isActive: true });
expect(findActiveHeader().exists()).toBe(true);
});
describe('for submodule', () => { describe('for submodule', () => {
const submoduleDiffFile = { const submoduleDiffFile = {
...diffFile, ...diffFile,
......
...@@ -72,6 +72,19 @@ describe('File row component', () => { ...@@ -72,6 +72,19 @@ describe('File row component', () => {
}); });
}); });
it('is marked as viewed if clicked', () => {
createComponent({
file: {
...file(),
type: 'blob',
fileHash: '#123456789',
},
level: 0,
viewedFiles: ['#123456789'],
});
expect(wrapper.classes()).toContain('is-viewed');
});
it('indents row based on level', () => { it('indents row based on level', () => {
createComponent({ createComponent({
file: file('t4'), file: file('t4'),
......
...@@ -100,4 +100,127 @@ describe Gitlab::HTTP do ...@@ -100,4 +100,127 @@ describe Gitlab::HTTP do
expect { described_class.head('http://example.org') }.to raise_error(Gitlab::HTTP::RedirectionTooDeep) expect { described_class.head('http://example.org') }.to raise_error(Gitlab::HTTP::RedirectionTooDeep)
end end
end end
describe '.try_get' do
let(:path) { 'http://example.org' }
let(:extra_log_info_proc) do
proc do |error, url, options|
{ klass: error.class, url: url, options: options }
end
end
let(:request_options) do
{
verify: false,
basic_auth: { username: 'user', password: 'pass' }
}
end
described_class::HTTP_ERRORS.each do |exception_class|
context "with #{exception_class}" do
let(:klass) { exception_class }
context 'with path' do
before do
expect(described_class).to receive(:get)
.with(path, {})
.and_raise(klass)
end
it 'handles requests without extra_log_info' do
expect(Gitlab::ErrorTracking)
.to receive(:log_exception)
.with(instance_of(klass), {})
expect(described_class.try_get(path)).to be_nil
end
it 'handles requests with extra_log_info as hash' do
expect(Gitlab::ErrorTracking)
.to receive(:log_exception)
.with(instance_of(klass), { a: :b })
expect(described_class.try_get(path, extra_log_info: { a: :b })).to be_nil
end
it 'handles requests with extra_log_info as proc' do
expect(Gitlab::ErrorTracking)
.to receive(:log_exception)
.with(instance_of(klass), { url: path, klass: klass, options: {} })
expect(described_class.try_get(path, extra_log_info: extra_log_info_proc)).to be_nil
end
end
context 'with path and options' do
before do
expect(described_class).to receive(:get)
.with(path, request_options)
.and_raise(klass)
end
it 'handles requests without extra_log_info' do
expect(Gitlab::ErrorTracking)
.to receive(:log_exception)
.with(instance_of(klass), {})
expect(described_class.try_get(path, request_options)).to be_nil
end
it 'handles requests with extra_log_info as hash' do
expect(Gitlab::ErrorTracking)
.to receive(:log_exception)
.with(instance_of(klass), { a: :b })
expect(described_class.try_get(path, **request_options, extra_log_info: { a: :b })).to be_nil
end
it 'handles requests with extra_log_info as proc' do
expect(Gitlab::ErrorTracking)
.to receive(:log_exception)
.with(instance_of(klass), { klass: klass, url: path, options: request_options })
expect(described_class.try_get(path, **request_options, extra_log_info: extra_log_info_proc)).to be_nil
end
end
context 'with path, options, and block' do
let(:block) do
proc {}
end
before do
expect(described_class).to receive(:get)
.with(path, request_options, &block)
.and_raise(klass)
end
it 'handles requests without extra_log_info' do
expect(Gitlab::ErrorTracking)
.to receive(:log_exception)
.with(instance_of(klass), {})
expect(described_class.try_get(path, request_options, &block)).to be_nil
end
it 'handles requests with extra_log_info as hash' do
expect(Gitlab::ErrorTracking)
.to receive(:log_exception)
.with(instance_of(klass), { a: :b })
expect(described_class.try_get(path, **request_options, extra_log_info: { a: :b }, &block)).to be_nil
end
it 'handles requests with extra_log_info as proc' do
expect(Gitlab::ErrorTracking)
.to receive(:log_exception)
.with(instance_of(klass), { klass: klass, url: path, options: request_options })
expect(described_class.try_get(path, **request_options, extra_log_info: extra_log_info_proc, &block)).to be_nil
end
end
end
end
end
end end
...@@ -7,6 +7,7 @@ describe TeamcityService, :use_clean_rails_memory_store_caching do ...@@ -7,6 +7,7 @@ describe TeamcityService, :use_clean_rails_memory_store_caching do
include StubRequests include StubRequests
let(:teamcity_url) { 'http://gitlab.com/teamcity' } let(:teamcity_url) { 'http://gitlab.com/teamcity' }
let(:teamcity_full_url) { 'http://gitlab.com/teamcity/httpAuth/app/rest/builds/branch:unspecified:any,revision:123' }
let(:project) { create(:project) } let(:project) { create(:project) }
subject(:service) do subject(:service) do
...@@ -165,6 +166,16 @@ describe TeamcityService, :use_clean_rails_memory_store_caching do ...@@ -165,6 +166,16 @@ describe TeamcityService, :use_clean_rails_memory_store_caching do
is_expected.to eq('http://gitlab.com/teamcity/viewLog.html?buildId=666&buildTypeId=foo') is_expected.to eq('http://gitlab.com/teamcity/viewLog.html?buildId=666&buildTypeId=foo')
end end
end end
it 'returns the teamcity_url when teamcity is unreachable' do
stub_full_request(teamcity_full_url).to_raise(Errno::ECONNREFUSED)
expect(Gitlab::ErrorTracking)
.to receive(:log_exception)
.with(instance_of(Errno::ECONNREFUSED), project_id: project.id)
is_expected.to eq(teamcity_url)
end
end end
context 'commit_status' do context 'commit_status' do
...@@ -205,6 +216,16 @@ describe TeamcityService, :use_clean_rails_memory_store_caching do ...@@ -205,6 +216,16 @@ describe TeamcityService, :use_clean_rails_memory_store_caching do
is_expected.to eq(:error) is_expected.to eq(:error)
end end
it 'sets commit status to :error when teamcity is unreachable' do
stub_full_request(teamcity_full_url).to_raise(Errno::ECONNREFUSED)
expect(Gitlab::ErrorTracking)
.to receive(:log_exception)
.with(instance_of(Errno::ECONNREFUSED), project_id: project.id)
is_expected.to eq(:error)
end
end end
end end
...@@ -300,7 +321,6 @@ describe TeamcityService, :use_clean_rails_memory_store_caching do ...@@ -300,7 +321,6 @@ describe TeamcityService, :use_clean_rails_memory_store_caching do
end end
def stub_request(status: 200, body: nil, build_status: 'success') def stub_request(status: 200, body: nil, build_status: 'success')
teamcity_full_url = 'http://gitlab.com/teamcity/httpAuth/app/rest/builds/branch:unspecified:any,revision:123'
auth = %w(mic password) auth = %w(mic password)
body ||= %Q({"build":{"status":"#{build_status}","id":"666"}}) body ||= %Q({"build":{"status":"#{build_status}","id":"666"}})
......
...@@ -215,7 +215,7 @@ describe Ci::CreateCrossProjectPipelineService, '#execute' do ...@@ -215,7 +215,7 @@ describe Ci::CreateCrossProjectPipelineService, '#execute' do
pipeline = service.execute(bridge) pipeline = service.execute(bridge)
pipeline.reload pipeline.reload
expect(pipeline.builds.map(&:name)).to eq %w[rspec echo] expect(pipeline.builds.map(&:name)).to match_array(%w[rspec echo])
expect(pipeline.user).to eq bridge.user expect(pipeline.user).to eq bridge.user
expect(pipeline.project).to eq bridge.project expect(pipeline.project).to eq bridge.project
expect(bridge.sourced_pipelines.first.pipeline).to eq pipeline expect(bridge.sourced_pipelines.first.pipeline).to eq pipeline
......
...@@ -17,7 +17,7 @@ describe AuthorizedKeysWorker do ...@@ -17,7 +17,7 @@ describe AuthorizedKeysWorker do
expect(instance).to receive(:add_key).with('foo', 'bar') expect(instance).to receive(:add_key).with('foo', 'bar')
end end
worker.perform(:add_key, 'foo', 'bar') worker.perform('add_key', 'foo', 'bar')
end end
end end
...@@ -27,15 +27,17 @@ describe AuthorizedKeysWorker do ...@@ -27,15 +27,17 @@ describe AuthorizedKeysWorker do
expect(instance).to receive(:remove_key).with('foo', 'bar') expect(instance).to receive(:remove_key).with('foo', 'bar')
end end
worker.perform(:remove_key, 'foo', 'bar') worker.perform('remove_key', 'foo', 'bar')
end end
end end
describe 'all other commands' do describe 'all other commands' do
it 'does nothing' do it 'raises an error' do
expect(Gitlab::AuthorizedKeys).not_to receive(:new) expect(Gitlab::AuthorizedKeys).not_to receive(:new)
worker.perform(:foo, 'bar', 'baz') expect do
worker.perform('foo', 'bar', 'baz')
end.to raise_error('Unknown action: "foo"')
end end
end end
end end
...@@ -48,7 +50,7 @@ describe AuthorizedKeysWorker do ...@@ -48,7 +50,7 @@ describe AuthorizedKeysWorker do
it 'does nothing' do it 'does nothing' do
expect(Gitlab::AuthorizedKeys).not_to receive(:new) expect(Gitlab::AuthorizedKeys).not_to receive(:new)
worker.perform(:add_key, 'foo', 'bar') worker.perform('add_key', 'foo', 'bar')
end end
end end
end end
......
...@@ -12,7 +12,7 @@ describe GitlabShellWorker do ...@@ -12,7 +12,7 @@ describe GitlabShellWorker do
expect(instance).to receive(:add_key).with('foo', 'bar') expect(instance).to receive(:add_key).with('foo', 'bar')
end end
worker.perform(:add_key, 'foo', 'bar') worker.perform('add_key', 'foo', 'bar')
end end
end end
...@@ -22,7 +22,7 @@ describe GitlabShellWorker do ...@@ -22,7 +22,7 @@ describe GitlabShellWorker do
expect(instance).to receive(:remove_key).with('foo', 'bar') expect(instance).to receive(:remove_key).with('foo', 'bar')
end end
worker.perform(:remove_key, 'foo', 'bar') worker.perform('remove_key', 'foo', 'bar')
end end
end end
...@@ -32,7 +32,7 @@ describe GitlabShellWorker do ...@@ -32,7 +32,7 @@ describe GitlabShellWorker do
expect(instance).to receive(:foo).with('bar', 'baz') expect(instance).to receive(:foo).with('bar', 'baz')
end end
worker.perform(:foo, 'bar', 'baz') worker.perform('foo', 'bar', 'baz')
end end
end end
end end
......
...@@ -1036,10 +1036,10 @@ ...@@ -1036,10 +1036,10 @@
"@sentry/types" "5.10.0" "@sentry/types" "5.10.0"
tslib "^1.9.3" tslib "^1.9.3"
"@sourcegraph/code-host-integration@0.0.31": "@sourcegraph/code-host-integration@0.0.33":
version "0.0.31" version "0.0.33"
resolved "https://registry.yarnpkg.com/@sourcegraph/code-host-integration/-/code-host-integration-0.0.31.tgz#c4d6c7adaaf937e4b8a143c206020e110ba73e25" resolved "https://registry.yarnpkg.com/@sourcegraph/code-host-integration/-/code-host-integration-0.0.33.tgz#133f11535be0cc937fbadc6a6951ee9fd21fbe1d"
integrity sha512-b0WQ1CKlEx9S+IHRs1YNRO7CcwW06ulQU6D+W9cQlfjJu+qQVTAvkyv1xjySkfrCNK8IcfVd8WZzWIhP16VVfw== integrity sha512-J49ljHsSIe8KD5+ke9C3ugGO9T6R2M96miiGEZFRHJQ7FXyKi/zP5N4BFVweHjE+b15BLSicoaAnnyg4nhIBIw==
"@types/anymatch@*": "@types/anymatch@*":
version "1.3.0" version "1.3.0"
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment