Commit 1e2cacf0 authored by GitLab Bot's avatar GitLab Bot

Merge remote-tracking branch 'upstream/master' into ce-to-ee-2017-12-14

# Conflicts:
#	app/assets/images/icons.json
#	app/assets/images/icons.svg
#	app/assets/javascripts/dispatcher.js
#	app/assets/javascripts/project_find_file.js
#	app/assets/javascripts/render_gfm.js
#	app/assets/javascripts/search.js
#	app/assets/javascripts/search_autocomplete.js
#	app/assets/stylesheets/framework/variables.scss
#	app/assets/stylesheets/pages/boards.scss
#	app/assets/stylesheets/pages/merge_requests.scss
#	app/controllers/admin/groups_controller.rb
#	app/presenters/group_member_presenter.rb
#	app/presenters/member_presenter.rb
#	app/presenters/project_member_presenter.rb
#	app/views/projects/clusters/index.html.haml
#	app/views/projects/merge_requests/_mr_title.html.haml
#	app/views/shared/members/_member.html.haml
#	app/workers/all_queues.yml
#	lib/gitlab/sidekiq_config.rb
#	spec/javascripts/search_autocomplete_spec.js
#	spec/models/ci/build_spec.rb
#	spec/models/merge_request_spec.rb

[ci skip]
parents c52a313f d7c1a9d9
{"iconCount":179,"spriteSize":81882,"icons":["abuse","account","admin","angle-double-left","angle-double-right","angle-down","angle-left","angle-right","angle-up","appearance","applications","approval","arrow-right","assignee","bold","book","branch","bullhorn","calendar","cancel","chart","chevron-down","chevron-left","chevron-right","chevron-up","clock","close","code","collapse","comment-dots","comment-next","comment","comments","commit","credit-card","cut","dashboard","disk","doc_code","doc_image","doc_text","double-headed-arrow","download","duplicate","earth","ellipsis_v","emoji_slightly_smiling_face","emoji_smile","emoji_smiley","epic","external-link","eye-slash","eye","file-addition","file-deletion","file-modified","filter","folder","fork","geo-nodes","git-merge","group","history","home","hook","hourglass","image-comment-dark","import","issue-block","issue-child","issue-close","issue-duplicate","issue-new","issue-open-m","issue-open","issue-parent","issues","italic","key-2","key","label","labels","leave","level-up","license","link","list-bulleted","list-numbered","location-dot","location","lock-open","lock","log","mail","menu","merge-request-close","messages","mobile-issue-close","monitor","more","notifications-off","notifications","overview","pencil-square","pencil","pipeline","play","plus-square-o","plus-square","plus","preferences","profile","project","push-rules","question-o","question","quote","redo","remove","repeat","retry","scale","screen-full","screen-normal","scroll_down","scroll_up","search","settings","shield","slight-frown","slight-smile","smile","smiley","snippet","spam","spinner","star-o","star","status_canceled_borderless","status_canceled","status_closed","status_created_borderless","status_created","status_failed_borderless","status_failed","status_manual_borderless","status_manual","status_notfound_borderless","status_open","status_pending_borderless","status_pending","status_running_borderless","status_running","status_skipped_borderless","status_skipped","status_success_borderless","status_success_solid","status_success","status_warning_borderless","status_warning","stop","task-done","template","terminal","thumb-down","thumb-up","thumbtack","timer","todo-add","todo-done","token","unapproval","unassignee","unlink","user","users","volume-up","warning","work"]} <<<<<<< HEAD
\ No newline at end of file {"iconCount":179,"spriteSize":81882,"icons":["abuse","account","admin","angle-double-left","angle-double-right","angle-down","angle-left","angle-right","angle-up","appearance","applications","approval","arrow-right","assignee","bold","book","branch","bullhorn","calendar","cancel","chart","chevron-down","chevron-left","chevron-right","chevron-up","clock","close","code","collapse","comment-dots","comment-next","comment","comments","commit","credit-card","cut","dashboard","disk","doc_code","doc_image","doc_text","double-headed-arrow","download","duplicate","earth","ellipsis_v","emoji_slightly_smiling_face","emoji_smile","emoji_smiley","epic","external-link","eye-slash","eye","file-addition","file-deletion","file-modified","filter","folder","fork","geo-nodes","git-merge","group","history","home","hook","hourglass","image-comment-dark","import","issue-block","issue-child","issue-close","issue-duplicate","issue-new","issue-open-m","issue-open","issue-parent","issues","italic","key-2","key","label","labels","leave","level-up","license","link","list-bulleted","list-numbered","location-dot","location","lock-open","lock","log","mail","menu","merge-request-close","messages","mobile-issue-close","monitor","more","notifications-off","notifications","overview","pencil-square","pencil","pipeline","play","plus-square-o","plus-square","plus","preferences","profile","project","push-rules","question-o","question","quote","redo","remove","repeat","retry","scale","screen-full","screen-normal","scroll_down","scroll_up","search","settings","shield","slight-frown","slight-smile","smile","smiley","snippet","spam","spinner","star-o","star","status_canceled_borderless","status_canceled","status_closed","status_created_borderless","status_created","status_failed_borderless","status_failed","status_manual_borderless","status_manual","status_notfound_borderless","status_open","status_pending_borderless","status_pending","status_running_borderless","status_running","status_skipped_borderless","status_skipped","status_success_borderless","status_success_solid","status_success","status_warning_borderless","status_warning","stop","task-done","template","terminal","thumb-down","thumb-up","thumbtack","timer","todo-add","todo-done","token","unapproval","unassignee","unlink","user","users","volume-up","warning","work"]}
=======
{"iconCount":181,"spriteSize":81482,"icons":["abuse","account","admin","angle-double-left","angle-double-right","angle-down","angle-left","angle-right","angle-up","appearance","applications","approval","arrow-down","arrow-right","assignee","bold","book","branch","bullhorn","calendar","cancel","chart","chevron-down","chevron-left","chevron-right","chevron-up","clock","close","code","collapse","comment-dots","comment-next","comment","comments","commit","credit-card","cut","dashboard","disk","doc_code","doc_image","doc_text","double-headed-arrow","download","duplicate","earth","ellipsis_v","emoji_slightly_smiling_face","emoji_smile","emoji_smiley","epic","external-link","eye-slash","eye","file-addition","file-deletion","file-modified","filter","folder","fork","geo-nodes","git-merge","group","history","home","hook","hourglass","image-comment-dark","image-comment-light","import","issue-block","issue-child","issue-close","issue-duplicate","issue-new","issue-open-m","issue-open","issue-parent","issues","italic","key-2","key","label","labels","leave","level-up","license","link","list-bulleted","list-numbered","location-dot","location","lock-open","lock","log","mail","menu","merge-request-close","messages","mobile-issue-close","monitor","more","notifications-off","notifications","overview","pencil-square","pencil","pipeline","play","plus-square-o","plus-square","plus","preferences","profile","project","push-rules","question-o","question","quote","redo","remove","repeat","retry","scale","screen-full","screen-normal","scroll_down","scroll_up","search","settings","shield","slight-frown","slight-smile","smile","smiley","snippet","spam","spinner","star-o","star","status_canceled_borderless","status_canceled","status_closed","status_created_borderless","status_created","status_failed_borderless","status_failed","status_manual_borderless","status_manual","status_notfound_borderless","status_open","status_pending_borderless","status_pending","status_running_borderless","status_running","status_skipped_borderless","status_skipped","status_success_borderless","status_success_solid","status_success","status_warning_borderless","status_warning","stop","task-done","template","terminal","thumb-down","thumb-up","thumbtack","timer","todo-add","todo-done","token","unapproval","unassignee","unlink","user","users","volume-up","warning","work"]}
>>>>>>> upstream/master
This source diff could not be displayed because it is too large. You can view the blob instead.
...@@ -24,7 +24,10 @@ import projectAvatar from './project_avatar'; ...@@ -24,7 +24,10 @@ import projectAvatar from './project_avatar';
/* global MergeRequest */ /* global MergeRequest */
import Compare from './compare'; import Compare from './compare';
import initCompareAutocomplete from './compare_autocomplete'; import initCompareAutocomplete from './compare_autocomplete';
<<<<<<< HEAD
/* global PathLocks */ /* global PathLocks */
=======
>>>>>>> upstream/master
import ProjectFindFile from './project_find_file'; import ProjectFindFile from './project_find_file';
import ProjectNew from './project_new'; import ProjectNew from './project_new';
import projectImport from './project_import'; import projectImport from './project_import';
...@@ -98,12 +101,15 @@ import ProjectLabelSubscription from './project_label_subscription'; ...@@ -98,12 +101,15 @@ import ProjectLabelSubscription from './project_label_subscription';
import ProjectVariables from './project_variables'; import ProjectVariables from './project_variables';
import SearchAutocomplete from './search_autocomplete'; import SearchAutocomplete from './search_autocomplete';
import Activities from './activities'; import Activities from './activities';
<<<<<<< HEAD
// EE-only // EE-only
import ApproversSelect from './approvers_select'; import ApproversSelect from './approvers_select';
import AuditLogs from './audit_logs'; import AuditLogs from './audit_logs';
import initGeoInfoModal from './init_geo_info_modal'; import initGeoInfoModal from './init_geo_info_modal';
import initGroupAnalytics from './init_group_analytics'; import initGroupAnalytics from './init_group_analytics';
=======
>>>>>>> upstream/master
(function() { (function() {
var Dispatcher; var Dispatcher;
...@@ -410,7 +416,10 @@ import initGroupAnalytics from './init_group_analytics'; ...@@ -410,7 +416,10 @@ import initGroupAnalytics from './init_group_analytics';
if ($('#tree-slider').length) new TreeView(); if ($('#tree-slider').length) new TreeView();
if ($('.blob-viewer').length) new BlobViewer(); if ($('.blob-viewer').length) new BlobViewer();
if ($('.project-show-activity').length) new Activities(); if ($('.project-show-activity').length) new Activities();
<<<<<<< HEAD
=======
>>>>>>> upstream/master
$('#tree-slider').waitForImages(function() { $('#tree-slider').waitForImages(function() {
ajaxGet(document.querySelector('.js-tree-content').dataset.logsPath); ajaxGet(document.querySelector('.js-tree-content').dataset.logsPath);
}); });
......
<script> <script>
import { s__ } from '../../locale'; import { s__ } from '../../locale';
import tooltip from '../../vue_shared/directives/tooltip'; import tooltip from '../../vue_shared/directives/tooltip';
import PopupDialog from '../../vue_shared/components/popup_dialog.vue'; import modal from '../../vue_shared/components/modal.vue';
import eventHub from '../event_hub'; import eventHub from '../event_hub';
import { COMMON_STR } from '../constants'; import { COMMON_STR } from '../constants';
import Icon from '../../vue_shared/components/icon.vue'; import Icon from '../../vue_shared/components/icon.vue';
...@@ -9,7 +9,7 @@ import Icon from '../../vue_shared/components/icon.vue'; ...@@ -9,7 +9,7 @@ import Icon from '../../vue_shared/components/icon.vue';
export default { export default {
components: { components: {
Icon, Icon,
PopupDialog, modal,
}, },
directives: { directives: {
tooltip, tooltip,
...@@ -27,7 +27,7 @@ export default { ...@@ -27,7 +27,7 @@ export default {
}, },
data() { data() {
return { return {
dialogStatus: false, modalStatus: false,
}; };
}, },
computed: { computed: {
...@@ -43,10 +43,10 @@ export default { ...@@ -43,10 +43,10 @@ export default {
}, },
methods: { methods: {
onLeaveGroup() { onLeaveGroup() {
this.dialogStatus = true; this.modalStatus = true;
}, },
leaveGroup(leaveConfirmed) { leaveGroup(leaveConfirmed) {
this.dialogStatus = false; this.modalStatus = false;
if (leaveConfirmed) { if (leaveConfirmed) {
eventHub.$emit('leaveGroup', this.group, this.parentGroup); eventHub.$emit('leaveGroup', this.group, this.parentGroup);
} }
...@@ -82,8 +82,8 @@ export default { ...@@ -82,8 +82,8 @@ export default {
class="fa fa-sign-out" class="fa fa-sign-out"
aria-hidden="true"/> aria-hidden="true"/>
</a> </a>
<popup-dialog <modal
v-show="dialogStatus" v-show="modalStatus"
:primary-button-label="__('Leave')" :primary-button-label="__('Leave')"
kind="warning" kind="warning"
:title="__('Are you sure?')" :title="__('Are you sure?')"
......
...@@ -48,7 +48,7 @@ export default class Issue { ...@@ -48,7 +48,7 @@ export default class Issue {
}) })
.fail(() => new Flash(issueFailMessage)) .fail(() => new Flash(issueFailMessage))
.done((data) => { .done((data) => {
const isClosedBadge = $('div.status-box-closed'); const isClosedBadge = $('div.status-box-issue-closed');
const isOpenBadge = $('div.status-box-open'); const isOpenBadge = $('div.status-box-open');
const projectIssuesCounter = $('.issue_counter'); const projectIssuesCounter = $('.issue_counter');
......
...@@ -9,7 +9,7 @@ import titleComponent from './title.vue'; ...@@ -9,7 +9,7 @@ import titleComponent from './title.vue';
import descriptionComponent from './description.vue'; import descriptionComponent from './description.vue';
import editedComponent from './edited.vue'; import editedComponent from './edited.vue';
import formComponent from './form.vue'; import formComponent from './form.vue';
import RecaptchaDialogImplementor from '../../vue_shared/mixins/recaptcha_dialog_implementor'; import recaptchaModalImplementor from '../../vue_shared/mixins/recaptcha_modal_implementor';
export default { export default {
props: { props: {
...@@ -152,7 +152,7 @@ export default { ...@@ -152,7 +152,7 @@ export default {
}, },
mixins: [ mixins: [
RecaptchaDialogImplementor, recaptchaModalImplementor,
], ],
methods: { methods: {
...@@ -197,7 +197,7 @@ export default { ...@@ -197,7 +197,7 @@ export default {
}); });
}, },
closeRecaptchaDialog() { closeRecaptchaModal() {
this.store.setFormState({ this.store.setFormState({
updateLoading: false, updateLoading: false,
}); });
...@@ -272,10 +272,10 @@ export default { ...@@ -272,10 +272,10 @@ export default {
:enable-autocomplete="enableAutocomplete" :enable-autocomplete="enableAutocomplete"
/> />
<recaptcha-dialog <recaptcha-modal
v-show="showRecaptcha" v-show="showRecaptcha"
:html="recaptchaHTML" :html="recaptchaHTML"
@close="closeRecaptchaDialog" @close="closeRecaptchaModal"
/> />
</div> </div>
<div v-else> <div v-else>
......
<script> <script>
import animateMixin from '../mixins/animate'; import animateMixin from '../mixins/animate';
import TaskList from '../../task_list'; import TaskList from '../../task_list';
import RecaptchaDialogImplementor from '../../vue_shared/mixins/recaptcha_dialog_implementor'; import recaptchaModalImplementor from '../../vue_shared/mixins/recaptcha_modal_implementor';
export default { export default {
mixins: [ mixins: [
animateMixin, animateMixin,
RecaptchaDialogImplementor, recaptchaModalImplementor,
], ],
props: { props: {
...@@ -126,7 +126,7 @@ ...@@ -126,7 +126,7 @@
> >
</textarea> </textarea>
<recaptcha-dialog <recaptcha-modal
v-show="showRecaptcha" v-show="showRecaptcha"
:html="recaptchaHTML" :html="recaptchaHTML"
@close="closeRecaptcha" @close="closeRecaptcha"
......
...@@ -47,7 +47,7 @@ ...@@ -47,7 +47,7 @@
<textarea <textarea
id="issue-description" id="issue-description"
class="note-textarea js-gfm-input js-autosize markdown-area" class="note-textarea js-gfm-input js-autosize markdown-area"
data-supports-quick-actionss="false" data-supports-quick-actions="false"
aria-label="Description" aria-label="Description"
v-model="formState.description" v-model="formState.description"
ref="textarea" ref="textarea"
......
...@@ -123,9 +123,7 @@ ...@@ -123,9 +123,7 @@
// we need to do this to prevent noteForm inconsistent content warning // we need to do this to prevent noteForm inconsistent content warning
// this is something we intentionally do so we need to recover the content // this is something we intentionally do so we need to recover the content
this.note.note = noteText; this.note.note = noteText;
if (this.$refs.noteBody) { this.$refs.noteBody.$refs.noteForm.note = noteText;
this.$refs.noteBody.$refs.noteForm.note = noteText; // TODO: This could be better
}
}, },
}, },
created() { created() {
......
<script> <script>
export default { export default {
props: { props: {
helpPagePath: { helpPagePath: {
type: String, type: String,
required: true, required: true,
},
emptyStateSvgPath: {
type: String,
required: true,
},
}, },
emptyStateSvgPath: { };
type: String,
required: true,
},
},
};
</script> </script>
<template> <template>
<div class="row empty-state js-empty-state"> <div class="row empty-state js-empty-state">
<div class="col-xs-12"> <div class="col-xs-12">
<div class="svg-content"> <div class="svg-content svg-250">
<img :src="emptyStateSvgPath"/> <img :src="emptyStateSvgPath" />
</div> </div>
</div> </div>
<div class="col-xs-12 text-center"> <div class="col-xs-12">
<div class="text-content"> <div class="text-content">
<h4>Build with confidence</h4> <h4 class="text-center">
{{ s__("Pipelines|Build with confidence") }}
</h4>
<p> <p>
Continous Integration can help catch bugs by running your tests automatically, {{ s__("Pipelines|Continous Integration can help catch bugs by running your tests automatically, while Continuous Deployment can help you deliver code to your product environment.") }}
while Continuous Deployment can help you deliver code to your product environment.
</p> </p>
<a :href="helpPagePath" class="btn btn-info"> <div class="text-center">
Get started with Pipelines <a
</a> :href="helpPagePath"
class="btn btn-info"
>
{{ s__("Pipelines|Get started with Pipelines") }}
</a>
</div>
</div> </div>
</div> </div>
</div> </div>
......
...@@ -59,8 +59,26 @@ ...@@ -59,8 +59,26 @@
}, },
computed: { computed: {
status() {
return this.job && this.job.status ? this.job.status : {};
},
tooltipText() { tooltipText() {
return `${this.job.name} - ${this.job.status.label}`; const textBuilder = [];
if (this.job.name) {
textBuilder.push(this.job.name);
}
if (this.job.name && this.status.label) {
textBuilder.push('-');
}
if (this.status.label) {
textBuilder.push(`${this.job.status.label}`);
}
return textBuilder.join(' ');
}, },
/** /**
...@@ -78,8 +96,8 @@ ...@@ -78,8 +96,8 @@
<div class="ci-job-component"> <div class="ci-job-component">
<a <a
v-tooltip v-tooltip
v-if="job.status.has_details" v-if="status.has_details"
:href="job.status.details_path" :href="status.details_path"
:title="tooltipText" :title="tooltipText"
:class="cssClassJobName" :class="cssClassJobName"
data-container="body" data-container="body"
...@@ -95,6 +113,7 @@ ...@@ -95,6 +113,7 @@
<div <div
v-else v-else
v-tooltip v-tooltip
class="js-job-component-tooltip"
:title="tooltipText" :title="tooltipText"
:class="cssClassJobName" :class="cssClassJobName"
data-container="body" data-container="body"
...@@ -108,18 +127,18 @@ ...@@ -108,18 +127,18 @@
<action-component <action-component
v-if="hasAction && !isDropdown" v-if="hasAction && !isDropdown"
:tooltip-text="job.status.action.title" :tooltip-text="status.action.title"
:link="job.status.action.path" :link="status.action.path"
:action-icon="job.status.action.icon" :action-icon="status.action.icon"
:action-method="job.status.action.method" :action-method="status.action.method"
/> />
<dropdown-action-component <dropdown-action-component
v-if="hasAction && isDropdown" v-if="hasAction && isDropdown"
:tooltip-text="job.status.action.title" :tooltip-text="status.action.title"
:link="job.status.action.path" :link="status.action.path"
:action-icon="job.status.action.icon" :action-icon="status.action.icon"
:action-method="job.status.action.method" :action-method="status.action.method"
/> />
</div> </div>
</template> </template>
import Vue from 'vue'; import Vue from 'vue';
import PipelinesStore from './stores/pipelines_store'; import PipelinesStore from './stores/pipelines_store';
import pipelinesComponent from './components/pipelines.vue'; import pipelinesComponent from './components/pipelines.vue';
import Translate from '../vue_shared/translate';
Vue.use(Translate);
document.addEventListener('DOMContentLoaded', () => new Vue({ document.addEventListener('DOMContentLoaded', () => new Vue({
el: '#pipelines-list-vue', el: '#pipelines-list-vue',
......
<script> <script>
import popupDialog from '../../../vue_shared/components/popup_dialog.vue'; import modal from '../../../vue_shared/components/modal.vue';
import { __, s__, sprintf } from '../../../locale'; import { __, s__, sprintf } from '../../../locale';
import csrf from '../../../lib/utils/csrf'; import csrf from '../../../lib/utils/csrf';
...@@ -26,7 +26,7 @@ ...@@ -26,7 +26,7 @@
}; };
}, },
components: { components: {
popupDialog, modal,
}, },
computed: { computed: {
csrfToken() { csrfToken() {
...@@ -89,7 +89,7 @@ Once you confirm %{deleteAccount}, it cannot be undone or recovered.`), ...@@ -89,7 +89,7 @@ Once you confirm %{deleteAccount}, it cannot be undone or recovered.`),
<template> <template>
<div> <div>
<popup-dialog <modal
v-if="isOpen" v-if="isOpen"
:title="s__('Profiles|Delete your account?')" :title="s__('Profiles|Delete your account?')"
:text="text" :text="text"
...@@ -134,7 +134,7 @@ Once you confirm %{deleteAccount}, it cannot be undone or recovered.`), ...@@ -134,7 +134,7 @@ Once you confirm %{deleteAccount}, it cannot be undone or recovered.`),
</form> </form>
</template> </template>
</popup-dialog> </modal>
<button <button
type="button" type="button"
......
...@@ -28,8 +28,12 @@ const highlighter = function(element, text, matches) { ...@@ -28,8 +28,12 @@ const highlighter = function(element, text, matches) {
}; };
export default class ProjectFindFile { export default class ProjectFindFile {
<<<<<<< HEAD
constructor (element1, options) { constructor (element1, options) {
=======
constructor(element1, options) {
>>>>>>> upstream/master
this.element = element1; this.element = element1;
this.options = options; this.options = options;
this.goToBlob = this.goToBlob.bind(this); this.goToBlob = this.goToBlob.bind(this);
...@@ -71,7 +75,11 @@ export default class ProjectFindFile { ...@@ -71,7 +75,11 @@ export default class ProjectFindFile {
// find file // find file
} }
<<<<<<< HEAD
// files pathes load // files pathes load
=======
// files pathes load
>>>>>>> upstream/master
load(url) { load(url) {
return $.ajax({ return $.ajax({
url: url, url: url,
......
import renderMath from './render_math'; import renderMath from './render_math';
import renderMermaid from './render_mermaid'; import renderMermaid from './render_mermaid';
import syntaxHighlight from './syntax_highlight'; import syntaxHighlight from './syntax_highlight';
<<<<<<< HEAD
=======
>>>>>>> upstream/master
// Render Gitlab flavoured Markdown // Render Gitlab flavoured Markdown
// //
// Delegates to syntax highlight and render math & mermaid diagrams. // Delegates to syntax highlight and render math & mermaid diagrams.
......
<script> <script>
import { mapActions } from 'vuex'; import { mapActions } from 'vuex';
import { __ } from '../../../locale'; import { __ } from '../../../locale';
import popupDialog from '../../../vue_shared/components/popup_dialog.vue'; import modal from '../../../vue_shared/components/modal.vue';
export default { export default {
props: { props: {
...@@ -20,7 +20,7 @@ ...@@ -20,7 +20,7 @@
}; };
}, },
components: { components: {
popupDialog, modal,
}, },
methods: { methods: {
...mapActions([ ...mapActions([
...@@ -68,7 +68,7 @@ ...@@ -68,7 +68,7 @@
</script> </script>
<template> <template>
<popup-dialog <modal
:title="modalTitle" :title="modalTitle"
:primary-button-label="buttonLabel" :primary-button-label="buttonLabel"
kind="success" kind="success"
...@@ -94,5 +94,5 @@ ...@@ -94,5 +94,5 @@
</div> </div>
</fieldset> </fieldset>
</form> </form>
</popup-dialog> </modal>
</template> </template>
...@@ -2,12 +2,12 @@ ...@@ -2,12 +2,12 @@
import { mapGetters, mapState, mapActions } from 'vuex'; import { mapGetters, mapState, mapActions } from 'vuex';
import tooltip from '../../vue_shared/directives/tooltip'; import tooltip from '../../vue_shared/directives/tooltip';
import icon from '../../vue_shared/components/icon.vue'; import icon from '../../vue_shared/components/icon.vue';
import PopupDialog from '../../vue_shared/components/popup_dialog.vue'; import modal from '../../vue_shared/components/modal.vue';
import commitFilesList from './commit_sidebar/list.vue'; import commitFilesList from './commit_sidebar/list.vue';
export default { export default {
components: { components: {
PopupDialog, modal,
icon, icon,
commitFilesList, commitFilesList,
}, },
...@@ -16,7 +16,7 @@ export default { ...@@ -16,7 +16,7 @@ export default {
}, },
data() { data() {
return { return {
showNewBranchDialog: false, showNewBranchModal: false,
submitCommitsLoading: false, submitCommitsLoading: false,
startNewMR: false, startNewMR: false,
commitMessage: '', commitMessage: '',
...@@ -58,7 +58,7 @@ export default { ...@@ -58,7 +58,7 @@ export default {
start_branch: createNewBranch ? this.currentBranch : undefined, start_branch: createNewBranch ? this.currentBranch : undefined,
}; };
this.showNewBranchDialog = false; this.showNewBranchModal = false;
this.submitCommitsLoading = true; this.submitCommitsLoading = true;
this.commitChanges({ payload, newMr: this.startNewMR }) this.commitChanges({ payload, newMr: this.startNewMR })
...@@ -76,7 +76,7 @@ export default { ...@@ -76,7 +76,7 @@ export default {
this.checkCommitStatus() this.checkCommitStatus()
.then((branchChanged) => { .then((branchChanged) => {
if (branchChanged) { if (branchChanged) {
this.showNewBranchDialog = true; this.showNewBranchModal = true;
} else { } else {
this.makeCommit(); this.makeCommit();
} }
...@@ -99,13 +99,13 @@ export default { ...@@ -99,13 +99,13 @@ export default {
'is-collapsed': collapsed, 'is-collapsed': collapsed,
}" }"
> >
<popup-dialog <modal
v-if="showNewBranchDialog" v-if="showNewBranchModal"
:primary-button-label="__('Create new branch')" :primary-button-label="__('Create new branch')"
kind="primary" kind="primary"
:title="__('Branch has changed')" :title="__('Branch has changed')"
:text="__('This branch has changed since you started editing. Would you like to create a new branch?')" :text="__('This branch has changed since you started editing. Would you like to create a new branch?')"
@toggle="showNewBranchDialog = false" @toggle="showNewBranchModal = false"
@submit="makeCommit(true)" @submit="makeCommit(true)"
/> />
<button <button
......
<script> <script>
import { mapGetters, mapActions, mapState } from 'vuex'; import { mapGetters, mapActions, mapState } from 'vuex';
import popupDialog from '../../vue_shared/components/popup_dialog.vue'; import modal from '../../vue_shared/components/modal.vue';
export default { export default {
components: { components: {
popupDialog, modal,
}, },
computed: { computed: {
...mapState([ ...mapState([
...@@ -43,7 +43,7 @@ export default { ...@@ -43,7 +43,7 @@ export default {
{{buttonLabel}} {{buttonLabel}}
</span> </span>
</button> </button>
<popup-dialog <modal
v-if="discardPopupOpen" v-if="discardPopupOpen"
class="text-left" class="text-left"
:primary-button-label="__('Discard changes')" :primary-button-label="__('Discard changes')"
......
...@@ -79,7 +79,11 @@ export default class Search { ...@@ -79,7 +79,11 @@ export default class Search {
.on('keyup', this.searchInput, this.searchKeyUp); .on('keyup', this.searchInput, this.searchKeyUp);
$(document) $(document)
.off('click', this.searchClear) .off('click', this.searchClear)
<<<<<<< HEAD
.on('click', this.searchClear, this.clearSearchField); .on('click', this.searchClear, this.clearSearchField);
=======
.on('click', this.searchClear, this.clearSearchField.bind(this));
>>>>>>> upstream/master
} }
static submitSearch() { static submitSearch() {
......
<script> <script>
export default { export default {
name: 'popup-dialog', name: 'modal',
props: { props: {
title: { title: {
...@@ -75,7 +75,7 @@ export default { ...@@ -75,7 +75,7 @@ export default {
<template> <template>
<div class="modal-open"> <div class="modal-open">
<div <div
class="modal popup-dialog" class="modal show"
role="dialog" role="dialog"
tabindex="-1" tabindex="-1"
> >
......
<script> <script>
import PopupDialog from './popup_dialog.vue'; import modal from './modal.vue';
export default { export default {
name: 'recaptcha-dialog', name: 'recaptcha-modal',
props: { props: {
html: { html: {
...@@ -20,7 +20,7 @@ export default { ...@@ -20,7 +20,7 @@ export default {
}, },
components: { components: {
PopupDialog, modal,
}, },
methods: { methods: {
...@@ -65,9 +65,9 @@ export default { ...@@ -65,9 +65,9 @@ export default {
</script> </script>
<template> <template>
<popup-dialog <modal
kind="warning" kind="warning"
class="recaptcha-dialog js-recaptcha-dialog" class="recaptcha-modal js-recaptcha-modal"
:hide-footer="true" :hide-footer="true"
:title="__('Please solve the reCAPTCHA')" :title="__('Please solve the reCAPTCHA')"
@toggle="close" @toggle="close"
...@@ -81,5 +81,5 @@ export default { ...@@ -81,5 +81,5 @@ export default {
v-html="html" v-html="html"
></div> ></div>
</div> </div>
</popup-dialog> </modal>
</template> </template>
import RecaptchaDialog from '../components/recaptcha_dialog.vue'; import recaptchaModal from '../components/recaptcha_modal.vue';
export default { export default {
data() { data() {
...@@ -9,7 +9,7 @@ export default { ...@@ -9,7 +9,7 @@ export default {
}, },
components: { components: {
RecaptchaDialog, recaptchaModal,
}, },
methods: { methods: {
......
...@@ -19,6 +19,13 @@ ...@@ -19,6 +19,13 @@
max-width: 425px; max-width: 425px;
width: 100%; width: 100%;
} }
&.svg-250 {
img,
svg {
width: 250px;
}
}
} }
@mixin svg-size($size) { @mixin svg-size($size) {
......
...@@ -24,10 +24,14 @@ ...@@ -24,10 +24,14 @@
font-size: $gl-font-size; font-size: $gl-font-size;
line-height: 25px; line-height: 25px;
&.status-box-closed { &.status-box-mr-closed {
background-color: $gl-danger; background-color: $gl-danger;
} }
&.status-box-issue-closed {
background-color: $gl-primary;
}
&.status-box-merged { &.status-box-merged {
background-color: $gl-primary; background-color: $gl-primary;
} }
......
...@@ -44,11 +44,18 @@ body.modal-open { ...@@ -44,11 +44,18 @@ body.modal-open {
} }
} }
.modal.popup-dialog { .modal {
display: block; background-color: $black-transparent;
z-index: 2100;
@media (min-width: $screen-md-min) {
.modal-dialog {
margin: 30px auto;
}
}
} }
.recaptcha-dialog .recaptcha-form { .recaptcha-modal .recaptcha-form {
display: inline-block; display: inline-block;
.recaptcha { .recaptcha {
......
...@@ -741,6 +741,7 @@ Image Commenting cursor ...@@ -741,6 +741,7 @@ Image Commenting cursor
*/ */
$image-comment-cursor-left-offset: 12; $image-comment-cursor-left-offset: 12;
$image-comment-cursor-top-offset: 12; $image-comment-cursor-top-offset: 12;
<<<<<<< HEAD
/* /*
Add GitLab Slack Application Add GitLab Slack Application
...@@ -752,6 +753,8 @@ $add-to-slack-logo-size: 100px; ...@@ -752,6 +753,8 @@ $add-to-slack-logo-size: 100px;
$double-headed-arrow-width: 100px; $double-headed-arrow-width: 100px;
$double-headed-arrow-height: 25px; $double-headed-arrow-height: 25px;
$right-arrow-size: 16px; $right-arrow-size: 16px;
=======
>>>>>>> upstream/master
/* /*
Popup Popup
......
...@@ -458,6 +458,7 @@ ...@@ -458,6 +458,7 @@
margin: 5px; margin: 5px;
} }
<<<<<<< HEAD
.boards-title-holder { .boards-title-holder {
padding: 25px 13px $gl-padding; padding: 25px 13px $gl-padding;
...@@ -482,6 +483,8 @@ ...@@ -482,6 +483,8 @@
border-top: 1px solid $border-color; border-top: 1px solid $border-color;
} }
=======
>>>>>>> upstream/master
.page-with-contextual-sidebar.layout-page .issue-boards-sidebar { .page-with-contextual-sidebar.layout-page .issue-boards-sidebar {
.issuable-sidebar-header { .issuable-sidebar-header {
position: relative; position: relative;
......
...@@ -610,11 +610,19 @@ ...@@ -610,11 +610,19 @@
} }
.issuable-status-box { .issuable-status-box {
float: none; align-self: stretch;
display: inline-block; display: flex;
justify-content: center;
align-items: center;
margin-top: 0; margin-top: 0;
height: auto; padding-left: 9px;
align-self: center; padding-right: 9px;
@media (min-width: $screen-sm-min) {
display: inline-block;
height: auto;
align-self: center;
}
} }
.issuable-gutter-toggle { .issuable-gutter-toggle {
......
...@@ -773,6 +773,7 @@ ...@@ -773,6 +773,7 @@
font-size: 16px; font-size: 16px;
} }
} }
<<<<<<< HEAD
.mr-widget-icon { .mr-widget-icon {
font-size: 22px; font-size: 22px;
...@@ -824,3 +825,5 @@ ...@@ -824,3 +825,5 @@
} }
} }
} }
=======
>>>>>>> upstream/master
.modal.popup-dialog {
display: block;
background-color: $black-transparent;
z-index: 2100;
@media (min-width: $screen-md-min) {
.modal-dialog {
width: 600px;
margin: 30px auto;
}
}
}
.project-refs-form, .project-refs-form,
.project-refs-target-form { .project-refs-target-form {
display: inline-block; display: inline-block;
......
class Admin::GroupsController < Admin::ApplicationController class Admin::GroupsController < Admin::ApplicationController
include MembersPresentation include MembersPresentation
<<<<<<< HEAD
prepend EE::Admin::GroupsController prepend EE::Admin::GroupsController
=======
>>>>>>> upstream/master
before_action :group, only: [:edit, :update, :destroy, :project_update, :members_update] before_action :group, only: [:edit, :update, :destroy, :project_update, :members_update]
......
...@@ -6,6 +6,7 @@ module WithPerformanceBar ...@@ -6,6 +6,7 @@ module WithPerformanceBar
end end
def peek_enabled? def peek_enabled?
return true if Rails.env.development?
return false unless Gitlab::PerformanceBar.enabled?(current_user) return false unless Gitlab::PerformanceBar.enabled?(current_user)
if RequestStore.active? if RequestStore.active?
......
...@@ -118,20 +118,24 @@ module BlobHelper ...@@ -118,20 +118,24 @@ module BlobHelper
icon("#{file_type_icon_class('file', mode, name)} fw") icon("#{file_type_icon_class('file', mode, name)} fw")
end end
def blob_raw_path def blob_raw_url(only_path: false)
if @build && @entry if @build && @entry
raw_project_job_artifacts_path(@project, @build, path: @entry.path) raw_project_job_artifacts_url(@project, @build, path: @entry.path, only_path: only_path)
elsif @snippet elsif @snippet
if @snippet.project_id if @snippet.project_id
raw_project_snippet_path(@project, @snippet) raw_project_snippet_url(@project, @snippet, only_path: only_path)
else else
raw_snippet_path(@snippet) raw_snippet_url(@snippet, only_path: only_path)
end end
elsif @blob elsif @blob
project_raw_path(@project, @id) project_raw_url(@project, @id, only_path: only_path)
end end
end end
def blob_raw_path
blob_raw_url(only_path: true)
end
# SVGs can contain malicious JavaScript; only include whitelisted # SVGs can contain malicious JavaScript; only include whitelisted
# elements and attributes. Note that this whitelist is by no means complete # elements and attributes. Note that this whitelist is by no means complete
# and may omit some elements. # and may omit some elements.
......
...@@ -104,15 +104,23 @@ module DiffHelper ...@@ -104,15 +104,23 @@ module DiffHelper
].join(' ').html_safe ].join(' ').html_safe
end end
def diff_file_blob_raw_path(diff_file) def diff_file_blob_raw_url(diff_file, only_path: false)
project_raw_path(@project, tree_join(diff_file.content_sha, diff_file.file_path)) project_raw_url(@project, tree_join(diff_file.content_sha, diff_file.file_path), only_path: only_path)
end end
def diff_file_old_blob_raw_path(diff_file) def diff_file_old_blob_raw_url(diff_file, only_path: false)
sha = diff_file.old_content_sha sha = diff_file.old_content_sha
return unless sha return unless sha
project_raw_path(@project, tree_join(diff_file.old_content_sha, diff_file.old_path)) project_raw_url(@project, tree_join(diff_file.old_content_sha, diff_file.old_path), only_path: only_path)
end
def diff_file_blob_raw_path(diff_file)
diff_file_blob_raw_url(diff_file, only_path: true)
end
def diff_file_old_blob_raw_path(diff_file)
diff_file_old_blob_raw_url(diff_file, only_path: true)
end end
def diff_file_html_data(project, diff_file_path, diff_commit_id) def diff_file_html_data(project, diff_file_path, diff_commit_id)
......
...@@ -76,7 +76,7 @@ module IssuesHelper ...@@ -76,7 +76,7 @@ module IssuesHelper
elsif item.try(:merged?) elsif item.try(:merged?)
'status-box-merged' 'status-box-merged'
elsif item.closed? elsif item.closed?
'status-box-closed' 'status-box-mr-closed'
elsif item.try(:upcoming?) elsif item.try(:upcoming?)
'status-box-upcoming' 'status-box-upcoming'
else else
......
module LabelsHelper module LabelsHelper
include ActionView::Helpers::TagHelper include ActionView::Helpers::TagHelper
def show_label_issuables_link?(label, issuables_type, current_user: nil, project: nil)
return true if label.is_a?(GroupLabel)
return true unless project
project.feature_available?(issuables_type, current_user)
end
# Link to a Label # Link to a Label
# #
# label - Label object to link to # label - Label object to link to
......
...@@ -5,7 +5,7 @@ module Emails ...@@ -5,7 +5,7 @@ module Emails
@commit = @note.noteable @commit = @note.noteable
@target_url = project_commit_url(*note_target_url_options) @target_url = project_commit_url(*note_target_url_options)
mail_answer_thread(@commit, note_thread_options(recipient_id)) mail_answer_note_thread(@commit, @note, note_thread_options(recipient_id))
end end
def note_issue_email(recipient_id, note_id) def note_issue_email(recipient_id, note_id)
...@@ -13,7 +13,7 @@ module Emails ...@@ -13,7 +13,7 @@ module Emails
@issue = @note.noteable @issue = @note.noteable
@target_url = project_issue_url(*note_target_url_options) @target_url = project_issue_url(*note_target_url_options)
mail_answer_thread(@issue, note_thread_options(recipient_id)) mail_answer_note_thread(@issue, @note, note_thread_options(recipient_id))
end end
def note_merge_request_email(recipient_id, note_id) def note_merge_request_email(recipient_id, note_id)
...@@ -21,7 +21,7 @@ module Emails ...@@ -21,7 +21,7 @@ module Emails
@merge_request = @note.noteable @merge_request = @note.noteable
@target_url = project_merge_request_url(*note_target_url_options) @target_url = project_merge_request_url(*note_target_url_options)
mail_answer_thread(@merge_request, note_thread_options(recipient_id)) mail_answer_note_thread(@merge_request, @note, note_thread_options(recipient_id))
end end
def note_snippet_email(recipient_id, note_id) def note_snippet_email(recipient_id, note_id)
...@@ -29,7 +29,7 @@ module Emails ...@@ -29,7 +29,7 @@ module Emails
@snippet = @note.noteable @snippet = @note.noteable
@target_url = project_snippet_url(*note_target_url_options) @target_url = project_snippet_url(*note_target_url_options)
mail_answer_thread(@snippet, note_thread_options(recipient_id)) mail_answer_note_thread(@snippet, @note, note_thread_options(recipient_id))
end end
def note_personal_snippet_email(recipient_id, note_id) def note_personal_snippet_email(recipient_id, note_id)
...@@ -37,7 +37,7 @@ module Emails ...@@ -37,7 +37,7 @@ module Emails
@snippet = @note.noteable @snippet = @note.noteable
@target_url = snippet_url(@note.noteable) @target_url = snippet_url(@note.noteable)
mail_answer_thread(@snippet, note_thread_options(recipient_id)) mail_answer_note_thread(@snippet, @note, note_thread_options(recipient_id))
end end
private private
......
...@@ -123,8 +123,8 @@ class Notify < BaseMailer ...@@ -123,8 +123,8 @@ class Notify < BaseMailer
headers['Reply-To'] = address headers['Reply-To'] = address
fallback_reply_message_id = "<reply-#{reply_key}@#{Gitlab.config.gitlab.host}>".freeze fallback_reply_message_id = "<reply-#{reply_key}@#{Gitlab.config.gitlab.host}>".freeze
headers['References'] ||= '' headers['References'] ||= []
headers['References'] << ' ' << fallback_reply_message_id headers['References'] << fallback_reply_message_id
@reply_by_email = true @reply_by_email = true
end end
...@@ -160,6 +160,18 @@ class Notify < BaseMailer ...@@ -160,6 +160,18 @@ class Notify < BaseMailer
mail_thread(model, headers) mail_thread(model, headers)
end end
def mail_answer_note_thread(model, note, headers = {})
headers['Message-ID'] = message_id(note)
headers['In-Reply-To'] = message_id(note.references.last)
headers['References'] = note.references.map { |ref| message_id(ref) }
headers['X-GitLab-Discussion-ID'] = note.discussion.id if note.part_of_discussion?
headers[:subject]&.prepend('Re: ')
mail_thread(model, headers)
end
def reply_key def reply_key
@reply_key ||= SentNotification.reply_key @reply_key ||= SentNotification.reply_key
end end
......
...@@ -501,7 +501,6 @@ module Ci ...@@ -501,7 +501,6 @@ module Ci
end end
def valid_dependency? def valid_dependency?
return false unless complete?
return false if artifacts_expired? return false if artifacts_expired?
return false if erased? return false if erased?
......
...@@ -52,6 +52,20 @@ class Commit ...@@ -52,6 +52,20 @@ class Commit
diffs.reduce(0) { |sum, d| sum + Gitlab::Git::Util.count_lines(d.diff) } diffs.reduce(0) { |sum, d| sum + Gitlab::Git::Util.count_lines(d.diff) }
end end
def order_by(collection:, order_by:, sort:)
return collection unless %w[email name commits].include?(order_by)
return collection unless %w[asc desc].include?(sort)
collection.sort do |a, b|
operands = [a, b].tap { |o| o.reverse! if sort == 'desc' }
attr1, attr2 = operands.first.public_send(order_by), operands.second.public_send(order_by) # rubocop:disable PublicSend
# use case insensitive comparison for string values
order_by.in?(%w[email name]) ? attr1.casecmp(attr2) : attr1 <=> attr2
end
end
# Truncate sha to 8 characters # Truncate sha to 8 characters
def truncate_sha(sha) def truncate_sha(sha)
sha[0..MIN_SHA_LENGTH] sha[0..MIN_SHA_LENGTH]
......
...@@ -85,8 +85,7 @@ module CacheMarkdownField ...@@ -85,8 +85,7 @@ module CacheMarkdownField
def cached_html_up_to_date?(markdown_field) def cached_html_up_to_date?(markdown_field)
html_field = cached_markdown_fields.html_field(markdown_field) html_field = cached_markdown_fields.html_field(markdown_field)
cached = cached_html_for(markdown_field).present? && __send__(markdown_field).present? # rubocop:disable GitlabSecurity/PublicSend return false if cached_html_for(markdown_field).nil? && !__send__(markdown_field).nil? # rubocop:disable GitlabSecurity/PublicSend
return false unless cached
markdown_changed = attribute_changed?(markdown_field) || false markdown_changed = attribute_changed?(markdown_field) || false
html_changed = attribute_changed?(html_field) || false html_changed = attribute_changed?(html_field) || false
......
...@@ -16,7 +16,7 @@ class Issue < ActiveRecord::Base ...@@ -16,7 +16,7 @@ class Issue < ActiveRecord::Base
include ThrottledTouch include ThrottledTouch
include IgnorableColumn include IgnorableColumn
ignore_column :assignee_id ignore_column :assignee_id, :branch_name
WEIGHT_RANGE = 1..9 WEIGHT_RANGE = 1..9
WEIGHT_ALL = 'Everything'.freeze WEIGHT_ALL = 'Everything'.freeze
......
...@@ -913,11 +913,11 @@ class MergeRequest < ActiveRecord::Base ...@@ -913,11 +913,11 @@ class MergeRequest < ActiveRecord::Base
def state_icon_name def state_icon_name
if merged? if merged?
"check" "git-merge"
elsif closed? elsif closed?
"times" "close"
else else
"circle-o" "issue-open-m"
end end
end end
......
...@@ -368,6 +368,16 @@ class Note < ActiveRecord::Base ...@@ -368,6 +368,16 @@ class Note < ActiveRecord::Base
end end
end end
def references
refs = [noteable]
if part_of_discussion?
refs += discussion.notes.take_while { |n| n.id < id }
end
refs
end
def expire_etag_cache def expire_etag_cache
return unless noteable&.discussions_rendered_on_frontend? return unless noteable&.discussions_rendered_on_frontend?
...@@ -409,6 +419,9 @@ class Note < ActiveRecord::Base ...@@ -409,6 +419,9 @@ class Note < ActiveRecord::Base
end end
noteable_object&.touch noteable_object&.touch
# We return the noteable object so we can re-use it in EE for ElasticSearch.
noteable_object
end end
def banzai_render_context(field) def banzai_render_context(field)
......
...@@ -669,7 +669,8 @@ class Project < ActiveRecord::Base ...@@ -669,7 +669,8 @@ class Project < ActiveRecord::Base
end end
def import_started? def import_started?
import? && import_status == 'started' # import? does SQL work so only run it if it looks like there's an import running
import_status == 'started' && import?
end end
def import_scheduled? def import_scheduled?
...@@ -1157,7 +1158,7 @@ class Project < ActiveRecord::Base ...@@ -1157,7 +1158,7 @@ class Project < ActiveRecord::Base
def change_head(branch) def change_head(branch)
if repository.branch_exists?(branch) if repository.branch_exists?(branch)
repository.before_change_head repository.before_change_head
repository.write_ref('HEAD', "refs/heads/#{branch}") repository.write_ref('HEAD', "refs/heads/#{branch}", force: true)
repository.copy_gitattributes(branch) repository.copy_gitattributes(branch)
repository.after_change_head repository.after_change_head
reload_default_branch reload_default_branch
......
...@@ -24,6 +24,7 @@ class Repository ...@@ -24,6 +24,7 @@ class Repository
attr_accessor :full_path, :disk_path, :project, :is_wiki attr_accessor :full_path, :disk_path, :project, :is_wiki
delegate :ref_name_for_sha, to: :raw_repository delegate :ref_name_for_sha, to: :raw_repository
delegate :write_ref, to: :raw_repository
CreateTreeError = Class.new(StandardError) CreateTreeError = Class.new(StandardError)
...@@ -244,11 +245,10 @@ class Repository ...@@ -244,11 +245,10 @@ class Repository
# This will still fail if the file is corrupted (e.g. 0 bytes) # This will still fail if the file is corrupted (e.g. 0 bytes)
begin begin
write_ref(keep_around_ref_name(sha), sha) write_ref(keep_around_ref_name(sha), sha, force: true)
rescue Rugged::ReferenceError => ex rescue Gitlab::Git::Repository::GitError => ex
Rails.logger.error "Unable to create #{REF_KEEP_AROUND} reference for repository #{path}: #{ex}" # Necessary because https://gitlab.com/gitlab-org/gitlab-ce/issues/20156
rescue Rugged::OSError => ex return true if ex.message =~ /Failed to create locked file/ && ex.message =~ /File exists/
raise unless ex.message =~ /Failed to create locked file/ && ex.message =~ /File exists/
Rails.logger.error "Unable to create #{REF_KEEP_AROUND} reference for repository #{path}: #{ex}" Rails.logger.error "Unable to create #{REF_KEEP_AROUND} reference for repository #{path}: #{ex}"
end end
...@@ -258,10 +258,6 @@ class Repository ...@@ -258,10 +258,6 @@ class Repository
ref_exists?(keep_around_ref_name(sha)) ref_exists?(keep_around_ref_name(sha))
end end
def write_ref(ref_path, sha)
rugged.references.create(ref_path, sha, force: true)
end
def diverging_commit_counts(branch) def diverging_commit_counts(branch)
root_ref_hash = raw_repository.commit(root_ref).id root_ref_hash = raw_repository.commit(root_ref).id
cache.fetch(:"diverging_commit_counts_#{branch.name}") do cache.fetch(:"diverging_commit_counts_#{branch.name}") do
...@@ -697,7 +693,9 @@ class Repository ...@@ -697,7 +693,9 @@ class Repository
def tags_sorted_by(value) def tags_sorted_by(value)
case value case value
when 'name' when 'name_asc'
VersionSorter.sort(tags) { |tag| tag.name }
when 'name_desc'
VersionSorter.rsort(tags) { |tag| tag.name } VersionSorter.rsort(tags) { |tag| tag.name }
when 'updated_desc' when 'updated_desc'
tags_sorted_by_committed_date.reverse tags_sorted_by_committed_date.reverse
...@@ -708,10 +706,14 @@ class Repository ...@@ -708,10 +706,14 @@ class Repository
end end
end end
def contributors # Params:
#
# order_by: name|email|commits
# sort: asc|desc default: 'asc'
def contributors(order_by: nil, sort: 'asc')
commits = self.commits(nil, limit: 2000, offset: 0, skip_merges: true) commits = self.commits(nil, limit: 2000, offset: 0, skip_merges: true)
commits.group_by(&:author_email).map do |email, commits| commits = commits.group_by(&:author_email).map do |email, commits|
contributor = Gitlab::Contributor.new contributor = Gitlab::Contributor.new
contributor.email = email contributor.email = email
...@@ -725,6 +727,7 @@ class Repository ...@@ -725,6 +727,7 @@ class Repository
contributor contributor
end end
Commit.order_by(collection: commits, order_by: order_by, sort: sort)
end end
def refs_contains_sha(ref_type, sha) def refs_contains_sha(ref_type, sha)
...@@ -1043,7 +1046,7 @@ class Repository ...@@ -1043,7 +1046,7 @@ class Repository
end end
def create_ref(ref, ref_path) def create_ref(ref, ref_path)
raw_repository.write_ref(ref_path, ref) write_ref(ref_path, ref)
end end
def ls_files(ref) def ls_files(ref)
......
class GroupMemberPresenter < MemberPresenter class GroupMemberPresenter < MemberPresenter
<<<<<<< HEAD
prepend EE::GroupMemberPresenter prepend EE::GroupMemberPresenter
=======
>>>>>>> upstream/master
private private
def admin_member_permission def admin_member_permission
......
class MemberPresenter < Gitlab::View::Presenter::Delegated class MemberPresenter < Gitlab::View::Presenter::Delegated
<<<<<<< HEAD
prepend EE::MemberPresenter prepend EE::MemberPresenter
=======
>>>>>>> upstream/master
presents :member presents :member
def access_level_roles def access_level_roles
......
class ProjectMemberPresenter < MemberPresenter class ProjectMemberPresenter < MemberPresenter
<<<<<<< HEAD
prepend EE::ProjectMemberPresenter prepend EE::ProjectMemberPresenter
=======
>>>>>>> upstream/master
private private
def admin_member_permission def admin_member_permission
......
...@@ -39,11 +39,15 @@ module Ci ...@@ -39,11 +39,15 @@ module Ci
begin begin
# In case when 2 runners try to assign the same build, second runner will be declined # In case when 2 runners try to assign the same build, second runner will be declined
# with StateMachines::InvalidTransition or StaleObjectError when doing run! or save method. # with StateMachines::InvalidTransition or StaleObjectError when doing run! or save method.
build.runner_id = runner.id begin
build.run! build.runner_id = runner.id
register_success(build) build.run!
register_success(build)
return Result.new(build, true)
return Result.new(build, true)
rescue Ci::Build::MissingDependenciesError
build.drop!(:missing_dependency_failure)
end
rescue StateMachines::InvalidTransition, ActiveRecord::StaleObjectError rescue StateMachines::InvalidTransition, ActiveRecord::StaleObjectError
# We are looping to find another build that is not conflicting # We are looping to find another build that is not conflicting
# It also indicates that this build can be picked and passed to runner. # It also indicates that this build can be picked and passed to runner.
...@@ -55,9 +59,6 @@ module Ci ...@@ -55,9 +59,6 @@ module Ci
# we still have to return 409 in the end, # we still have to return 409 in the end,
# to make sure that this is properly handled by runner. # to make sure that this is properly handled by runner.
valid = false valid = false
rescue Ci::Build::MissingDependenciesError
build.drop!(:missing_dependency_failure)
valid = false
end end
end end
......
...@@ -108,12 +108,14 @@ class IssuableBaseService < BaseService ...@@ -108,12 +108,14 @@ class IssuableBaseService < BaseService
end end
def merge_quick_actions_into_params!(issuable) def merge_quick_actions_into_params!(issuable)
original_description = params.fetch(:description, issuable.description)
description, command_params = description, command_params =
QuickActions::InterpretService.new(project, current_user) QuickActions::InterpretService.new(project, current_user)
.execute(params[:description], issuable) .execute(original_description, issuable)
# Avoid a description already set on an issuable to be overwritten by a nil # Avoid a description already set on an issuable to be overwritten by a nil
params[:description] = description if params.key?(:description) params[:description] = description if description
params.merge!(command_params) params.merge!(command_params)
end end
......
...@@ -83,12 +83,12 @@ ...@@ -83,12 +83,12 @@
You're all done! You're all done!
- elsif current_user.todos.any? - elsif current_user.todos.any?
.todos-all-done .todos-all-done
.svg-content .svg-content.svg-250
= image_tag 'illustrations/todos_all_done.svg' = image_tag 'illustrations/todos_all_done.svg'
- if todos_filter_empty? - if todos_filter_empty?
%h4.text-center %h4.text-center
= Gitlab.config.gitlab.no_todos_messages.sample = Gitlab.config.gitlab.no_todos_messages.sample
%p.text-center %p
Are you looking for things to do? Take a look at Are you looking for things to do? Take a look at
= succeed "," do = succeed "," do
= link_to "the opened issues", issues_dashboard_path = link_to "the opened issues", issues_dashboard_path
...@@ -104,7 +104,7 @@ ...@@ -104,7 +104,7 @@
= image_tag 'illustrations/todos_empty.svg' = image_tag 'illustrations/todos_empty.svg'
.todos-empty-content .todos-empty-content
%h4 %h4
Todos let you see what you should do next. Todos let you see what you should do next
%p %p
When an issue or merge request is assigned to you, or when you When an issue or merge request is assigned to you, or when you
%strong %strong
......
- project_meta = { id: @project.id, name: @project.name, namespace: @project.name_with_namespace, web_url: @project.web_url, avatar_url: @project.avatar_url } if @project&.persisted? - project_meta = { id: @project.id, name: @project.name, namespace: @project.name_with_namespace, web_url: project_path(@project), avatar_url: @project.avatar_url } if @project&.persisted?
.projects-dropdown-container .projects-dropdown-container
.project-dropdown-sidebar .project-dropdown-sidebar
%ul %ul
......
.file-content.image_file .file-content.image_file
= image_tag(blob_raw_path, alt: viewer.blob.name) -# Uses the full URL rather than the path, to prevent it from getting prefixed with the asset host.
= image_tag(blob_raw_url, alt: viewer.blob.name)
.row.empty-state .row.empty-state
.col-xs-12 .col-xs-12
.svg-content= image_tag 'illustrations/clusters_empty.svg' .svg-content= image_tag 'illustrations/clusters_empty.svg'
.col-xs-12.text-center .col-xs-12
.text-content .text-content
%h4= s_('ClusterIntegration|Integrate cluster automation') %h4.text-center= s_('ClusterIntegration|Integrate cluster automation')
- link_to_help_page = link_to(s_('ClusterIntegration|Learn more about Clusters'), help_page_path('user/project/clusters/index'), target: '_blank', rel: 'noopener noreferrer') - link_to_help_page = link_to(s_('ClusterIntegration|Learn more about Clusters'), help_page_path('user/project/clusters/index'), target: '_blank', rel: 'noopener noreferrer')
%p= s_('ClusterIntegration|Clusters allow you to use review apps, deploy your applications, run your pipelines, and much more in an easy way. %{link_to_help_page}').html_safe % { link_to_help_page: link_to_help_page} %p= s_('ClusterIntegration|Clusters allow you to use review apps, deploy your applications, run your pipelines, and much more in an easy way. %{link_to_help_page}').html_safe % { link_to_help_page: link_to_help_page}
%p .text-center
= link_to s_('ClusterIntegration|Add cluster'), new_project_cluster_path(@project), class: 'btn btn-success' = link_to s_('ClusterIntegration|Add cluster'), new_project_cluster_path(@project), class: 'btn btn-success'
...@@ -8,7 +8,11 @@ ...@@ -8,7 +8,11 @@
.top-area.adjust .top-area.adjust
.nav-text .nav-text
= s_("ClusterIntegration|Clusters can be used to deploy applications and to provide Review Apps for this project") = s_("ClusterIntegration|Clusters can be used to deploy applications and to provide Review Apps for this project")
<<<<<<< HEAD
= render 'projects/ee/clusters/buttons', project: @project = render 'projects/ee/clusters/buttons', project: @project
=======
.ci-table.js-clusters-list
>>>>>>> upstream/master
.gl-responsive-table-row.table-row-header{ role: "row" } .gl-responsive-table-row.table-row-header{ role: "row" }
.table-section.section-30{ role: "rowheader" } .table-section.section-30{ role: "rowheader" }
= s_("ClusterIntegration|Cluster") = s_("ClusterIntegration|Cluster")
......
- blob = diff_file.blob - blob = diff_file.blob
- old_blob = diff_file.old_blob - old_blob = diff_file.old_blob
- blob_raw_path = diff_file_blob_raw_path(diff_file) - blob_raw_url = diff_file_blob_raw_url(diff_file)
- old_blob_raw_path = diff_file_old_blob_raw_path(diff_file) - old_blob_raw_url = diff_file_old_blob_raw_url(diff_file)
- click_to_comment = local_assigns.fetch(:click_to_comment, true) - click_to_comment = local_assigns.fetch(:click_to_comment, true)
- diff_view_data = local_assigns.fetch(:diff_view_data, '') - diff_view_data = local_assigns.fetch(:diff_view_data, '')
- class_name = '' - class_name = ''
...@@ -13,7 +13,7 @@ ...@@ -13,7 +13,7 @@
.two-up.view .two-up.view
.wrap .wrap
.frame.deleted .frame.deleted
= image_tag(old_blob_raw_path, alt: diff_file.old_path, lazy: false) = image_tag(old_blob_raw_url, alt: diff_file.old_path, lazy: false)
%p.image-info.hide %p.image-info.hide
%span.meta-filesize= number_to_human_size(old_blob.size) %span.meta-filesize= number_to_human_size(old_blob.size)
| |
...@@ -23,7 +23,7 @@ ...@@ -23,7 +23,7 @@
%strong H: %strong H:
%span.meta-height %span.meta-height
.wrap .wrap
= render partial: "projects/diffs/image_diff_frame", locals: { class_name: "added js-image-frame #{class_name}", position: position, note_type: DiffNote.name, image_path: blob_raw_path, alt: diff_file.new_path } = render partial: "projects/diffs/image_diff_frame", locals: { class_name: "added js-image-frame #{class_name}", position: position, note_type: DiffNote.name, image_path: blob_raw_url, alt: diff_file.new_path }
%p.image-info.hide %p.image-info.hide
%span.meta-filesize= number_to_human_size(blob.size) %span.meta-filesize= number_to_human_size(blob.size)
| |
...@@ -36,9 +36,9 @@ ...@@ -36,9 +36,9 @@
.swipe.view.hide .swipe.view.hide
.swipe-frame .swipe-frame
.frame.deleted .frame.deleted
= image_tag(old_blob_raw_path, alt: diff_file.old_path, lazy: false) = image_tag(old_blob_raw_url, alt: diff_file.old_path, lazy: false)
.swipe-wrap .swipe-wrap
= render partial: "projects/diffs/image_diff_frame", locals: { class_name: "added js-image-frame #{class_name}", position: position, note_type: DiffNote.name, image_path: blob_raw_path, alt: diff_file.new_path } = render partial: "projects/diffs/image_diff_frame", locals: { class_name: "added js-image-frame #{class_name}", position: position, note_type: DiffNote.name, image_path: blob_raw_url, alt: diff_file.new_path }
%span.swipe-bar %span.swipe-bar
%span.top-handle %span.top-handle
%span.bottom-handle %span.bottom-handle
...@@ -46,8 +46,8 @@ ...@@ -46,8 +46,8 @@
.onion-skin.view.hide .onion-skin.view.hide
.onion-skin-frame .onion-skin-frame
.frame.deleted .frame.deleted
= image_tag(old_blob_raw_path, alt: diff_file.old_path, lazy: false) = image_tag(old_blob_raw_url, alt: diff_file.old_path, lazy: false)
= render partial: "projects/diffs/image_diff_frame", locals: { class_name: "added js-image-frame #{class_name}", position: position, note_type: DiffNote.name, image_path: blob_raw_path, alt: diff_file.new_path } = render partial: "projects/diffs/image_diff_frame", locals: { class_name: "added js-image-frame #{class_name}", position: position, note_type: DiffNote.name, image_path: blob_raw_url, alt: diff_file.new_path }
.controls .controls
.transparent .transparent
.drag-track .drag-track
......
- blob = diff_file.blob - blob = diff_file.blob
- old_blob = diff_file.old_blob - old_blob = diff_file.old_blob
- blob_raw_path = diff_file_blob_raw_path(diff_file) - blob_raw_url = diff_file_blob_raw_url(diff_file)
- old_blob_raw_path = diff_file_old_blob_raw_path(diff_file) - old_blob_raw_url = diff_file_old_blob_raw_url(diff_file)
- click_to_comment = local_assigns.fetch(:click_to_comment, true) - click_to_comment = local_assigns.fetch(:click_to_comment, true)
- diff_view_data = local_assigns.fetch(:diff_view_data, '') - diff_view_data = local_assigns.fetch(:diff_view_data, '')
- class_name = '' - class_name = ''
...@@ -12,5 +12,5 @@ ...@@ -12,5 +12,5 @@
.image.js-single-image{ data: diff_view_data } .image.js-single-image{ data: diff_view_data }
.wrap .wrap
- single_class_name = diff_file.deleted_file? ? 'deleted' : 'added' - single_class_name = diff_file.deleted_file? ? 'deleted' : 'added'
= render partial: "projects/diffs/image_diff_frame", locals: { class_name: "#{single_class_name} #{class_name} js-image-frame", position: position, note_type: DiffNote.name, image_path: blob_raw_path, alt: diff_file.file_path } = render partial: "projects/diffs/image_diff_frame", locals: { class_name: "#{single_class_name} #{class_name} js-image-frame", position: position, note_type: DiffNote.name, image_path: blob_raw_url, alt: diff_file.file_path }
%p.image-info= number_to_human_size(blob.size) %p.image-info= number_to_human_size(blob.size)
...@@ -17,12 +17,12 @@ ...@@ -17,12 +17,12 @@
.detail-page-header .detail-page-header
.detail-page-header-body .detail-page-header-body
.issuable-status-box.status-box.status-box-closed{ class: issue_button_visibility(@issue, false) } .issuable-status-box.status-box.status-box-issue-closed{ class: issue_button_visibility(@issue, false) }
= icon('check', class: "hidden-sm hidden-md hidden-lg") = sprite_icon('mobile-issue-close', size: 16, css_class: 'hidden-sm hidden-md hidden-lg')
%span.hidden-xs %span.hidden-xs
Closed Closed
.issuable-status-box.status-box.status-box-open{ class: issue_button_visibility(@issue, true) } .issuable-status-box.status-box.status-box-open{ class: issue_button_visibility(@issue, true) }
= icon('circle-o', class: "hidden-sm hidden-md hidden-lg") = sprite_icon('issue-open-m', size: 16, css_class: 'hidden-sm hidden-md hidden-lg')
%span.hidden-xs Open %span.hidden-xs Open
.issuable-meta .issuable-meta
......
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
.detail-page-header .detail-page-header
.detail-page-header-body .detail-page-header-body
.issuable-status-box.status-box{ class: status_box_class(@merge_request) } .issuable-status-box.status-box{ class: status_box_class(@merge_request) }
= icon(@merge_request.state_icon_name, class: "hidden-sm hidden-md hidden-lg") = sprite_icon(@merge_request.state_icon_name, size: 16, css_class: 'hidden-sm hidden-md hidden-lg')
%span.hidden-xs %span.hidden-xs
= @merge_request.state_human_name = @merge_request.state_human_name
...@@ -27,7 +27,11 @@ ...@@ -27,7 +27,11 @@
.dropdown-menu.dropdown-menu-align-right.hidden-lg .dropdown-menu.dropdown-menu-align-right.hidden-lg
%ul %ul
- if can_update_merge_request - if can_update_merge_request
<<<<<<< HEAD
%li= link_to 'Edit', edit_namespace_project_merge_request_path(@project.namespace, @project, @merge_request), class: 'js-issuable-edit' %li= link_to 'Edit', edit_namespace_project_merge_request_path(@project.namespace, @project, @merge_request), class: 'js-issuable-edit'
=======
%li= link_to 'Edit', edit_namespace_project_merge_request_path(@project.namespace, @project, @merge_request)
>>>>>>> upstream/master
- unless current_user == @merge_request.author - unless current_user == @merge_request.author
%li= link_to 'Report abuse', new_abuse_report_path(user_id: @merge_request.author.id, ref_url: merge_request_url(@merge_request)) %li= link_to 'Report abuse', new_abuse_report_path(user_id: @merge_request.author.id, ref_url: merge_request_url(@merge_request))
- if can_update_merge_request - if can_update_merge_request
......
...@@ -14,7 +14,7 @@ ...@@ -14,7 +14,7 @@
.form-group .form-group
= label_tag :tag_name, nil, class: 'control-label' = label_tag :tag_name, nil, class: 'control-label'
.col-sm-10 .col-sm-10
= text_field_tag :tag_name, params[:tag_name], required: true, tabindex: 1, autofocus: true, class: 'form-control' = text_field_tag :tag_name, params[:tag_name], required: true, autofocus: true, class: 'form-control'
.form-group .form-group
= label_tag :ref, 'Create from', class: 'control-label' = label_tag :ref, 'Create from', class: 'control-label'
.col-sm-10.create-from .col-sm-10.create-from
...@@ -28,7 +28,7 @@ ...@@ -28,7 +28,7 @@
.form-group .form-group
= label_tag :message, nil, class: 'control-label' = label_tag :message, nil, class: 'control-label'
.col-sm-10 .col-sm-10
= text_area_tag :message, @message, required: false, tabindex: 3, class: 'form-control', rows: 5 = text_area_tag :message, @message, required: false, class: 'form-control', rows: 5
.help-block .help-block
= s_('TagsPage|Optionally, add a message to the tag.') = s_('TagsPage|Optionally, add a message to the tag.')
%hr %hr
...@@ -41,6 +41,6 @@ ...@@ -41,6 +41,6 @@
.help-block .help-block
= s_('TagsPage|Optionally, add release notes to the tag. They will be stored in the GitLab database and displayed on the tags page.') = s_('TagsPage|Optionally, add release notes to the tag. They will be stored in the GitLab database and displayed on the tags page.')
.form-actions .form-actions
= button_tag s_('TagsPage|Create tag'), class: 'btn btn-create', tabindex: 3 = button_tag s_('TagsPage|Create tag'), class: 'btn btn-create'
= link_to s_('TagsPage|Cancel'), project_tags_path(@project), class: 'btn btn-cancel' = link_to s_('TagsPage|Cancel'), project_tags_path(@project), class: 'btn btn-cancel'
%script#availableRefs{ type: "application/json" }= @project.repository.ref_names.to_json.html_safe %script#availableRefs{ type: "application/json" }= @project.repository.ref_names.to_json.html_safe
...@@ -2,6 +2,8 @@ ...@@ -2,6 +2,8 @@
- status = label_subscription_status(label, @project).inquiry if current_user - status = label_subscription_status(label, @project).inquiry if current_user
- subject = local_assigns[:subject] - subject = local_assigns[:subject]
- toggle_subscription_path = toggle_subscription_label_path(label, @project) if current_user - toggle_subscription_path = toggle_subscription_label_path(label, @project) if current_user
- show_label_merge_requests_link = show_label_issuables_link?(label, :merge_requests, project: @project)
- show_label_issues_link = show_label_issuables_link?(label, :issues, project: @project)
%li{ id: label_css_id, data: { id: label.id } } %li{ id: label_css_id, data: { id: label.id } }
= render "shared/label_row", label: label = render "shared/label_row", label: label
...@@ -12,12 +14,14 @@ ...@@ -12,12 +14,14 @@
= icon('caret-down') = icon('caret-down')
.dropdown-menu.dropdown-menu-align-right .dropdown-menu.dropdown-menu-align-right
%ul %ul
%li - if show_label_merge_requests_link
= link_to_label(label, subject: subject, type: :merge_request) do %li
View merge requests = link_to_label(label, subject: subject, type: :merge_request) do
%li View merge requests
= link_to_label(label, subject: subject) do - if show_label_issues_link
View open issues %li
= link_to_label(label, subject: subject) do
View open issues
- if current_user - if current_user
%li.label-subscription %li.label-subscription
- if can_subscribe_to_label_in_different_levels?(label) - if can_subscribe_to_label_in_different_levels?(label)
...@@ -43,10 +47,12 @@ ...@@ -43,10 +47,12 @@
class: 'text-danger' class: 'text-danger'
.pull-right.hidden-xs.hidden-sm.hidden-md .pull-right.hidden-xs.hidden-sm.hidden-md
= link_to_label(label, subject: subject, type: :merge_request, css_class: 'btn btn-transparent btn-action btn-link') do - if show_label_merge_requests_link
view merge requests = link_to_label(label, subject: subject, type: :merge_request, css_class: 'btn btn-transparent btn-action btn-link') do
= link_to_label(label, subject: subject, css_class: 'btn btn-transparent btn-action btn-link') do view merge requests
view open issues - if show_label_issues_link
= link_to_label(label, subject: subject, css_class: 'btn btn-transparent btn-action btn-link') do
view open issues
- if current_user - if current_user
.label-subscription.inline .label-subscription.inline
......
...@@ -6,18 +6,21 @@ ...@@ -6,18 +6,21 @@
.col-xs-12 .col-xs-12
.svg-content .svg-content
= image_tag 'illustrations/issues.svg' = image_tag 'illustrations/issues.svg'
.col-xs-12.text-center .col-xs-12
.text-content .text-content
- if has_button && current_user - if has_button && current_user
%h4 %h4
The Issue Tracker is the place to add things that need to be improved or solved in a project = _("The Issue Tracker is the place to add things that need to be improved or solved in a project")
%p %p
Issues can be bugs, tasks or ideas to be discussed. = _("Issues can be bugs, tasks or ideas to be discussed. Also, issues are searchable and filterable.")
Also, issues are searchable and filterable. .text-center
- if project_select_button - if project_select_button
= render 'shared/new_project_item_select', path: 'issues/new', label: 'New issue', type: :issues = render 'shared/new_project_item_select', path: 'issues/new', label: 'New issue', type: :issues
- else - else
= link_to 'New issue', button_path, class: 'btn btn-new', title: 'New issue', id: 'new_issue_link' = link_to 'New issue', button_path, class: 'btn btn-success', title: 'New issue', id: 'new_issue_link'
- else - else
%h4.text-center= _("There are no issues to show")
%p
= _("The Issue Tracker is the place to add things that need to be improved or solved in a project. You can register or sign in to create issues for this project.")
.text-center .text-center
%h4 There are no issues to show. = link_to _('Register / Sign In'), new_user_session_path, class: 'btn btn-success'
...@@ -2,10 +2,10 @@ ...@@ -2,10 +2,10 @@
.col-xs-12 .col-xs-12
.svg-content .svg-content
= image_tag 'illustrations/labels.svg' = image_tag 'illustrations/labels.svg'
.col-xs-12.text-center .col-xs-12
.text-content .text-content
%h4 Labels can be applied to issues and merge requests to categorize them. %h4= _("Labels can be applied to issues and merge requests to categorize them.")
%p You can also star a label to make it a priority label. %p= _("You can also star a label to make it a priority label.")
- if can?(current_user, :admin_label, @project) - if can?(current_user, :admin_label, @project)
= link_to 'New label', new_project_label_path(@project), class: 'btn btn-new', title: 'New label', id: 'new_label_link' = link_to _('New label'), new_project_label_path(@project), class: 'btn btn-new', title: _('New label'), id: 'new_label_link'
= link_to 'Generate a default set of labels', generate_project_labels_path(@project), method: :post, class: 'btn btn-success btn-inverted', title: 'Generate a default set of labels', id: 'generate_labels_link' = link_to _('Generate a default set of labels'), generate_project_labels_path(@project), method: :post, class: 'btn btn-success btn-inverted', title: _('Generate a default set of labels'), id: 'generate_labels_link'
...@@ -6,17 +6,18 @@ ...@@ -6,17 +6,18 @@
.col-xs-12 .col-xs-12
.svg-content .svg-content
= image_tag 'illustrations/merge_requests.svg' = image_tag 'illustrations/merge_requests.svg'
.col-xs-12.text-center .col-xs-12
.text-content .text-content
- if has_button - if has_button
%h4 %h4
Merge requests are a place to propose changes you've made to a project and discuss those changes with others. = _("Merge requests are a place to propose changes you've made to a project and discuss those changes with others")
%p %p
Interested parties can even contribute by pushing commits if they want to. = _("Interested parties can even contribute by pushing commits if they want to.")
- if project_select_button .text-center
= render 'shared/new_project_item_select', path: 'merge_requests/new', label: 'New merge request', type: :merge_requests - if project_select_button
- else = render 'shared/new_project_item_select', path: 'merge_requests/new', label: _('New merge request'), type: :merge_requests
= link_to 'New merge request', button_path, class: 'btn btn-new', title: 'New merge request', id: 'new_merge_request_link' - else
= link_to _('New merge request'), button_path, class: 'btn btn-new', title: _('New merge request'), id: 'new_merge_request_link'
- else - else
%h4.text-center %h4.text-center
There are no merge requests to show. = _("There are no merge requests to show")
...@@ -62,7 +62,10 @@ ...@@ -62,7 +62,10 @@
= f.hidden_field :access_level = f.hidden_field :access_level
.member-form-control.dropdown.append-right-5 .member-form-control.dropdown.append-right-5
%button.dropdown-menu-toggle.js-member-permissions-dropdown{ type: "button", %button.dropdown-menu-toggle.js-member-permissions-dropdown{ type: "button",
<<<<<<< HEAD
disabled: member.can_override?, disabled: member.can_override?,
=======
>>>>>>> upstream/master
data: { toggle: "dropdown", field_name: "#{f.object_name}[access_level]" } } data: { toggle: "dropdown", field_name: "#{f.object_name}[access_level]" } }
%span.dropdown-toggle-text %span.dropdown-toggle-text
= member.human_access = member.human_access
...@@ -82,7 +85,10 @@ ...@@ -82,7 +85,10 @@
can_override: member.can_override? can_override: member.can_override?
.prepend-left-5.clearable-input.member-form-control .prepend-left-5.clearable-input.member-form-control
= f.text_field :expires_at, = f.text_field :expires_at,
<<<<<<< HEAD
disabled: member.can_override?, disabled: member.can_override?,
=======
>>>>>>> upstream/master
class: 'form-control js-access-expiration-date js-member-update-control', class: 'form-control js-access-expiration-date js-member-update-control',
placeholder: 'Expiration date', placeholder: 'Expiration date',
id: "member_expires_at_#{member.id}", id: "member_expires_at_#{member.id}",
......
...@@ -96,6 +96,7 @@ ...@@ -96,6 +96,7 @@
- update_user_activity - update_user_activity
- upload_checksum - upload_checksum
- web_hook - web_hook
<<<<<<< HEAD
# EE-specific queues # EE-specific queues
- cronjob:clear_shared_runners_minutes - cronjob:clear_shared_runners_minutes
...@@ -130,3 +131,5 @@ ...@@ -130,3 +131,5 @@
- rebase - rebase
- repository_update_mirror - repository_update_mirror
- repository_update_remote_mirror - repository_update_remote_mirror
=======
>>>>>>> upstream/master
---
title: Adds ordering to projects contributors in API
merge_request: 15469
author: Jacopo Beschi @jacopo-beschi
type: added
---
title: Update issuable status icons
merge_request: 15898
author:
type: changed
---
title: Fix broken illustration images for monitoring page empty states
merge_request: 15889
author:
type: fixed
---
title: add support for sorting in tags api
merge_request: 15772
author: haseebeqx
type: added
---
title: Use relative URL for projects to avoid storing domains
merge_request: 15876
author:
type: fixed
---
title: Add a gitlab:tcp_check rake task
merge_request: 15759
author:
type: added
---
title: Use app host instead of asset host when rendering image blob or diff
merge_request:
author:
type: fixed
---
title: Execute quick actions (if present) when creating MR from issue
merge_request: 15810
author:
type: fixed
---
title: Fixed typo for issue description field declaration
merge_request:
author: Marcus Amargi
type: fixed
---
title: Treat empty markdown and html strings as valid cached text, not missing cache
that needs to be updated
merge_request:
author:
type: performance
---
title: check the import_status field before doing SQL operations to check the import
url
merge_request:
author:
type: performance
---
title: removed tabindexes from tag form
merge_request:
author: Marcus Amargi
type: changed
---
title: Hide link to issues/MRs from labels list if issues/MRs are disabled.
merge_request: 15863
author: Sophie Herold
type: fixed
---
title: Make mail notifications of discussion notes In-Reply-To of each other
merge_request: 14289
author:
type: changed
...@@ -3,9 +3,9 @@ ...@@ -3,9 +3,9 @@
# #
# If you come up with a fun one, please feel free to contribute it to GitLab! # If you come up with a fun one, please feel free to contribute it to GitLab!
# https://about.gitlab.com/contributing/ # https://about.gitlab.com/contributing/
--- ---
- Good job! Looks like you don't have any todos left. - Good job! Looks like you don't have any todos left
- Isn't an empty todo list beautiful? - Isn't an empty todo list beautiful?
- Give yourself a pat on the back! - Give yourself a pat on the back!
- Nothing left to do, high five! - Nothing left to do, high five!
- Henceforth you shall be known as "Todo Destroyer". - Henceforth you shall be known as "Todo Destroyer"
...@@ -4,6 +4,12 @@ class AddNewProjectGuidelinesToAppearances < ActiveRecord::Migration ...@@ -4,6 +4,12 @@ class AddNewProjectGuidelinesToAppearances < ActiveRecord::Migration
DOWNTIME = false DOWNTIME = false
def change def change
# Clears the current Appearance cache otherwise it breaks since
# new_project_guidelines_html would be missing. See
# https://gitlab.com/gitlab-org/gitlab-ce/issues/41041
# We're not using Appearance#flush_redis_cache on purpose here.
Rails.cache.delete('current_appearance')
change_table :appearances do |t| change_table :appearances do |t|
t.text :new_project_guidelines t.text :new_project_guidelines
t.text :new_project_guidelines_html t.text :new_project_guidelines_html
......
...@@ -23,6 +23,7 @@ Learn how to install, configure, update, and maintain your GitLab instance. ...@@ -23,6 +23,7 @@ Learn how to install, configure, update, and maintain your GitLab instance.
- **(EEP)** [GitLab GEO](../gitlab-geo/README.md): Replicate your GitLab instance to other geographical locations as a read-only fully operational version. - **(EEP)** [GitLab GEO](../gitlab-geo/README.md): Replicate your GitLab instance to other geographical locations as a read-only fully operational version.
- **(EEP)** [Pivotal Tile](../install/pivotal/index.md): Deploy GitLab as a pre-configured appliance using Ops Manager (BOSH) for Pivotal Cloud Foundry. - **(EEP)** [Pivotal Tile](../install/pivotal/index.md): Deploy GitLab as a pre-configured appliance using Ops Manager (BOSH) for Pivotal Cloud Foundry.
- [High Availability](high_availability/README.md): Configure multiple servers for scaling or high availability. - [High Availability](high_availability/README.md): Configure multiple servers for scaling or high availability.
- [High Availability on AWS](../university/high-availability/aws/README.md): Set up GitLab HA on Amazon AWS.
### Configuring GitLab ### Configuring GitLab
...@@ -44,6 +45,13 @@ Learn how to install, configure, update, and maintain your GitLab instance. ...@@ -44,6 +45,13 @@ Learn how to install, configure, update, and maintain your GitLab instance.
- [Welcome message](../customization/welcome_message.md): Add a custom welcome message to the sign-in page. - [Welcome message](../customization/welcome_message.md): Add a custom welcome message to the sign-in page.
- ["New Project" page](../customization/new_project_page.md): Customize the text to be displayed on the page that opens whenever your users create a new project. - ["New Project" page](../customization/new_project_page.md): Customize the text to be displayed on the page that opens whenever your users create a new project.
#### Customizing GitLab's appearance
- [Header logo](../customization/branded_page_and_email_header.md): Change the logo on all pages and email headers.
- [Branded login page](../customization/branded_login_page.md): Customize the login page with your own logo, title, and description.
- [Welcome message](../customization/welcome_message.md): Add a custom welcome message to the sign-in page.
- ["New Project" page](../customization/new_project_page.md): Customize the text to be displayed on the page that opens whenever your users create a new project.
### Maintaining GitLab ### Maintaining GitLab
- [Raketasks](../raketasks/README.md): Perform various tasks for maintenance, backups, automatic webhooks setup, etc. - [Raketasks](../raketasks/README.md): Perform various tasks for maintenance, backups, automatic webhooks setup, etc.
...@@ -123,20 +131,22 @@ server with IMAP authentication on Ubuntu, to be used with Reply by email. ...@@ -123,20 +131,22 @@ server with IMAP authentication on Ubuntu, to be used with Reply by email.
## Monitoring GitLab ## Monitoring GitLab
- [Monitoring uptime](../user/admin_area/monitoring/health_check.md): Check the server status using the health check endpoint. - [Monitoring GitLab](monitoring/index.md):
- [IP whitelist](monitoring/ip_whitelist.md): Monitor endpoints that provide health check information when probed. - [Monitoring uptime](../user/admin_area/monitoring/health_check.md): Check the server status using the health check endpoint.
- [Monitoring GitHub imports](monitoring/github_imports.md): GitLab's GitHub Importer displays Prometheus metrics to monitor the health and progress of the importer. - [IP whitelist](monitoring/ip_whitelist.md): Monitor endpoints that provide health check information when probed.
- [Monitoring GitHub imports](monitoring/github_imports.md): GitLab's GitHub Importer displays Prometheus metrics to monitor the health and progress of the importer.
- [Conversational Development (ConvDev) Index](../user/admin_area/monitoring/convdev.md): Provides an overview of your entire instance's feature usage. - [Conversational Development (ConvDev) Index](../user/admin_area/monitoring/convdev.md): Provides an overview of your entire instance's feature usage.
### Performance Monitoring ### Performance Monitoring
- [GitLab Performance Monitoring](monitoring/performance/gitlab_configuration.md): Enable GitLab Performance Monitoring. - [GitLab Performance Monitoring](monitoring/performance/index.md):
- [GitLab performance monitoring with InfluxDB](monitoring/performance/introduction.md): Configure GitLab and InfluxDB for measuring performance metrics. - [Enable Performance Monitoring](monitoring/performance/gitlab_configuration.md): Enable GitLab Performance Monitoring.
- [InfluxDB Schema](monitoring/performance/influxdb_schema.md): Measurements stored in InfluxDB. - [GitLab performance monitoring with InfluxDB](monitoring/performance/influxdb_configuration.md): Configure GitLab and InfluxDB for measuring performance metrics.
- [GitLab performance monitoring with Prometheus](monitoring/prometheus/index.md): Configure GitLab and Prometheus for measuring performance metrics. - [InfluxDB Schema](monitoring/performance/influxdb_schema.md): Measurements stored in InfluxDB.
- [GitLab performance monitoring with Grafana](monitoring/prometheus/index.md): Configure GitLab to visualize time series metrics through graphs and dashboards. - [GitLab performance monitoring with Prometheus](monitoring/prometheus/index.md): Configure GitLab and Prometheus for measuring performance metrics.
- [Request Profiling](monitoring/performance/request_profiling.md): Get a detailed profile on slow requests. - [GitLab performance monitoring with Grafana](monitoring/performance/grafana_configuration.md): Configure GitLab to visualize time series metrics through graphs and dashboards.
- [Performance Bar](monitoring/performance/performance_bar.md): Get performance information for the current page. - [Request Profiling](monitoring/performance/request_profiling.md): Get a detailed profile on slow requests.
- [Performance Bar](monitoring/performance/performance_bar.md): Get performance information for the current page.
## Troubleshooting ## Troubleshooting
......
# Monitoring GitLab
Explore our features to monitor your GitLab instance:
- [Performance monitoring](performance/index.md): GitLab Performance Monitoring makes it possible to measure a wide variety of statistics of your instance.
- [Prometheus](prometheus/index.md): Prometheus is a powerful time-series monitoring service, providing a flexible platform for monitoring GitLab and other software products.
- [GitHub imports](github_imports.md): Monitor the health and progress of GitLab's GitHub importer with various Prometheus metrics.
- [Monitoring uptime](../user/admin_area/monitoring/health_check.md): Check the server status using the health check endpoint.
- [IP whitelists](ip_whitelist.md): Configure GitLab for monitoring endpoints that provide health check information when probed.
# GitLab Performance Monitoring
GitLab comes with its own application performance measuring system as of GitLab
8.4, simply called "GitLab Performance Monitoring". GitLab Performance Monitoring is available in both the
Community and Enterprise editions.
Apart from this introduction, you are advised to read through the following
documents in order to understand and properly configure GitLab Performance Monitoring:
- [GitLab Configuration](gitlab_configuration.md)
- [InfluxDB Install/Configuration](influxdb_configuration.md)
- [InfluxDB Schema](influxdb_schema.md)
- [Grafana Install/Configuration](grafana_configuration.md)
- [Performance bar](performance_bar.md)
- [Request profiling](request_profiling.md)
>**Note:**
Omnibus GitLab 8.16 includes Prometheus as an additional tool to collect
metrics. It will eventually replace InfluxDB when their metrics collection is
on par. Read more in the [Prometheus documentation](../prometheus/index.md).
## Introduction to GitLab Performance Monitoring
GitLab Performance Monitoring makes it possible to measure a wide variety of statistics
including (but not limited to):
- The time it took to complete a transaction (a web request or Sidekiq job).
- The time spent in running SQL queries and rendering HAML views.
- The time spent executing (instrumented) Ruby methods.
- Ruby object allocations, and retained objects in particular.
- System statistics such as the process' memory usage and open file descriptors.
- Ruby garbage collection statistics.
Metrics data is written to [InfluxDB][influxdb] over [UDP][influxdb-udp]. Stored
data can be visualized using [Grafana][grafana] or any other application that
supports reading data from InfluxDB. Alternatively data can be queried using the
InfluxDB CLI.
## Metric Types
Two types of metrics are collected:
1. Transaction specific metrics.
1. Sampled metrics, collected at a certain interval in a separate thread.
### Transaction Metrics
Transaction metrics are metrics that can be associated with a single
transaction. This includes statistics such as the transaction duration, timings
of any executed SQL queries, time spent rendering HAML views, etc. These metrics
are collected for every Rack request and Sidekiq job processed.
### Sampled Metrics
Sampled metrics are metrics that can't be associated with a single transaction.
Examples include garbage collection statistics and retained Ruby objects. These
metrics are collected at a regular interval. This interval is made up out of two
parts:
1. A user defined interval.
1. A randomly generated offset added on top of the interval, the same offset
can't be used twice in a row.
The actual interval can be anywhere between a half of the defined interval and a
half above the interval. For example, for a user defined interval of 15 seconds
the actual interval can be anywhere between 7.5 and 22.5. The interval is
re-generated for every sampling run instead of being generated once and re-used
for the duration of the process' lifetime.
[influxdb]: https://influxdata.com/time-series-platform/influxdb/
[influxdb-udp]: https://docs.influxdata.com/influxdb/v0.9/write_protocols/udp/
[grafana]: http://grafana.org/
# GitLab Performance Monitoring This document was moved to [another location](index.md).
GitLab comes with its own application performance measuring system as of GitLab
8.4, simply called "GitLab Performance Monitoring". GitLab Performance Monitoring is available in both the
Community and Enterprise editions.
Apart from this introduction, you are advised to read through the following
documents in order to understand and properly configure GitLab Performance Monitoring:
- [GitLab Configuration](gitlab_configuration.md)
- [InfluxDB Install/Configuration](influxdb_configuration.md)
- [InfluxDB Schema](influxdb_schema.md)
- [Grafana Install/Configuration](grafana_configuration.md)
>**Note:**
Omnibus GitLab 8.16 includes Prometheus as an additional tool to collect
metrics. It will eventually replace InfluxDB when their metrics collection is
on par. Read more in the [Prometheus documentation](../prometheus/index.md).
## Introduction to GitLab Performance Monitoring
GitLab Performance Monitoring makes it possible to measure a wide variety of statistics
including (but not limited to):
- The time it took to complete a transaction (a web request or Sidekiq job).
- The time spent in running SQL queries and rendering HAML views.
- The time spent executing (instrumented) Ruby methods.
- Ruby object allocations, and retained objects in particular.
- System statistics such as the process' memory usage and open file descriptors.
- Ruby garbage collection statistics.
Metrics data is written to [InfluxDB][influxdb] over [UDP][influxdb-udp]. Stored
data can be visualized using [Grafana][grafana] or any other application that
supports reading data from InfluxDB. Alternatively data can be queried using the
InfluxDB CLI.
## Metric Types
Two types of metrics are collected:
1. Transaction specific metrics.
1. Sampled metrics, collected at a certain interval in a separate thread.
### Transaction Metrics
Transaction metrics are metrics that can be associated with a single
transaction. This includes statistics such as the transaction duration, timings
of any executed SQL queries, time spent rendering HAML views, etc. These metrics
are collected for every Rack request and Sidekiq job processed.
### Sampled Metrics
Sampled metrics are metrics that can't be associated with a single transaction.
Examples include garbage collection statistics and retained Ruby objects. These
metrics are collected at a regular interval. This interval is made up out of two
parts:
1. A user defined interval.
1. A randomly generated offset added on top of the interval, the same offset
can't be used twice in a row.
The actual interval can be anywhere between a half of the defined interval and a
half above the interval. For example, for a user defined interval of 15 seconds
the actual interval can be anywhere between 7.5 and 22.5. The interval is
re-generated for every sampling run instead of being generated once and re-used
for the duration of the process' lifetime.
[influxdb]: https://influxdata.com/time-series-platform/influxdb/
[influxdb-udp]: https://docs.influxdata.com/influxdb/v0.9/write_protocols/udp/
[grafana]: http://grafana.org/
...@@ -221,3 +221,22 @@ sudo gitlab-rake gitlab:shell:create_hooks ...@@ -221,3 +221,22 @@ sudo gitlab-rake gitlab:shell:create_hooks
cd /home/git/gitlab cd /home/git/gitlab
sudo -u git -H bundle exec rake gitlab:shell:create_hooks RAILS_ENV=production sudo -u git -H bundle exec rake gitlab:shell:create_hooks RAILS_ENV=production
``` ```
## Check TCP connectivity to a remote site
Sometimes you need to know if your GitLab installation can connect to a TCP
service on another machine - perhaps a PostgreSQL or HTTPS server. A rake task
is included to help you with this:
**Omnibus Installation**
```
sudo gitlab-rake gitlab:tcp_check[example.com,80]
```
**Source Installation**
```
cd /home/git/gitlab
sudo -u git -H bundle exec rake gitlab:tcp_check[example.com,80] RAILS_ENV=production
```
...@@ -89,9 +89,11 @@ email address in order to sign up. ...@@ -89,9 +89,11 @@ email address in order to sign up.
If you also host a public-facing GitLab instance at `hooli.com` and set your If you also host a public-facing GitLab instance at `hooli.com` and set your
incoming email domain to `hooli.com`, an attacker could abuse the "Create new incoming email domain to `hooli.com`, an attacker could abuse the "Create new
issue by email" feature by using a project's unique address as the email when issue by email" or
signing up for Slack, which would send a confirmation email, which would create "[Create new merge request by email](../user/project/merge_requests/index.md#create-new-merge-requests-by-email)"
a new issue on the project owned by the attacker, allowing them to click the features by using a project's unique address as the email when signing up for
Slack, which would send a confirmation email, which would create a new issue or
merge request on the project owned by the attacker, allowing them to click the
confirmation link and validate their account on your company's private Slack confirmation link and validate their account on your company's private Slack
instance. instance.
......
...@@ -520,9 +520,9 @@ PUT /projects/:id/issues/:issue_iid ...@@ -520,9 +520,9 @@ PUT /projects/:id/issues/:issue_iid
| `title` | string | no | The title of an issue | | `title` | string | no | The title of an issue |
| `description` | string | no | The description of an issue | | `description` | string | no | The description of an issue |
| `confidential` | boolean | no | Updates an issue to be confidential | | `confidential` | boolean | no | Updates an issue to be confidential |
| `assignee_ids` | Array[integer] | no | The ID of the users to assign the issue to | | `assignee_ids` | Array[integer] | no | The ID of the user(s) to assign the issue to. Set to `0` or provide an empty value to unassign all assignees. |
| `milestone_id` | integer | no | The ID of a milestone to assign the issue to | | `milestone_id` | integer | no | The ID of a milestone to assign the issue to. Set to `0` or provide an empty value to unassign a milestone.|
| `labels` | string | no | Comma-separated label names for an issue | | `labels` | string | no | Comma-separated label names for an issue. Set to an empty string to unassign all labels. |
| `state_event` | string | no | The state event of an issue. Set `close` to close the issue and `reopen` to reopen it | | `state_event` | string | no | The state event of an issue. Set `close` to close the issue and `reopen` to reopen it |
| `updated_at` | string | no | Date time string, ISO 8601 formatted, e.g. `2016-03-11T03:45:40Z` (requires admin or project owner rights) | | `updated_at` | string | no | Date time string, ISO 8601 formatted, e.g. `2016-03-11T03:45:40Z` (requires admin or project owner rights) |
| `due_date` | string | no | Date time string in the format YEAR-MONTH-DAY, e.g. `2016-03-11` | | `due_date` | string | no | Date time string in the format YEAR-MONTH-DAY, e.g. `2016-03-11` |
......
...@@ -543,15 +543,15 @@ PUT /projects/:id/merge_requests/:merge_request_iid ...@@ -543,15 +543,15 @@ PUT /projects/:id/merge_requests/:merge_request_iid
| Attribute | Type | Required | Description | | Attribute | Type | Required | Description |
| --------- | ---- | -------- | ----------- | | --------- | ---- | -------- | ----------- |
| `id` | integer/string | yes | The ID or [URL-encoded path of the project](README.md#namespaced-path-encoding) owned by the authenticated user | | `id` | integer/string | yes | The ID or [URL-encoded path of the project](README.md#namespaced-path-encoding) owned by the authenticated user |
| `merge_request_iid` | integer | yes | The ID of a merge request | | `merge_request_iid` | integer | yes | The ID of a merge request |
| `target_branch` | string | no | The target branch | | `target_branch` | string | no | The target branch |
| `title` | string | no | Title of MR | | `title` | string | no | Title of MR |
| `assignee_id` | integer | no | Assignee user ID | | `assignee_id` | integer | no | The ID of the user to assign the merge request to. Set to `0` or provide an empty value to unassign all assignees. |
| `milestone_id` | integer | no | The ID of a milestone to assign the merge request to. Set to `0` or provide an empty value to unassign a milestone.|
| `labels` | string | no | Comma-separated label names for an merge request. Set to an empty string to unassign all labels. |
| `description` | string | no | Description of MR | | `description` | string | no | Description of MR |
| `state_event` | string | no | New state (close/reopen) | | `state_event` | string | no | New state (close/reopen) |
| `labels` | string | no | Labels for MR as a comma-separated list |
| `milestone_id` | integer | no | The ID of a milestone |
| `remove_source_branch` | boolean | no | Flag indicating if a merge request should remove the source branch when merging | | `remove_source_branch` | boolean | no | Flag indicating if a merge request should remove the source branch when merging |
| `squash` | boolean| no | Squash commits into a single commit when merging | | `squash` | boolean| no | Squash commits into a single commit when merging |
| `discussion_locked` | boolean | no | Flag indicating if the merge request's discussion is locked. If the discussion is locked only project members can add, edit or resolve comments. | | `discussion_locked` | boolean | no | Flag indicating if the merge request's discussion is locked. If the discussion is locked only project members can add, edit or resolve comments. |
......
...@@ -182,6 +182,8 @@ GET /projects/:id/repository/contributors ...@@ -182,6 +182,8 @@ GET /projects/:id/repository/contributors
Parameters: Parameters:
- `id` (required) - The ID or [URL-encoded path of the project](README.md#namespaced-path-encoding) owned by the authenticated user - `id` (required) - The ID or [URL-encoded path of the project](README.md#namespaced-path-encoding) owned by the authenticated user
- `order_by` (optional) - Return contributors ordered by `name`, `email`, or `commits` fields. If not given contributors are ordered by commit date.
- `sort` (optional) - Return contributors sorted in `asc` or `desc` order. Default is `asc`
Response: Response:
......
...@@ -12,7 +12,11 @@ GET /projects/:id/repository/tags ...@@ -12,7 +12,11 @@ GET /projects/:id/repository/tags
Parameters: Parameters:
- `id` (required) - The ID or [URL-encoded path of the project](README.md#namespaced-path-encoding) owned by the authenticated user | Attribute | Type | Required | Description |
| --------- | ---- | -------- | ----------- |
| `id` | integer/string| yes | The ID or [URL-encoded path of the project](README.md#namespaced-path-encoding) owned by the authenticated user|
| `order_by` | string | no | Return tags ordered by `name` or `updated` fields. Default is `updated` |
| `sort` | string | no | Return tags sorted in `asc` or `desc` order. Default is `desc` |
```json ```json
[ [
......
...@@ -319,45 +319,62 @@ As you can see, the syntax of `command` is similar to [Dockerfile's `CMD`][cmd]. ...@@ -319,45 +319,62 @@ As you can see, the syntax of `command` is similar to [Dockerfile's `CMD`][cmd].
> Introduced in GitLab and GitLab Runner 9.4. Read more about the [extended > Introduced in GitLab and GitLab Runner 9.4. Read more about the [extended
configuration options](#extended-docker-configuration-options). configuration options](#extended-docker-configuration-options).
Before showing the available entrypoint override methods, let's describe shortly
how the Runner starts and uses a Docker image for the containers used in the
CI jobs:
1. The Runner starts a Docker container using the defined entrypoint (default
from `Dockerfile` that may be overridden in `.gitlab-ci.yml`)
1. The Runner attaches itself to a running container.
1. The Runner prepares a script (the combination of
[`before_script`](../yaml/README.md#before_script),
[`script`](../yaml/README.md#script),
and [`after_script`](../yaml/README.md#after_script)).
1. The Runner sends the script to the container's shell STDIN and receives the
output.
To override the entrypoint of a Docker image, the recommended solution is to
define an empty `entrypoint` in `.gitlab-ci.yml`, so the Runner doesn't start
a useless shell layer. However, that will not work for all Docker versions, and
you should check which one your Runner is using. Specifically:
- If Docker 17.06 or later is used, the `entrypoint` can be set to an empty value.
- If Docker 17.03 or previous versions are used, the `entrypoint` can be set to
`/bin/sh -c`, `/bin/bash -c` or an equivalent shell available in the image.
The syntax of `image:entrypoint` is similar to [Dockerfile's `ENTRYPOINT`][entrypoint].
----
Let's assume you have a `super/sql:experimental` image with some SQL database Let's assume you have a `super/sql:experimental` image with some SQL database
inside it and you would like to use it as a base image for your job because you inside it and you would like to use it as a base image for your job because you
want to execute some tests with this database binary. Let's also assume that want to execute some tests with this database binary. Let's also assume that
this image is configured with `/usr/bin/super-sql run` as an entrypoint. That this image is configured with `/usr/bin/super-sql run` as an entrypoint. That
means, that when starting the container without additional options, it will run means that when starting the container without additional options, it will run
the database's process, while Runner expects that the image will have no the database's process, while Runner expects that the image will have no
entrypoint or at least will start with a shell as its entrypoint. entrypoint or that the entrypoint is prepared to start a shell command.
Before the new extended Docker configuration options, you would need to create
your own image based on the `super/sql:experimental` image, set the entrypoint
to a shell and then use it in job's configuration, like:
```Dockerfile With the extended Docker configuration options, instead of creating your
# my-super-sql:experimental image's Dockerfile own image based on `super/sql:experimental`, setting the `ENTRYPOINT`
to a shell, and then using the new image in your CI job, you can now simply
define an `entrypoint` in `.gitlab-ci.yml`.
FROM super/sql:experimental **For Docker 17.06+:**
ENTRYPOINT ["/bin/sh"]
```
```yaml ```yaml
# .gitlab-ci.yml image:
name: super/sql:experimental
image: my-super-sql:experimental entrypoint: [""]
``` ```
After the new extended Docker configuration options, you can now simply **For Docker =< 17.03:**
set an `entrypoint` in `.gitlab-ci.yml`, like:
```yaml ```yaml
# .gitlab-ci.yml
image: image:
name: super/sql:experimental name: super/sql:experimental
entrypoint: ["/bin/sh"] entrypoint: ["/bin/sh", "-c"]
``` ```
As you can see the syntax of `entrypoint` is similar to
[Dockerfile's `ENTRYPOINT`][entrypoint].
## Define image and services in `config.toml` ## Define image and services in `config.toml`
Look for the `[runners.docker]` section: Look for the `[runners.docker]` section:
......
This diff is collapsed.
...@@ -232,14 +232,15 @@ An example project service that defines deployment variables is ...@@ -232,14 +232,15 @@ An example project service that defines deployment variables is
## Debug tracing ## Debug tracing
> Introduced in GitLab Runner 1.7. > Introduced in GitLab Runner 1.7.
>
> **WARNING:** Enabling debug tracing can have severe security implications. The CAUTION: **Warning:**
output **will** contain the content of all your secret variables and any other Enabling debug tracing can have severe security implications. The
secrets! The output **will** be uploaded to the GitLab server and made visible output **will** contain the content of all your secret variables and any other
in job traces! secrets! The output **will** be uploaded to the GitLab server and made visible
in job traces!
By default, GitLab Runner hides most of the details of what it is doing when By default, GitLab Runner hides most of the details of what it is doing when
processing a job. This behaviour keeps job traces short, and prevents secrets processing a job. This behavior keeps job traces short, and prevents secrets
from being leaked into the trace unless your script writes them to the screen. from being leaked into the trace unless your script writes them to the screen.
If a job isn't working as expected, this can make the problem difficult to If a job isn't working as expected, this can make the problem difficult to
......
...@@ -215,6 +215,9 @@ There is also and alternative method to [translate messages from validation erro ...@@ -215,6 +215,9 @@ There is also and alternative method to [translate messages from validation erro
sprintf(__('Hello %{username}'), { username: 'Joe' }) => 'Hello Joe' sprintf(__('Hello %{username}'), { username: 'Joe' }) => 'Hello Joe'
``` ```
The placeholders should match the code style of the respective source file.
For example use `%{created_at}` in Ruby but `%{createdAt}` in JavaScript.
### Plurals ### Plurals
- In Ruby/HAML: - In Ruby/HAML:
......
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.
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.
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.
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