Commit f2135520 authored by Dmitriy Zaporozhets's avatar Dmitriy Zaporozhets

Merge branch 'ce-to-ee-2018-04-23' into 'master'

CE upstream - 2018-04-23 12:26 UTC

Closes gitaly#1113

See merge request gitlab-org/gitlab-ee!5451
parents 987324f6 c8112f99
<script> <script>
import commitIconSvg from 'icons/_icon_commit.svg'; import UserAvatarLink from './user_avatar/user_avatar_link.vue';
import userAvatarLink from './user_avatar/user_avatar_link.vue'; import tooltip from '../directives/tooltip';
import tooltip from '../directives/tooltip'; import Icon from '../../vue_shared/components/icon.vue';
import icon from '../../vue_shared/components/icon.vue';
export default { export default {
directives: { directives: {
tooltip, tooltip,
},
components: {
UserAvatarLink,
Icon,
},
props: {
/**
* Indicates the existance of a tag.
* Used to render the correct icon, if true will render `fa-tag` icon,
* if false will render a svg sprite fork icon
*/
tag: {
type: Boolean,
required: false,
default: false,
}, },
components: { /**
userAvatarLink, * If provided is used to render the branch name and url.
icon, * Should contain the following properties:
* name
* ref_url
*/
commitRef: {
type: Object,
required: false,
default: () => ({}),
},
/**
* Used to link to the commit sha.
*/
commitUrl: {
type: String,
required: false,
default: '',
}, },
props: {
/**
* Indicates the existance of a tag.
* Used to render the correct icon, if true will render `fa-tag` icon,
* if false will render a svg sprite fork icon
*/
tag: {
type: Boolean,
required: false,
default: false,
},
/**
* If provided is used to render the branch name and url.
* Should contain the following properties:
* name
* ref_url
*/
commitRef: {
type: Object,
required: false,
default: () => ({}),
},
/**
* Used to link to the commit sha.
*/
commitUrl: {
type: String,
required: false,
default: '',
},
/** /**
* Used to show the commit short sha that links to the commit url. * Used to show the commit short sha that links to the commit url.
*/ */
shortSha: { shortSha: {
type: String, type: String,
required: false, required: false,
default: '', default: '',
}, },
/** /**
* If provided shows the commit tile. * If provided shows the commit tile.
*/ */
title: { title: {
type: String, type: String,
required: false, required: false,
default: '', default: '',
}, },
/** /**
* If provided renders information about the author of the commit. * If provided renders information about the author of the commit.
* When provided should include: * When provided should include:
* `avatar_url` to render the avatar icon * `avatar_url` to render the avatar icon
* `web_url` to link to user profile * `web_url` to link to user profile
* `username` to render alt and title tags * `username` to render alt and title tags
*/ */
author: { author: {
type: Object, type: Object,
required: false, required: false,
default: () => ({}), default: () => ({}),
}, },
showBranch: { showBranch: {
type: Boolean, type: Boolean,
required: false, required: false,
default: true, default: true,
},
}, },
computed: { },
/** computed: {
* Used to verify if all the properties needed to render the commit /**
* ref section were provided. * Used to verify if all the properties needed to render the commit
* * ref section were provided.
* @returns {Boolean} *
*/ * @returns {Boolean}
hasCommitRef() { */
return this.commitRef && this.commitRef.name && this.commitRef.ref_url; hasCommitRef() {
}, return this.commitRef && this.commitRef.name && this.commitRef.ref_url;
/**
* Used to verify if all the properties needed to render the commit
* author section were provided.
*
* @returns {Boolean}
*/
hasAuthor() {
return this.author &&
this.author.avatar_url &&
this.author.path &&
this.author.username;
},
/**
* If information about the author is provided will return a string
* to be rendered as the alt attribute of the img tag.
*
* @returns {String}
*/
userImageAltDescription() {
return this.author &&
this.author.username ? `${this.author.username}'s avatar` : null;
},
}, },
created() { /**
this.commitIconSvg = commitIconSvg; * Used to verify if all the properties needed to render the commit
* author section were provided.
*
* @returns {Boolean}
*/
hasAuthor() {
return this.author && this.author.avatar_url && this.author.path && this.author.username;
}, },
}; /**
* If information about the author is provided will return a string
* to be rendered as the alt attribute of the img tag.
*
* @returns {String}
*/
userImageAltDescription() {
return this.author && this.author.username ? `${this.author.username}'s avatar` : null;
},
},
};
</script> </script>
<template> <template>
<div class="branch-commit"> <div class="branch-commit">
...@@ -141,11 +133,10 @@ ...@@ -141,11 +133,10 @@
{{ commitRef.name }} {{ commitRef.name }}
</a> </a>
</template> </template>
<div <icon
v-html="commitIconSvg" name="commit"
class="commit-icon js-commit-icon" class="commit-icon js-commit-icon"
> />
</div>
<a <a
class="commit-sha" class="commit-sha"
......
<script> <script>
import { __ } from '~/locale'; import { __ } from '~/locale';
/** /**
* Port of detail_behavior expand button. * Port of detail_behavior expand button.
* *
* @example * @example
* <expand-button> * <expand-button>
* <template slot="expanded"> * <template slot="expanded">
* Text goes here. * Text goes here.
* </template> * </template>
* </expand-button> * </expand-button>
*/ */
export default { export default {
name: 'ExpandButton', name: 'ExpandButton',
data() { data() {
return { return {
isCollapsed: true, isCollapsed: true,
}; };
},
computed: {
ariaLabel() {
return __('Click to expand text');
}, },
computed: { },
ariaLabel() { methods: {
return __('Click to expand text'); onClick() {
}, this.isCollapsed = !this.isCollapsed;
}, },
methods: { },
onClick() { };
this.isCollapsed = !this.isCollapsed;
},
},
};
</script> </script>
<template> <template>
<span> <span>
......
<script> <script>
import ciIconBadge from './ci_badge_link.vue'; import CiIconBadge from './ci_badge_link.vue';
import loadingIcon from './loading_icon.vue'; import LoadingIcon from './loading_icon.vue';
import timeagoTooltip from './time_ago_tooltip.vue'; import TimeagoTooltip from './time_ago_tooltip.vue';
import tooltip from '../directives/tooltip'; import tooltip from '../directives/tooltip';
import userAvatarImage from './user_avatar/user_avatar_image.vue'; import UserAvatarImage from './user_avatar/user_avatar_image.vue';
/** /**
* Renders header component for job and pipeline page based on UI mockups * Renders header component for job and pipeline page based on UI mockups
* *
* Used in: * Used in:
* - job show page * - job show page
* - pipeline show page * - pipeline show page
*/ */
export default { export default {
components: { components: {
ciIconBadge, CiIconBadge,
loadingIcon, LoadingIcon,
timeagoTooltip, TimeagoTooltip,
userAvatarImage, UserAvatarImage,
},
directives: {
tooltip,
},
props: {
status: {
type: Object,
required: true,
}, },
directives: { itemName: {
tooltip, type: String,
required: true,
}, },
props: { itemId: {
status: { type: Number,
type: Object, required: true,
required: true,
},
itemName: {
type: String,
required: true,
},
itemId: {
type: Number,
required: true,
},
time: {
type: String,
required: true,
},
user: {
type: Object,
required: false,
default: () => ({}),
},
actions: {
type: Array,
required: false,
default: () => [],
},
hasSidebarButton: {
type: Boolean,
required: false,
default: false,
},
shouldRenderTriggeredLabel: {
type: Boolean,
required: false,
default: true,
},
}, },
time: {
type: String,
required: true,
},
user: {
type: Object,
required: false,
default: () => ({}),
},
actions: {
type: Array,
required: false,
default: () => [],
},
hasSidebarButton: {
type: Boolean,
required: false,
default: false,
},
shouldRenderTriggeredLabel: {
type: Boolean,
required: false,
default: true,
},
},
computed: { computed: {
userAvatarAltText() { userAvatarAltText() {
return `${this.user.name}'s avatar`; return `${this.user.name}'s avatar`;
},
}, },
},
methods: { methods: {
onClickAction(action) { onClickAction(action) {
this.$emit('actionClicked', action); this.$emit('actionClicked', action);
},
}, },
}; },
};
</script> </script>
<template> <template>
......
<script> <script>
/* This is a re-usable vue component for rendering a svg sprite
icon
/* This is a re-usable vue component for rendering a svg sprite Sample configuration:
icon
Sample configuration: <icon
name="retry"
:size="32"
css-classes="top"
/>
<icon */
name="retry" // only allow classes in images.scss e.g. s12
:size="32" const validSizes = [8, 12, 16, 18, 24, 32, 48, 72];
css-classes="top"
/>
*/ export default {
// only allow classes in images.scss e.g. s12 props: {
const validSizes = [8, 12, 16, 18, 24, 32, 48, 72]; name: {
type: String,
export default { required: true,
props: { },
name: {
type: String,
required: true,
},
size: { size: {
type: Number, type: Number,
required: false, required: false,
default: 16, default: 16,
validator(value) { validator(value) {
return validSizes.includes(value); return validSizes.includes(value);
},
}, },
},
cssClasses: { cssClasses: {
type: String, type: String,
required: false, required: false,
default: '', default: '',
}, },
width: { width: {
type: Number, type: Number,
required: false, required: false,
default: null, default: null,
}, },
height: { height: {
type: Number, type: Number,
required: false, required: false,
default: null, default: null,
}, },
y: { y: {
type: Number, type: Number,
required: false, required: false,
default: null, default: null,
}, },
x: { x: {
type: Number, type: Number,
required: false, required: false,
default: null, default: null,
},
}, },
},
computed: { computed: {
spriteHref() { spriteHref() {
return `${gon.sprite_icons}#${this.name}`; return `${gon.sprite_icons}#${this.name}`;
}, },
iconSizeClass() { iconSizeClass() {
return this.size ? `s${this.size}` : ''; return this.size ? `s${this.size}` : '';
},
}, },
}; },
};
</script> </script>
<template> <template>
...@@ -79,7 +78,8 @@ ...@@ -79,7 +78,8 @@
:width="width" :width="width"
:height="height" :height="height"
:x="x" :x="x"
:y="y"> :y="y"
>
<use v-bind="{ 'xlink:href':spriteHref }" /> <use v-bind="{ 'xlink:href':spriteHref }" />
</svg> </svg>
</template> </template>
<script> <script>
import $ from 'jquery';
import { __ } from '~/locale'; import { __ } from '~/locale';
import LabelsSelect from '~/labels_select'; import LabelsSelect from '~/labels_select';
import LoadingIcon from '../../loading_icon.vue'; import LoadingIcon from '../../loading_icon.vue';
...@@ -98,11 +99,18 @@ export default { ...@@ -98,11 +99,18 @@ export default {
this.labelsDropdown = new LabelsSelect(this.$refs.dropdownButton, { this.labelsDropdown = new LabelsSelect(this.$refs.dropdownButton, {
handleClick: this.handleClick, handleClick: this.handleClick,
}); });
$(this.$refs.dropdown).on('hidden.gl.dropdown', this.handleDropdownHidden);
}, },
methods: { methods: {
handleClick(label) { handleClick(label) {
this.$emit('onLabelClick', label); this.$emit('onLabelClick', label);
}, },
handleCollapsedValueClick() {
this.$emit('toggleCollapse');
},
handleDropdownHidden() {
this.$emit('onDropdownClose');
},
}, },
}; };
</script> </script>
...@@ -112,6 +120,7 @@ export default { ...@@ -112,6 +120,7 @@ export default {
<dropdown-value-collapsed <dropdown-value-collapsed
v-if="showCreate" v-if="showCreate"
:labels="context.labels" :labels="context.labels"
@onValueClick="handleCollapsedValueClick"
/> />
<dropdown-title <dropdown-title
:can-edit="canEdit" :can-edit="canEdit"
...@@ -133,7 +142,10 @@ export default { ...@@ -133,7 +142,10 @@ export default {
:name="hiddenInputName" :name="hiddenInputName"
:label="label" :label="label"
/> />
<div class="dropdown"> <div
class="dropdown"
ref="dropdown"
>
<dropdown-button <dropdown-button
:ability-name="abilityName" :ability-name="abilityName"
:field-name="hiddenInputName" :field-name="hiddenInputName"
......
...@@ -26,6 +26,11 @@ export default { ...@@ -26,6 +26,11 @@ export default {
return labelsString; return labelsString;
}, },
}, },
methods: {
handleClick() {
this.$emit('onValueClick');
},
},
}; };
</script> </script>
...@@ -36,6 +41,7 @@ export default { ...@@ -36,6 +41,7 @@ export default {
data-placement="left" data-placement="left"
data-container="body" data-container="body"
:title="labelsList" :title="labelsList"
@click="handleClick"
> >
<i <i
aria-hidden="true" aria-hidden="true"
......
require "flowdock-git-hook" require "flowdock-git-hook"
# Flow dock depends on Grit to compute the number of commits between two given
# commits. To make this depend on Gitaly, a monkey patch is applied
module Flowdock
class Git
# pass down a Repository all the way down
def repo
@options[:repo]
end
def config
{}
end
def messages
Git::Builder.new(repo: repo,
ref: @ref,
before: @from,
after: @to,
commit_url: @commit_url,
branch_url: @branch_url,
diff_url: @diff_url,
repo_url: @repo_url,
repo_name: @repo_name,
permanent_refs: @permanent_refs,
tags: tags
).to_hashes
end
class Builder
def commits
@repo.commits_between(@before, @after).map do |commit|
{
url: @opts[:commit_url] ? @opts[:commit_url] % [commit.sha] : nil,
id: commit.sha,
message: commit.message,
author: {
name: commit.author_name,
email: commit.author_email
}
}
end
end
end
end
end
class FlowdockService < Service class FlowdockService < Service
prop_accessor :token prop_accessor :token
validates :token, presence: true, if: :activated? validates :token, presence: true, if: :activated?
...@@ -34,7 +80,7 @@ class FlowdockService < Service ...@@ -34,7 +80,7 @@ class FlowdockService < Service
data[:before], data[:before],
data[:after], data[:after],
token: token, token: token,
repo: project.repository.path_to_repo, repo: project.repository,
repo_url: "#{Gitlab.config.gitlab.url}/#{project.full_path}", repo_url: "#{Gitlab.config.gitlab.url}/#{project.full_path}",
commit_url: "#{Gitlab.config.gitlab.url}/#{project.full_path}/commit/%s", commit_url: "#{Gitlab.config.gitlab.url}/#{project.full_path}/commit/%s",
diff_url: "#{Gitlab.config.gitlab.url}/#{project.full_path}/compare/%s...%s" diff_url: "#{Gitlab.config.gitlab.url}/#{project.full_path}/compare/%s...%s"
......
...@@ -260,7 +260,7 @@ class ProjectPresenter < Gitlab::View::Presenter::Delegated ...@@ -260,7 +260,7 @@ class ProjectPresenter < Gitlab::View::Presenter::Delegated
if current_user && can?(current_user, :admin_pipeline, project) && repository.gitlab_ci_yml.blank? && !show_auto_devops_callout if current_user && can?(current_user, :admin_pipeline, project) && repository.gitlab_ci_yml.blank? && !show_auto_devops_callout
OpenStruct.new(enabled: auto_devops_enabled?, OpenStruct.new(enabled: auto_devops_enabled?,
label: auto_devops_enabled? ? _('Auto DevOps enabled') : _('Enable Auto DevOps'), label: auto_devops_enabled? ? _('Auto DevOps enabled') : _('Enable Auto DevOps'),
link: project_settings_ci_cd_path(project, anchor: 'js-general-pipeline-settings')) link: project_settings_ci_cd_path(project, anchor: 'autodevops-settings'))
elsif auto_devops_enabled? elsif auto_devops_enabled?
OpenStruct.new(enabled: true, OpenStruct.new(enabled: true,
label: _('Auto DevOps enabled'), label: _('Auto DevOps enabled'),
......
...@@ -22,7 +22,7 @@ ...@@ -22,7 +22,7 @@
%hr %hr
%p %p
- link_to_auto_devops_settings = link_to(s_('AutoDevOps|enable Auto DevOps (Beta)'), project_settings_ci_cd_path(@project, anchor: 'js-general-pipeline-settings')) - link_to_auto_devops_settings = link_to(s_('AutoDevOps|enable Auto DevOps (Beta)'), 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)) - 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 } = 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 }
......
.row.prepend-top-default
.col-lg-12
= form_for @project, url: project_settings_ci_cd_path(@project) do |f|
= form_errors(@project)
%fieldset.builds-feature
.form-group
- message = auto_devops_warning_message(@project)
- ci_file_formatted = '<code>.gitlab-ci.yml</code>'.html_safe
- if message
%p.settings-message.text-center
= message.html_safe
= f.fields_for :auto_devops_attributes, @auto_devops do |form|
.radio
= form.label :enabled_true do
= form.radio_button :enabled, 'true'
%strong= s_('CICD|Enable Auto DevOps')
%br
= s_('CICD|The Auto DevOps pipeline configuration will be used when there is no %{ci_file} in the project.').html_safe % { ci_file: ci_file_formatted }
.radio
= form.label :enabled_false do
= form.radio_button :enabled, 'false'
%strong= s_('CICD|Disable Auto DevOps')
%br
= s_('CICD|An explicit %{ci_file} needs to be specified before you can begin using Continuous Integration and Delivery.').html_safe % { ci_file: ci_file_formatted }
.radio
= form.label :enabled_ do
= form.radio_button :enabled, ''
%strong= s_('CICD|Instance default (%{state})') % { state: "#{Gitlab::CurrentSettings.auto_devops_enabled? ? _('enabled') : _('disabled')}" }
%br
= s_('CICD|Follow the instance default to either have Auto DevOps enabled or disabled when there is no project specific %{ci_file}.').html_safe % { ci_file: ci_file_formatted }
= form.label :domain, class:"prepend-top-10" do
= _('Domain')
= form.text_field :domain, class: 'form-control', placeholder: 'domain.com'
.help-block
= s_('CICD|You need to specify a domain if you want to use Auto Review Apps and Auto Deploy stages.')
= f.submit 'Save changes', class: "btn btn-success prepend-top-15"
...@@ -3,44 +3,6 @@ ...@@ -3,44 +3,6 @@
= form_for @project, url: project_settings_ci_cd_path(@project) do |f| = form_for @project, url: project_settings_ci_cd_path(@project) do |f|
= form_errors(@project) = form_errors(@project)
%fieldset.builds-feature %fieldset.builds-feature
.form-group
%h5 Auto DevOps (Beta)
%p
Auto DevOps will automatically build, test, and deploy your application based on a predefined Continuous Integration and Delivery configuration.
= link_to 'Learn more about Auto DevOps', help_page_path('topics/autodevops/index.md')
- message = auto_devops_warning_message(@project)
- if message
%p.settings-message.text-center
= message.html_safe
= f.fields_for :auto_devops_attributes, @auto_devops do |form|
.radio
= form.label :enabled_true do
= form.radio_button :enabled, 'true'
%strong Enable Auto DevOps
%br
%span.descr
The Auto DevOps pipeline configuration will be used when there is no <code>.gitlab-ci.yml</code> in the project.
.radio
= form.label :enabled_false do
= form.radio_button :enabled, 'false'
%strong Disable Auto DevOps
%br
%span.descr
An explicit <code>.gitlab-ci.yml</code> needs to be specified before you can begin using Continuous Integration and Delivery.
.radio
= form.label :enabled_ do
= form.radio_button :enabled, ''
%strong Instance default (#{Gitlab::CurrentSettings.auto_devops_enabled? ? 'enabled' : 'disabled'})
%br
%span.descr
Follow the instance default to either have Auto DevOps enabled or disabled when there is no project specific <code>.gitlab-ci.yml</code>.
%p
You need to specify a domain if you want to use Auto Review Apps and Auto Deploy stages.
= form.text_field :domain, class: 'form-control', placeholder: 'domain.com'
%hr
.form-group.append-bottom-default.js-secret-runner-token .form-group.append-bottom-default.js-secret-runner-token
= f.label :runners_token, "Runner token", class: 'label-light' = f.label :runners_token, "Runner token", class: 'label-light'
.form-control.js-secret-value-placeholder .form-control.js-secret-value-placeholder
......
...@@ -12,10 +12,22 @@ ...@@ -12,10 +12,22 @@
%button.btn.js-settings-toggle{ type: 'button' } %button.btn.js-settings-toggle{ type: 'button' }
= expanded ? 'Collapse' : 'Expand' = expanded ? 'Collapse' : 'Expand'
%p %p
Update your CI/CD configuration, like job timeout or Auto DevOps. Access your runner token, customize your pipeline configuration, and view your pipeline status and coverage report.
.settings-content .settings-content
= render 'form' = render 'form'
%section.settings#autodevops-settings.no-animate{ class: ('expanded' if expanded) }
.settings-header
%h4
= s_('CICD|Auto DevOps (Beta)')
%button.btn.btn-default.js-settings-toggle{ type: 'button' }
= expanded ? _('Collapse') : _('Expand')
%p
= s_('CICD|Auto DevOps will automatically build, test, and deploy your application based on a predefined Continuous Integration and Delivery configuration.')
= link_to s_('CICD|Learn more about Auto DevOps'), help_page_path('topics/autodevops/index.md')
.settings-content
= render 'autodevops_form'
%section.settings.no-animate{ class: ('expanded' if expanded) } %section.settings.no-animate{ class: ('expanded' if expanded) }
.settings-header .settings-header
%h4 %h4
......
...@@ -9,7 +9,7 @@ ...@@ -9,7 +9,7 @@
- link = link_to(s_('AutoDevOps|Auto DevOps documentation'), help_page_path('topics/autodevops/index.md'), target: '_blank', rel: 'noopener noreferrer') - link = link_to(s_('AutoDevOps|Auto DevOps documentation'), help_page_path('topics/autodevops/index.md'), target: '_blank', rel: 'noopener noreferrer')
= s_('AutoDevOps|Learn more in the %{link_to_documentation}').html_safe % { link_to_documentation: link } = s_('AutoDevOps|Learn more in the %{link_to_documentation}').html_safe % { link_to_documentation: link }
.banner-buttons .banner-buttons
= link_to s_('AutoDevOps|Enable in settings'), project_settings_ci_cd_path(@project, anchor: 'js-general-pipeline-settings'), class: 'btn js-close-callout' = link_to s_('AutoDevOps|Enable in settings'), project_settings_ci_cd_path(@project, anchor: 'autodevops-settings'), class: 'btn js-close-callout'
%button.btn-transparent.banner-close.close.js-close-callout{ type: 'button', %button.btn-transparent.banner-close.close.js-close-callout{ type: 'button',
'aria-label' => 'Dismiss Auto DevOps box' } 'aria-label' => 'Dismiss Auto DevOps box' }
......
---
title: Create settings section for autodevops
merge_request: 18321
author:
type: changed
---
title: Fix project creation for user endpoint when jobs_enabled parameter supplied
merge_request:
author:
type: fixed
---
title: Add missing changelog type to docs
merge_request: 18526
author: "@blackst0ne"
type: other
---
title: Add 2FA filter to users API for admins only
merge_request: 18503
author:
type: changed
---
title: Fix missing namespace for some internal users
merge_request: 18357
author:
type: fixed
class CreateMissingNamespaceForInternalUsers < ActiveRecord::Migration
DOWNTIME = false
def up
connection.exec_query(users_query.to_sql).rows.each do |id, username|
create_namespace(id, username)
# When testing locally I've noticed that these internal users are missing
# the notification email, for more details visit the below link:
# https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/18357#note_68327560
set_notification_email(id)
end
end
def down
# no-op
end
private
def users
@users ||= Arel::Table.new(:users)
end
def namespaces
@namespaces ||= Arel::Table.new(:namespaces)
end
def users_query
condition = users[:ghost].eq(true)
if column_exists?(:users, :support_bot)
condition = condition.or(users[:support_bot].eq(true))
end
users.join(namespaces, Arel::Nodes::OuterJoin)
.on(namespaces[:type].eq(nil).and(namespaces[:owner_id].eq(users[:id])))
.where(namespaces[:owner_id].eq(nil))
.where(condition)
.project(users[:id], users[:username])
end
def create_namespace(user_id, username)
path = Uniquify.new.string(username) do |str|
query = "SELECT id FROM namespaces WHERE parent_id IS NULL AND path='#{str}' LIMIT 1"
connection.exec_query(query).present?
end
insert_query = "INSERT INTO namespaces(owner_id, path, name) VALUES(#{user_id}, '#{path}', '#{path}')"
namespace_id = connection.insert_sql(insert_query)
create_route(namespace_id)
end
def create_route(namespace_id)
return unless namespace_id
row = connection.exec_query("SELECT id, path FROM namespaces WHERE id=#{namespace_id}").first
id, path = row.values_at('id', 'path')
execute("INSERT INTO routes(source_id, source_type, path, name) VALUES(#{id}, 'Namespace', '#{path}', '#{path}')")
end
def set_notification_email(user_id)
execute "UPDATE users SET notification_email = email WHERE notification_email IS NULL AND id = #{user_id}"
end
end
...@@ -112,13 +112,13 @@ POST /projects/import ...@@ -112,13 +112,13 @@ POST /projects/import
| `file` | string | yes | The file to be uploaded | | `file` | string | yes | The file to be uploaded |
| `path` | string | yes | Name and path for new project | | `path` | string | yes | Name and path for new project |
| `overwrite` | boolean | no | If there is a project with the same path the import will overwrite it. Default to false | | `overwrite` | boolean | no | If there is a project with the same path the import will overwrite it. Default to false |
| `override_params` | Hash | no | Supports all fields defined in the [Project API](projects.md)] | | `override_params` | Hash | no | Supports all fields defined in the [Project API](projects.md) |
The override params passed will take precendence over all values defined inside the export file. The override params passed will take precedence over all values defined inside the export file.
To upload a file from your filesystem, use the `--form` argument. This causes To upload a file from your file system, use the `--form` argument. This causes
cURL to post data using the header `Content-Type: multipart/form-data`. cURL to post data using the header `Content-Type: multipart/form-data`.
The `file=` parameter must point to a file on your filesystem and be preceded The `file=` parameter must point to a file on your file system and be preceded
by `@`. For example: by `@`. For example:
```console ```console
......
...@@ -22,7 +22,7 @@ The `merge_request` value is a reference to a merge request that adds this ...@@ -22,7 +22,7 @@ The `merge_request` value is a reference to a merge request that adds this
entry, and the `author` key is used to give attribution to community entry, and the `author` key is used to give attribution to community
contributors. **Both are optional**. contributors. **Both are optional**.
The `type` field maps the category of the change, The `type` field maps the category of the change,
valid options are: added, fixed, changed, deprecated, removed, security, other. **Type field is mandatory**. valid options are: added, fixed, changed, deprecated, removed, security, performance, other. **Type field is mandatory**.
Community contributors and core team members are encouraged to add their name to Community contributors and core team members are encouraged to add their name to
the `author` field. GitLab team members **should not**. the `author` field. GitLab team members **should not**.
......
...@@ -74,6 +74,11 @@ module API ...@@ -74,6 +74,11 @@ module API
present options[:with].prepare_relation(projects, options), options present options[:with].prepare_relation(projects, options), options
end end
def translate_params_for_compatibility(params)
params[:builds_enabled] = params.delete(:jobs_enabled) if params.key?(:jobs_enabled)
params
end
end end
resource :users, requirements: API::PROJECT_ENDPOINT_REQUIREMENTS do resource :users, requirements: API::PROJECT_ENDPOINT_REQUIREMENTS do
...@@ -123,7 +128,7 @@ module API ...@@ -123,7 +128,7 @@ module API
end end
post do post do
attrs = declared_params(include_missing: false) attrs = declared_params(include_missing: false)
attrs[:builds_enabled] = attrs.delete(:jobs_enabled) if attrs.key?(:jobs_enabled) attrs = translate_params_for_compatibility(attrs)
project = ::Projects::CreateService.new(current_user, attrs).execute project = ::Projects::CreateService.new(current_user, attrs).execute
if project.saved? if project.saved?
...@@ -155,6 +160,7 @@ module API ...@@ -155,6 +160,7 @@ module API
not_found!('User') unless user not_found!('User') unless user
attrs = declared_params(include_missing: false) attrs = declared_params(include_missing: false)
attrs = translate_params_for_compatibility(attrs)
project = ::Projects::CreateService.new(user, attrs).execute project = ::Projects::CreateService.new(user, attrs).execute
if project.saved? if project.saved?
...@@ -283,7 +289,7 @@ module API ...@@ -283,7 +289,7 @@ module API
authorize! :rename_project, user_project if attrs[:name].present? authorize! :rename_project, user_project if attrs[:name].present?
authorize! :change_visibility_level, user_project if attrs[:visibility].present? authorize! :change_visibility_level, user_project if attrs[:visibility].present?
attrs[:builds_enabled] = attrs.delete(:jobs_enabled) if attrs.key?(:jobs_enabled) attrs = translate_params_for_compatibility(attrs)
result = ::Projects::UpdateService.new(user_project, current_user, attrs).execute result = ::Projects::UpdateService.new(user_project, current_user, attrs).execute
......
module Gitlab module Gitlab
module Wiki module Git
class CommitterWithHooks < Gollum::Committer class CommitterWithHooks < Gollum::Committer
attr_reader :gl_wiki attr_reader :gl_wiki
...@@ -9,6 +9,9 @@ module Gitlab ...@@ -9,6 +9,9 @@ module Gitlab
end end
def commit def commit
# TODO: Remove after 10.8
return super unless allowed_to_run_hooks?
result = Gitlab::Git::OperationService.new(git_user, gl_wiki.repository).with_branch( result = Gitlab::Git::OperationService.new(git_user, gl_wiki.repository).with_branch(
@wiki.ref, @wiki.ref,
start_branch_name: @wiki.ref start_branch_name: @wiki.ref
...@@ -24,6 +27,11 @@ module Gitlab ...@@ -24,6 +27,11 @@ module Gitlab
private private
# TODO: Remove after 10.8
def allowed_to_run_hooks?
@options[:user_id] != 0 && @options[:username].present?
end
def git_user def git_user
@git_user ||= Gitlab::Git::User.new(@options[:username], @git_user ||= Gitlab::Git::User.new(@options[:username],
@options[:name], @options[:name],
......
...@@ -290,7 +290,7 @@ module Gitlab ...@@ -290,7 +290,7 @@ module Gitlab
end end
def committer_with_hooks(commit_details) def committer_with_hooks(commit_details)
Gitlab::Wiki::CommitterWithHooks.new(self, commit_details.to_h) Gitlab::Git::CommitterWithHooks.new(self, commit_details.to_h)
end end
def with_committer_with_hooks(commit_details, &block) def with_committer_with_hooks(commit_details, &block)
......
...@@ -8,6 +8,7 @@ describe "Projects > Settings > Pipelines settings" do ...@@ -8,6 +8,7 @@ describe "Projects > Settings > Pipelines settings" do
before do before do
sign_in(user) sign_in(user)
project.add_role(user, role) project.add_role(user, role)
create(:project_auto_devops, project: project)
end end
context 'for developer' do context 'for developer' do
...@@ -27,10 +28,17 @@ describe "Projects > Settings > Pipelines settings" do ...@@ -27,10 +28,17 @@ describe "Projects > Settings > Pipelines settings" do
visit project_settings_ci_cd_path(project) visit project_settings_ci_cd_path(project)
fill_in('Test coverage parsing', with: 'coverage_regex') fill_in('Test coverage parsing', with: 'coverage_regex')
click_on 'Save changes'
page.within '#js-general-pipeline-settings' do
click_on 'Save changes'
end
expect(page.status_code).to eq(200) expect(page.status_code).to eq(200)
expect(page).to have_button('Save changes', disabled: false)
page.within '#js-general-pipeline-settings' do
expect(page).to have_button('Save changes', disabled: false)
end
expect(page).to have_field('Test coverage parsing', with: 'coverage_regex') expect(page).to have_field('Test coverage parsing', with: 'coverage_regex')
end end
...@@ -38,10 +46,15 @@ describe "Projects > Settings > Pipelines settings" do ...@@ -38,10 +46,15 @@ describe "Projects > Settings > Pipelines settings" do
visit project_settings_ci_cd_path(project) visit project_settings_ci_cd_path(project)
page.check('Auto-cancel redundant, pending pipelines') page.check('Auto-cancel redundant, pending pipelines')
click_on 'Save changes' page.within '#js-general-pipeline-settings' do
click_on 'Save changes'
end
expect(page.status_code).to eq(200) expect(page.status_code).to eq(200)
expect(page).to have_button('Save changes', disabled: false)
page.within '#js-general-pipeline-settings' do
expect(page).to have_button('Save changes', disabled: false)
end
checkbox = find_field('project_auto_cancel_pending_pipelines') checkbox = find_field('project_auto_cancel_pending_pipelines')
expect(checkbox).to be_checked expect(checkbox).to be_checked
...@@ -51,13 +64,16 @@ describe "Projects > Settings > Pipelines settings" do ...@@ -51,13 +64,16 @@ describe "Projects > Settings > Pipelines settings" do
it 'update auto devops settings' do it 'update auto devops settings' do
visit project_settings_ci_cd_path(project) visit project_settings_ci_cd_path(project)
fill_in('project_auto_devops_attributes_domain', with: 'test.com') page.within '#autodevops-settings' do
page.choose('project_auto_devops_attributes_enabled_false') fill_in('project_auto_devops_attributes_domain', with: 'test.com')
click_on 'Save changes' page.choose('project_auto_devops_attributes_enabled_false')
click_on 'Save changes'
end
expect(page.status_code).to eq(200) expect(page.status_code).to eq(200)
expect(project.auto_devops).to be_present expect(project.auto_devops).to be_present
expect(project.auto_devops).not_to be_enabled expect(project.auto_devops).not_to be_enabled
expect(project.auto_devops.domain).to eq('test.com')
end end
end end
end end
......
...@@ -65,7 +65,7 @@ describe 'Projects > Show > User sees setup shortcut buttons' do ...@@ -65,7 +65,7 @@ describe 'Projects > Show > User sees setup shortcut buttons' do
describe 'Auto DevOps button' do describe 'Auto DevOps button' do
it '"Enable Auto DevOps" button linked to settings page' do it '"Enable Auto DevOps" button linked to settings page' do
page.within('.project-stats') do page.within('.project-stats') do
expect(page).to have_link('Enable Auto DevOps', href: project_settings_ci_cd_path(project, anchor: 'js-general-pipeline-settings')) expect(page).to have_link('Enable Auto DevOps', href: project_settings_ci_cd_path(project, anchor: 'autodevops-settings'))
end end
end end
...@@ -75,7 +75,7 @@ describe 'Projects > Show > User sees setup shortcut buttons' do ...@@ -75,7 +75,7 @@ describe 'Projects > Show > User sees setup shortcut buttons' do
visit project_path(project) visit project_path(project)
page.within('.project-stats') do page.within('.project-stats') do
expect(page).to have_link('Auto DevOps enabled', href: project_settings_ci_cd_path(project, anchor: 'js-general-pipeline-settings')) expect(page).to have_link('Auto DevOps enabled', href: project_settings_ci_cd_path(project, anchor: 'autodevops-settings'))
end end
end end
end end
...@@ -212,7 +212,7 @@ describe 'Projects > Show > User sees setup shortcut buttons' do ...@@ -212,7 +212,7 @@ describe 'Projects > Show > User sees setup shortcut buttons' do
describe 'Auto DevOps button' do describe 'Auto DevOps button' do
it '"Enable Auto DevOps" button linked to settings page' do it '"Enable Auto DevOps" button linked to settings page' do
page.within('.project-stats') do page.within('.project-stats') do
expect(page).to have_link('Enable Auto DevOps', href: project_settings_ci_cd_path(project, anchor: 'js-general-pipeline-settings')) expect(page).to have_link('Enable Auto DevOps', href: project_settings_ci_cd_path(project, anchor: 'autodevops-settings'))
end end
end end
...@@ -222,7 +222,7 @@ describe 'Projects > Show > User sees setup shortcut buttons' do ...@@ -222,7 +222,7 @@ describe 'Projects > Show > User sees setup shortcut buttons' do
visit project_path(project) visit project_path(project)
page.within('.project-stats') do page.within('.project-stats') do
expect(page).to have_link('Auto DevOps enabled', href: project_settings_ci_cd_path(project, anchor: 'js-general-pipeline-settings')) expect(page).to have_link('Auto DevOps enabled', href: project_settings_ci_cd_path(project, anchor: 'autodevops-settings'))
end end
end end
......
...@@ -13,9 +13,9 @@ describe('Settings Panels', () => { ...@@ -13,9 +13,9 @@ describe('Settings Panels', () => {
}); });
it('should expand linked hash fragment panel', () => { it('should expand linked hash fragment panel', () => {
location.hash = '#js-general-pipeline-settings'; location.hash = '#autodevops-settings';
const pipelineSettingsPanel = document.querySelector('#js-general-pipeline-settings'); const pipelineSettingsPanel = document.querySelector('#autodevops-settings');
// Our test environment automatically expands everything so we need to clear that out first // Our test environment automatically expands everything so we need to clear that out first
pipelineSettingsPanel.classList.remove('expanded'); pipelineSettingsPanel.classList.remove('expanded');
......
...@@ -55,7 +55,6 @@ describe('Commit component', () => { ...@@ -55,7 +55,6 @@ describe('Commit component', () => {
path: '/jschatz1', path: '/jschatz1',
username: 'jschatz1', username: 'jschatz1',
}, },
commitIconSvg: '<svg></svg>',
}; };
component = mountComponent(CommitComponent, props); component = mountComponent(CommitComponent, props);
...@@ -82,8 +81,10 @@ describe('Commit component', () => { ...@@ -82,8 +81,10 @@ describe('Commit component', () => {
expect(component.$el.querySelector('.commit-sha').textContent).toContain(props.shortSha); expect(component.$el.querySelector('.commit-sha').textContent).toContain(props.shortSha);
}); });
it('should render the given commitIconSvg', () => { it('should render icon for commit', () => {
expect(component.$el.querySelector('.js-commit-icon').children).toContain('svg'); expect(
component.$el.querySelector('.js-commit-icon use').getAttribute('xlink:href'),
).toContain('commit');
}); });
describe('Given commit title and author props', () => { describe('Given commit title and author props', () => {
......
...@@ -3,10 +3,10 @@ import expandButton from '~/vue_shared/components/expand_button.vue'; ...@@ -3,10 +3,10 @@ import expandButton from '~/vue_shared/components/expand_button.vue';
import mountComponent from 'spec/helpers/vue_mount_component_helper'; import mountComponent from 'spec/helpers/vue_mount_component_helper';
describe('expand button', () => { describe('expand button', () => {
const Component = Vue.extend(expandButton);
let vm; let vm;
beforeEach(() => { beforeEach(() => {
const Component = Vue.extend(expandButton);
vm = mountComponent(Component, { vm = mountComponent(Component, {
slots: { slots: {
expanded: '<p>Expanded!</p>', expanded: '<p>Expanded!</p>',
...@@ -22,7 +22,7 @@ describe('expand button', () => { ...@@ -22,7 +22,7 @@ describe('expand button', () => {
expect(vm.$el.textContent.trim()).toEqual('...'); expect(vm.$el.textContent.trim()).toEqual('...');
}); });
it('hides expander on click', (done) => { it('hides expander on click', done => {
vm.$el.querySelector('button').click(); vm.$el.querySelector('button').click();
vm.$nextTick(() => { vm.$nextTick(() => {
expect(vm.$el.querySelector('button').getAttribute('style')).toEqual('display: none;'); expect(vm.$el.querySelector('button').getAttribute('style')).toEqual('display: none;');
......
...@@ -73,6 +73,22 @@ describe('BaseComponent', () => { ...@@ -73,6 +73,22 @@ describe('BaseComponent', () => {
expect(vm.$emit).toHaveBeenCalledWith('onLabelClick', mockLabels[0]); expect(vm.$emit).toHaveBeenCalledWith('onLabelClick', mockLabels[0]);
}); });
}); });
describe('handleCollapsedValueClick', () => {
it('emits toggleCollapse event on component', () => {
spyOn(vm, '$emit');
vm.handleCollapsedValueClick();
expect(vm.$emit).toHaveBeenCalledWith('toggleCollapse');
});
});
describe('handleDropdownHidden', () => {
it('emits onDropdownClose event on component', () => {
spyOn(vm, '$emit');
vm.handleDropdownHidden();
expect(vm.$emit).toHaveBeenCalledWith('onDropdownClose');
});
});
}); });
describe('mounted', () => { describe('mounted', () => {
......
...@@ -56,6 +56,16 @@ describe('DropdownValueCollapsedComponent', () => { ...@@ -56,6 +56,16 @@ describe('DropdownValueCollapsedComponent', () => {
}); });
}); });
describe('methods', () => {
describe('handleClick', () => {
it('emits onValueClick event on component', () => {
spyOn(vm, '$emit');
vm.handleClick();
expect(vm.$emit).toHaveBeenCalledWith('onValueClick');
});
});
});
describe('template', () => { describe('template', () => {
it('renders component container element with tooltip`', () => { it('renders component container element with tooltip`', () => {
expect(vm.$el.dataset.placement).toBe('left'); expect(vm.$el.dataset.placement).toBe('left');
......
require 'spec_helper' require 'spec_helper'
describe Gitlab::Wiki::CommitterWithHooks, seed_helper: true do describe Gitlab::Git::CommitterWithHooks, seed_helper: true do
shared_examples 'calling wiki hooks' do shared_examples 'calling wiki hooks' do
let(:project) { create(:project) } let(:project) { create(:project) }
let(:user) { project.owner } let(:user) { project.owner }
......
require 'spec_helper'
require Rails.root.join('db', 'migrate', '20180413022611_create_missing_namespace_for_internal_users.rb')
describe CreateMissingNamespaceForInternalUsers, :migration do
let(:users) { table(:users) }
let(:namespaces) { table(:namespaces) }
let(:routes) { table(:routes) }
internal_user_types = [:ghost]
internal_user_types << :support_bot if ActiveRecord::Base.connection.column_exists?(:users, :support_bot)
internal_user_types.each do |attr|
context "for #{attr} user" do
let(:internal_user) do
users.create!(email: 'test@example.com', projects_limit: 100, username: 'test', attr => true)
end
it 'creates the missing namespace' do
expect(namespaces.find_by(owner_id: internal_user.id)).to be_nil
migrate!
namespace = Namespace.find_by(type: nil, owner_id: internal_user.id)
route = namespace.route
expect(namespace.path).to eq(route.path)
expect(namespace.name).to eq(route.name)
end
it 'sets notification email' do
users.update(internal_user.id, notification_email: nil)
expect(users.find(internal_user.id).notification_email).to be_nil
migrate!
user = users.find(internal_user.id)
expect(user.notification_email).to eq(user.email)
end
end
end
end
...@@ -321,7 +321,7 @@ describe ProjectPresenter do ...@@ -321,7 +321,7 @@ describe ProjectPresenter do
expect(presenter.autodevops_anchor_data).to eq(OpenStruct.new(enabled: false, expect(presenter.autodevops_anchor_data).to eq(OpenStruct.new(enabled: false,
label: 'Enable Auto DevOps', label: 'Enable Auto DevOps',
link: presenter.project_settings_ci_cd_path(project, anchor: 'js-general-pipeline-settings'))) link: presenter.project_settings_ci_cd_path(project, anchor: 'autodevops-settings')))
end end
end end
end end
......
...@@ -685,7 +685,8 @@ describe API::Projects do ...@@ -685,7 +685,8 @@ describe API::Projects do
issues_enabled: false, issues_enabled: false,
merge_requests_enabled: false, merge_requests_enabled: false,
wiki_enabled: false, wiki_enabled: false,
request_access_enabled: true request_access_enabled: true,
jobs_enabled: true
}) })
post api("/projects/user/#{user.id}", admin), project post api("/projects/user/#{user.id}", admin), project
......
require 'spec_helper' require 'spec_helper'
describe 'projects/settings/ci_cd/_form' do describe 'projects/settings/ci_cd/_autodevops_form' do
let(:project) { create(:project, :repository) } let(:project) { create(:project, :repository) }
before do before do
......
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