Commit 45a4bc30 authored by GitLab Release Tools Bot's avatar GitLab Release Tools Bot

Merge branch 'master' of gitlab.com:gitlab-org/gitlab-ce

parents c7e6c8ef 4891e8a5
...@@ -8,6 +8,7 @@ require: ...@@ -8,6 +8,7 @@ require:
- rubocop-rspec - rubocop-rspec
AllCops: AllCops:
TargetRubyVersion: 2.5
TargetRailsVersion: 5.0 TargetRailsVersion: 5.0
Exclude: Exclude:
- 'vendor/**/*' - 'vendor/**/*'
...@@ -184,3 +185,8 @@ Cop/InjectEnterpriseEditionModule: ...@@ -184,3 +185,8 @@ Cop/InjectEnterpriseEditionModule:
Style/ReturnNil: Style/ReturnNil:
Enabled: true Enabled: true
# It isn't always safe to replace `=~` with `.match?`, especially when there are
# nil values on the left hand side
Performance/RegexpMatch:
Enabled: false
<script> <script>
import folderMixin from 'ee_else_ce/environments/mixins/environments_folder_view_mixin';
import environmentsMixin from '../mixins/environments_mixin'; import environmentsMixin from '../mixins/environments_mixin';
import CIPaginationMixin from '../../vue_shared/mixins/ci_pagination_api_mixin'; import CIPaginationMixin from '../../vue_shared/mixins/ci_pagination_api_mixin';
import StopEnvironmentModal from '../components/stop_environment_modal.vue'; import StopEnvironmentModal from '../components/stop_environment_modal.vue';
...@@ -8,7 +9,7 @@ export default { ...@@ -8,7 +9,7 @@ export default {
StopEnvironmentModal, StopEnvironmentModal,
}, },
mixins: [environmentsMixin, CIPaginationMixin], mixins: [environmentsMixin, CIPaginationMixin, folderMixin],
props: { props: {
endpoint: { endpoint: {
...@@ -41,7 +42,8 @@ export default { ...@@ -41,7 +42,8 @@ export default {
<div v-if="!isLoading" class="top-area"> <div v-if="!isLoading" class="top-area">
<h4 class="js-folder-name environments-folder-name"> <h4 class="js-folder-name environments-folder-name">
{{ s__('Environments|Environments') }} / <b>{{ folderName }}</b> {{ s__('Environments|Environments') }} /
<b>{{ folderName }}</b>
</h4> </h4>
<tabs :tabs="tabs" scope="environments" @onChangeTab="onChangeTab" /> <tabs :tabs="tabs" scope="environments" @onChangeTab="onChangeTab" />
...@@ -52,6 +54,11 @@ export default { ...@@ -52,6 +54,11 @@ export default {
:environments="state.environments" :environments="state.environments"
:pagination="state.paginationInformation" :pagination="state.paginationInformation"
:can-read-environment="canReadEnvironment" :can-read-environment="canReadEnvironment"
:canary-deployment-feature-id="canaryDeploymentFeatureId"
:show-canary-deployment-callout="showCanaryDeploymentCallout"
:user-callouts-path="userCalloutsPath"
:lock-promotion-svg-path="lockPromotionSvgPath"
:help-canary-deployments-path="helpCanaryDeploymentsPath"
@onChangePage="onChangePage" @onChangePage="onChangePage"
/> />
</div> </div>
......
import Vue from 'vue'; import Vue from 'vue';
import canaryCalloutMixin from 'ee_else_ce/environments/mixins/canary_callout_mixin';
import environmentsComponent from './components/environments_app.vue'; import environmentsComponent from './components/environments_app.vue';
import { parseBoolean } from '../lib/utils/common_utils'; import { parseBoolean } from '../lib/utils/common_utils';
import Translate from '../vue_shared/translate'; import Translate from '../vue_shared/translate';
...@@ -11,6 +12,7 @@ export default () => ...@@ -11,6 +12,7 @@ export default () =>
components: { components: {
environmentsComponent, environmentsComponent,
}, },
mixins: [canaryCalloutMixin],
data() { data() {
const environmentsData = document.querySelector(this.$options.el).dataset; const environmentsData = document.querySelector(this.$options.el).dataset;
...@@ -32,6 +34,7 @@ export default () => ...@@ -32,6 +34,7 @@ export default () =>
cssContainerClass: this.cssContainerClass, cssContainerClass: this.cssContainerClass,
canCreateEnvironment: this.canCreateEnvironment, canCreateEnvironment: this.canCreateEnvironment,
canReadEnvironment: this.canReadEnvironment, canReadEnvironment: this.canReadEnvironment,
...this.canaryCalloutProps,
}, },
}); });
}, },
......
export default {
computed: {
canaryCalloutProps() {},
},
};
export default {
props: {
canaryDeploymentFeatureId: {
type: String,
required: false,
default: '',
},
showCanaryDeploymentCallout: {
type: Boolean,
required: false,
default: false,
},
userCalloutsPath: {
type: String,
required: false,
default: '',
},
lockPromotionSvgPath: {
type: String,
required: false,
default: '',
},
helpCanaryDeploymentsPath: {
type: String,
required: false,
default: '',
},
},
};
...@@ -3,13 +3,13 @@ ...@@ -3,13 +3,13 @@
*/ */
import _ from 'underscore'; import _ from 'underscore';
import Visibility from 'visibilityjs'; import Visibility from 'visibilityjs';
import EnvironmentsStore from 'ee_else_ce/environments/stores/environments_store';
import Poll from '../../lib/utils/poll'; import Poll from '../../lib/utils/poll';
import { getParameterByName } from '../../lib/utils/common_utils'; import { getParameterByName } from '../../lib/utils/common_utils';
import { s__ } from '../../locale'; import { s__ } from '../../locale';
import Flash from '../../flash'; import Flash from '../../flash';
import eventHub from '../event_hub'; import eventHub from '../event_hub';
import EnvironmentsStore from '../stores/environments_store';
import EnvironmentsService from '../services/environments_service'; import EnvironmentsService from '../services/environments_service';
import tablePagination from '../../vue_shared/components/table_pagination.vue'; import tablePagination from '../../vue_shared/components/table_pagination.vue';
import environmentTable from '../components/environments_table.vue'; import environmentTable from '../components/environments_table.vue';
......
import { parseIntPagination, normalizeHeaders } from '~/lib/utils/common_utils'; import { parseIntPagination, normalizeHeaders } from '~/lib/utils/common_utils';
import { setDeployBoard } from 'ee_else_ce/environments/stores/helpers';
/** /**
* Environments Store. * Environments Store.
* *
...@@ -31,6 +33,14 @@ export default class EnvironmentsStore { ...@@ -31,6 +33,14 @@ export default class EnvironmentsStore {
* If the `size` is bigger than 1, it means it should be rendered as a folder. * If the `size` is bigger than 1, it means it should be rendered as a folder.
* In those cases we add `isFolder` key in order to render it properly. * In those cases we add `isFolder` key in order to render it properly.
* *
* Top level environments - when the size is 1 - with `rollout_status`
* can render a deploy board. We add `isDeployBoardVisible` and `deployBoardData`
* keys to those environments.
* The first key will let's us know if we should or not render the deploy board.
* It will be toggled when the user clicks to seee the deploy board.
*
* The second key will allow us to update the environment with the received deploy board data.
*
* @param {Array} environments * @param {Array} environments
* @returns {Array} * @returns {Array}
*/ */
...@@ -63,6 +73,7 @@ export default class EnvironmentsStore { ...@@ -63,6 +73,7 @@ export default class EnvironmentsStore {
filtered = Object.assign(filtered, env); filtered = Object.assign(filtered, env);
} }
filtered = setDeployBoard(oldEnvironmentState, filtered);
return filtered; return filtered;
}); });
...@@ -71,6 +82,20 @@ export default class EnvironmentsStore { ...@@ -71,6 +82,20 @@ export default class EnvironmentsStore {
return filteredEnvironments; return filteredEnvironments;
} }
/**
* Stores the pagination information needed to render the pagination for the
* table.
*
* Normalizes the headers to uppercase since they can be provided either
* in uppercase or lowercase.
*
* Parses to an integer the normalized ones needed for the pagination component.
*
* Stores the normalized and parsed information.
*
* @param {Object} pagination = {}
* @return {Object}
*/
setPagination(pagination = {}) { setPagination(pagination = {}) {
const normalizedHeaders = normalizeHeaders(pagination); const normalizedHeaders = normalizeHeaders(pagination);
const paginationInformation = parseIntPagination(normalizedHeaders); const paginationInformation = parseIntPagination(normalizedHeaders);
......
/**
* Deploy boards are EE only.
*
* @param {Object} environment
* @returns {Object}
*/
// eslint-disable-next-line import/prefer-default-export
export const setDeployBoard = (oldEnvironmentState, environment) => environment;
import initGroupDetails from '../shared/group_details';
document.addEventListener('DOMContentLoaded', () => {
initGroupDetails('details');
});
/* eslint-disable no-new */
import { getPagePath } from '~/lib/utils/common_utils';
import { ACTIVE_TAB_SHARED, ACTIVE_TAB_ARCHIVED } from '~/groups/constants';
import NewGroupChild from '~/groups/new_group_child';
import notificationsDropdown from '~/notifications_dropdown';
import NotificationsForm from '~/notifications_form';
import ProjectsList from '~/projects_list';
import ShortcutsNavigation from '~/behaviors/shortcuts/shortcuts_navigation';
import GroupTabs from './group_tabs';
export default function initGroupDetails(actionName = 'show') {
const newGroupChildWrapper = document.querySelector('.js-new-project-subgroup');
const loadableActions = [ACTIVE_TAB_SHARED, ACTIVE_TAB_ARCHIVED];
const paths = window.location.pathname.split('/');
const subpath = paths[paths.length - 1];
let action = loadableActions.includes(subpath) ? subpath : getPagePath(1);
if (actionName && action === actionName) {
action = 'show'; // 'show' resets GroupTabs to default action through base class
}
new GroupTabs({ parentEl: '.groups-listing', action });
new ShortcutsNavigation();
new NotificationsForm();
notificationsDropdown();
new ProjectsList();
if (newGroupChildWrapper) {
new NewGroupChild(newGroupChildWrapper);
}
}
/* eslint-disable no-new */ import initGroupDetails from '../shared/group_details';
import { getPagePath } from '~/lib/utils/common_utils';
import { ACTIVE_TAB_SHARED, ACTIVE_TAB_ARCHIVED } from '~/groups/constants';
import NewGroupChild from '~/groups/new_group_child';
import notificationsDropdown from '~/notifications_dropdown';
import NotificationsForm from '~/notifications_form';
import ProjectsList from '~/projects_list';
import ShortcutsNavigation from '~/behaviors/shortcuts/shortcuts_navigation';
import GroupTabs from './group_tabs';
document.addEventListener('DOMContentLoaded', () => { document.addEventListener('DOMContentLoaded', () => {
const newGroupChildWrapper = document.querySelector('.js-new-project-subgroup'); initGroupDetails();
const loadableActions = [ACTIVE_TAB_SHARED, ACTIVE_TAB_ARCHIVED];
const paths = window.location.pathname.split('/');
const subpath = paths[paths.length - 1];
const action = loadableActions.includes(subpath) ? subpath : getPagePath(1);
new GroupTabs({ parentEl: '.groups-listing', action });
new ShortcutsNavigation();
new NotificationsForm();
notificationsDropdown();
new ProjectsList();
if (newGroupChildWrapper) {
new NewGroupChild(newGroupChildWrapper);
}
}); });
...@@ -91,6 +91,7 @@ export default class UserTabs { ...@@ -91,6 +91,7 @@ export default class UserTabs {
this.actions = Object.keys(this.loaded); this.actions = Object.keys(this.loaded);
this.bindEvents(); this.bindEvents();
// TODO: refactor to make this configurable via constructor params with a default value of 'show'
if (this.action === 'show') { if (this.action === 'show') {
this.action = this.defaultAction; this.action = this.defaultAction;
} }
......
<script> <script>
import _ from 'underscore'; import _ from 'underscore';
import stageColumnMixin from 'ee_else_ce/pipelines/mixins/stage_column_mixin';
import JobItem from './job_item.vue'; import JobItem from './job_item.vue';
import JobGroupDropdown from './job_group_dropdown.vue'; import JobGroupDropdown from './job_group_dropdown.vue';
...@@ -8,6 +9,7 @@ export default { ...@@ -8,6 +9,7 @@ export default {
JobItem, JobItem,
JobGroupDropdown, JobGroupDropdown,
}, },
mixins: [stageColumnMixin],
props: { props: {
title: { title: {
type: String, type: String,
...@@ -32,9 +34,6 @@ export default { ...@@ -32,9 +34,6 @@ export default {
groupId(group) { groupId(group) {
return `ci-badge-${_.escape(group.name)}`; return `ci-badge-${_.escape(group.name)}`;
}, },
buildConnnectorClass(index) {
return index === 0 && !this.isFirstColumn ? 'left-connector' : '';
},
pipelineActionRequestComplete() { pipelineActionRequestComplete() {
this.$emit('refreshPipelineGraph'); this.$emit('refreshPipelineGraph');
}, },
......
export default {
methods: {
clickTriggeredByPipeline() {},
clickTriggeredPipeline() {},
},
};
export default {
methods: {
buildConnnectorClass(index) {
return index === 0 && !this.isFirstColumn ? 'left-connector' : '';
},
},
};
...@@ -2,8 +2,9 @@ import Vue from 'vue'; ...@@ -2,8 +2,9 @@ import Vue from 'vue';
import Flash from '~/flash'; import Flash from '~/flash';
import Translate from '~/vue_shared/translate'; import Translate from '~/vue_shared/translate';
import { __ } from '~/locale'; import { __ } from '~/locale';
import pipelineGraph from 'ee_else_ce/pipelines/components/graph/graph_component.vue';
import GraphEEMixin from 'ee_else_ce/pipelines/mixins/graph_pipeline_bundle_mixin';
import PipelinesMediator from './pipeline_details_mediator'; import PipelinesMediator from './pipeline_details_mediator';
import pipelineGraph from './components/graph/graph_component.vue';
import pipelineHeader from './components/header_component.vue'; import pipelineHeader from './components/header_component.vue';
import eventHub from './event_hub'; import eventHub from './event_hub';
...@@ -22,6 +23,7 @@ export default () => { ...@@ -22,6 +23,7 @@ export default () => {
components: { components: {
pipelineGraph, pipelineGraph,
}, },
mixins: [GraphEEMixin],
data() { data() {
return { return {
mediator, mediator,
...@@ -44,6 +46,10 @@ export default () => { ...@@ -44,6 +46,10 @@ export default () => {
}, },
on: { on: {
refreshPipelineGraph: this.requestRefreshPipelineGraph, refreshPipelineGraph: this.requestRefreshPipelineGraph,
onClickTriggeredBy: (parentPipeline, pipeline) =>
this.clickTriggeredByPipeline(parentPipeline, pipeline),
onClickTriggered: (parentPipeline, pipeline) =>
this.clickTriggeredPipeline(parentPipeline, pipeline),
}, },
}); });
}, },
......
...@@ -376,18 +376,21 @@ img.emoji { ...@@ -376,18 +376,21 @@ img.emoji {
.prepend-top-default { margin-top: $gl-padding !important; } .prepend-top-default { margin-top: $gl-padding !important; }
.prepend-top-16 { margin-top: 16px; } .prepend-top-16 { margin-top: 16px; }
.prepend-top-20 { margin-top: 20px; } .prepend-top-20 { margin-top: 20px; }
.prepend-top-32 { margin-top: 32px; }
.prepend-left-4 { margin-left: 4px; } .prepend-left-4 { margin-left: 4px; }
.prepend-left-5 { margin-left: 5px; } .prepend-left-5 { margin-left: 5px; }
.prepend-left-8 { margin-left: 8px; } .prepend-left-8 { margin-left: 8px; }
.prepend-left-10 { margin-left: 10px; } .prepend-left-10 { margin-left: 10px; }
.prepend-left-default { margin-left: $gl-padding; } .prepend-left-default { margin-left: $gl-padding; }
.prepend-left-20 { margin-left: 20px; } .prepend-left-20 { margin-left: 20px; }
.prepend-left-32 { margin-left: 32px; }
.append-right-4 { margin-right: 4px; } .append-right-4 { margin-right: 4px; }
.append-right-5 { margin-right: 5px; } .append-right-5 { margin-right: 5px; }
.append-right-8 { margin-right: 8px; } .append-right-8 { margin-right: 8px; }
.append-right-10 { margin-right: 10px; } .append-right-10 { margin-right: 10px; }
.append-right-default { margin-right: $gl-padding; } .append-right-default { margin-right: $gl-padding; }
.append-right-20 { margin-right: 20px; } .append-right-20 { margin-right: 20px; }
.prepend-right-32 { margin-right: 32px; }
.append-bottom-0 { margin-bottom: 0; } .append-bottom-0 { margin-bottom: 0; }
.append-bottom-4 { margin-bottom: $gl-padding-4; } .append-bottom-4 { margin-bottom: $gl-padding-4; }
.append-bottom-5 { margin-bottom: 5px; } .append-bottom-5 { margin-bottom: 5px; }
...@@ -396,6 +399,7 @@ img.emoji { ...@@ -396,6 +399,7 @@ img.emoji {
.append-bottom-15 { margin-bottom: 15px; } .append-bottom-15 { margin-bottom: 15px; }
.append-bottom-20 { margin-bottom: 20px; } .append-bottom-20 { margin-bottom: 20px; }
.append-bottom-default { margin-bottom: $gl-padding; } .append-bottom-default { margin-bottom: $gl-padding; }
.prepend-bottom-32 { margin-bottom: 32px; }
.inline { display: inline-block; } .inline { display: inline-block; }
.center { text-align: center; } .center { text-align: center; }
.vertical-align-middle { vertical-align: middle; } .vertical-align-middle { vertical-align: middle; }
......
...@@ -693,10 +693,6 @@ ...@@ -693,10 +693,6 @@
} }
} }
.project-empty-note-panel {
border-bottom: 1px solid $border-color;
}
.project-stats, .project-stats,
.project-buttons { .project-buttons {
.scrolling-tabs-container { .scrolling-tabs-container {
......
...@@ -58,11 +58,24 @@ class GroupsController < Groups::ApplicationController ...@@ -58,11 +58,24 @@ class GroupsController < Groups::ApplicationController
def show def show
respond_to do |format| respond_to do |format|
format.html format.html do
render_show_html
end
format.atom do format.atom do
load_events render_details_view_atom
render layout: 'xml.atom' end
end
end
def details
respond_to do |format|
format.html do
render_details_html
end
format.atom do
render_details_view_atom
end end
end end
end end
...@@ -119,6 +132,19 @@ class GroupsController < Groups::ApplicationController ...@@ -119,6 +132,19 @@ class GroupsController < Groups::ApplicationController
protected protected
def render_show_html
render 'groups/show'
end
def render_details_html
render 'groups/show'
end
def render_details_view_atom
load_events
render layout: 'xml.atom', template: 'groups/show'
end
# rubocop: disable CodeReuse/ActiveRecord # rubocop: disable CodeReuse/ActiveRecord
def authorize_create_group! def authorize_create_group!
allowed = if params[:parent_id].present? allowed = if params[:parent_id].present?
......
...@@ -4,6 +4,7 @@ module GroupsHelper ...@@ -4,6 +4,7 @@ module GroupsHelper
def group_overview_nav_link_paths def group_overview_nav_link_paths
%w[ %w[
groups#show groups#show
groups#details
groups#activity groups#activity
groups#subgroups groups#subgroups
analytics#show analytics#show
......
...@@ -286,7 +286,6 @@ class MergeRequestDiff < ActiveRecord::Base ...@@ -286,7 +286,6 @@ class MergeRequestDiff < ActiveRecord::Base
return yield(@external_diff_file) if @external_diff_file return yield(@external_diff_file) if @external_diff_file
external_diff.open do |file| external_diff.open do |file|
begin
@external_diff_file = file @external_diff_file = file
yield(@external_diff_file) yield(@external_diff_file)
...@@ -294,7 +293,6 @@ class MergeRequestDiff < ActiveRecord::Base ...@@ -294,7 +293,6 @@ class MergeRequestDiff < ActiveRecord::Base
@external_diff_file = nil @external_diff_file = nil
end end
end end
end
private private
......
...@@ -23,6 +23,6 @@ class MergeRequestDiffFile < ActiveRecord::Base ...@@ -23,6 +23,6 @@ class MergeRequestDiffFile < ActiveRecord::Base
super super
end end
binary? ? content.unpack('m0').first : content binary? ? content.unpack1('m0') : content
end end
end end
...@@ -1209,13 +1209,11 @@ class Project < ActiveRecord::Base ...@@ -1209,13 +1209,11 @@ class Project < ActiveRecord::Base
def repo_exists? def repo_exists?
strong_memoize(:repo_exists) do strong_memoize(:repo_exists) do
begin
repository.exists? repository.exists?
rescue rescue
false false
end end
end end
end
def root_ref?(branch) def root_ref?(branch)
repository.root_ref == branch repository.root_ref == branch
......
...@@ -205,14 +205,12 @@ class JiraService < IssueTrackerService ...@@ -205,14 +205,12 @@ class JiraService < IssueTrackerService
# if any transition fails it will log the error message and stop the transition sequence # if any transition fails it will log the error message and stop the transition sequence
def transition_issue(issue) def transition_issue(issue)
jira_issue_transition_id.scan(Gitlab::Regex.jira_transition_id_regex).each do |transition_id| jira_issue_transition_id.scan(Gitlab::Regex.jira_transition_id_regex).each do |transition_id|
begin
issue.transitions.build.save!(transition: { id: transition_id }) issue.transitions.build.save!(transition: { id: transition_id })
rescue => error rescue => error
log_error("Issue transition failed", error: error.message, client_url: client_url) log_error("Issue transition failed", error: error.message, client_url: client_url)
return false return false
end end
end end
end
def add_issue_solved_comment(issue, commit_id, commit_url) def add_issue_solved_comment(issue, commit_id, commit_url)
link_title = "Solved by commit #{commit_id}." link_title = "Solved by commit #{commit_id}."
......
...@@ -265,7 +265,6 @@ class Repository ...@@ -265,7 +265,6 @@ class Repository
# to avoid unnecessary syncing. # to avoid unnecessary syncing.
def keep_around(*shas) def keep_around(*shas)
shas.each do |sha| shas.each do |sha|
begin
next unless sha.present? && commit_by(oid: sha) next unless sha.present? && commit_by(oid: sha)
next if kept_around?(sha) next if kept_around?(sha)
...@@ -276,7 +275,6 @@ class Repository ...@@ -276,7 +275,6 @@ class Repository
Rails.logger.error "Unable to create keep-around reference for repository #{disk_path}: #{ex}" Rails.logger.error "Unable to create keep-around reference for repository #{disk_path}: #{ex}"
end end
end end
end
def kept_around?(sha) def kept_around?(sha)
ref_exists?(keep_around_ref_name(sha)) ref_exists?(keep_around_ref_name(sha))
......
...@@ -26,7 +26,6 @@ class UserInteractedProject < ActiveRecord::Base ...@@ -26,7 +26,6 @@ class UserInteractedProject < ActiveRecord::Base
cached_exists?(attributes) do cached_exists?(attributes) do
transaction(requires_new: true) do transaction(requires_new: true) do
begin
where(attributes).select(1).first || create!(attributes) where(attributes).select(1).first || create!(attributes)
true # not caching the whole record here for now true # not caching the whole record here for now
rescue ActiveRecord::RecordNotUnique rescue ActiveRecord::RecordNotUnique
...@@ -38,7 +37,6 @@ class UserInteractedProject < ActiveRecord::Base ...@@ -38,7 +37,6 @@ class UserInteractedProject < ActiveRecord::Base
end end
end end
end end
end
# Check if we can safely call .track (table exists) # Check if we can safely call .track (table exists)
def available? def available?
......
...@@ -42,11 +42,7 @@ class ProjectPresenter < Gitlab::View::Presenter::Delegated ...@@ -42,11 +42,7 @@ class ProjectPresenter < Gitlab::View::Presenter::Delegated
def empty_repo_statistics_anchors def empty_repo_statistics_anchors
[ [
license_anchor_data, license_anchor_data
commits_anchor_data,
branches_anchor_data,
tags_anchor_data,
files_anchor_data
].compact.select { |item| item.is_link } ].compact.select { |item| item.is_link }
end end
...@@ -55,9 +51,7 @@ class ProjectPresenter < Gitlab::View::Presenter::Delegated ...@@ -55,9 +51,7 @@ class ProjectPresenter < Gitlab::View::Presenter::Delegated
new_file_anchor_data, new_file_anchor_data,
readme_anchor_data, readme_anchor_data,
changelog_anchor_data, changelog_anchor_data,
contribution_guide_anchor_data, contribution_guide_anchor_data
autodevops_anchor_data,
kubernetes_cluster_anchor_data
].compact.reject { |item| item.is_link } ].compact.reject { |item| item.is_link }
end end
......
...@@ -9,7 +9,6 @@ class DetailedStatusEntity < Grape::Entity ...@@ -9,7 +9,6 @@ class DetailedStatusEntity < Grape::Entity
expose :details_path expose :details_path
expose :illustration do |status| expose :illustration do |status|
begin
illustration = { illustration = {
image: ActionController::Base.helpers.image_path(status.illustration[:image]) image: ActionController::Base.helpers.image_path(status.illustration[:image])
} }
...@@ -19,7 +18,6 @@ class DetailedStatusEntity < Grape::Entity ...@@ -19,7 +18,6 @@ class DetailedStatusEntity < Grape::Entity
rescue NotImplementedError rescue NotImplementedError
# ignored # ignored
end end
end
expose :favicon do |status| expose :favicon do |status|
Gitlab::Favicon.status_overlay(status.favicon) Gitlab::Favicon.status_overlay(status.favicon)
......
...@@ -42,7 +42,6 @@ module Projects ...@@ -42,7 +42,6 @@ module Projects
def parse_response_links(objects_response) def parse_response_links(objects_response)
objects_response.each_with_object([]) do |entry, link_list| objects_response.each_with_object([]) do |entry, link_list|
begin
link = entry.dig('actions', DOWNLOAD_ACTION, 'href') link = entry.dig('actions', DOWNLOAD_ACTION, 'href')
raise DownloadLinkNotFound unless link raise DownloadLinkNotFound unless link
...@@ -54,7 +53,6 @@ module Projects ...@@ -54,7 +53,6 @@ module Projects
log_error("Link for Lfs Object with oid #{entry['oid']} not found or invalid.") log_error("Link for Lfs Object with oid #{entry['oid']} not found or invalid.")
end end
end end
end
def request_body(oids) def request_body(oids)
{ {
......
...@@ -75,7 +75,6 @@ module Projects ...@@ -75,7 +75,6 @@ module Projects
create_tmp_storage_dir create_tmp_storage_dir
File.open(tmp_filename, 'wb') do |file| File.open(tmp_filename, 'wb') do |file|
begin
yield file yield file
rescue StandardError => e rescue StandardError => e
# If the lfs file is successfully downloaded it will be removed # If the lfs file is successfully downloaded it will be removed
...@@ -87,7 +86,6 @@ module Projects ...@@ -87,7 +86,6 @@ module Projects
raise e raise e
end end
end end
end
def tmp_filename def tmp_filename
File.join(tmp_storage_dir, lfs_oid) File.join(tmp_storage_dir, lfs_oid)
......
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
class ShaValidator < ActiveModel::EachValidator class ShaValidator < ActiveModel::EachValidator
def validate_each(record, attribute, value) def validate_each(record, attribute, value)
return if value.blank? || value.match(/\A\h{40}\z/) return if value.blank? || Commit.valid_hash?(value)
record.errors.add(attribute, 'is not a valid SHA') record.errors.add(attribute, 'is not a valid SHA')
end end
......
...@@ -38,4 +38,4 @@ ...@@ -38,4 +38,4 @@
%li= link_to _('New project'), new_project_path, class: 'qa-global-new-project-link' %li= link_to _('New project'), new_project_path, class: 'qa-global-new-project-link'
- if current_user.can_create_group? - if current_user.can_create_group?
%li= link_to _('New group'), new_group_path %li= link_to _('New group'), new_group_path
%li= link_to _('New snippet'), new_snippet_path %li= link_to _('New snippet'), new_snippet_path, class: 'qa-global-new-snippet-link'
...@@ -29,7 +29,7 @@ ...@@ -29,7 +29,7 @@
- if dashboard_nav_link?(:snippets) - if dashboard_nav_link?(:snippets)
= nav_link(controller: 'dashboard/snippets', html_options: { class: ["d-none d-xl-block", ("d-lg-block" unless has_extra_nav_icons?)] }) do = nav_link(controller: 'dashboard/snippets', html_options: { class: ["d-none d-xl-block", ("d-lg-block" unless has_extra_nav_icons?)] }) do
= link_to dashboard_snippets_path, class: 'dashboard-shortcuts-snippets', title: _('Snippets') do = link_to dashboard_snippets_path, class: 'dashboard-shortcuts-snippets qa-snippets-link', title: _('Snippets') do
= _('Snippets') = _('Snippets')
- if any_dashboard_nav_link?([:groups, :milestones, :activity, :snippets]) - if any_dashboard_nav_link?([:groups, :milestones, :activity, :snippets])
......
...@@ -20,13 +20,14 @@ ...@@ -20,13 +20,14 @@
= _('Overview') = _('Overview')
%ul.sidebar-sub-level-items %ul.sidebar-sub-level-items
= nav_link(path: ['groups#show', 'groups#activity', 'groups#subgroups'], html_options: { class: "fly-out-top-item" } ) do = nav_link(path: ['groups#show', 'groups#details', 'groups#activity', 'groups#subgroups'], html_options: { class: "fly-out-top-item" } ) do
= link_to group_path(@group) do = link_to group_path(@group) do
%strong.fly-out-top-item-name %strong.fly-out-top-item-name
= _('Overview') = _('Overview')
%li.divider.fly-out-top-item %li.divider.fly-out-top-item
= nav_link(path: ['groups#show', 'groups#subgroups'], html_options: { class: 'home' }) do
= link_to group_path(@group), title: _('Group details') do = nav_link(path: ['groups#show', 'groups#details', 'groups#subgroups'], html_options: { class: 'home' }) do
= link_to details_group_path(@group), title: _('Group details') do
%span %span
= _('Details') = _('Details')
...@@ -40,9 +41,9 @@ ...@@ -40,9 +41,9 @@
- if group_sidebar_link?(:contribution_analytics) - if group_sidebar_link?(:contribution_analytics)
= nav_link(path: 'analytics#show') do = nav_link(path: 'analytics#show') do
= link_to group_analytics_path(@group), title: 'Contribution Analytics', data: {placement: 'right'} do = link_to group_analytics_path(@group), title: _('Contribution Analytics'), data: { placement: 'right' } do
%span %span
Contribution Analytics = _('Contribution Analytics')
= render_if_exists "layouts/nav/ee/epic_link", group: @group = render_if_exists "layouts/nav/ee/epic_link", group: @group
......
...@@ -5,4 +5,5 @@ ...@@ -5,4 +5,5 @@
- if current_user && can?(current_user, :download_code, project) - if current_user && can?(current_user, :download_code, project)
= render 'shared/no_ssh' = render 'shared/no_ssh'
= render 'shared/no_password' = render 'shared/no_password'
- unless project.empty_repo?
= render 'shared/auto_devops_implicitly_enabled_banner', project: project = render 'shared/auto_devops_implicitly_enabled_banner', project: project
...@@ -57,6 +57,9 @@ ...@@ -57,6 +57,9 @@
- if can?(current_user, :download_code, @project) - if can?(current_user, :download_code, @project)
%nav.project-stats %nav.project-stats
.nav-links.quick-links .nav-links.quick-links
- if @project.empty_repo?
= render 'stat_anchor_list', anchors: @project.empty_repo_statistics_anchors
- else
= render 'stat_anchor_list', anchors: @project.statistics_anchors(show_auto_devops_callout: show_auto_devops_callout) = render 'stat_anchor_list', anchors: @project.statistics_anchors(show_auto_devops_callout: show_auto_devops_callout)
.home-panel-home-desc.mt-1 .home-panel-home-desc.mt-1
......
.file-header-content .file-header-content
= blob_icon blob.mode, blob.name = blob_icon blob.mode, blob.name
%strong.file-title-name %strong.file-title-name.qa-file-title-name
= blob.name = blob.name
= copy_file_path_button(blob.path) = copy_file_path_button(blob.path)
......
...@@ -7,43 +7,22 @@ ...@@ -7,43 +7,22 @@
%div{ class: [container_class, ("limit-container-width" unless fluid_layout)] } %div{ class: [container_class, ("limit-container-width" unless fluid_layout)] }
= render "home_panel" = render "home_panel"
.project-empty-note-panel %h4.prepend-top-0.append-bottom-8
%h4.append-bottom-20
= _('The repository for this project is empty') = _('The repository for this project is empty')
- if @project.can_current_user_push_code? - if @project.can_current_user_push_code?
%p %p.append-bottom-0
- link_to_cli = link_to _('command line instructions'), '#repo-command-line-instructions' = _('You can create files directly in GitLab using one of the following options.')
= _('If you already have files you can push them using the %{link_to_cli} below.').html_safe % { link_to_cli: link_to_cli }
%p
%em
- link_to_protected_branches = link_to _('Learn more about protected branches'), help_page_path('user/project/protected_branches')
= _('Note that the master branch is automatically protected. %{link_to_protected_branches}').html_safe % { link_to_protected_branches: link_to_protected_branches }
%hr
%p
- link_to_auto_devops_settings = link_to(s_('AutoDevOps|enable Auto DevOps'), project_settings_ci_cd_path(@project, anchor: 'autodevops-settings'))
- link_to_add_kubernetes_cluster = link_to(s_('AutoDevOps|add a Kubernetes cluster'), new_project_cluster_path(@project))
= s_('AutoDevOps|You can automatically build and test your application if you %{link_to_auto_devops_settings} for this project. You can automatically deploy it as well, if you %{link_to_add_kubernetes_cluster}.').html_safe % { link_to_auto_devops_settings: link_to_auto_devops_settings, link_to_add_kubernetes_cluster: link_to_add_kubernetes_cluster }
%hr .project-buttons.qa-quick-actions
%p
= _('Otherwise it is recommended you start with one of the options below.')
.prepend-top-20
%nav.project-buttons
.scrolling-tabs-container.inner-page-scroll-tabs.is-smaller.qa-quick-actions
.fade-left= icon('angle-left')
.fade-right= icon('angle-right')
.nav-links.scrolling-tabs.quick-links
= render 'stat_anchor_list', anchors: @project.empty_repo_statistics_buttons = render 'stat_anchor_list', anchors: @project.empty_repo_statistics_buttons
- if can?(current_user, :push_code, @project) - if can?(current_user, :push_code, @project)
%div .empty-wrapper.prepend-top-32
.prepend-top-20
.empty_wrapper
%h3#repo-command-line-instructions.page-title-empty %h3#repo-command-line-instructions.page-title-empty
= _('Command line instructions') = _('Command line instructions')
%p
= _('You can also upload existing files from your computer using the instructions below.')
.git-empty.js-git-empty .git-empty.js-git-empty
%fieldset %fieldset
%h5= _('Git global setup') %h5= _('Git global setup')
...@@ -66,7 +45,7 @@ ...@@ -66,7 +45,7 @@
git push -u origin master git push -u origin master
%fieldset %fieldset
%h5= _('Existing folder') %h5= _('Push an existing folder')
%pre.bg-light %pre.bg-light
:preserve :preserve
cd existing_folder cd existing_folder
...@@ -79,7 +58,7 @@ ...@@ -79,7 +58,7 @@
git push -u origin master git push -u origin master
%fieldset %fieldset
%h5= _('Existing Git repository') %h5= _('Push an existing Git repository')
%pre.bg-light %pre.bg-light
:preserve :preserve
cd existing_repo cd existing_repo
...@@ -89,7 +68,3 @@ ...@@ -89,7 +68,3 @@
%span>< %span><
git push -u origin --all git push -u origin --all
git push -u origin --tags git push -u origin --tags
- if can? current_user, :remove_project, @project
.prepend-top-20
= link_to _('Remove project'), [@project.namespace.becomes(Namespace), @project], data: { confirm: remove_project_message(@project)}, method: :delete, class: "btn btn-inverted btn-remove float-right"
.file-content.code.js-syntax-highlight .file-content.code.js-syntax-highlight.qa-file-content
.line-numbers .line-numbers
- if blob.data.present? - if blob.data.present?
- link_icon = icon('link') - link_icon = icon('link')
......
...@@ -9,7 +9,7 @@ ...@@ -9,7 +9,7 @@
.form-group.row .form-group.row
= f.label :title, class: 'col-form-label col-sm-2' = f.label :title, class: 'col-form-label col-sm-2'
.col-sm-10 .col-sm-10
= f.text_field :title, class: 'form-control', required: true, autofocus: true = f.text_field :title, class: 'form-control qa-snippet-title', required: true, autofocus: true
= render 'shared/form_elements/description', model: @snippet, project: @project, form: f = render 'shared/form_elements/description', model: @snippet, project: @project, form: f
...@@ -21,7 +21,7 @@ ...@@ -21,7 +21,7 @@
.col-sm-10 .col-sm-10
.file-holder.snippet .file-holder.snippet
.js-file-title.file-title .js-file-title.file-title
= f.text_field :file_name, placeholder: "Optionally name this file to add code highlighting, e.g. example.rb for Ruby.", class: 'form-control snippet-file-name' = f.text_field :file_name, placeholder: "Optionally name this file to add code highlighting, e.g. example.rb for Ruby.", class: 'form-control snippet-file-name qa-snippet-file-name'
.file-content.code .file-content.code
%pre#editor= @snippet.content %pre#editor= @snippet.content
= f.hidden_field :content, class: 'snippet-file-content' = f.hidden_field :content, class: 'snippet-file-content'
...@@ -31,7 +31,7 @@ ...@@ -31,7 +31,7 @@
.form-actions .form-actions
- if @snippet.new_record? - if @snippet.new_record?
= f.submit 'Create snippet', class: "btn-success btn" = f.submit 'Create snippet', class: "btn-success btn qa-create-snippet-button"
- else - else
= f.submit 'Save changes', class: "btn-success btn" = f.submit 'Save changes', class: "btn-success btn"
......
.detail-page-header .detail-page-header
.detail-page-header-body .detail-page-header-body
.snippet-box.has-tooltip.inline.append-right-5{ title: snippet_visibility_level_description(@snippet.visibility_level, @snippet), data: { container: "body" } } .snippet-box.qa-snippet-box.has-tooltip.inline.append-right-5{ title: snippet_visibility_level_description(@snippet.visibility_level, @snippet), data: { container: "body" } }
%span.sr-only %span.sr-only
= visibility_level_label(@snippet.visibility_level) = visibility_level_label(@snippet.visibility_level)
= visibility_level_icon(@snippet.visibility_level, fw: false) = visibility_level_icon(@snippet.visibility_level, fw: false)
...@@ -17,11 +17,11 @@ ...@@ -17,11 +17,11 @@
= render "snippets/actions" = render "snippets/actions"
.snippet-header.limited-header-width .snippet-header.limited-header-width
%h2.snippet-title.prepend-top-0.append-bottom-0 %h2.snippet-title.prepend-top-0.append-bottom-0.qa-snippet-title
= markdown_field(@snippet, :title) = markdown_field(@snippet, :title)
- if @snippet.description.present? - if @snippet.description.present?
.description .description.qa-snippet-description
.wiki .wiki
= markdown_field(@snippet, :description) = markdown_field(@snippet, :description)
%textarea.hidden.js-task-list-field %textarea.hidden.js-task-list-field
...@@ -34,7 +34,7 @@ ...@@ -34,7 +34,7 @@
.embed-snippet .embed-snippet
.input-group .input-group
.input-group-prepend .input-group-prepend
%button.btn.btn-svg.embed-toggle.input-group-text{ 'data-toggle': 'dropdown', type: 'button' } %button.btn.btn-svg.embed-toggle.input-group-text.qa-embed-type{ 'data-toggle': 'dropdown', type: 'button' }
%span.js-embed-action= _("Embed") %span.js-embed-action= _("Embed")
= sprite_icon('angle-down', size: 12, css_class: 'caret-down') = sprite_icon('angle-down', size: 12, css_class: 'caret-down')
%ul.dropdown-menu.dropdown-menu-selectable.embed-toggle-list %ul.dropdown-menu.dropdown-menu-selectable.embed-toggle-list
......
...@@ -25,12 +25,10 @@ module WaitableWorker ...@@ -25,12 +25,10 @@ module WaitableWorker
failed = [] failed = []
args_list.each do |args| args_list.each do |args|
begin
new.perform(*args) new.perform(*args)
rescue rescue
failed << args failed << args
end end
end
bulk_perform_async(failed) if failed.present? bulk_perform_async(failed) if failed.present?
end end
......
...@@ -20,12 +20,10 @@ class CreateGpgSignatureWorker ...@@ -20,12 +20,10 @@ class CreateGpgSignatureWorker
# This calculates and caches the signature in the database # This calculates and caches the signature in the database
commits.each do |commit| commits.each do |commit|
begin
Gitlab::Gpg::Commit.new(commit).signature Gitlab::Gpg::Commit.new(commit).signature
rescue => e rescue => e
Rails.logger.error("Failed to create signature for commit #{commit.id}. Error: #{e.message}") Rails.logger.error("Failed to create signature for commit #{commit.id}. Error: #{e.message}")
end end
end end
end
# rubocop: enable CodeReuse/ActiveRecord # rubocop: enable CodeReuse/ActiveRecord
end end
...@@ -52,7 +52,6 @@ class EmailsOnPushWorker ...@@ -52,7 +52,6 @@ class EmailsOnPushWorker
end end
valid_recipients(recipients).each do |recipient| valid_recipients(recipients).each do |recipient|
begin
send_email( send_email(
recipient, recipient,
project_id, project_id,
...@@ -70,7 +69,6 @@ class EmailsOnPushWorker ...@@ -70,7 +69,6 @@ class EmailsOnPushWorker
rescue Net::SMTPFatalError, Net::SMTPSyntaxError => e rescue Net::SMTPFatalError, Net::SMTPSyntaxError => e
logger.info("Failed to send e-mail for project '#{project.full_name}' to #{recipient}: #{e}") logger.info("Failed to send e-mail for project '#{project.full_name}' to #{recipient}: #{e}")
end end
end
ensure ensure
@email = nil @email = nil
compare = nil compare = nil
......
...@@ -126,12 +126,10 @@ module ObjectStorage ...@@ -126,12 +126,10 @@ module ObjectStorage
def process_uploader(uploader) def process_uploader(uploader)
MigrationResult.new(uploader.upload).tap do |result| MigrationResult.new(uploader.upload).tap do |result|
begin
uploader.migrate!(@to_store) uploader.migrate!(@to_store)
rescue => e rescue => e
result.error = e result.error = e
end end
end end
end end
end
end end
...@@ -8,7 +8,7 @@ class PipelineScheduleWorker ...@@ -8,7 +8,7 @@ class PipelineScheduleWorker
def perform def perform
Ci::PipelineSchedule.active.where("next_run_at < ?", Time.now) Ci::PipelineSchedule.active.where("next_run_at < ?", Time.now)
.preload(:owner, :project).find_each do |schedule| .preload(:owner, :project).find_each do |schedule|
begin
Ci::CreatePipelineService.new(schedule.project, Ci::CreatePipelineService.new(schedule.project,
schedule.owner, schedule.owner,
ref: schedule.ref) ref: schedule.ref)
...@@ -19,7 +19,6 @@ class PipelineScheduleWorker ...@@ -19,7 +19,6 @@ class PipelineScheduleWorker
schedule.schedule_next_run! schedule.schedule_next_run!
end end
end end
end
# rubocop: enable CodeReuse/ActiveRecord # rubocop: enable CodeReuse/ActiveRecord
private private
......
...@@ -6,11 +6,9 @@ class RemoveExpiredMembersWorker ...@@ -6,11 +6,9 @@ class RemoveExpiredMembersWorker
def perform def perform
Member.expired.find_each do |member| Member.expired.find_each do |member|
begin
Members::DestroyService.new.execute(member, skip_authorization: true) Members::DestroyService.new.execute(member, skip_authorization: true)
rescue => ex rescue => ex
logger.error("Expired Member ID=#{member.id} cannot be removed - #{ex}") logger.error("Expired Member ID=#{member.id} cannot be removed - #{ex}")
end end
end end
end
end end
---
title: 'Project: Improve empty repository state UI'
merge_request: 26024
author:
type: other
---
title: Explicitly set master_auth setting to enable basic auth and client certificate
for new GKE clusters
merge_request: 26018
author:
type: other
---
title: Fix bug in BitBucket imports with SHA shorter than 40 chars
merge_request: 26050
author:
type: fixed
...@@ -14,10 +14,8 @@ module Rack ...@@ -14,10 +14,8 @@ module Rack
end end
gitlab_trusted_proxies = Array(Gitlab.config.gitlab.trusted_proxies).map do |proxy| gitlab_trusted_proxies = Array(Gitlab.config.gitlab.trusted_proxies).map do |proxy|
begin
IPAddr.new(proxy) IPAddr.new(proxy)
rescue IPAddr::InvalidAddressError rescue IPAddr::InvalidAddressError
end
end.compact end.compact
Rails.application.config.action_dispatch.trusted_proxies = ( Rails.application.config.action_dispatch.trusted_proxies = (
......
...@@ -6,6 +6,7 @@ const argumentsParser = require('commander'); ...@@ -6,6 +6,7 @@ const argumentsParser = require('commander');
const webpackConfig = require('./webpack.config.js'); const webpackConfig = require('./webpack.config.js');
const ROOT_PATH = path.resolve(__dirname, '..'); const ROOT_PATH = path.resolve(__dirname, '..');
const SPECS_PATH = /^(?:\.[\\\/])?(ee[\\\/])?spec[\\\/]javascripts[\\\/]/;
function fatalError(message) { function fatalError(message) {
console.error(chalk.red(`\nError: ${message}\n`)); console.error(chalk.red(`\nError: ${message}\n`));
...@@ -41,9 +42,19 @@ const specFilters = argumentsParser ...@@ -41,9 +42,19 @@ const specFilters = argumentsParser
) )
.parse(process.argv).filterSpec; .parse(process.argv).filterSpec;
if (specFilters.length) { const createContext = (specFiles, regex, suffix) => {
const specsPath = /^(?:\.[\\\/])?spec[\\\/]javascripts[\\\/]/; const newContext = specFiles.reduce((context, file) => {
const relativePath = file.replace(SPECS_PATH, '');
context[file] = `./${relativePath}`;
return context;
}, {});
webpackConfig.plugins.push(
new webpack.ContextReplacementPlugin(regex, path.join(ROOT_PATH, suffix), newContext),
);
};
if (specFilters.length) {
// resolve filters // resolve filters
let filteredSpecFiles = specFilters.map(filter => let filteredSpecFiles = specFilters.map(filter =>
glob glob
...@@ -64,23 +75,15 @@ if (specFilters.length) { ...@@ -64,23 +75,15 @@ if (specFilters.length) {
fatalError('Your filter did not match any test files.'); fatalError('Your filter did not match any test files.');
} }
if (!filteredSpecFiles.every(file => specsPath.test(file))) { if (!filteredSpecFiles.every(file => SPECS_PATH.test(file))) {
fatalError('Test files must be located within /spec/javascripts.'); fatalError('Test files must be located within /spec/javascripts.');
} }
const newContext = filteredSpecFiles.reduce((context, file) => { const CE_FILES = filteredSpecFiles.filter(file => !file.startsWith('ee'));
const relativePath = file.replace(specsPath, ''); createContext(CE_FILES, /[^e]{2}[\\\/]spec[\\\/]javascripts$/, 'spec/javascripts');
context[file] = `./${relativePath}`;
return context;
}, {});
webpackConfig.plugins.push( const EE_FILES = filteredSpecFiles.filter(file => file.startsWith('ee'));
new webpack.ContextReplacementPlugin( createContext(EE_FILES, /ee[\\\/]spec[\\\/]javascripts$/, 'ee/spec/javascripts');
/spec[\\\/]javascripts$/,
path.join(ROOT_PATH, 'spec/javascripts'),
newContext,
),
);
} }
// Karma configuration // Karma configuration
...@@ -111,10 +114,20 @@ module.exports = function(config) { ...@@ -111,10 +114,20 @@ module.exports = function(config) {
], ],
preprocessors: { preprocessors: {
'spec/javascripts/**/*.js': ['webpack', 'sourcemap'], 'spec/javascripts/**/*.js': ['webpack', 'sourcemap'],
'ee/spec/javascripts/**/*.js': ['webpack', 'sourcemap'],
}, },
reporters: ['mocha'], reporters: ['mocha'],
webpack: webpackConfig, webpack: webpackConfig,
webpackMiddleware: { stats: 'errors-only' }, webpackMiddleware: { stats: 'errors-only' },
plugins: [
'karma-chrome-launcher',
'karma-coverage-istanbul-reporter',
'karma-jasmine',
'karma-junit-reporter',
'karma-mocha-reporter',
'karma-sourcemap-loader',
'karma-webpack',
],
}; };
if (process.env.CI) { if (process.env.CI) {
...@@ -123,6 +136,19 @@ module.exports = function(config) { ...@@ -123,6 +136,19 @@ module.exports = function(config) {
outputFile: 'junit_karma.xml', outputFile: 'junit_karma.xml',
useBrowserName: false, useBrowserName: false,
}; };
} else {
// ignore 404s in local environment because we are not fixing them and they bloat the log
function ignore404() {
return (request, response /* next */) => {
response.writeHead(404);
return response.end('NOT FOUND');
};
}
karmaConfig.middleware = ['ignore-404'];
karmaConfig.plugins.push({
'middleware:ignore-404': ['factory', ignore404],
});
} }
if (process.env.BABEL_ENV === 'coverage' || process.env.NODE_ENV === 'coverage') { if (process.env.BABEL_ENV === 'coverage' || process.env.NODE_ENV === 'coverage') {
......
...@@ -14,6 +14,7 @@ constraints(::Constraints::GroupUrlConstrainer.new) do ...@@ -14,6 +14,7 @@ constraints(::Constraints::GroupUrlConstrainer.new) do
get :issues, as: :issues_group get :issues, as: :issues_group
get :merge_requests, as: :merge_requests_group get :merge_requests, as: :merge_requests_group
get :projects, as: :projects_group get :projects, as: :projects_group
get :details, as: :details_group
get :activity, as: :activity_group get :activity, as: :activity_group
put :transfer, as: :transfer_group put :transfer, as: :transfer_group
# TODO: Remove as part of refactor in https://gitlab.com/gitlab-org/gitlab-ce/issues/49693 # TODO: Remove as part of refactor in https://gitlab.com/gitlab-org/gitlab-ce/issues/49693
......
...@@ -324,6 +324,10 @@ module.exports = { ...@@ -324,6 +324,10 @@ module.exports = {
reportFilename: path.join(ROOT_PATH, 'webpack-report/index.html'), reportFilename: path.join(ROOT_PATH, 'webpack-report/index.html'),
statsFilename: path.join(ROOT_PATH, 'webpack-report/stats.json'), statsFilename: path.join(ROOT_PATH, 'webpack-report/stats.json'),
}), }),
new webpack.DefinePlugin({
'process.env.EE': JSON.stringify(IS_EE),
}),
].filter(Boolean), ].filter(Boolean),
devServer: { devServer: {
......
...@@ -126,12 +126,11 @@ class ProjectForeignKeysWithCascadingDeletes < ActiveRecord::Migration[4.2] ...@@ -126,12 +126,11 @@ class ProjectForeignKeysWithCascadingDeletes < ActiveRecord::Migration[4.2]
queues.each do |queue| queues.each do |queue|
# Stealing is racy so it's possible a pop might be called on an # Stealing is racy so it's possible a pop might be called on an
# already-empty queue. # already-empty queue.
begin
remove_orphans(*queue.pop(true)) remove_orphans(*queue.pop(true))
stolen = true stolen = true
rescue ThreadError rescue ThreadError
end end
end
break unless stolen break unless stolen
end end
......
...@@ -269,7 +269,7 @@ The `releases` directory will hold all our deployments: ...@@ -269,7 +269,7 @@ The `releases` directory will hold all our deployments:
echo 'Cloning repository' echo 'Cloning repository'
[ -d {{ $releases_dir }} ] || mkdir {{ $releases_dir }} [ -d {{ $releases_dir }} ] || mkdir {{ $releases_dir }}
git clone --depth 1 {{ $repository }} {{ $new_release_dir }} git clone --depth 1 {{ $repository }} {{ $new_release_dir }}
cd {{ $releases_dir }} cd {{ $new_release_dir }}
git reset --hard {{ $commit }} git reset --hard {{ $commit }}
@endtask @endtask
...@@ -347,7 +347,7 @@ At the end, our `Envoy.blade.php` file will look like this: ...@@ -347,7 +347,7 @@ At the end, our `Envoy.blade.php` file will look like this:
echo 'Cloning repository' echo 'Cloning repository'
[ -d {{ $releases_dir }} ] || mkdir {{ $releases_dir }} [ -d {{ $releases_dir }} ] || mkdir {{ $releases_dir }}
git clone --depth 1 {{ $repository }} {{ $new_release_dir }} git clone --depth 1 {{ $repository }} {{ $new_release_dir }}
cd {{ $releases_dir }} cd {{ $new_release_dir }}
git reset --hard {{ $commit }} git reset --hard {{ $commit }}
@endtask @endtask
......
...@@ -2561,4 +2561,4 @@ git push -o ci.skip ...@@ -2561,4 +2561,4 @@ git push -o ci.skip
[environment]: ../environments.md "CI/CD environments" [environment]: ../environments.md "CI/CD environments"
[schedules]: ../../user/project/pipelines/schedules.md "Pipelines schedules" [schedules]: ../../user/project/pipelines/schedules.md "Pipelines schedules"
[variables]: ../variables/README.md "CI/CD variables" [variables]: ../variables/README.md "CI/CD variables"
[push-option]: https://git-scm.com/docs/git-push#git-push--oltoptiongt [push-option]: https://git-scm.com/docs/git-push#Documentation/git-push.txt--oltoptiongt
...@@ -119,6 +119,7 @@ This [documentation](merge_request_workflow.md) outlines the current merge reque ...@@ -119,6 +119,7 @@ This [documentation](merge_request_workflow.md) outlines the current merge reque
- [Merge request guidelines](merge_request_workflow.md#merge-request-guidelines) - [Merge request guidelines](merge_request_workflow.md#merge-request-guidelines)
- [Contribution acceptance criteria](merge_request_workflow.md#contribution-acceptance-criteria) - [Contribution acceptance criteria](merge_request_workflow.md#contribution-acceptance-criteria)
- [Definition of done](merge_request_workflow.md#definition-of-done) - [Definition of done](merge_request_workflow.md#definition-of-done)
- [Dependencies](merge_request_workflow.md#dependencies)
## Style guides ## Style guides
......
...@@ -80,11 +80,10 @@ yield a useful result, and ensuring content is helpful and easy to consume. ...@@ -80,11 +80,10 @@ yield a useful result, and ensuring content is helpful and easy to consume.
## Text ## Text
- Split up long lines (wrap text), this makes it much easier to review and edit. Only - Splitting long lines (preferably up to 100 characters) can make it easier to provide feedback on small chunks of text.
double line breaks are shown as a full line break by creating new paragraphs. - Insert an empty line for new paragraphs.
80-100 characters is the recommended line length.
- Use sentence case for titles, headings, labels, menu items, and buttons. - Use sentence case for titles, headings, labels, menu items, and buttons.
- Jump a line between different markups (e.g., after every paragraph, header, list, etc). Example: - Insert an empty line between different markups (e.g., after every paragraph, header, list, etc). Example:
```md ```md
## Header ## Header
......
...@@ -15,7 +15,7 @@ information on general testing practices at GitLab. ...@@ -15,7 +15,7 @@ information on general testing practices at GitLab.
## Jest ## Jest
GitLab has started to migrate tests to the (Jest)[https://jestjs.io] GitLab has started to migrate tests to the [Jest](https://jestjs.io)
testing framework. You can read a [detailed evaluation](https://gitlab.com/gitlab-org/gitlab-ce/issues/49171) testing framework. You can read a [detailed evaluation](https://gitlab.com/gitlab-org/gitlab-ce/issues/49171)
of Jest compared to our use of Karma and Jasmine. In summary, it will allow us of Jest compared to our use of Karma and Jasmine. In summary, it will allow us
to improve the performance and consistency of our frontend tests. to improve the performance and consistency of our frontend tests.
......
...@@ -704,6 +704,7 @@ also be customized, and you can easily use a [custom buildpack](#custom-buildpac ...@@ -704,6 +704,7 @@ also be customized, and you can easily use a [custom buildpack](#custom-buildpac
| `INCREMENTAL_ROLLOUT_MODE`| From GitLab 11.4, this variable, if present, can be used to enable an [incremental rollout](#incremental-rollout-to-production-premium) of your application for the production environment.<br/>Set to: <ul><li>`manual`, for manual deployment jobs.</li><li>`timed`, for automatic rollout deployments with a 5 minute delay each one.</li></ul> | | `INCREMENTAL_ROLLOUT_MODE`| From GitLab 11.4, this variable, if present, can be used to enable an [incremental rollout](#incremental-rollout-to-production-premium) of your application for the production environment.<br/>Set to: <ul><li>`manual`, for manual deployment jobs.</li><li>`timed`, for automatic rollout deployments with a 5 minute delay each one.</li></ul> |
| `TEST_DISABLED` | From GitLab 11.0, this variable can be used to disable the `test` job. If the variable is present, the job will not be created. | | `TEST_DISABLED` | From GitLab 11.0, this variable can be used to disable the `test` job. If the variable is present, the job will not be created. |
| `CODE_QUALITY_DISABLED` | From GitLab 11.0, this variable can be used to disable the `codequality` job. If the variable is present, the job will not be created. | | `CODE_QUALITY_DISABLED` | From GitLab 11.0, this variable can be used to disable the `codequality` job. If the variable is present, the job will not be created. |
| `LICENSE_MANAGEMENT_DISABLED` | From GitLab 11.0, this variable can be used to disable the `license_management` job. If the variable is present, the job will not be created. |
| `SAST_DISABLED` | From GitLab 11.0, this variable can be used to disable the `sast` job. If the variable is present, the job will not be created. | | `SAST_DISABLED` | From GitLab 11.0, this variable can be used to disable the `sast` job. If the variable is present, the job will not be created. |
| `DEPENDENCY_SCANNING_DISABLED` | From GitLab 11.0, this variable can be used to disable the `dependency_scanning` job. If the variable is present, the job will not be created. | | `DEPENDENCY_SCANNING_DISABLED` | From GitLab 11.0, this variable can be used to disable the `dependency_scanning` job. If the variable is present, the job will not be created. |
| `CONTAINER_SCANNING_DISABLED` | From GitLab 11.0, this variable can be used to disable the `sast:container` job. If the variable is present, the job will not be created. | | `CONTAINER_SCANNING_DISABLED` | From GitLab 11.0, this variable can be used to disable the `sast:container` job. If the variable is present, the job will not be created. |
......
...@@ -63,6 +63,12 @@ are available: ...@@ -63,6 +63,12 @@ are available:
- `%{commit_sha}`: ID of the most recent commit to the default branch of a - `%{commit_sha}`: ID of the most recent commit to the default branch of a
project's repository project's repository
NOTE: **NOTE**
Placeholders allow badges to expose otherwise-private information, such as the
default branch or commit SHA when the project is configured to have a private
repository. This is by design, as badges are intended to be used publicly. Avoid
using these placeholders if the information is sensitive.
## API ## API
You can also configure badges via the GitLab API. As in the settings, there is You can also configure badges via the GitLab API. As in the settings, there is
......
...@@ -75,6 +75,14 @@ new Kubernetes cluster to your project: ...@@ -75,6 +75,14 @@ new Kubernetes cluster to your project:
After a couple of minutes, your cluster will be ready to go. You can now proceed After a couple of minutes, your cluster will be ready to go. You can now proceed
to install some [pre-defined applications](#installing-applications). to install some [pre-defined applications](#installing-applications).
NOTE: **Note:**
GitLab requires basic authentication enabled and a client certificate issued for
the cluster in order to setup an [initial service
account](#access-controls). Starting from [GitLab
11.10](https://gitlab.com/gitlab-org/gitlab-ce/issues/58208), the cluster
creation process will explicitly request that basic authentication and
client certificate is enabled.
## Adding an existing Kubernetes cluster ## Adding an existing Kubernetes cluster
To add an existing Kubernetes cluster to your project: To add an existing Kubernetes cluster to your project:
......
...@@ -96,7 +96,7 @@ all matching branches: ...@@ -96,7 +96,7 @@ all matching branches:
## Creating a protected branch ## Creating a protected branch
> [Introduced][https://gitlab.com/gitlab-org/gitlab-ce/issues/53361] in GitLab 11.9. > [Introduced](https://gitlab.com/gitlab-org/gitlab-ce/issues/53361) in GitLab 11.9.
When a protected branch or wildcard protected branches are set to When a protected branch or wildcard protected branches are set to
[**No one** is **Allowed to push**](#using-the-allowed-to-merge-and-allowed-to-push-settings), [**No one** is **Allowed to push**](#using-the-allowed-to-merge-and-allowed-to-push-settings),
......
...@@ -103,7 +103,6 @@ module API ...@@ -103,7 +103,6 @@ module API
detail 'This feature was introduced in GitLab 11.9' detail 'This feature was introduced in GitLab 11.9'
end end
post ':id/milestones/:milestone_id/promote' do post ':id/milestones/:milestone_id/promote' do
begin
authorize! :admin_milestone, user_project authorize! :admin_milestone, user_project
authorize! :admin_milestone, user_project.group authorize! :admin_milestone, user_project.group
...@@ -116,5 +115,4 @@ module API ...@@ -116,5 +115,4 @@ module API
end end
end end
end end
end
end end
...@@ -89,12 +89,10 @@ module API ...@@ -89,12 +89,10 @@ module API
optional :format, type: String, desc: 'The archive format' optional :format, type: String, desc: 'The archive format'
end end
get ':id/repository/archive', requirements: { format: Gitlab::PathRegex.archive_formats_regex } do get ':id/repository/archive', requirements: { format: Gitlab::PathRegex.archive_formats_regex } do
begin
send_git_archive user_project.repository, ref: params[:sha], format: params[:format], append_sha: true send_git_archive user_project.repository, ref: params[:sha], format: params[:format], append_sha: true
rescue rescue
not_found!('File') not_found!('File')
end end
end
desc 'Compare two branches, tags, or commits' do desc 'Compare two branches, tags, or commits' do
success Entities::Compare success Entities::Compare
...@@ -118,13 +116,11 @@ module API ...@@ -118,13 +116,11 @@ module API
optional :sort, type: String, values: %w[asc desc], default: 'asc', desc: 'Sort by asc (ascending) or desc (descending)' optional :sort, type: String, values: %w[asc desc], default: 'asc', desc: 'Sort by asc (ascending) or desc (descending)'
end end
get ':id/repository/contributors' do get ':id/repository/contributors' do
begin
contributors = ::Kaminari.paginate_array(user_project.repository.contributors(order_by: params[:order_by], sort: params[:sort])) contributors = ::Kaminari.paginate_array(user_project.repository.contributors(order_by: params[:order_by], sort: params[:sort]))
present paginate(contributors), with: Entities::Contributor present paginate(contributors), with: Entities::Contributor
rescue rescue
not_found! not_found!
end end
end
desc 'Get the common ancestor between commits' do desc 'Get the common ancestor between commits' do
success Entities::Commit success Entities::Commit
......
...@@ -11,7 +11,7 @@ module Gitlab ...@@ -11,7 +11,7 @@ module Gitlab
# So we chose a way to use ::Ci::Build directly and we don't change the `archive!` method until 11.1 # So we chose a way to use ::Ci::Build directly and we don't change the `archive!` method until 11.1
::Ci::Build.finished.without_archived_trace ::Ci::Build.finished.without_archived_trace
.where(id: start_id..stop_id).find_each do |build| .where(id: start_id..stop_id).find_each do |build|
begin
build.trace.archive! build.trace.archive!
rescue => e rescue => e
Rails.logger.error "Failed to archive live trace. id: #{build.id} message: #{e.message}" Rails.logger.error "Failed to archive live trace. id: #{build.id} message: #{e.message}"
...@@ -19,5 +19,4 @@ module Gitlab ...@@ -19,5 +19,4 @@ module Gitlab
end end
end end
end end
end
end end
...@@ -302,7 +302,6 @@ module Gitlab ...@@ -302,7 +302,6 @@ module Gitlab
ldap_identities = Identity.where("provider like 'ldap%'").where(id: start_id..end_id) ldap_identities = Identity.where("provider like 'ldap%'").where(id: start_id..end_id)
ldap_identities.each do |identity| ldap_identities.each do |identity|
begin
identity.extern_uid = Gitlab::Auth::LDAP::DN.new(identity.extern_uid).to_normalized_s identity.extern_uid = Gitlab::Auth::LDAP::DN.new(identity.extern_uid).to_normalized_s
unless identity.save unless identity.save
Rails.logger.info "Unable to normalize \"#{identity.extern_uid}\". Skipping." Rails.logger.info "Unable to normalize \"#{identity.extern_uid}\". Skipping."
...@@ -311,7 +310,6 @@ module Gitlab ...@@ -311,7 +310,6 @@ module Gitlab
Rails.logger.info "Unable to normalize \"#{identity.extern_uid}\" due to \"#{e.message}\". Skipping." Rails.logger.info "Unable to normalize \"#{identity.extern_uid}\" due to \"#{e.message}\". Skipping."
end end
end end
end
def migrate? def migrate?
Identity.table_exists? Identity.table_exists?
......
...@@ -34,7 +34,6 @@ module Gitlab ...@@ -34,7 +34,6 @@ module Gitlab
def filter_error_files(files) def filter_error_files(files)
files.partition do |file| files.partition do |file|
begin
file.to_h file.to_h
true true
rescue => e rescue => e
...@@ -47,7 +46,6 @@ module Gitlab ...@@ -47,7 +46,6 @@ module Gitlab
false false
end end
end end
end
def filter_existing_uploads(files) def filter_existing_uploads(files)
paths = files.map(&:upload_path) paths = files.map(&:upload_path)
......
...@@ -79,7 +79,6 @@ module Gitlab ...@@ -79,7 +79,6 @@ module Gitlab
create_labels create_labels
client.issues(repo).each do |issue| client.issues(repo).each do |issue|
begin
description = '' description = ''
description += @formatter.author_line(issue.author) unless find_user_id(issue.author) description += @formatter.author_line(issue.author) unless find_user_id(issue.author)
description += issue.description description += issue.description
...@@ -105,7 +104,6 @@ module Gitlab ...@@ -105,7 +104,6 @@ module Gitlab
errors << { type: :issue, iid: issue.iid, errors: e.message } errors << { type: :issue, iid: issue.iid, errors: e.message }
end end
end end
end
# rubocop: enable CodeReuse/ActiveRecord # rubocop: enable CodeReuse/ActiveRecord
def import_issue_comments(issue, gitlab_issue) def import_issue_comments(issue, gitlab_issue)
...@@ -150,7 +148,6 @@ module Gitlab ...@@ -150,7 +148,6 @@ module Gitlab
pull_requests = client.pull_requests(repo) pull_requests = client.pull_requests(repo)
pull_requests.each do |pull_request| pull_requests.each do |pull_request|
begin
description = '' description = ''
description += @formatter.author_line(pull_request.author) unless find_user_id(pull_request.author) description += @formatter.author_line(pull_request.author) unless find_user_id(pull_request.author)
description += pull_request.description description += pull_request.description
...@@ -182,7 +179,6 @@ module Gitlab ...@@ -182,7 +179,6 @@ module Gitlab
errors << { type: :pull_request, iid: pull_request.iid, errors: e.message, trace: e.backtrace.join("\n"), raw_response: pull_request.raw } errors << { type: :pull_request, iid: pull_request.iid, errors: e.message, trace: e.backtrace.join("\n"), raw_response: pull_request.raw }
end end
end end
end
def import_pull_request_comments(pull_request, merge_request) def import_pull_request_comments(pull_request, merge_request)
comments = client.pull_request_comments(repo, pull_request.iid) comments = client.pull_request_comments(repo, pull_request.iid)
...@@ -211,7 +207,6 @@ module Gitlab ...@@ -211,7 +207,6 @@ module Gitlab
end end
inline_comments.each do |comment| inline_comments.each do |comment|
begin
attributes = pull_request_comment_attributes(comment) attributes = pull_request_comment_attributes(comment)
attributes[:discussion_id] = discussion_map[comment.parent_id] if comment.has_parent? attributes[:discussion_id] = discussion_map[comment.parent_id] if comment.has_parent?
...@@ -229,7 +224,6 @@ module Gitlab ...@@ -229,7 +224,6 @@ module Gitlab
errors << { type: :pull_request, iid: comment.iid, errors: e.message } errors << { type: :pull_request, iid: comment.iid, errors: e.message }
end end
end end
end
def build_position(merge_request, pr_comment) def build_position(merge_request, pr_comment)
params = { params = {
...@@ -245,13 +239,11 @@ module Gitlab ...@@ -245,13 +239,11 @@ module Gitlab
def import_standalone_pr_comments(pr_comments, merge_request) def import_standalone_pr_comments(pr_comments, merge_request)
pr_comments.each do |comment| pr_comments.each do |comment|
begin
merge_request.notes.create!(pull_request_comment_attributes(comment)) merge_request.notes.create!(pull_request_comment_attributes(comment))
rescue StandardError => e rescue StandardError => e
errors << { type: :pull_request, iid: comment.iid, errors: e.message } errors << { type: :pull_request, iid: comment.iid, errors: e.message }
end end
end end
end
def pull_request_comment_attributes(comment) def pull_request_comment_attributes(comment)
{ {
......
...@@ -162,7 +162,6 @@ module Gitlab ...@@ -162,7 +162,6 @@ module Gitlab
restore_branches(batch) if recover_missing_commits restore_branches(batch) if recover_missing_commits
batch.each do |pull_request| batch.each do |pull_request|
begin
import_bitbucket_pull_request(pull_request) import_bitbucket_pull_request(pull_request)
rescue StandardError => e rescue StandardError => e
backtrace = Gitlab::Profiler.clean_backtrace(e.backtrace) backtrace = Gitlab::Profiler.clean_backtrace(e.backtrace)
...@@ -172,11 +171,9 @@ module Gitlab ...@@ -172,11 +171,9 @@ module Gitlab
end end
end end
end end
end
def delete_temp_branches def delete_temp_branches
@temp_branches.each do |branch| @temp_branches.each do |branch|
begin
client.delete_branch(project_key, repository_slug, branch.name, branch.sha) client.delete_branch(project_key, repository_slug, branch.name, branch.sha)
project.repository.delete_branch(branch.name) project.repository.delete_branch(branch.name)
rescue BitbucketServer::Connection::ConnectionError => e rescue BitbucketServer::Connection::ConnectionError => e
...@@ -184,7 +181,6 @@ module Gitlab ...@@ -184,7 +181,6 @@ module Gitlab
@errors << { type: :delete_temp_branches, branch_name: branch.name, errors: e.message } @errors << { type: :delete_temp_branches, branch_name: branch.name, errors: e.message }
end end
end end
end
def import_bitbucket_pull_request(pull_request) def import_bitbucket_pull_request(pull_request)
log_info(stage: 'import_bitbucket_pull_requests', message: 'starting', iid: pull_request.iid) log_info(stage: 'import_bitbucket_pull_requests', message: 'starting', iid: pull_request.iid)
...@@ -323,7 +319,6 @@ module Gitlab ...@@ -323,7 +319,6 @@ module Gitlab
def import_standalone_pr_comments(pr_comments, merge_request) def import_standalone_pr_comments(pr_comments, merge_request)
pr_comments.each do |comment| pr_comments.each do |comment|
begin
merge_request.notes.create!(pull_request_comment_attributes(comment)) merge_request.notes.create!(pull_request_comment_attributes(comment))
comment.comments.each do |replies| comment.comments.each do |replies|
...@@ -334,7 +329,6 @@ module Gitlab ...@@ -334,7 +329,6 @@ module Gitlab
errors << { type: :pull_request, comment_id: comment.id, errors: e.message } errors << { type: :pull_request, comment_id: comment.id, errors: e.message }
end end
end end
end
def pull_request_comment_attributes(comment) def pull_request_comment_attributes(comment)
author = find_user_id(comment.author_email) author = find_user_id(comment.author_email)
......
...@@ -98,7 +98,7 @@ module Gitlab ...@@ -98,7 +98,7 @@ module Gitlab
def read_uint32(gz) def read_uint32(gz)
binary = gz.read(4) binary = gz.read(4)
binary.unpack('L>')[0] if binary binary.unpack1('L>') if binary
end end
def read_string(gz) def read_string(gz)
......
...@@ -76,7 +76,7 @@ module Gitlab ...@@ -76,7 +76,7 @@ module Gitlab
postgresql? && version.to_f >= 9.4 postgresql? && version.to_f >= 9.4
end end
def self.pg_stat_wal_receiver_supported? def self.postgresql_minimum_supported_version?
postgresql? && version.to_f >= 9.6 postgresql? && version.to_f >= 9.6
end end
...@@ -98,6 +98,10 @@ module Gitlab ...@@ -98,6 +98,10 @@ module Gitlab
Gitlab::Database.postgresql_9_or_less? ? 'pg_last_xlog_replay_location' : 'pg_last_wal_replay_lsn' Gitlab::Database.postgresql_9_or_less? ? 'pg_last_xlog_replay_location' : 'pg_last_wal_replay_lsn'
end end
def self.pg_last_xact_replay_timestamp
'pg_last_xact_replay_timestamp'
end
def self.nulls_last_order(field, direction = 'ASC') def self.nulls_last_order(field, direction = 'ASC')
order = "#{field} #{direction}" order = "#{field} #{direction}"
......
...@@ -35,7 +35,6 @@ module Gitlab ...@@ -35,7 +35,6 @@ module Gitlab
threads = Array.new(thread_count) do threads = Array.new(thread_count) do
Thread.new do Thread.new do
pool.with_connection do |connection| pool.with_connection do |connection|
begin
Thread.current[MULTI_THREAD_AR_CONNECTION] = connection Thread.current[MULTI_THREAD_AR_CONNECTION] = connection
yield yield
ensure ensure
...@@ -43,7 +42,6 @@ module Gitlab ...@@ -43,7 +42,6 @@ module Gitlab
end end
end end
end end
end
threads.each(&:join) if join threads.each(&:join) if join
......
...@@ -22,7 +22,7 @@ module Gitlab ...@@ -22,7 +22,7 @@ module Gitlab
# Casts binary data to a SHA1 in hexadecimal. # Casts binary data to a SHA1 in hexadecimal.
def deserialize(value) def deserialize(value)
value = super(value) value = super(value)
value ? value.unpack(PACK_FORMAT)[0] : nil value ? value.unpack1(PACK_FORMAT) : nil
end end
# Casts a SHA1 in hexadecimal to the proper binary format. # Casts a SHA1 in hexadecimal to the proper binary format.
......
...@@ -75,13 +75,11 @@ module Gitlab ...@@ -75,13 +75,11 @@ module Gitlab
@certs = stub_cert_paths.flat_map do |cert_file| @certs = stub_cert_paths.flat_map do |cert_file|
File.read(cert_file).scan(PEM_REGEX).map do |cert| File.read(cert_file).scan(PEM_REGEX).map do |cert|
begin
OpenSSL::X509::Certificate.new(cert).to_pem OpenSSL::X509::Certificate.new(cert).to_pem
rescue OpenSSL::OpenSSLError => e rescue OpenSSL::OpenSSLError => e
Rails.logger.error "Could not load certificate #{cert_file} #{e}" Rails.logger.error "Could not load certificate #{cert_file} #{e}"
Gitlab::Sentry.track_exception(e, extra: { cert_file: cert_file }) Gitlab::Sentry.track_exception(e, extra: { cert_file: cert_file })
nil nil
end
end.compact end.compact
end.uniq.join("\n") end.uniq.join("\n")
end end
......
...@@ -13,7 +13,6 @@ module Gitlab ...@@ -13,7 +13,6 @@ module Gitlab
current_blob_data = nil current_blob_data = nil
@rpc_response.each do |msg| @rpc_response.each do |msg|
begin
if msg.oid.blank? && msg.data.blank? if msg.oid.blank? && msg.data.blank?
next next
elsif msg.oid.present? elsif msg.oid.present?
...@@ -25,7 +24,6 @@ module Gitlab ...@@ -25,7 +24,6 @@ module Gitlab
current_blob_data[:data] << msg.data current_blob_data[:data] << msg.data
end end
end end
end
yield new_blob(current_blob_data) if current_blob_data yield new_blob(current_blob_data) if current_blob_data
end end
......
...@@ -89,14 +89,12 @@ module Gitlab ...@@ -89,14 +89,12 @@ module Gitlab
def import_labels def import_labels
fetch_resources(:labels, repo, per_page: 100) do |labels| fetch_resources(:labels, repo, per_page: 100) do |labels|
labels.each do |raw| labels.each do |raw|
begin
gh_label = LabelFormatter.new(project, raw) gh_label = LabelFormatter.new(project, raw)
gh_label.create! gh_label.create!
rescue => e rescue => e
errors << { type: :label, url: Gitlab::UrlSanitizer.sanitize(gh_label.url), errors: e.message } errors << { type: :label, url: Gitlab::UrlSanitizer.sanitize(gh_label.url), errors: e.message }
end end
end end
end
cache_labels! cache_labels!
end end
...@@ -104,7 +102,6 @@ module Gitlab ...@@ -104,7 +102,6 @@ module Gitlab
def import_milestones def import_milestones
fetch_resources(:milestones, repo, state: :all, per_page: 100) do |milestones| fetch_resources(:milestones, repo, state: :all, per_page: 100) do |milestones|
milestones.each do |raw| milestones.each do |raw|
begin
gh_milestone = MilestoneFormatter.new(project, raw) gh_milestone = MilestoneFormatter.new(project, raw)
gh_milestone.create! gh_milestone.create!
rescue => e rescue => e
...@@ -112,7 +109,6 @@ module Gitlab ...@@ -112,7 +109,6 @@ module Gitlab
end end
end end
end end
end
# rubocop: disable CodeReuse/ActiveRecord # rubocop: disable CodeReuse/ActiveRecord
def import_issues def import_issues
...@@ -223,7 +219,6 @@ module Gitlab ...@@ -223,7 +219,6 @@ module Gitlab
def create_comments(comments) def create_comments(comments)
ActiveRecord::Base.no_touching do ActiveRecord::Base.no_touching do
comments.each do |raw| comments.each do |raw|
begin
comment = CommentFormatter.new(project, raw, client) comment = CommentFormatter.new(project, raw, client)
# GH does not return info about comment's parent, so we guess it by checking its URL! # GH does not return info about comment's parent, so we guess it by checking its URL!
...@@ -243,7 +238,6 @@ module Gitlab ...@@ -243,7 +238,6 @@ module Gitlab
end end
end end
end end
end
# rubocop: enable CodeReuse/ActiveRecord # rubocop: enable CodeReuse/ActiveRecord
def discard_inserted_comments(comments, last_note) def discard_inserted_comments(comments, last_note)
...@@ -281,7 +275,6 @@ module Gitlab ...@@ -281,7 +275,6 @@ module Gitlab
def import_releases def import_releases
fetch_resources(:releases, repo, per_page: 100) do |releases| fetch_resources(:releases, repo, per_page: 100) do |releases|
releases.each do |raw| releases.each do |raw|
begin
gh_release = ReleaseFormatter.new(project, raw) gh_release = ReleaseFormatter.new(project, raw)
gh_release.create! if gh_release.valid? gh_release.create! if gh_release.valid?
rescue => e rescue => e
...@@ -289,7 +282,6 @@ module Gitlab ...@@ -289,7 +282,6 @@ module Gitlab
end end
end end
end end
end
def cache_labels! def cache_labels!
project.labels.select(:id, :title).find_each do |label| project.labels.select(:id, :title).find_each do |label|
......
...@@ -52,12 +52,10 @@ module Gitlab ...@@ -52,12 +52,10 @@ module Gitlab
pool&.with do |connection| pool&.with do |connection|
prepared.each_slice(settings[:packet_size]) do |slice| prepared.each_slice(settings[:packet_size]) do |slice|
begin
connection.write_points(slice) connection.write_points(slice)
rescue StandardError rescue StandardError
end end
end end
end
rescue Errno::EADDRNOTAVAIL, SocketError => ex rescue Errno::EADDRNOTAVAIL, SocketError => ex
Gitlab::EnvironmentLogger.error('Cannot resolve InfluxDB address. GitLab Performance Monitoring will not work.') Gitlab::EnvironmentLogger.error('Cannot resolve InfluxDB address. GitLab Performance Monitoring will not work.')
Gitlab::EnvironmentLogger.error(ex) Gitlab::EnvironmentLogger.error(ex)
......
...@@ -10,6 +10,7 @@ module GoogleApi ...@@ -10,6 +10,7 @@ module GoogleApi
class Client < GoogleApi::Auth class Client < GoogleApi::Auth
SCOPE = 'https://www.googleapis.com/auth/cloud-platform'.freeze SCOPE = 'https://www.googleapis.com/auth/cloud-platform'.freeze
LEAST_TOKEN_LIFE_TIME = 10.minutes LEAST_TOKEN_LIFE_TIME = 10.minutes
CLUSTER_MASTER_AUTH_USERNAME = 'admin'.freeze
class << self class << self
def session_key_for_token def session_key_for_token
...@@ -64,6 +65,12 @@ module GoogleApi ...@@ -64,6 +65,12 @@ module GoogleApi
"node_config": { "node_config": {
"machine_type": machine_type "machine_type": machine_type
}, },
"master_auth": {
"username": CLUSTER_MASTER_AUTH_USERNAME,
"client_certificate_config": {
issue_client_certificate: true
}
},
"legacy_abac": { "legacy_abac": {
"enabled": legacy_abac "enabled": legacy_abac
} }
......
...@@ -11,7 +11,7 @@ namespace :gitlab do ...@@ -11,7 +11,7 @@ namespace :gitlab do
Ci::Build.joins(:project) Ci::Build.joins(:project)
.with_artifacts_stored_locally .with_artifacts_stored_locally
.find_each(batch_size: 10) do |build| .find_each(batch_size: 10) do |build|
begin
build.artifacts_file.migrate!(ObjectStorage::Store::REMOTE) build.artifacts_file.migrate!(ObjectStorage::Store::REMOTE)
build.artifacts_metadata.migrate!(ObjectStorage::Store::REMOTE) build.artifacts_metadata.migrate!(ObjectStorage::Store::REMOTE)
...@@ -21,5 +21,4 @@ namespace :gitlab do ...@@ -21,5 +21,4 @@ namespace :gitlab do
end end
end end
end end
end
end end
...@@ -9,7 +9,7 @@ namespace :gitlab do ...@@ -9,7 +9,7 @@ namespace :gitlab do
LfsObject.with_files_stored_locally LfsObject.with_files_stored_locally
.find_each(batch_size: 10) do |lfs_object| .find_each(batch_size: 10) do |lfs_object|
begin
lfs_object.file.migrate!(LfsObjectUploader::Store::REMOTE) lfs_object.file.migrate!(LfsObjectUploader::Store::REMOTE)
logger.info("Transferred LFS object #{lfs_object.oid} of size #{lfs_object.size.to_i.bytes} to object storage") logger.info("Transferred LFS object #{lfs_object.oid} of size #{lfs_object.size.to_i.bytes} to object storage")
...@@ -18,5 +18,4 @@ namespace :gitlab do ...@@ -18,5 +18,4 @@ namespace :gitlab do
end end
end end
end end
end
end end
...@@ -26,7 +26,7 @@ namespace :gitlab do ...@@ -26,7 +26,7 @@ namespace :gitlab do
Ci::Build.joins(:project) Ci::Build.joins(:project)
.with_archived_trace_stored_locally .with_archived_trace_stored_locally
.find_each(batch_size: 10) do |build| .find_each(batch_size: 10) do |build|
begin
build.job_artifacts_trace.file.migrate!(ObjectStorage::Store::REMOTE) build.job_artifacts_trace.file.migrate!(ObjectStorage::Store::REMOTE)
logger.info("Transferred job trace of #{build.id} to object storage") logger.info("Transferred job trace of #{build.id} to object storage")
...@@ -35,5 +35,4 @@ namespace :gitlab do ...@@ -35,5 +35,4 @@ namespace :gitlab do
end end
end end
end end
end
end end
...@@ -19,12 +19,10 @@ unless Rails.env.production? ...@@ -19,12 +19,10 @@ unless Rails.env.production?
desc "GitLab | lint | Lint HAML files" desc "GitLab | lint | Lint HAML files"
task :haml do task :haml do
begin
Rake::Task['haml_lint'].invoke Rake::Task['haml_lint'].invoke
rescue RuntimeError # The haml_lint tasks raise a RuntimeError rescue RuntimeError # The haml_lint tasks raise a RuntimeError
exit(1) exit(1)
end end
end
desc "GitLab | lint | Run several lint checks" desc "GitLab | lint | Run several lint checks"
task :all do task :all do
......
...@@ -2,7 +2,6 @@ desc "GitLab | Build internal ids for issues and merge requests" ...@@ -2,7 +2,6 @@ desc "GitLab | Build internal ids for issues and merge requests"
task migrate_iids: :environment do task migrate_iids: :environment do
puts 'Issues'.color(:yellow) puts 'Issues'.color(:yellow)
Issue.where(iid: nil).find_each(batch_size: 100) do |issue| Issue.where(iid: nil).find_each(batch_size: 100) do |issue|
begin
issue.set_iid issue.set_iid
if issue.update_attribute(:iid, issue.iid) if issue.update_attribute(:iid, issue.iid)
...@@ -13,12 +12,10 @@ task migrate_iids: :environment do ...@@ -13,12 +12,10 @@ task migrate_iids: :environment do
rescue rescue
print 'F' print 'F'
end end
end
puts 'done' puts 'done'
puts 'Merge Requests'.color(:yellow) puts 'Merge Requests'.color(:yellow)
MergeRequest.where(iid: nil).find_each(batch_size: 100) do |mr| MergeRequest.where(iid: nil).find_each(batch_size: 100) do |mr|
begin
mr.set_iid mr.set_iid
if mr.update_attribute(:iid, mr.iid) if mr.update_attribute(:iid, mr.iid)
...@@ -29,12 +26,10 @@ task migrate_iids: :environment do ...@@ -29,12 +26,10 @@ task migrate_iids: :environment do
rescue rescue
print 'F' print 'F'
end end
end
puts 'done' puts 'done'
puts 'Milestones'.color(:yellow) puts 'Milestones'.color(:yellow)
Milestone.where(iid: nil).find_each(batch_size: 100) do |m| Milestone.where(iid: nil).find_each(batch_size: 100) do |m|
begin
m.set_iid m.set_iid
if m.update_attribute(:iid, m.iid) if m.update_attribute(:iid, m.iid)
...@@ -45,7 +40,6 @@ task migrate_iids: :environment do ...@@ -45,7 +40,6 @@ task migrate_iids: :environment do
rescue rescue
print 'F' print 'F'
end end
end
puts 'done' puts 'done'
end end
...@@ -966,15 +966,6 @@ msgstr "" ...@@ -966,15 +966,6 @@ msgstr ""
msgid "AutoDevOps|The Auto DevOps pipeline has been enabled and will be used if no alternative CI configuration file is found. %{more_information_link}" msgid "AutoDevOps|The Auto DevOps pipeline has been enabled and will be used if no alternative CI configuration file is found. %{more_information_link}"
msgstr "" msgstr ""
msgid "AutoDevOps|You can automatically build and test your application if you %{link_to_auto_devops_settings} for this project. You can automatically deploy it as well, if you %{link_to_add_kubernetes_cluster}."
msgstr ""
msgid "AutoDevOps|add a Kubernetes cluster"
msgstr ""
msgid "AutoDevOps|enable Auto DevOps"
msgstr ""
msgid "Automatically marked as default internal user" msgid "Automatically marked as default internal user"
msgstr "" msgstr ""
...@@ -2315,6 +2306,9 @@ msgstr "" ...@@ -2315,6 +2306,9 @@ msgstr ""
msgid "Contribution" msgid "Contribution"
msgstr "" msgstr ""
msgid "Contribution Analytics"
msgstr ""
msgid "Contribution Charts" msgid "Contribution Charts"
msgstr "" msgstr ""
...@@ -3373,12 +3367,6 @@ msgstr "" ...@@ -3373,12 +3367,6 @@ msgstr ""
msgid "Except policy:" msgid "Except policy:"
msgstr "" msgstr ""
msgid "Existing Git repository"
msgstr ""
msgid "Existing folder"
msgstr ""
msgid "Existing members and groups" msgid "Existing members and groups"
msgstr "" msgstr ""
...@@ -4073,9 +4061,6 @@ msgstr "" ...@@ -4073,9 +4061,6 @@ msgstr ""
msgid "If enabled" msgid "If enabled"
msgstr "" msgstr ""
msgid "If you already have files you can push them using the %{link_to_cli} below."
msgstr ""
msgid "If your HTTP repository is not publicly accessible, add authentication information to the URL: <code>https://username:password@gitlab.company.com/group/project.git</code>." msgid "If your HTTP repository is not publicly accessible, add authentication information to the URL: <code>https://username:password@gitlab.company.com/group/project.git</code>."
msgstr "" msgstr ""
...@@ -4540,9 +4525,6 @@ msgstr "" ...@@ -4540,9 +4525,6 @@ msgstr ""
msgid "Learn more about Kubernetes" msgid "Learn more about Kubernetes"
msgstr "" msgstr ""
msgid "Learn more about protected branches"
msgstr ""
msgid "Learn more about signing commits" msgid "Learn more about signing commits"
msgstr "" msgstr ""
...@@ -5210,9 +5192,6 @@ msgstr "" ...@@ -5210,9 +5192,6 @@ msgstr ""
msgid "Not started" msgid "Not started"
msgstr "" msgstr ""
msgid "Note that the master branch is automatically protected. %{link_to_protected_branches}"
msgstr ""
msgid "Note that this invitation was sent to %{mail_to_invite_email}, but you are signed in as %{link_to_current_user} with email %{mail_to_current_user}." msgid "Note that this invitation was sent to %{mail_to_invite_email}, but you are signed in as %{link_to_current_user} with email %{mail_to_current_user}."
msgstr "" msgstr ""
...@@ -5404,9 +5383,6 @@ msgstr "" ...@@ -5404,9 +5383,6 @@ msgstr ""
msgid "Other Labels" msgid "Other Labels"
msgstr "" msgstr ""
msgid "Otherwise it is recommended you start with one of the options below."
msgstr ""
msgid "Outbound requests" msgid "Outbound requests"
msgstr "" msgstr ""
...@@ -6265,6 +6241,12 @@ msgstr "" ...@@ -6265,6 +6241,12 @@ msgstr ""
msgid "Push" msgid "Push"
msgstr "" msgstr ""
msgid "Push an existing Git repository"
msgstr ""
msgid "Push an existing folder"
msgstr ""
msgid "Push events" msgid "Push events"
msgstr "" msgstr ""
...@@ -8768,6 +8750,12 @@ msgstr "" ...@@ -8768,6 +8750,12 @@ msgstr ""
msgid "You can also star a label to make it a priority label." msgid "You can also star a label to make it a priority label."
msgstr "" msgstr ""
msgid "You can also upload existing files from your computer using the instructions below."
msgstr ""
msgid "You can create files directly in GitLab using one of the following options."
msgstr ""
msgid "You can easily contribute to them by requesting to join these groups." msgid "You can easily contribute to them by requesting to join these groups."
msgstr "" msgstr ""
...@@ -8972,9 +8960,6 @@ msgstr "" ...@@ -8972,9 +8960,6 @@ msgstr ""
msgid "branch name" msgid "branch name"
msgstr "" msgstr ""
msgid "command line instructions"
msgstr ""
msgid "commented on %{link_to_project}" msgid "commented on %{link_to_project}"
msgstr "" msgstr ""
......
This diff is collapsed.
...@@ -61,6 +61,7 @@ module QA ...@@ -61,6 +61,7 @@ module QA
autoload :File, 'qa/resource/file' autoload :File, 'qa/resource/file'
autoload :Fork, 'qa/resource/fork' autoload :Fork, 'qa/resource/fork'
autoload :SSHKey, 'qa/resource/ssh_key' autoload :SSHKey, 'qa/resource/ssh_key'
autoload :Snippet, 'qa/resource/snippet'
module Events module Events
autoload :Base, 'qa/resource/events/base' autoload :Base, 'qa/resource/events/base'
...@@ -142,6 +143,12 @@ module QA ...@@ -142,6 +143,12 @@ module QA
module Dashboard module Dashboard
autoload :Projects, 'qa/page/dashboard/projects' autoload :Projects, 'qa/page/dashboard/projects'
autoload :Groups, 'qa/page/dashboard/groups' autoload :Groups, 'qa/page/dashboard/groups'
module Snippet
autoload :New, 'qa/page/dashboard/snippet/new'
autoload :Index, 'qa/page/dashboard/snippet/index'
autoload :Show, 'qa/page/dashboard/snippet/show'
end
end end
module Group module Group
......
...@@ -2,8 +2,6 @@ module QA ...@@ -2,8 +2,6 @@ module QA
module Page module Page
module Dashboard module Dashboard
class Projects < Page::Base class Projects < Page::Base
view 'app/views/dashboard/projects/index.html.haml'
view 'app/views/shared/projects/_search_form.html.haml' do view 'app/views/shared/projects/_search_form.html.haml' do
element :form_filter_by_name, /form_tag.+id: 'project-filter-form'/ # rubocop:disable QA/ElementWithPattern element :form_filter_by_name, /form_tag.+id: 'project-filter-form'/ # rubocop:disable QA/ElementWithPattern
end end
......
# frozen_string_literal: true
module QA
module Page
module Dashboard
module Snippet
class Index < Page::Base
view 'app/views/layouts/header/_new_dropdown.haml' do
element :new_menu_toggle
element :global_new_snippet_link
end
def go_to_new_snippet_page
click_element :new_menu_toggle
click_element :global_new_snippet_link
end
end
end
end
end
end
# frozen_string_literal: true
module QA
module Page
module Dashboard
module Snippet
class New < Page::Base
view 'app/views/shared/form_elements/_description.html.haml' do
element :issuable_form_description
end
view 'app/views/shared/snippets/_form.html.haml' do
element :snippet_title
element :snippet_file_name
element :create_snippet_button
end
def fill_title(title)
fill_element :snippet_title, title
end
def fill_description(description)
fill_element :issuable_form_description, description
end
def set_visibility(visibility)
choose visibility
end
def fill_file_name(name)
finished_loading?
fill_element :snippet_file_name, name
end
def fill_file_content(content)
finished_loading?
text_area.set content
end
def create_snippet
click_element :create_snippet_button
end
private
def text_area
find('#editor>textarea', visible: false)
end
end
end
end
end
end
# frozen_string_literal: true
module QA
module Page
module Dashboard
module Snippet
class Show < Page::Base
view 'app/views/shared/snippets/_header.html.haml' do
element :snippet_title
element :snippet_description
element :embed_type
element :snippet_box
end
view 'app/views/projects/blob/_header_content.html.haml' do
element :file_title_name
end
view 'app/views/shared/_file_highlight.html.haml' do
element :file_content
end
def has_snippet_title?(snippet_title)
within_element(:snippet_title) do
has_text?(snippet_title)
end
end
def has_snippet_description?(snippet_description)
within_element(:snippet_description) do
has_text?(snippet_description)
end
end
def has_embed_type?(embed_type)
within_element(:embed_type) do
has_text?(embed_type)
end
end
def has_visibility_type?(visibility_type)
within_element(:snippet_box) do
has_text?(visibility_type)
end
end
def has_file_name?(file_name)
within_element(:file_title_name) do
has_text?(file_name)
end
end
def has_file_content?(file_content)
finished_loading?
within_element(:file_content) do
has_text?(file_content)
end
end
end
end
end
end
end
...@@ -19,6 +19,7 @@ module QA ...@@ -19,6 +19,7 @@ module QA
element :admin_area_link element :admin_area_link
element :projects_dropdown element :projects_dropdown
element :groups_dropdown element :groups_dropdown
element :snippets_link
end end
view 'app/views/layouts/nav/projects_dropdown/_show.html.haml' do view 'app/views/layouts/nav/projects_dropdown/_show.html.haml' do
...@@ -66,6 +67,10 @@ module QA ...@@ -66,6 +67,10 @@ module QA
end end
end end
def go_to_snippets
click_element :snippets_link
end
def has_personal_area?(wait: Capybara.default_max_wait_time) def has_personal_area?(wait: Capybara.default_max_wait_time)
has_element?(:user_avatar, wait: wait) has_element?(:user_avatar, wait: wait)
end end
......
...@@ -43,12 +43,10 @@ module QA ...@@ -43,12 +43,10 @@ module QA
def create_new_file_from_template(file_name, template) def create_new_file_from_template(file_name, template)
click_element :new_file click_element :new_file
within_element(:template_list) do within_element(:template_list) do
begin
click_on file_name click_on file_name
rescue Capybara::ElementNotFound rescue Capybara::ElementNotFound
raise ElementNotFound, %Q(Couldn't find file template named "#{file_name}". Please confirm that it is a valid option.) raise ElementNotFound, %Q(Couldn't find file template named "#{file_name}". Please confirm that it is a valid option.)
end end
end
wait(reload: false) do wait(reload: false) do
within_element(:file_templates_bar) do within_element(:file_templates_bar) do
......
# frozen_string_literal: true
module QA
module Resource
class Snippet < Base
attr_accessor :title, :description, :file_content, :visibility, :file_name
def initialize
@title = 'New snippet title'
@description = 'The snippet description'
@visibility = 'Public'
@file_content = 'The snippet content'
@file_name = 'New snippet file name'
end
def fabricate!
Page::Dashboard::Snippet::Index.perform(&:go_to_new_snippet_page)
Page::Dashboard::Snippet::New.perform do |page|
page.fill_title(@title)
page.fill_description(@description)
page.set_visibility(@visibility)
page.fill_file_name(@file_name)
page.fill_file_content(@file_content)
page.create_snippet
end
end
end
end
end
# frozen_string_literal: true
module QA
context 'Create', :smoke do
describe 'Snippet creation' do
it 'User creates a snippet' do
Runtime::Browser.visit(:gitlab, Page::Main::Login)
Page::Main::Login.perform(&:sign_in_using_credentials)
Page::Main::Menu.perform(&:go_to_snippets)
Resource::Snippet.fabricate_via_browser_ui! do |snippet|
snippet.title = 'Snippet title'
snippet.description = 'Snippet description'
snippet.visibility = 'Public'
snippet.file_name = 'New snippet file name'
snippet.file_content = 'Snippet file text'
end
Page::Dashboard::Snippet::Show.perform do |snippet|
expect(snippet).to have_snippet_title('Snippet title')
expect(snippet).to have_snippet_description('Snippet description')
expect(snippet).to have_embed_type('Embed')
expect(snippet).to have_visibility_type('Public')
expect(snippet).to have_file_name('New snippet file name')
expect(snippet).to have_file_content('Snippet file text')
end
end
end
end
end
# frozen_string_literal: true # frozen_string_literal: true
module QA module QA
context 'Create' do # Failure issue: https://gitlab.com/gitlab-org/quality/staging/issues/46
context 'Create', :quarantine do
describe 'Web IDE file templates' do describe 'Web IDE file templates' do
include Runtime::Fixtures include Runtime::Fixtures
......
...@@ -79,7 +79,6 @@ module GitalyTest ...@@ -79,7 +79,6 @@ module GitalyTest
socket = read_socket_path socket = read_socket_path
Integer(timeout / delay).times do Integer(timeout / delay).times do
begin
UNIXSocket.new(socket) UNIXSocket.new(socket)
puts ' OK' puts ' OK'
...@@ -88,7 +87,6 @@ module GitalyTest ...@@ -88,7 +87,6 @@ module GitalyTest
print '.' print '.'
sleep delay sleep delay
end end
end
puts ' FAILED' puts ' FAILED'
......
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
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