Commit ab44f531 authored by Filipa Lacerda's avatar Filipa Lacerda

Merge branch 'master' into 25990-web-terminal-improvements

* master: (66 commits)
  Allows to cancel a Created job
  Enable frozen string in rest of app/models/**/*.rb
  docs: removed duplicate `git_ssh_url` field from build event example
  Bump pry to 0.11.3; pry-byebug to 3.4.3
  Update GitLab Shell to v8.1.1 to fix regressions
  Rails5 fix specs duplicate key value violates unique constraint 'index_gpg_signatures_on_commit_sha'
  Add mock data for spam logs
  Disable danger in preparation branches
  [ci-skip] add changelog
  Add default avatar to group
  Fix label item height when no desc
  Fix docs linting
  Fix missed port
  Consistent padding but correct label-actions-list positioning and label-links margin
  Phase 2: #47282 Improving Contributor On-Boarding Documentation
  Fix label item height when no desc
  Resolve "docs update api for usage with an array of hashes"
  removed un-used commits for currentProject & currentBranchId
  Allow the Web IDE to open empty merge requests
  Add rubocop check for add_reference to require index.
  ...
parents b4f9379e 91795dcd
......@@ -453,6 +453,7 @@ danger-review:
- master
variables:
- $CI_COMMIT_REF_NAME =~ /^ce-to-ee-.*/
- $CI_COMMIT_REF_NAME =~ /.*-stable(-ee)?-prepare-.*/
script:
- git version
- danger --fail-on-errors=true
......
This diff is collapsed.
......@@ -123,7 +123,7 @@ GEM
numerizer (~> 0.1.1)
chunky_png (1.3.5)
citrus (3.0.2)
coderay (1.1.1)
coderay (1.1.2)
coercible (1.0.0)
descendants_tracker (~> 0.0.1)
commonmarker (0.17.8)
......@@ -494,7 +494,7 @@ GEM
memoist (0.16.0)
memoizable (0.4.2)
thread_safe (~> 0.3, >= 0.3.1)
method_source (0.8.2)
method_source (0.9.0)
mime-types (3.1)
mime-types-data (~> 3.2015)
mime-types-data (3.2016.0521)
......@@ -636,12 +636,11 @@ GEM
unparser
procto (0.0.3)
prometheus-client-mmap (0.9.4)
pry (0.10.4)
pry (0.11.3)
coderay (~> 1.1.0)
method_source (~> 0.8.1)
slop (~> 3.4)
pry-byebug (3.4.2)
byebug (~> 9.0)
method_source (~> 0.9.0)
pry-byebug (3.4.3)
byebug (>= 9.0, < 9.1)
pry (~> 0.10)
pry-rails (0.3.5)
pry (>= 0.9.10)
......@@ -872,7 +871,6 @@ GEM
simplecov-html (~> 0.10.0)
simplecov-html (0.10.0)
slack-notifier (1.5.1)
slop (3.6.0)
spring (2.0.1)
activesupport (>= 4.2)
spring-commands-rspec (1.0.4)
......@@ -1207,4 +1205,4 @@ DEPENDENCIES
wikicloth (= 0.8.1)
BUNDLED WITH
1.16.2
1.16.3
......@@ -117,7 +117,7 @@ router.beforeEach((to, from, next) => {
mergeRequestId: to.params.mrid,
})
.then(mr => {
store.dispatch('updateActivityBarView', activityBarViews.review);
store.dispatch('setCurrentBranchId', mr.source_branch);
store.dispatch('getBranchData', {
projectId: fullProjectId,
......@@ -144,6 +144,10 @@ router.beforeEach((to, from, next) => {
}),
)
.then(mrChanges => {
if (mrChanges.changes.length) {
store.dispatch('updateActivityBarView', activityBarViews.review);
}
mrChanges.changes.forEach((change, ind) => {
const changeTreeEntry = store.state.entries[change.new_path];
......
......@@ -54,9 +54,6 @@ export const setFileActive = ({ commit, state, getters, dispatch }, path) => {
commit(types.SET_FILE_ACTIVE, { path, active: true });
dispatch('scrollToTab');
commit(types.SET_CURRENT_PROJECT, file.projectId);
commit(types.SET_CURRENT_BRANCH, file.branchId);
};
export const getFileData = ({ state, commit, dispatch }, { path, makeFileActive = true }) => {
......
import initForm from '../form';
import MirrorRepos from './mirror_repos';
document.addEventListener('DOMContentLoaded', initForm);
document.addEventListener('DOMContentLoaded', () => {
initForm();
const mirrorReposContainer = document.querySelector('.js-mirror-settings');
if (mirrorReposContainer) new MirrorRepos(mirrorReposContainer).init();
});
import $ from 'jquery';
import _ from 'underscore';
import { __ } from '~/locale';
import Flash from '~/flash';
import axios from '~/lib/utils/axios_utils';
export default class MirrorRepos {
constructor(container) {
this.$container = $(container);
this.$form = $('.js-mirror-form', this.$container);
this.$urlInput = $('.js-mirror-url', this.$form);
this.$protectedBranchesInput = $('.js-mirror-protected', this.$form);
this.$table = $('.js-mirrors-table-body', this.$container);
this.mirrorEndpoint = this.$form.data('projectMirrorEndpoint');
}
init() {
this.initMirrorPush();
this.registerUpdateListeners();
}
initMirrorPush() {
this.$passwordGroup = $('.js-password-group', this.$container);
this.$password = $('.js-password', this.$passwordGroup);
this.$authMethod = $('.js-auth-method', this.$form);
this.$authMethod.on('change', () => this.togglePassword());
this.$password.on('input.updateUrl', () => this.debouncedUpdateUrl());
}
updateUrl() {
let val = this.$urlInput.val();
if (this.$password) {
const password = this.$password.val();
if (password) val = val.replace('@', `:${password}@`);
}
$('.js-mirror-url-hidden', this.$form).val(val);
}
updateProtectedBranches() {
const val = this.$protectedBranchesInput.get(0).checked
? this.$protectedBranchesInput.val()
: '0';
$('.js-mirror-protected-hidden', this.$form).val(val);
}
registerUpdateListeners() {
this.debouncedUpdateUrl = _.debounce(() => this.updateUrl(), 200);
this.$urlInput.on('input', () => this.debouncedUpdateUrl());
this.$protectedBranchesInput.on('change', () => this.updateProtectedBranches());
this.$table.on('click', '.js-delete-mirror', event => this.deleteMirror(event));
}
togglePassword() {
const isPassword = this.$authMethod.val() === 'password';
if (!isPassword) {
this.$password.val('');
this.updateUrl();
}
this.$passwordGroup.collapse(isPassword ? 'show' : 'hide');
}
deleteMirror(event, existingPayload) {
const $target = $(event.currentTarget);
let payload = existingPayload;
if (!payload) {
payload = {
project: {
remote_mirrors_attributes: {
id: $target.data('mirrorId'),
enabled: 0,
},
},
};
}
return axios
.put(this.mirrorEndpoint, payload)
.then(() => this.removeRow($target))
.catch(() => Flash(__('Failed to remove mirror.')));
}
/* eslint-disable class-methods-use-this */
removeRow($target) {
const row = $target.closest('tr');
$('.js-delete-mirror', row).tooltip('hide');
row.remove();
}
/* eslint-enable class-methods-use-this */
}
<script>
import { mapActions, mapGetters, mapState } from 'vuex';
import { s__ } from '~/locale';
import { componentNames } from '~/vue_shared/components/reports/issue_body';
import ReportSection from '~/vue_shared/components/reports/report_section.vue';
import SummaryRow from '~/vue_shared/components/reports/summary_row.vue';
import IssuesList from '~/vue_shared/components/reports/issues_list.vue';
import { componentNames } from './issue_body';
import ReportSection from './report_section.vue';
import SummaryRow from './summary_row.vue';
import IssuesList from './issues_list.vue';
import Modal from './modal.vue';
import createStore from '../store';
import { summaryTextBuilder, reportTextBuilder, statusIcon } from '../store/utils';
......
import TestIssueBody from '~/reports/components/test_issue_body.vue';
import TestIssueBody from './test_issue_body.vue';
export const components = {
TestIssueBody,
......
<script>
import Icon from '~/vue_shared/components/icon.vue';
import {
STATUS_FAILED,
STATUS_NEUTRAL,
STATUS_SUCCESS,
} from '~/vue_shared/components/reports/constants';
} from '../constants';
export default {
name: 'IssueStatusIcon',
......
<script>
import IssuesBlock from '~/vue_shared/components/reports/report_issues.vue';
import IssuesBlock from './report_issues.vue';
import {
STATUS_SUCCESS,
STATUS_FAILED,
STATUS_NEUTRAL,
} from '~/vue_shared/components/reports/constants';
} from '../constants';
/**
* Renders block of issues
......
<script>
import IssueStatusIcon from '~/vue_shared/components/reports/issue_status_icon.vue';
import { components, componentNames } from '~/vue_shared/components/reports/issue_body';
import IssueStatusIcon from './issue_status_icon.vue';
import { components, componentNames } from './issue_body';
export default {
name: 'ReportIssues',
......
<script>
import { __ } from '~/locale';
import StatusIcon from '~/vue_merge_request_widget/components/mr_widget_status_icon.vue';
import Popover from '~/vue_shared/components/help_popover.vue';
import IssuesList from './issues_list.vue';
import Popover from '../help_popover.vue';
const LOADING = 'LOADING';
const ERROR = 'ERROR';
......
<script>
import CiIcon from '~/vue_shared/components/ci_icon.vue';
import LoadingIcon from '~/vue_shared/components/loading_icon.vue';
import Popover from '../help_popover.vue';
import Popover from '~/vue_shared/components/help_popover.vue';
/**
* Renders the summary row for each report
......
......@@ -11,6 +11,8 @@ export const SUCCESS = 'SUCCESS';
export const STATUS_FAILED = 'failed';
export const STATUS_SUCCESS = 'success';
export const STATUS_NEUTRAL = 'neutral';
export const ICON_WARNING = 'warning';
export const ICON_SUCCESS = 'success';
export const ICON_NOTFOUND = 'notfound';
export const STATUS_FAILED = 'failed';
export const STATUS_SUCCESS = 'success';
export const STATUS_NEUTRAL = 'neutral';
......@@ -103,6 +103,7 @@
display: flex;
a {
width: 100%;
display: flex;
}
......
......@@ -201,7 +201,7 @@ label {
}
.gl-show-field-errors {
.form-control {
.form-control:not(textarea) {
height: 34px;
}
......
......@@ -253,7 +253,7 @@
text-align: right;
padding: 0;
position: relative;
top: -3px;
margin: 0;
}
.label-badge {
......@@ -274,6 +274,7 @@
.label-links {
list-style: none;
margin: 0;
padding: 0;
white-space: nowrap;
}
......
......@@ -823,10 +823,6 @@ pre.light-well {
.avatar-container {
align-self: flex-start;
> a {
width: 100%;
}
}
.project-details {
......
......@@ -301,3 +301,17 @@
margin-bottom: 0;
}
}
.mirror-error-badge {
background-color: $error-bg;
border-radius: $border-radius-default;
color: $white-light;
}
.push-pull-table {
margin-top: 1em;
.mirror-action-buttons {
padding-right: 0;
}
}
module AvatarsHelper
def project_icon(project_id, options = {})
project =
if project_id.respond_to?(:avatar_url)
project_id
else
Project.find_by_full_path(project_id)
end
if project.avatar_url
image_tag project.avatar_url, options
else # generated icon
project_identicon(project, options)
end
source_icon(Project, project_id, options)
end
def project_identicon(project, options = {})
bg_key = (project.id % 7) + 1
options[:class] ||= ''
options[:class] << ' identicon'
options[:class] << " bg#{bg_key}"
content_tag(:div, class: options[:class]) do
project.name[0, 1].upcase
end
def group_icon(group_id, options = {})
source_icon(Group, group_id, options)
end
# Takes both user and email and returns the avatar_icon by
......@@ -123,4 +105,32 @@ module AvatarsHelper
mail_to(options[:user_email], avatar)
end
end
private
def source_icon(klass, source_id, options = {})
source =
if source_id.respond_to?(:avatar_url)
source_id
else
klass.find_by_full_path(source_id)
end
if source.avatar_url
image_tag source.avatar_url, options
else
source_identicon(source, options)
end
end
def source_identicon(source, options = {})
bg_key = (source.id % 7) + 1
options[:class] ||= ''
options[:class] << ' identicon'
options[:class] << " bg#{bg_key}"
content_tag(:div, class: options[:class].strip) do
source.name[0, 1].upcase
end
end
end
......@@ -33,11 +33,6 @@ module GroupsHelper
.count
end
def group_icon(group, options = {})
img_path = group_icon_url(group, options)
image_tag img_path, options
end
def group_icon_url(group, options = {})
if group.is_a?(String)
group = Group.find_by_full_path(group)
......
module MirrorHelper
def mirrors_form_data_attributes
{ project_mirror_endpoint: project_mirror_path(@project) }
end
end
......@@ -226,7 +226,7 @@ module Ci
end
def cancelable?
active?
active? || created?
end
def retryable?
......
# frozen_string_literal: true
class ProgrammingLanguage < ActiveRecord::Base
validates :name, presence: true
validates :color, allow_blank: false, color: true
......
......@@ -470,6 +470,24 @@ class Project < ActiveRecord::Base
}x
end
def reference_postfix
'>'
end
def reference_postfix_escaped
'&gt;'
end
# Pattern used to extract `namespace/project>` project references from text.
# '>' or its escaped form ('&gt;') are checked for because '>' is sometimes escaped
# when the reference comes from an external source.
def markdown_reference_pattern
%r{
#{reference_pattern}
(#{reference_postfix}|#{reference_postfix_escaped})
}x
end
def trending
joins('INNER JOIN trending_projects ON projects.id = trending_projects.project_id')
.reorder('trending_projects.id ASC')
......@@ -908,6 +926,10 @@ class Project < ActiveRecord::Base
end
end
def to_reference_with_postfix
"#{to_reference(full: true)}#{self.class.reference_postfix}"
end
# `from` argument can be a Namespace or Project.
def to_reference(from = nil, full: false)
if full || cross_namespace_reference?(from)
......
# frozen_string_literal: true
require 'asana'
class AsanaService < Service
......
# frozen_string_literal: true
class AssemblaService < Service
prop_accessor :token, :subdomain
validates :token, presence: true, if: :activated?
......
# frozen_string_literal: true
class BambooService < CiService
include ReactiveService
......
# frozen_string_literal: true
class BugzillaService < IssueTrackerService
validates :project_url, :issues_url, :new_issue_url, presence: true, public_url: true, if: :activated?
......
# frozen_string_literal: true
require "addressable/uri"
class BuildkiteService < CiService
......
# frozen_string_literal: true
# This class is to be removed with 9.1
# We should also by then remove BuildsEmailService from database
class BuildsEmailService < Service
......
# frozen_string_literal: true
class CampfireService < Service
prop_accessor :token, :subdomain, :room
validates :token, presence: true, if: :activated?
......@@ -82,7 +84,7 @@ class CampfireService < Service
before = push[:before]
after = push[:after]
message = ""
message = []
message << "[#{project.full_name}] "
message << "#{push[:user_name]} "
......@@ -95,6 +97,6 @@ class CampfireService < Service
message << "#{project.web_url}/compare/#{before}...#{after}"
end
message
message.join
end
end
# frozen_string_literal: true
require 'slack-notifier'
module ChatMessage
......
# frozen_string_literal: true
module ChatMessage
class IssueMessage < BaseMessage
attr_reader :title
......
# frozen_string_literal: true
module ChatMessage
class MergeMessage < BaseMessage
attr_reader :merge_request_iid
......
# frozen_string_literal: true
module ChatMessage
class NoteMessage < BaseMessage
attr_reader :note
......
# frozen_string_literal: true
module ChatMessage
class PipelineMessage < BaseMessage
attr_reader :ref_type
......
# frozen_string_literal: true
module ChatMessage
class PushMessage < BaseMessage
attr_reader :after
......
# frozen_string_literal: true
module ChatMessage
class WikiPageMessage < BaseMessage
attr_reader :title
......
# frozen_string_literal: true
# Base class for Chat notifications services
# This class is not meant to be used directly, but only to inherit from.
class ChatNotificationService < Service
......
# frozen_string_literal: true
# Base class for CI services
# List methods you need to implement to get your CI service
# working with GitLab Merge Requests
......
# frozen_string_literal: true
class CustomIssueTrackerService < IssueTrackerService
validates :project_url, :issues_url, :new_issue_url, presence: true, public_url: true, if: :activated?
......
# frozen_string_literal: true
# Base class for deployment services
#
# These services integrate with a deployment solution like Kubernetes/OpenShift,
......
# frozen_string_literal: true
class DroneCiService < CiService
include ReactiveService
......
# frozen_string_literal: true
class EmailsOnPushService < Service
boolean_accessor :send_from_committer_email
boolean_accessor :disable_diffs
......
# frozen_string_literal: true
class ExternalWikiService < Service
prop_accessor :external_wiki_url
......
# frozen_string_literal: true
require "flowdock-git-hook"
# Flow dock depends on Grit to compute the number of commits between two given
......
# frozen_string_literal: true
require "gemnasium/gitlab_service"
class GemnasiumService < Service
......
# frozen_string_literal: true
class GitlabIssueTrackerService < IssueTrackerService
include Gitlab::Routing
......
# frozen_string_literal: true
require 'hangouts_chat'
class HangoutsChatService < ChatNotificationService
......
# frozen_string_literal: true
class HipchatService < Service
include ActionView::Helpers::SanitizeHelper
......@@ -108,7 +110,7 @@ class HipchatService < Service
before = push[:before]
after = push[:after]
message = ""
message = []
message << "#{push[:user_name]} "
if Gitlab::Git.blank_ref?(before)
......@@ -132,7 +134,7 @@ class HipchatService < Service
end
end
message
message.join
end
def markdown(text, options = {})
......@@ -165,11 +167,11 @@ class HipchatService < Service
description = obj_attr[:description]
issue_link = "<a href=\"#{issue_url}\">issue ##{issue_iid}</a>"
message = "#{user_name} #{state} #{issue_link} in #{project_link}: <b>#{title}</b>"
message = ["#{user_name} #{state} #{issue_link} in #{project_link}: <b>#{title}</b>"]
message << "<pre>#{markdown(description)}</pre>"
message
message.join
end
def create_merge_request_message(data)
......@@ -184,12 +186,11 @@ class HipchatService < Service
merge_request_url = "#{project_url}/merge_requests/#{merge_request_id}"
merge_request_link = "<a href=\"#{merge_request_url}\">merge request !#{merge_request_id}</a>"
message = "#{user_name} #{state} #{merge_request_link} in " \
"#{project_link}: <b>#{title}</b>"
message = ["#{user_name} #{state} #{merge_request_link} in " \
"#{project_link}: <b>#{title}</b>"]
message << "<pre>#{markdown(description)}</pre>"
message
message.join
end
def format_title(title)
......@@ -235,12 +236,11 @@ class HipchatService < Service
end
subject_html = "<a href=\"#{note_url}\">#{subject_type} #{subject_desc}</a>"
message = "#{user_name} commented on #{subject_html} in #{project_link}: "
message = ["#{user_name} commented on #{subject_html} in #{project_link}: "]
message << title
message << "<pre>#{markdown(note, ref: commit_id)}</pre>"
message
message.join
end
def create_pipeline_message(data)
......
# frozen_string_literal: true
require 'uri'
class IrkerService < Service
......
# frozen_string_literal: true
class IssueTrackerService < Service
validate :one_issue_tracker, if: :activated?, on: :manual_change
......
# frozen_string_literal: true
class JiraService < IssueTrackerService
include Gitlab::Routing
include ApplicationHelper
......
# frozen_string_literal: true
##
# NOTE:
# We'll move this class to Clusters::Platforms::Kubernetes, which contains exactly the same logic.
......
# frozen_string_literal: true
class MattermostService < ChatNotificationService
def title
'Mattermost notifications'
......
# frozen_string_literal: true
class MattermostSlashCommandsService < SlashCommandsService
include TriggersHelper
......
# frozen_string_literal: true
class MicrosoftTeamsService < ChatNotificationService
def title
'Microsoft Teams Notification'
......
# frozen_string_literal: true
# For an example companion mocking service, see https://gitlab.com/gitlab-org/gitlab-mock-ci-service
class MockCiService < CiService
ALLOWED_STATES = %w[failed canceled running pending success success_with_warnings skipped not_found].freeze
......
# frozen_string_literal: true
class MockDeploymentService < DeploymentService
def title
'Mock deployment'
......
# frozen_string_literal: true
class MockMonitoringService < MonitoringService
def title
'Mock monitoring'
......
# frozen_string_literal: true
# Base class for monitoring services
#
# These services integrate with a deployment solution like Prometheus
......
# frozen_string_literal: true
class PackagistService < Service
prop_accessor :username, :token, :server
......
# frozen_string_literal: true
class PipelinesEmailService < Service
prop_accessor :recipients
boolean_accessor :notify_only_broken_pipelines
......
# frozen_string_literal: true
class PivotaltrackerService < Service
API_ENDPOINT = 'https://www.pivotaltracker.com/services/v5/source_commits'.freeze
......
# frozen_string_literal: true
class PrometheusService < MonitoringService
include PrometheusAdapter
......
# frozen_string_literal: true
class PushoverService < Service
BASE_URI = 'https://api.pushover.net/1'.freeze
......@@ -79,7 +81,7 @@ class PushoverService < Service
end
if data[:total_commits_count] > 0
message << "\nTotal commits count: #{data[:total_commits_count]}"
message = [message, "Total commits count: #{data[:total_commits_count]}"].join("\n")
end
pushover_data = {
......
# frozen_string_literal: true
class RedmineService < IssueTrackerService
validates :project_url, :issues_url, :new_issue_url, presence: true, public_url: true, if: :activated?
......
# frozen_string_literal: true
class SlackService < ChatNotificationService
def title
'Slack notifications'
......
# frozen_string_literal: true
class SlackSlashCommandsService < SlashCommandsService
include TriggersHelper
......
# frozen_string_literal: true
# Base class for Chat services
# This class is not meant to be used directly, but only to inherrit from.
class SlashCommandsService < Service
......
# frozen_string_literal: true
class TeamcityService < CiService
include ReactiveService
......
# frozen_string_literal: true
class ProtectedBranch::MergeAccessLevel < ActiveRecord::Base
include ProtectedBranchAccess
end
# frozen_string_literal: true
class ProtectedBranch::PushAccessLevel < ActiveRecord::Base
include ProtectedBranchAccess
end
# frozen_string_literal: true
class ProtectedTag::CreateAccessLevel < ActiveRecord::Base
include ProtectedTagAccess
......
# frozen_string_literal: true
class RepositoryLanguage < ActiveRecord::Base
belongs_to :project
belongs_to :programming_language
......
# frozen_string_literal: true
class SiteStatistic < ActiveRecord::Base
# prevents the creation of multiple rows
default_value_for :id, 1
......
# frozen_string_literal: true
module Storage
class HashedProject
attr_accessor :project
......
# frozen_string_literal: true
module Storage
class LegacyProject
attr_accessor :project
......
class ProjectMirrorSerializer < BaseSerializer
entity ProjectMirrorEntity
end
......@@ -5,7 +5,7 @@
.bordered-box.fork-thumbnail.text-center.prepend-left-default.append-right-default.prepend-top-default.append-bottom-default.forked
= link_to project_path(forked_project) do
- if /no_((\w*)_)*avatar/.match(avatar)
= project_identicon(namespace, class: "avatar s100 identicon")
= project_icon(namespace, class: "avatar s100 identicon")
- else
.avatar-container.s100
= image_tag(avatar, class: "avatar s100")
......@@ -18,7 +18,7 @@
class: ("disabled has-tooltip" unless can_create_project),
title: (_('You have reached your project limit') unless can_create_project) do
- if /no_((\w*)_)*avatar/.match(avatar)
= project_identicon(namespace, class: "avatar s100 identicon")
= project_icon(namespace, class: "avatar s100 identicon")
- else
.avatar-container.s100
= image_tag(avatar, class: "avatar s100")
......
.account-well.prepend-top-default.append-bottom-default
%ul
%li
The repository must be accessible over <code>http://</code>, <code>https://</code>, <code>ssh://</code> or <code>git://</code>.
%li
Include the username in the URL if required: <code>https://username@gitlab.company.com/group/project.git</code>.
%li
The update action will time out after 10 minutes. For big repositories, use a clone/push combination.
%li
The Git LFS objects will <strong>not</strong> be synced.
= _('The repository must be accessible over <code>http://</code>,
<code>https://</code>, <code>ssh://</code> and <code>git://</code>.').html_safe
%li= _('Include the username in the URL if required: <code>https://username@gitlab.company.com/group/project.git</code>.').html_safe
%li= _('The update action will time out after 15 minutes. For big repositories, use a clone/push combination.')
%li= _('The Git LFS objects will <strong>not</strong> be synced.').html_safe
%li
= _('This user will be the author of all events in the activity feed that are the result of an update,
like new branches being created or new commits being pushed to existing branches.')
- expanded = Rails.env.test?
- protocols = Gitlab::UrlSanitizer::ALLOWED_SCHEMES.join('|')
%section.settings.project-mirror-settings.js-mirror-settings.no-animate{ class: ('expanded' if expanded) }
.settings-header
%h4= _('Mirroring repositories')
%button.btn.js-settings-toggle
= expanded ? _('Collapse') : _('Expand')
%p
= _('Set up your project to automatically push and/or pull changes to/from another repository. Branches, tags, and commits will be synced automatically.')
= link_to _('Read more'), help_page_path('workflow/repository_mirroring'), target: '_blank'
.settings-content
= form_for @project, url: project_mirror_path(@project), html: { class: 'gl-show-field-errors js-mirror-form', autocomplete: 'false', data: mirrors_form_data_attributes } do |f|
.panel.panel-default
.panel-heading
%h3.panel-title= _('Mirror a repository')
.panel-body
%div= form_errors(@project)
.form-group.has-feedback
= label_tag :url, _('Git repository URL'), class: 'label-light'
= text_field_tag :url, nil, class: 'form-control js-mirror-url js-repo-url', placeholder: _('Input your repository URL'), required: true, pattern: "(#{protocols}):\/\/.+"
= render 'projects/mirrors/instructions'
= render 'projects/mirrors/mirror_repos_form', f: f
.form-check.append-bottom-10
= check_box_tag :only_protected_branches, '1', false, class: 'js-mirror-protected form-check-input'
= label_tag :only_protected_branches, _('Only mirror protected branches'), class: 'form-check-label'
= link_to icon('question-circle'), help_page_path('user/project/protected_branches')
.panel-footer
= f.submit _('Mirror repository'), class: 'btn btn-create', name: :update_remote_mirror
.panel.panel-default
.table-responsive
%table.table.push-pull-table
%thead
%tr
%th
= _('Mirrored repositories')
= render_if_exists 'projects/mirrors/mirrored_repositories_count'
%th= _('Direction')
%th= _('Last update')
%th
%th
%tbody.js-mirrors-table-body
= render_if_exists 'projects/mirrors/table_pull_row'
- @project.remote_mirrors.each_with_index do |mirror, index|
- if mirror.enabled
%tr
%td= mirror.safe_url
%td= _('Push')
%td= mirror.last_update_at.present? ? time_ago_with_tooltip(mirror.last_update_at) : _('Never')
%td
- if mirror.last_error.present?
.badge.mirror-error-badge{ data: { toggle: 'tooltip', html: 'true' }, title: html_escape(mirror.last_error.try(:strip)) }= _('Error')
%td.mirror-action-buttons
.btn-group.mirror-actions-group.pull-right{ role: 'group' }
= render 'shared/remote_mirror_update_button', remote_mirror: mirror
%button.js-delete-mirror.btn.btn-danger{ type: 'button', data: { mirror_id: mirror.id, toggle: 'tooltip', container: 'body' }, title: _('Remove') }= icon('trash-o')
- protocols = Gitlab::UrlSanitizer::ALLOWED_SCHEMES.join('|')
.form-group
= label_tag :mirror_direction, _('Mirror direction'), class: 'label-light'
= select_tag :mirror_direction, options_for_select([[_('Push'), 'push']]), class: 'form-control js-mirror-direction', disabled: true
= f.fields_for :remote_mirrors, @project.remote_mirrors.build do |rm_f|
= rm_f.hidden_field :enabled, value: '1'
= rm_f.hidden_field :url, class: 'js-mirror-url-hidden', required: true, pattern: "(#{protocols}):\/\/.+"
= rm_f.hidden_field :only_protected_branches, class: 'js-mirror-protected-hidden'
.form-group
= label_tag :auth_method, _('Authentication method'), class: 'label-bold'
= select_tag :auth_method, options_for_select([[_('None'), 'none'], [_('Password'), 'password']], 'none'), { class: "form-control js-auth-method" }
.form-group.js-password-group.collapse
= label_tag :password, _('Password'), class: 'label-bold'
= text_field_tag :password, '', class: 'form-control js-password'
- expanded = Rails.env.test?
%section.settings.no-animate#js-push-remote-settings{ class: ('expanded' if expanded) }
.settings-header
%h4
Push to a remote repository
%button.btn.js-settings-toggle
= expanded ? 'Collapse' : 'Expand'
%p
Set up the remote repository that you want to update with the content of the current repository
every time someone pushes to it.
= link_to 'Read more', help_page_path('workflow/repository_mirroring', anchor: 'pushing-to-a-remote-repository'), target: '_blank'
.settings-content
= form_for @project, url: project_mirror_path(@project) do |f|
%div
= form_errors(@project)
= render "shared/remote_mirror_update_button", remote_mirror: @remote_mirror
- if @remote_mirror.last_error.present?
.panel.panel-danger
.panel-heading
- if @remote_mirror.last_update_at
The remote repository failed to update #{time_ago_with_tooltip(@remote_mirror.last_update_at)}.
- else
The remote repository failed to update.
- if @remote_mirror.last_successful_update_at
Last successful update #{time_ago_with_tooltip(@remote_mirror.last_successful_update_at)}.
.panel-body
%pre
:preserve
#{h(@remote_mirror.last_error.strip)}
= f.fields_for :remote_mirrors, @remote_mirror do |rm_form|
.form-group
= rm_form.check_box :enabled, class: "float-left"
.prepend-left-20
= rm_form.label :enabled, "Remote mirror repository", class: "label-bold append-bottom-0"
%p.light.append-bottom-0
Automatically update the remote mirror's branches, tags, and commits from this repository every time someone pushes to it.
.form-group.has-feedback
= rm_form.label :url, "Git repository URL", class: "label-bold"
= rm_form.text_field :url, class: "form-control", placeholder: 'https://username:password@gitlab.company.com/group/project.git'
= render "projects/mirrors/instructions"
.form-group
= rm_form.check_box :only_protected_branches, class: 'float-left'
.prepend-left-20
= rm_form.label :only_protected_branches, class: 'label-bold'
= link_to icon('question-circle'), help_page_path('user/project/protected_branches')
= f.submit 'Save changes', class: 'btn btn-create', name: 'update_remote_mirror'
- if can?(current_user, :admin_remote_mirror, @project)
= render 'projects/mirrors/push'
= render 'projects/mirrors/mirror_repos'
- if @project.has_remote_mirror?
.append-bottom-default
- if remote_mirror.update_in_progress?
%span.btn.disabled
= icon("refresh spin")
Updating&hellip;
- else
= link_to update_now_project_mirror_path(@project, sync_remote: true), method: :post, class: "btn" do
= icon("refresh")
Update Now
- if @remote_mirror.last_successful_update_at
%p.inline.prepend-left-10
Successfully updated #{time_ago_with_tooltip(@remote_mirror.last_successful_update_at)}.
- if remote_mirror.update_in_progress?
%button.btn.disabled{ type: 'button', data: { toggle: 'tooltip', container: 'body' }, title: _('Updating') }
= icon("refresh spin")
- else
= link_to update_now_project_mirror_path(@project, sync_remote: true), method: :post, class: "btn", data: { toggle: 'tooltip', container: 'body' }, title: _('Update now') do
= icon("refresh")
title: First Improvements made to the contributor on-boarding experience.
merge_request: 20682
author: Eddie Stubbington
type: added
---
title: Add the ability to reference projects in comments and other markdown text.
merge_request: 20285
author: Reuben Pereira
type: added
---
title: Allows to cancel a Created job
merge_request: 20635
author: Jacopo Beschi @jacopo-beschi
type: added
---
title: Add default avatar to group
merge_request: 17271
author: George Tsiolis
type: changed
---
title: Fix label list item container height when there is no label description
merge_request: 21106
author:
type: fixed
---
title: Enable frozen string in rest of app/models/**/*.rb
merge_request: gfyoung
author:
type: performance
---
title: Fix empty merge requests not opening in the Web IDE
merge_request: 21102
author:
type: fixed
---
title: Rails5 fix specs duplicate key value violates unique constraint 'index_gpg_signatures_on_commit_sha'
merge_request: 21119
author: Jasper Maes
type: fixed
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.
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