Commit 388488fd authored by Rémy Coutable's avatar Rémy Coutable

Merge branch 'rc/ce-to-ee-wednesday' into 'master'

CE Upstream - Wednesday

See merge request !1330
parents eee5d2b4 164942db
...@@ -23,6 +23,7 @@ AllCops: ...@@ -23,6 +23,7 @@ AllCops:
- 'tmp/**/*' - 'tmp/**/*'
- 'bin/**/*' - 'bin/**/*'
- 'generator_templates/**/*' - 'generator_templates/**/*'
- 'builds/**/*'
# Gems in consecutive lines should be alphabetically sorted # Gems in consecutive lines should be alphabetically sorted
Bundler/OrderedGems: Bundler/OrderedGems:
......
## Contributor license agreement
By submitting code as an individual you agree to the
[individual contributor license agreement](doc/legal/individual_contributor_license_agreement.md).
By submitting code as an entity you agree to the
[corporate contributor license agreement](doc/legal/corporate_contributor_license_agreement.md).
_This notice should stay as the first item in the CONTRIBUTING.MD file._
---
<!-- START doctoc generated TOC please keep comment here to allow auto update --> <!-- START doctoc generated TOC please keep comment here to allow auto update -->
<!-- DON'T EDIT THIS SECTION, INSTEAD RE-RUN doctoc TO UPDATE --> <!-- DON'T EDIT THIS SECTION, INSTEAD RE-RUN doctoc TO UPDATE -->
**Table of Contents** *generated with [DocToc](https://github.com/thlorenz/doctoc)* **Table of Contents** *generated with [DocToc](https://github.com/thlorenz/doctoc)*
- [Contributor license agreement](#contributor-license-agreement)
- [Contribute to GitLab](#contribute-to-gitlab) - [Contribute to GitLab](#contribute-to-gitlab)
- [Contributor license agreement](#contributor-license-agreement) - [Security vulnerability disclosure](#security-vulnerability-disclosure)
- [Security vulnerability disclosure](#security-vulnerability-disclosure) - [Closing policy for issues and merge requests](#closing-policy-for-issues-and-merge-requests)
- [Closing policy for issues and merge requests](#closing-policy-for-issues-and-merge-requests) - [Helping others](#helping-others)
- [Helping others](#helping-others) - [I want to contribute!](#i-want-to-contribute)
- [I want to contribute!](#i-want-to-contribute) - [Implement design & UI elements](#implement-design-ui-elements)
- [Implement design & UI elements](#implement-design-ui-elements) - [Release retrospective and kickoff](#release-retrospective-and-kickoff)
- [Issue tracker](#issue-tracker) - [Retrospective](#retrospective)
- [Feature proposals](#feature-proposals) - [Kickoff](#kickoff)
- [Issue tracker guidelines](#issue-tracker-guidelines) - [Issue tracker](#issue-tracker)
- [Issue weight](#issue-weight) - [Feature proposals](#feature-proposals)
- [Regression issues](#regression-issues) - [Issue tracker guidelines](#issue-tracker-guidelines)
- [Technical debt](#technical-debt) - [Issue weight](#issue-weight)
- [Stewardship](#stewardship) - [Regression issues](#regression-issues)
- [Merge requests](#merge-requests) - [Technical debt](#technical-debt)
- [Merge request guidelines](#merge-request-guidelines) - [Stewardship](#stewardship)
- [Contribution acceptance criteria](#contribution-acceptance-criteria) - [Merge requests](#merge-requests)
- [Changes for Stable Releases](#changes-for-stable-releases) - [Merge request guidelines](#merge-request-guidelines)
- [Definition of done](#definition-of-done) - [Contribution acceptance criteria](#contribution-acceptance-criteria)
- [Style guides](#style-guides) - [Changes for Stable Releases](#changes-for-stable-releases)
- [Code of conduct](#code-of-conduct) - [Definition of done](#definition-of-done)
- [Style guides](#style-guides)
- [Code of conduct](#code-of-conduct)
<!-- END doctoc generated TOC please keep comment here to allow auto update --> <!-- END doctoc generated TOC please keep comment here to allow auto update -->
# Contribute to GitLab ---
## Contribute to GitLab
Thank you for your interest in contributing to GitLab. This guide details how Thank you for your interest in contributing to GitLab. This guide details how
to contribute to GitLab in a way that is efficient for everyone. to contribute to GitLab in a way that is efficient for everyone.
...@@ -41,13 +57,6 @@ operates please see [the GitLab contributing process](PROCESS.md). ...@@ -41,13 +57,6 @@ operates please see [the GitLab contributing process](PROCESS.md).
- [GitLab Inc engineers should refer to the engineering workflow document](https://about.gitlab.com/handbook/engineering/workflow/) - [GitLab Inc engineers should refer to the engineering workflow document](https://about.gitlab.com/handbook/engineering/workflow/)
## Contributor license agreement
By submitting code as an individual you agree to the
[individual contributor license agreement](doc/legal/individual_contributor_license_agreement.md).
By submitting code as an entity you agree to the
[corporate contributor license agreement](doc/legal/corporate_contributor_license_agreement.md).
## Security vulnerability disclosure ## Security vulnerability disclosure
Please report suspected security vulnerabilities in private to Please report suspected security vulnerabilities in private to
......
...@@ -70,7 +70,7 @@ gem 'gollum-rugged_adapter', '~> 0.4.2', require: false ...@@ -70,7 +70,7 @@ gem 'gollum-rugged_adapter', '~> 0.4.2', require: false
gem 'github-linguist', '~> 4.7.0', require: 'linguist' gem 'github-linguist', '~> 4.7.0', require: 'linguist'
# API # API
gem 'grape', '~> 0.18.0' gem 'grape', '~> 0.19.0'
gem 'grape-entity', '~> 0.6.0' gem 'grape-entity', '~> 0.6.0'
gem 'rack-cors', '~> 0.4.0', require: 'rack/cors' gem 'rack-cors', '~> 0.4.0', require: 'rack/cors'
......
...@@ -330,7 +330,7 @@ GEM ...@@ -330,7 +330,7 @@ GEM
multi_json (~> 1.11) multi_json (~> 1.11)
os (~> 0.9) os (~> 0.9)
signet (~> 0.7) signet (~> 0.7)
grape (0.18.0) grape (0.19.1)
activesupport activesupport
builder builder
hashie (>= 2.1.0) hashie (>= 2.1.0)
...@@ -384,8 +384,8 @@ GEM ...@@ -384,8 +384,8 @@ GEM
json (~> 1.8) json (~> 1.8)
multi_xml (>= 0.5.2) multi_xml (>= 0.5.2)
httpclient (2.8.2) httpclient (2.8.2)
i18n (0.8.0) i18n (0.8.1)
ice_nine (0.11.1) ice_nine (0.11.2)
influxdb (0.2.3) influxdb (0.2.3)
cause cause
json json
...@@ -448,7 +448,7 @@ GEM ...@@ -448,7 +448,7 @@ GEM
minitest (5.7.0) minitest (5.7.0)
mousetrap-rails (1.4.6) mousetrap-rails (1.4.6)
multi_json (1.12.1) multi_json (1.12.1)
multi_xml (0.5.5) multi_xml (0.6.0)
multipart-post (2.0.0) multipart-post (2.0.0)
mustermann (0.4.0) mustermann (0.4.0)
tool (~> 0.2) tool (~> 0.2)
...@@ -788,7 +788,7 @@ GEM ...@@ -788,7 +788,7 @@ GEM
eventmachine (~> 1.0, >= 1.0.4) eventmachine (~> 1.0, >= 1.0.4)
rack (>= 1, < 3) rack (>= 1, < 3)
thor (0.19.4) thor (0.19.4)
thread_safe (0.3.5) thread_safe (0.3.6)
tilt (2.0.6) tilt (2.0.6)
timecop (0.8.1) timecop (0.8.1)
timfel-krb5-auth (0.8.3) timfel-krb5-auth (0.8.3)
...@@ -922,7 +922,7 @@ DEPENDENCIES ...@@ -922,7 +922,7 @@ DEPENDENCIES
gollum-rugged_adapter (~> 0.4.2) gollum-rugged_adapter (~> 0.4.2)
gon (~> 6.1.0) gon (~> 6.1.0)
google-api-client (~> 0.8.6) google-api-client (~> 0.8.6)
grape (~> 0.18.0) grape (~> 0.19.0)
grape-entity (~> 0.6.0) grape-entity (~> 0.6.0)
gssapi gssapi
haml_lint (~> 0.21.0) haml_lint (~> 0.21.0)
...@@ -1048,4 +1048,4 @@ DEPENDENCIES ...@@ -1048,4 +1048,4 @@ DEPENDENCIES
wikicloth (= 0.8.1) wikicloth (= 0.8.1)
BUNDLED WITH BUNDLED WITH
1.14.3 1.14.4
...@@ -75,8 +75,11 @@ const DEFAULT_EVENT_OBJECTS = require('./default_event_objects'); ...@@ -75,8 +75,11 @@ const DEFAULT_EVENT_OBJECTS = require('./default_event_objects');
const eventItem = Object.assign({}, DEFAULT_EVENT_OBJECTS[stage.slug], item); const eventItem = Object.assign({}, DEFAULT_EVENT_OBJECTS[stage.slug], item);
eventItem.totalTime = eventItem.total_time; eventItem.totalTime = eventItem.total_time;
eventItem.author.webUrl = eventItem.author.web_url;
eventItem.author.avatarUrl = eventItem.author.avatar_url; if (eventItem.author) {
eventItem.author.webUrl = eventItem.author.web_url;
eventItem.author.avatarUrl = eventItem.author.avatar_url;
}
if (eventItem.created_at) eventItem.createdAt = eventItem.created_at; if (eventItem.created_at) eventItem.createdAt = eventItem.created_at;
if (eventItem.short_sha) eventItem.shortSha = eventItem.short_sha; if (eventItem.short_sha) eventItem.shortSha = eventItem.short_sha;
......
...@@ -163,7 +163,7 @@ module.exports = Vue.component('environment-component', { ...@@ -163,7 +163,7 @@ module.exports = Vue.component('environment-component', {
</div> </div>
</div> </div>
<div class="environments-container"> <div class="content-list environments-container">
<div class="environments-list-loading text-center" v-if="isLoading"> <div class="environments-list-loading text-center" v-if="isLoading">
<i class="fa fa-spinner fa-spin"></i> <i class="fa fa-spinner fa-spin"></i>
</div> </div>
...@@ -202,12 +202,12 @@ module.exports = Vue.component('environment-component', { ...@@ -202,12 +202,12 @@ module.exports = Vue.component('environment-component', {
:store="store" :store="store"
:service="service"> :service="service">
</environment-table> </environment-table>
<table-pagination v-if="shouldRenderPagination"
:change="changePage"
:pageInfo="state.paginationInformation">
</table-pagination>
</div> </div>
<table-pagination v-if="state.paginationInformation && state.paginationInformation.totalPages > 1"
:change="changePage"
:pageInfo="state.paginationInformation">
</table-pagination>
</div> </div>
</div> </div>
`, `,
......
...@@ -523,7 +523,7 @@ module.exports = Vue.component('environment-item', { ...@@ -523,7 +523,7 @@ module.exports = Vue.component('environment-item', {
</span> </span>
</td> </td>
<td class="hidden-xs environments-actions"> <td class="environments-actions">
<div v-if="!model.isFolder" class="btn-group pull-right" role="group"> <div v-if="!model.isFolder" class="btn-group pull-right" role="group">
<actions-component v-if="hasManualActions && canCreateDeployment" <actions-component v-if="hasManualActions && canCreateDeployment"
:play-icon-svg="playIconSvg" :play-icon-svg="playIconSvg"
......
...@@ -69,7 +69,7 @@ module.exports = Vue.component('environment-table-component', { ...@@ -69,7 +69,7 @@ module.exports = Vue.component('environment-table-component', {
}, },
template: ` template: `
<table class="table ci-table environments"> <table class="table ci-table">
<thead> <thead>
<tr> <tr>
<th class="environments-name">Environment</th> <th class="environments-name">Environment</th>
...@@ -77,7 +77,7 @@ module.exports = Vue.component('environment-table-component', { ...@@ -77,7 +77,7 @@ module.exports = Vue.component('environment-table-component', {
<th class="environments-build">Job</th> <th class="environments-build">Job</th>
<th class="environments-commit">Commit</th> <th class="environments-commit">Commit</th>
<th class="environments-date">Updated</th> <th class="environments-date">Updated</th>
<th class="hidden-xs environments-actions"></th> <th class="environments-actions"></th>
</tr> </tr>
</thead> </thead>
<tbody> <tbody>
......
...@@ -39,8 +39,9 @@ require('../../subbable_resource'); ...@@ -39,8 +39,9 @@ require('../../subbable_resource');
listenForSlashCommands() { listenForSlashCommands() {
$(document).on('ajax:success', '.gfm-form', (e, data) => { $(document).on('ajax:success', '.gfm-form', (e, data) => {
const subscribedCommands = ['spend_time', 'time_estimate']; const subscribedCommands = ['spend_time', 'time_estimate'];
const changedCommands = data.commands_changes; const changedCommands = data.commands_changes
? Object.keys(data.commands_changes)
: [];
if (changedCommands && _.intersection(subscribedCommands, changedCommands).length) { if (changedCommands && _.intersection(subscribedCommands, changedCommands).length) {
this.fetchIssuable(); this.fetchIssuable();
} }
......
...@@ -246,12 +246,21 @@ require('./task_list'); ...@@ -246,12 +246,21 @@ require('./task_list');
}; };
Notes.prototype.handleCreateChanges = function(note) { Notes.prototype.handleCreateChanges = function(note) {
var votesBlock;
if (typeof note === 'undefined') { if (typeof note === 'undefined') {
return; return;
} }
if (note.commands_changes && note.commands_changes.indexOf('merge') !== -1) { if (note.commands_changes) {
$.get(mrRefreshWidgetUrl); if ('merge' in note.commands_changes) {
$.get(mrRefreshWidgetUrl);
}
if ('emoji_award' in note.commands_changes) {
votesBlock = $('.js-awards-block').eq(0);
gl.awardsHandler.addAwardToEmojiBar(votesBlock, note.commands_changes.emoji_award);
return gl.awardsHandler.scrollToAwards();
}
} }
}; };
...@@ -262,26 +271,16 @@ require('./task_list'); ...@@ -262,26 +271,16 @@ require('./task_list');
*/ */
Notes.prototype.renderNote = function(note) { Notes.prototype.renderNote = function(note) {
var $notesList, votesBlock; var $notesList;
if (!note.valid) { if (!note.valid) {
if (note.award) { if (note.errors.commands_only) {
new Flash('You have already awarded this emoji!', 'alert', this.parentTimeline); new Flash(note.errors.commands_only, 'notice', this.parentTimeline);
} this.refresh();
else {
if (note.errors.commands_only) {
new Flash(note.errors.commands_only, 'notice', this.parentTimeline);
this.refresh();
}
} }
return; return;
} }
if (note.award) {
votesBlock = $('.js-awards-block').eq(0); if (this.isNewNote(note)) {
gl.awardsHandler.addAwardToEmojiBar(votesBlock, note.name);
return gl.awardsHandler.scrollToAwards();
// render note if it not present in loaded list
// or skip if rendered
} else if (this.isNewNote(note)) {
this.note_ids.push(note.id); this.note_ids.push(note.id);
$notesList = $('ul.main-notes-list'); $notesList = $('ul.main-notes-list');
$notesList.append(note.html).syntaxHighlight(); $notesList.append(note.html).syntaxHighlight();
......
...@@ -32,7 +32,7 @@ ...@@ -32,7 +32,7 @@
}, },
}, },
template: ` template: `
<td class="pipeline-actions hidden-xs"> <td class="pipeline-actions">
<div class="pull-right"> <div class="pull-right">
<div class="btn-group"> <div class="btn-group">
<div class="btn-group" v-if="actions"> <div class="btn-group" v-if="actions">
......
...@@ -45,18 +45,15 @@ const CommitPipelinesStoreWithTimeAgo = require('../commit/pipelines/pipelines_s ...@@ -45,18 +45,15 @@ const CommitPipelinesStoreWithTimeAgo = require('../commit/pipelines/pipelines_s
methods: { methods: {
/** /**
* Changes the URL according to the pagination component. * Will change the page number and update the URL.
* *
* If no scope is provided, 'all' is assumed. * @param {Number} pageNumber desired page to go to.
*
* Pagination component sends "null" when no scope is provided.
*
* @param {Number} pagenum
* @param {String} apiScope = 'all'
*/ */
change(pagenum, apiScope) { change(pageNumber) {
if (!apiScope) apiScope = 'all'; const param = gl.utils.setParamInURL('page', pageNumber);
gl.utils.visitUrl(`?scope=${apiScope}&page=${pagenum}`);
gl.utils.visitUrl(param);
return param;
}, },
}, },
template: ` template: `
......
...@@ -44,7 +44,7 @@ require('./pipelines_table_row'); ...@@ -44,7 +44,7 @@ require('./pipelines_table_row');
<th class="js-pipeline-commit pipeline-commit">Commit</th> <th class="js-pipeline-commit pipeline-commit">Commit</th>
<th class="js-pipeline-stages pipeline-stages">Stages</th> <th class="js-pipeline-stages pipeline-stages">Stages</th>
<th class="js-pipeline-date pipeline-date"></th> <th class="js-pipeline-date pipeline-date"></th>
<th class="js-pipeline-actions pipeline-actions hidden-xs"></th> <th class="js-pipeline-actions pipeline-actions"></th>
</tr> </tr>
</thead> </thead>
<tbody> <tbody>
......
...@@ -23,8 +23,8 @@ window.Vue = require('vue'); ...@@ -23,8 +23,8 @@ window.Vue = require('vue');
Here is an example `change` method: Here is an example `change` method:
change(pagenum, apiScope) { change(pagenum) {
gl.utils.visitUrl(`?scope=${apiScope}&p=${pagenum}`); gl.utils.visitUrl(`?page=${pagenum}`);
}, },
*/ */
...@@ -57,8 +57,6 @@ window.Vue = require('vue'); ...@@ -57,8 +57,6 @@ window.Vue = require('vue');
}, },
methods: { methods: {
changePage(e) { changePage(e) {
const apiScope = gl.utils.getParameterByName('scope');
const text = e.target.innerText; const text = e.target.innerText;
const { totalPages, nextPage, previousPage } = this.pageInfo; const { totalPages, nextPage, previousPage } = this.pageInfo;
...@@ -66,19 +64,19 @@ window.Vue = require('vue'); ...@@ -66,19 +64,19 @@ window.Vue = require('vue');
case SPREAD: case SPREAD:
break; break;
case LAST: case LAST:
this.change(totalPages, apiScope); this.change(totalPages);
break; break;
case NEXT: case NEXT:
this.change(nextPage, apiScope); this.change(nextPage);
break; break;
case PREV: case PREV:
this.change(previousPage, apiScope); this.change(previousPage);
break; break;
case FIRST: case FIRST:
this.change(1, apiScope); this.change(1);
break; break;
default: default:
this.change(+text, apiScope); this.change(+text);
break; break;
} }
}, },
......
...@@ -148,16 +148,11 @@ header { ...@@ -148,16 +148,11 @@ header {
} }
.header-logo { .header-logo {
position: absolute; display: inline-block;
left: 50%; margin: 0 8px 0 3px;
position: relative;
top: 7px; top: 7px;
transition-duration: .3s; transition-duration: .3s;
z-index: 999;
#logo {
position: relative;
left: -50%;
}
svg, svg,
img { img {
...@@ -167,15 +162,6 @@ header { ...@@ -167,15 +162,6 @@ header {
&:hover { &:hover {
cursor: pointer; cursor: pointer;
} }
@media (max-width: $screen-xs-max) {
right: 20px;
left: auto;
#logo {
left: auto;
}
}
} }
.title { .title {
...@@ -183,7 +169,6 @@ header { ...@@ -183,7 +169,6 @@ header {
padding-right: 20px; padding-right: 20px;
margin: 0; margin: 0;
font-size: 18px; font-size: 18px;
max-width: 385px;
display: inline-block; display: inline-block;
line-height: $header-height; line-height: $header-height;
font-weight: normal; font-weight: normal;
...@@ -193,14 +178,18 @@ header { ...@@ -193,14 +178,18 @@ header {
vertical-align: top; vertical-align: top;
white-space: nowrap; white-space: nowrap;
@media (min-width: $screen-sm-min) and (max-width: $screen-sm-max) {
max-width: 300px;
}
@media (max-width: $screen-xs-max) { @media (max-width: $screen-xs-max) {
max-width: 190px; max-width: 190px;
} }
@media (min-width: $screen-sm-min) and (max-width: $screen-md-max) {
max-width: 428px;
}
@media (min-width: $screen-lg-min) {
max-width: 685px;
}
a { a {
color: $gl-text-color; color: $gl-text-color;
......
...@@ -15,112 +15,97 @@ ...@@ -15,112 +15,97 @@
padding-top: 20px; padding-top: 20px;
} }
@media (max-width: $screen-xs-max) { .environments-container {
.environments-container { .table-holder {
width: 100%; width: 100%;
overflow: auto; overflow: auto;
} }
}
.environments {
table-layout: fixed;
.environments-commit,
.environments-actions,
.environments-deploy,
.environments-build,
.environments-date {
position: static;
float: none;
display: table-cell;
}
.environments-commit,
.environments-actions {
width: 20%;
}
.environments-date {
width: 10%;
}
.environments-name, .table.ci-table {
.environments-deploy, .environments-actions {
.environments-build { min-width: 200px;
width: 15%;
}
.environment-name,
.environments-build-cell,
.deployment-column {
word-break: break-all;
}
.deployment-column {
.avatar {
float: none;
} }
}
.btn-group { .environments-commit,
.environments-actions {
width: 20%;
}
> a { .environments-date {
color: $gl-text-color-secondary; width: 10%;
} }
svg path { .environments-name,
fill: $gl-text-color-secondary; .environments-deploy,
.environments-build {
width: 15%;
} }
.dropdown { .deployment-column {
outline: none; > span {
word-break: break-all;
}
.avatar {
float: none;
}
} }
}
.btn-group {
.commit-title { > a {
margin: 0; color: $gl-text-color-secondary;
} }
.avatar-image-container { svg path {
text-decoration: none; fill: $gl-text-color-secondary;
} }
.icon-play { .dropdown {
height: 13px; outline: none;
width: 12px; }
} }
.external-url, .commit-title {
.dropdown-new { margin: 0;
color: $gl-text-color-secondary; }
}
.dropdown-menu { .avatar-image-container {
text-decoration: none;
}
.fa { .icon-play {
margin-right: 6px; height: 13px;
color: $gl-text-color-secondary; width: 12px;
} }
}
.build-link, .external-url,
.branch-name { .dropdown-new {
color: $gl-text-color; color: $gl-text-color-secondary;
} }
.stop-env-link, .dropdown-menu {
.external-url { .fa {
color: $gl-text-color-secondary; margin-right: 6px;
color: $gl-text-color-secondary;
}
}
.stop-env-icon { .build-link,
font-size: 14px; .branch-name {
color: $gl-text-color;
} }
}
.deployment { .stop-env-link,
.build-column { .external-url {
color: $gl-text-color-secondary;
.stop-env-icon {
font-size: 14px;
}
}
.deployment .build-column {
.build-link { .build-link {
color: $gl-text-color; color: $gl-text-color;
} }
...@@ -129,34 +114,32 @@ ...@@ -129,34 +114,32 @@
float: none; float: none;
} }
} }
}
.folder-icon { .folder-icon {
margin-right: 3px;
color: $gl-text-color-secondary;
display: inline-block;
.fa:nth-child(1) {
margin-right: 3px; margin-right: 3px;
color: $gl-text-color-secondary;
display: inline-block;
.fa:nth-child(1) {
margin-right: 3px;
}
} }
}
.folder-name { .folder-name {
cursor: pointer; cursor: pointer;
color: $gl-text-color-secondary; color: $gl-text-color-secondary;
display: inline-block; display: inline-block;
} }
}
.table.ci-table.environments { .icon-container {
.icon-container { width: 20px;
width: 20px; text-align: center;
text-align: center; }
}
.branch-commit { .branch-commit {
.commit-id { .commit-id {
margin-right: 0; margin-right: 0;
}
} }
} }
} }
......
...@@ -105,6 +105,7 @@ ...@@ -105,6 +105,7 @@
@media (max-width: $screen-md-max) { @media (max-width: $screen-md-max) {
.content-list { .content-list {
&.pipelines, &.pipelines,
&.environments-container,
&.builds-content-list { &.builds-content-list {
width: 100%; width: 100%;
overflow: auto; overflow: auto;
......
...@@ -148,17 +148,10 @@ class Projects::NotesController < Projects::ApplicationController ...@@ -148,17 +148,10 @@ class Projects::NotesController < Projects::ApplicationController
def note_json(note) def note_json(note)
attrs = { attrs = {
award: false,
id: note.id id: note.id
} }
if note.is_a?(AwardEmoji) if note.persisted?
attrs.merge!(
valid: note.valid?,
award: true,
name: note.name
)
elsif note.persisted?
Banzai::NoteRenderer.render([note], @project, current_user) Banzai::NoteRenderer.render([note], @project, current_user)
attrs.merge!( attrs.merge!(
...@@ -198,8 +191,7 @@ class Projects::NotesController < Projects::ApplicationController ...@@ -198,8 +191,7 @@ class Projects::NotesController < Projects::ApplicationController
) )
end end
attrs[:commands_changes] = note.commands_changes unless attrs[:award] attrs[:commands_changes] = note.commands_changes
attrs attrs
end end
......
...@@ -97,7 +97,7 @@ module MilestonesHelper ...@@ -97,7 +97,7 @@ module MilestonesHelper
def milestone_date_range(milestone) def milestone_date_range(milestone)
if milestone.start_date && milestone.due_date if milestone.start_date && milestone.due_date
"#{milestone.start_date.to_s(:medium)} - #{milestone.due_date.to_s(:medium)}" "#{milestone.start_date.to_s(:medium)}#{milestone.due_date.to_s(:medium)}"
elsif milestone.due_date elsif milestone.due_date
if milestone.due_date.past? if milestone.due_date.past?
"expired on #{milestone.due_date.to_s(:medium)}" "expired on #{milestone.due_date.to_s(:medium)}"
......
...@@ -96,10 +96,6 @@ class MergeRequest < ActiveRecord::Base ...@@ -96,10 +96,6 @@ class MergeRequest < ActiveRecord::Base
around_transition do |merge_request, transition, block| around_transition do |merge_request, transition, block|
Gitlab::Timeless.timeless(merge_request, &block) Gitlab::Timeless.timeless(merge_request, &block)
end end
after_transition unchecked: :cannot_be_merged do |merge_request, transition|
TodoService.new.merge_request_became_unmergeable(merge_request)
end
end end
validates :source_project, presence: true, unless: [:allow_broken, :importing?, :closed_without_fork?] validates :source_project, presence: true, unless: [:allow_broken, :importing?, :closed_without_fork?]
......
...@@ -237,10 +237,6 @@ class Note < ActiveRecord::Base ...@@ -237,10 +237,6 @@ class Note < ActiveRecord::Base
note =~ /\A#{Banzai::Filter::EmojiFilter.emoji_pattern}\s?\Z/ note =~ /\A#{Banzai::Filter::EmojiFilter.emoji_pattern}\s?\Z/
end end
def award_emoji_name
note.match(Banzai::Filter::EmojiFilter.emoji_pattern)[1]
end
def to_ability_name def to_ability_name
for_personal_snippet? ? 'personal_snippet' : noteable_type.underscore for_personal_snippet? ? 'personal_snippet' : noteable_type.underscore
end end
......
...@@ -34,8 +34,15 @@ class ProjectGroupLink < ActiveRecord::Base ...@@ -34,8 +34,15 @@ class ProjectGroupLink < ActiveRecord::Base
private private
def different_group def different_group
if self.group && self.project && self.project.group == self.group return unless self.group && self.project
errors.add(:base, "Project cannot be shared with the project it is in.")
project_group = self.project.group
return unless project_group
group_ids = project_group.ancestors.map(&:id).push(project_group.id)
if group_ids.include?(self.group.id)
errors.add(:base, "Project cannot be shared with the group it is in or one of its ancestors.")
end end
end end
......
...@@ -499,7 +499,7 @@ class User < ActiveRecord::Base ...@@ -499,7 +499,7 @@ class User < ActiveRecord::Base
Group.member_descendants(id) Group.member_descendants(id)
end end
def nested_projects def nested_groups_projects
Project.joins(:namespace).where('namespaces.parent_id IS NOT NULL'). Project.joins(:namespace).where('namespaces.parent_id IS NOT NULL').
member_descendants(id) member_descendants(id)
end end
......
AccessTokenValidationService = Struct.new(:token) do class AccessTokenValidationService
# Results: # Results:
VALID = :valid VALID = :valid
EXPIRED = :expired EXPIRED = :expired
REVOKED = :revoked REVOKED = :revoked
INSUFFICIENT_SCOPE = :insufficient_scope INSUFFICIENT_SCOPE = :insufficient_scope
attr_reader :token
def initialize(token)
@token = token
end
def validate(scopes: []) def validate(scopes: [])
if token.expired? if token.expired?
return EXPIRED return EXPIRED
......
...@@ -21,21 +21,33 @@ module Ci ...@@ -21,21 +21,33 @@ module Ci
builds_for_specific_runner builds_for_specific_runner
end end
build = builds.find do |build| valid = true
runner.can_pick?(build)
end
if build builds.find do |build|
# In case when 2 runners try to assign the same build, second runner will be declined next unless runner.can_pick?(build)
# with StateMachines::InvalidTransition or StaleObjectError when doing run! or save method.
build.runner_id = runner.id begin
build.run! # In case when 2 runners try to assign the same build, second runner will be declined
end # with StateMachines::InvalidTransition or StaleObjectError when doing run! or save method.
build.runner_id = runner.id
build.run!
Result.new(build, true) return Result.new(build, true)
rescue StateMachines::InvalidTransition, ActiveRecord::StaleObjectError
# We are looping to find another build that is not conflicting
# It also indicates that this build can be picked and passed to runner.
# If we don't do it, basically a bunch of runners would be competing for a build
# and thus we will generate a lot of 409. This will increase
# the number of generated requests, also will reduce significantly
# how many builds can be picked by runner in a unit of time.
# In case we hit the concurrency-access lock,
# we still have to return 409 in the end,
# to make sure that this is properly handled by runner.
valid = false
end
end
rescue StateMachines::InvalidTransition, ActiveRecord::StaleObjectError Result.new(nil, valid)
Result.new(build, false)
end end
private private
......
...@@ -203,6 +203,7 @@ class IssuableBaseService < BaseService ...@@ -203,6 +203,7 @@ class IssuableBaseService < BaseService
change_state(issuable) change_state(issuable)
change_subscription(issuable) change_subscription(issuable)
change_todo(issuable) change_todo(issuable)
toggle_award(issuable)
filter_params(issuable) filter_params(issuable)
old_labels = issuable.labels.to_a old_labels = issuable.labels.to_a
old_mentioned_users = issuable.mentioned_users.to_a old_mentioned_users = issuable.mentioned_users.to_a
...@@ -263,6 +264,14 @@ class IssuableBaseService < BaseService ...@@ -263,6 +264,14 @@ class IssuableBaseService < BaseService
end end
end end
def toggle_award(issuable)
award = params.delete(:emoji_award)
if award
todo_service.new_award_emoji(issuable, current_user)
issuable.toggle_award_emoji(award, current_user)
end
end
def has_changes?(issuable, old_labels: []) def has_changes?(issuable, old_labels: [])
valid_attrs = [:title, :description, :assignee_id, :milestone_id, :target_branch] valid_attrs = [:title, :description, :assignee_id, :milestone_id, :target_branch]
......
...@@ -24,7 +24,11 @@ module MergeRequests ...@@ -24,7 +24,11 @@ module MergeRequests
pipeline_merge_requests(pipeline) do |merge_request| pipeline_merge_requests(pipeline) do |merge_request|
next unless merge_request.merge_when_pipeline_succeeds? next unless merge_request.merge_when_pipeline_succeeds?
next unless merge_request.mergeable?
unless merge_request.mergeable?
todo_service.merge_request_became_unmergeable(merge_request)
next
end
MergeWorker.perform_async(merge_request.id, merge_request.merge_user_id, merge_request.merge_params) MergeWorker.perform_async(merge_request.id, merge_request.merge_user_id, merge_request.merge_params)
end end
......
...@@ -8,14 +8,6 @@ module Notes ...@@ -8,14 +8,6 @@ module Notes
note.author = current_user note.author = current_user
note.system = false note.system = false
if note.award_emoji?
noteable = note.noteable
if noteable.user_can_award?(current_user, note.award_emoji_name)
todo_service.new_award_emoji(noteable, current_user)
return noteable.create_award_emoji(note.award_emoji_name, current_user)
end
end
# We execute commands (extracted from `params[:note]`) on the noteable # We execute commands (extracted from `params[:note]`) on the noteable
# **before** we save the note because if the note consists of commands # **before** we save the note because if the note consists of commands
# only, there is no need be create a note! # only, there is no need be create a note!
...@@ -48,7 +40,7 @@ module Notes ...@@ -48,7 +40,7 @@ module Notes
note.errors.add(:commands_only, 'Commands applied') note.errors.add(:commands_only, 'Commands applied')
end end
note.commands_changes = command_params.keys note.commands_changes = command_params
end end
note note
......
...@@ -255,6 +255,18 @@ module SlashCommands ...@@ -255,6 +255,18 @@ module SlashCommands
@updates[:wip_event] = issuable.work_in_progress? ? 'unwip' : 'wip' @updates[:wip_event] = issuable.work_in_progress? ? 'unwip' : 'wip'
end end
desc 'Toggle emoji reward'
params ':emoji:'
condition do
issuable.persisted?
end
command :award do |emoji|
name = award_emoji_name(emoji)
if name && issuable.user_can_award?(current_user, name)
@updates[:emoji_award] = name
end
end
desc 'Set time estimate' desc 'Set time estimate'
params '<1w 3d 2h 14m>' params '<1w 3d 2h 14m>'
condition do condition do
...@@ -352,5 +364,10 @@ module SlashCommands ...@@ -352,5 +364,10 @@ module SlashCommands
ext.references(type) ext.references(type)
end end
def award_emoji_name(emoji)
match = emoji.match(Banzai::Filter::EmojiFilter.emoji_pattern)
match[1] if match
end
end end
end end
...@@ -115,11 +115,23 @@ module Users ...@@ -115,11 +115,23 @@ module Users
# Returns a union query of projects that the user is authorized to access # Returns a union query of projects that the user is authorized to access
def project_authorizations_union def project_authorizations_union
relations = [ relations = [
# Personal projects
user.personal_projects.select("#{user.id} AS user_id, projects.id AS project_id, #{Gitlab::Access::MASTER} AS access_level"), user.personal_projects.select("#{user.id} AS user_id, projects.id AS project_id, #{Gitlab::Access::MASTER} AS access_level"),
user.groups_projects.select_for_project_authorization,
# Projects the user is a member of
user.projects.select_for_project_authorization, user.projects.select_for_project_authorization,
# Projects of groups the user is a member of
user.groups_projects.select_for_project_authorization,
# Projects of subgroups of groups the user is a member of
user.nested_groups_projects.select_for_project_authorization,
# Projects shared with groups the user is a member of
user.groups.joins(:shared_projects).select_for_project_authorization, user.groups.joins(:shared_projects).select_for_project_authorization,
user.nested_projects.select_for_project_authorization
# Projects shared with subgroups of groups the user is a member of
user.nested_groups.joins(:shared_projects).select_for_project_authorization
] ]
Gitlab::SQL::Union.new(relations) Gitlab::SQL::Union.new(relations)
......
...@@ -3,7 +3,7 @@ ...@@ -3,7 +3,7 @@
= render 'shared/nav_scroll' = render 'shared/nav_scroll'
.nav-links.sub-nav.scrolling-tabs .nav-links.sub-nav.scrolling-tabs
%ul{ class: container_class } %ul{ class: container_class }
= nav_link(path: 'groups#show', html_options: { class: 'home' }) do = nav_link(path: ['groups#show', 'groups#subgroups'], html_options: { class: 'home' }) do
= link_to group_path(@group), title: 'Group Home' do = link_to group_path(@group), title: 'Group Home' do
%span %span
Home Home
...@@ -12,8 +12,3 @@ ...@@ -12,8 +12,3 @@
= link_to activity_group_path(@group), title: 'Activity' do = link_to activity_group_path(@group), title: 'Activity' do
%span %span
Activity Activity
= nav_link(path: 'group_members#index') do
= link_to group_group_members_path(@group), title: 'Members' do
%span
Members
- page_title "Members" - page_title "Members"
= render 'groups/head'
.project-members-page.prepend-top-default .project-members-page.prepend-top-default
%h4 %h4
......
- @no_container = true - @no_container = true
= render 'head'
= render 'groups/home_panel' = render 'groups/home_panel'
.groups-header{ class: container_class } .groups-header{ class: container_class }
......
...@@ -40,6 +40,7 @@ ...@@ -40,6 +40,7 @@
%li %li
= link_to new_project_path, title: 'New project', aria: { label: "New project" }, data: {toggle: 'tooltip', placement: 'bottom', container: 'body'} do = link_to new_project_path, title: 'New project', aria: { label: "New project" }, data: {toggle: 'tooltip', placement: 'bottom', container: 'body'} do
= icon('plus fw') = icon('plus fw')
- if Gitlab::Geo.secondary? - if Gitlab::Geo.secondary?
%li %li
= link_to Gitlab::Geo.primary_node.url, title: 'Go to primary node', data: {toggle: 'tooltip', placement: 'bottom', container: 'body'} do = link_to Gitlab::Geo.primary_node.url, title: 'Go to primary node', data: {toggle: 'tooltip', placement: 'bottom', container: 'body'} do
...@@ -60,8 +61,6 @@ ...@@ -60,8 +61,6 @@
= link_to "Profile", current_user, class: 'profile-link', aria: { label: "Profile" }, data: { user: current_user.username } = link_to "Profile", current_user, class: 'profile-link', aria: { label: "Profile" }, data: { user: current_user.username }
%li %li
= link_to "Settings", profile_path, aria: { label: "Settings" } = link_to "Settings", profile_path, aria: { label: "Settings" }
%li
= link_to "Help", help_path, aria: { label: "Help" }
%li.divider %li.divider
%li %li
= link_to "Sign out", destroy_user_session_path, method: :delete, class: "sign-out-link", aria: { label: "Sign out" } = link_to "Sign out", destroy_user_session_path, method: :delete, class: "sign-out-link", aria: { label: "Sign out" }
...@@ -70,12 +69,12 @@ ...@@ -70,12 +69,12 @@
%div %div
= link_to "Sign in", new_session_path(:user, redirect_to_referer: 'yes'), class: 'btn btn-sign-in btn-success' = link_to "Sign in", new_session_path(:user, redirect_to_referer: 'yes'), class: 'btn btn-sign-in btn-success'
%h1.title= title
.header-logo .header-logo
= link_to root_path, class: 'home', title: 'Dashboard', id: 'logo' do = link_to root_path, class: 'home', title: 'Dashboard', id: 'logo' do
= brand_header_logo = brand_header_logo
%h1.title= title
= yield :header_content = yield :header_content
= render 'shared/outdated_browser' = render 'shared/outdated_browser'
......
...@@ -36,4 +36,4 @@ ...@@ -36,4 +36,4 @@
Snippets Snippets
%li.divider %li.divider
%li %li
= link_to "About GitLab EE", help_path, title: 'About GitLab EE', class: 'about-gitlab' = link_to "Help", help_path, title: 'About GitLab EE', class: 'about-gitlab'
...@@ -5,7 +5,7 @@ ...@@ -5,7 +5,7 @@
.fade-right .fade-right
= icon('angle-right') = icon('angle-right')
%ul.nav-links.scrolling-tabs %ul.nav-links.scrolling-tabs
= nav_link(path: ['groups#show', 'groups#activity', 'group_members#index'], html_options: { class: 'home' }) do = nav_link(path: ['groups#show', 'groups#activity', 'groups#subgroups'], html_options: { class: 'home' }) do
= link_to group_path(@group), title: 'Home' do = link_to group_path(@group), title: 'Home' do
%span %span
Group Group
...@@ -21,6 +21,11 @@ ...@@ -21,6 +21,11 @@
Merge Requests Merge Requests
- merge_requests = MergeRequestsFinder.new(current_user, group_id: @group.id, state: 'opened', non_archived: true).execute - merge_requests = MergeRequestsFinder.new(current_user, group_id: @group.id, state: 'opened', non_archived: true).execute
%span.badge.count= number_with_delimiter(merge_requests.count) %span.badge.count= number_with_delimiter(merge_requests.count)
= nav_link(path: 'group_members#index') do
= link_to group_group_members_path(@group), title: 'Members' do
%span
Members
= nav_link(controller: [:stats]) do = nav_link(controller: [:stats]) do
= link_to group_analytics_path(@group), title: 'Contribution Analytics', data: {placement: 'right'} do = link_to group_analytics_path(@group), title: 'Contribution Analytics', data: {placement: 'right'} do
%span %span
......
...@@ -19,10 +19,9 @@ ...@@ -19,10 +19,9 @@
Open Open
.header-text-content .header-text-content
%span.identifier %span.identifier
Milestone ##{@milestone.iid} %strong
Milestone %#{@milestone.iid}
- if @milestone.due_date || @milestone.start_date - if @milestone.due_date || @milestone.start_date
%span.creator
&middot;
= milestone_date_range(@milestone) = milestone_date_range(@milestone)
.milestone-buttons .milestone-buttons
- if can?(current_user, :admin_milestone, @project) - if can?(current_user, :admin_milestone, @project)
......
...@@ -3,7 +3,7 @@ ...@@ -3,7 +3,7 @@
= render "projects/commits/head" = render "projects/commits/head"
.flex-list{ class: container_class } .flex-list{ class: container_class }
.top-area.flex-row .top-area.adjust
.nav-text.row-main-content .nav-text.row-main-content
Tags give the ability to mark specific points in history as being important Tags give the ability to mark specific points in history as being important
......
---
title: Add spec for todo with target_type Commit
merge_request: 9351
author: George Andrinopoulos
---
title: Introduce /award slash command; Allow posting of just an emoji in comment
merge_request: 9382
author: mhasbini
---
title: Re-add the New Project button in nav bar
merge_request:
author:
---
title: Left align logo
merge_request:
author:
---
title: Improve grammar in GitLab flow documentation
merge_request: 9552
author: infogrind
---
title: Remove help link from right dropdown
merge_request:
author:
---
title: 'API project create: Make name or path required'
merge_request: 9416
author:
---
title: 'API: Return 204 for all delete endpoints'
merge_request: 9397
author: Robert Schilling
---
title: Fix 'New Tag' layout on Tags page
merge_request:
author: Robert Marcano
---
title: Only create unmergeable todos once when MR fails to merge
merge_request:
author:
...@@ -160,6 +160,7 @@ The following table shows the possible return codes for API requests. ...@@ -160,6 +160,7 @@ The following table shows the possible return codes for API requests.
| Return values | Description | | Return values | Description |
| ------------- | ----------- | | ------------- | ----------- |
| `200 OK` | The `GET`, `PUT` or `DELETE` request was successful, the resource(s) itself is returned as JSON. | | `200 OK` | The `GET`, `PUT` or `DELETE` request was successful, the resource(s) itself is returned as JSON. |
| `204 OK` | The server has successfully fulfilled the request and that there is no additional content to send in the response payload body. |
| `201 Created` | The `POST` request was successful and the resource is returned as JSON. | | `201 Created` | The `POST` request was successful and the resource is returned as JSON. |
| `304 Not Modified` | Indicates that the resource has not been modified since the last request. | | `304 Not Modified` | Indicates that the resource has not been modified since the last request. |
| `400 Bad Request` | A required attribute of the API request is missing, e.g., the title of an issue is not given. | | `400 Bad Request` | A required attribute of the API request is missing, e.g., the title of an issue is not given. |
......
...@@ -178,27 +178,6 @@ Parameters: ...@@ -178,27 +178,6 @@ Parameters:
curl --request DELETE --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" https://gitlab.example.com/api/v4/projects/1/issues/80/award_emoji/344 curl --request DELETE --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" https://gitlab.example.com/api/v4/projects/1/issues/80/award_emoji/344
``` ```
Example Response:
```json
{
"id": 344,
"name": "blowfish",
"user": {
"name": "Administrator",
"username": "root",
"id": 1,
"state": "active",
"avatar_url": "http://www.gravatar.com/avatar/e64c7d89f26bd1972efa854d13d7dd61?s=80&d=identicon",
"web_url": "http://gitlab.example.com/root"
},
"created_at": "2016-06-17T17:47:29.266Z",
"updated_at": "2016-06-17T17:47:29.266Z",
"awardable_id": 80,
"awardable_type": "Issue"
}
```
## Award Emoji on Notes ## Award Emoji on Notes
The endpoints documented above are available for Notes as well. Notes The endpoints documented above are available for Notes as well. Notes
...@@ -350,25 +329,4 @@ Parameters: ...@@ -350,25 +329,4 @@ Parameters:
curl --request DELETE --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" https://gitlab.example.com/api/v4/projects/1/issues/80/award_emoji/345 curl --request DELETE --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" https://gitlab.example.com/api/v4/projects/1/issues/80/award_emoji/345
``` ```
Example Response:
```json
{
"id": 345,
"name": "rocket",
"user": {
"name": "Administrator",
"username": "root",
"id": 1,
"state": "active",
"avatar_url": "http://www.gravatar.com/avatar/e64c7d89f26bd1972efa854d13d7dd61?s=80&d=identicon",
"web_url": "http://gitlab.example.com/root"
},
"created_at": "2016-06-17T19:59:55.888Z",
"updated_at": "2016-06-17T19:59:55.888Z",
"awardable_id": 1,
"awardable_type": "Note"
}
```
[ce-4575]: https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/4575 [ce-4575]: https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/4575
...@@ -226,16 +226,3 @@ DELETE /projects/:id/boards/:board_id/lists/:list_id ...@@ -226,16 +226,3 @@ DELETE /projects/:id/boards/:board_id/lists/:list_id
```bash ```bash
curl --request DELETE --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" https://gitlab.example.com/api/v4/projects/5/boards/1/lists/1 curl --request DELETE --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" https://gitlab.example.com/api/v4/projects/5/boards/1/lists/1
``` ```
Example response:
```json
{
"id" : 1,
"label" : {
"name" : "Testing",
"color" : "#F0AD4E",
"description" : null
},
"position" : 1
}
```
...@@ -244,14 +244,6 @@ In case of an error, an explaining message is provided. ...@@ -244,14 +244,6 @@ In case of an error, an explaining message is provided.
curl --request DELETE --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" "https://gitlab.example.com/api/v4/projects/5/repository/branches/newbranch" curl --request DELETE --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" "https://gitlab.example.com/api/v4/projects/5/repository/branches/newbranch"
``` ```
Example response:
```json
{
"branch_name": "newbranch"
}
```
## Delete merged branches ## Delete merged branches
Will delete all branches that are merged into the project's default branch. Will delete all branches that are merged into the project's default branch.
......
...@@ -138,17 +138,3 @@ DELETE /broadcast_messages/:id ...@@ -138,17 +138,3 @@ DELETE /broadcast_messages/:id
```bash ```bash
curl --request DELETE --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" https://gitlab.example.com/api/v4/broadcast_messages/1 curl --request DELETE --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" https://gitlab.example.com/api/v4/broadcast_messages/1
``` ```
Example response:
```json
{
"message":"Update message",
"starts_at":"2016-08-26T00:41:35.060Z",
"ends_at":"2016-08-26T01:41:35.060Z",
"color":"#000",
"font":"#FFFFFF",
"id":1,
"active": true
}
```
...@@ -106,13 +106,3 @@ DELETE /projects/:id/triggers/:token ...@@ -106,13 +106,3 @@ DELETE /projects/:id/triggers/:token
``` ```
curl --request DELETE --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" "https://gitlab.example.com/api/v4/projects/1/triggers/7b9148c158980bbd9bcea92c17522d" curl --request DELETE --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" "https://gitlab.example.com/api/v4/projects/1/triggers/7b9148c158980bbd9bcea92c17522d"
``` ```
```json
{
"created_at": "2015-12-23T16:25:56.760Z",
"deleted_at": "2015-12-24T12:32:20.100Z",
"last_used": null,
"token": "7b9148c158980bbd9bcea92c17522d",
"updated_at": "2015-12-24T12:32:20.100Z"
}
```
...@@ -119,10 +119,3 @@ DELETE /projects/:id/variables/:key ...@@ -119,10 +119,3 @@ DELETE /projects/:id/variables/:key
``` ```
curl --request DELETE --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" "https://gitlab.example.com/api/v4/projects/1/variables/VARIABLE_1" curl --request DELETE --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" "https://gitlab.example.com/api/v4/projects/1/variables/VARIABLE_1"
``` ```
```json
{
"key": "VARIABLE_1",
"value": "VALUE_1"
}
```
...@@ -152,18 +152,6 @@ DELETE /projects/:id/deploy_keys/:key_id ...@@ -152,18 +152,6 @@ DELETE /projects/:id/deploy_keys/:key_id
curl --request DELETE --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" "https://gitlab.example.com/api/v4/projects/5/deploy_keys/13" curl --request DELETE --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" "https://gitlab.example.com/api/v4/projects/5/deploy_keys/13"
``` ```
Example response:
```json
{
"id": 6,
"deploy_key_id": 14,
"project_id": 1,
"created_at" : "2015-08-29T12:50:57.259Z",
"updated_at" : "2015-08-29T12:50:57.259Z"
}
```
## Enable a deploy key ## Enable a deploy key
Enables a deploy key for a project so this can be used. Returns the enabled key, with a status code 201 when successful. Enables a deploy key for a project so this can be used. Returns the enabled key, with a status code 201 when successful.
......
...@@ -108,14 +108,3 @@ DELETE /projects/:id/environments/:environment_id ...@@ -108,14 +108,3 @@ DELETE /projects/:id/environments/:environment_id
```bash ```bash
curl --request DELETE --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" "https://gitlab.example.com/api/v4/projects/1/environments/1" curl --request DELETE --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" "https://gitlab.example.com/api/v4/projects/1/environments/1"
``` ```
Example response:
```json
{
"id": 1,
"name": "deploy",
"slug": "deploy",
"external_url": "https://deploy.example.gitlab.com"
}
```
...@@ -591,44 +591,6 @@ POST /projects/:id/issues/:issue_id/unsubscribe ...@@ -591,44 +591,6 @@ POST /projects/:id/issues/:issue_id/unsubscribe
curl --request POST --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" https://gitlab.example.com/api/v4/projects/5/issues/93/unsubscribe curl --request POST --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" https://gitlab.example.com/api/v4/projects/5/issues/93/unsubscribe
``` ```
Example response:
```json
{
"id": 93,
"iid": 12,
"project_id": 5,
"title": "Incidunt et rerum ea expedita iure quibusdam.",
"description": "Et cumque architecto sed aut ipsam.",
"state": "opened",
"created_at": "2016-04-05T21:41:45.217Z",
"updated_at": "2016-04-07T13:02:37.905Z",
"labels": [],
"milestone": null,
"assignee": {
"name": "Edwardo Grady",
"username": "keyon",
"id": 21,
"state": "active",
"avatar_url": "http://www.gravatar.com/avatar/3e6f06a86cf27fa8b56f3f74f7615987?s=80&d=identicon",
"web_url": "https://gitlab.example.com/keyon"
},
"author": {
"name": "Vivian Hermann",
"username": "orville",
"id": 11,
"state": "active",
"avatar_url": "http://www.gravatar.com/avatar/5224fd70153710e92fb8bcf79ac29d67?s=80&d=identicon",
"web_url": "https://gitlab.example.com/orville"
},
"subscribed": false,
"due_date": null,
"web_url": "http://example.com/example/example/issues/12",
"confidential": false,
"weight": null
}
```
## Create a todo ## Create a todo
Manually creates a todo for the current user on an issue. If Manually creates a todo for the current user on an issue. If
......
...@@ -131,22 +131,6 @@ DELETE /projects/:id/labels ...@@ -131,22 +131,6 @@ DELETE /projects/:id/labels
curl --request DELETE --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" "https://gitlab.example.com/api/v4/projects/1/labels?name=bug" curl --request DELETE --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" "https://gitlab.example.com/api/v4/projects/1/labels?name=bug"
``` ```
Example response:
```json
{
"id" : 1,
"name" : "bug",
"color" : "#d9534f",
"description": "Bug reported by user",
"open_issues_count": 1,
"closed_issues_count": 0,
"open_merge_requests_count": 1,
"subscribed": false,
"priority": null
}
```
## Edit an existing label ## Edit an existing label
Updates an existing label with new name or new color. At least one parameter Updates an existing label with new name or new color. At least one parameter
...@@ -239,19 +223,3 @@ POST /projects/:id/labels/:label_id/unsubscribe ...@@ -239,19 +223,3 @@ POST /projects/:id/labels/:label_id/unsubscribe
```bash ```bash
curl --request POST --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" https://gitlab.example.com/api/v4/projects/5/labels/1/unsubscribe curl --request POST --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" https://gitlab.example.com/api/v4/projects/5/labels/1/unsubscribe
``` ```
Example response:
```json
{
"id" : 1,
"name" : "bug",
"color" : "#d9534f",
"description": "Bug reported by user",
"open_issues_count": 1,
"closed_issues_count": 0,
"open_merge_requests_count": 1,
"subscribed": false,
"priority": null
}
```
...@@ -123,30 +123,6 @@ Parameters: ...@@ -123,30 +123,6 @@ Parameters:
curl --request DELETE --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" https://gitlab.example.com/api/v4/projects/5/issues/11/notes/636 curl --request DELETE --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" https://gitlab.example.com/api/v4/projects/5/issues/11/notes/636
``` ```
Example Response:
```json
{
"id": 636,
"body": "This is a good idea.",
"attachment": null,
"author": {
"id": 1,
"username": "pipin",
"email": "admin@example.com",
"name": "Pip",
"state": "active",
"created_at": "2013-09-30T13:46:01Z",
"avatar_url": "http://www.gravatar.com/avatar/5224fd70153710e92fb8bcf79ac29d67?s=80&d=identicon",
"web_url": "https://gitlab.example.com/pipin"
},
"created_at": "2016-04-05T22:10:44.164Z",
"system": false,
"noteable_id": 11,
"noteable_type": "Issue"
}
```
## Snippets ## Snippets
### List all snippet notes ### List all snippet notes
...@@ -245,30 +221,6 @@ Parameters: ...@@ -245,30 +221,6 @@ Parameters:
curl --request DELETE --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" https://gitlab.example.com/api/v4/projects/5/snippets/52/notes/1659 curl --request DELETE --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" https://gitlab.example.com/api/v4/projects/5/snippets/52/notes/1659
``` ```
Example Response:
```json
{
"id": 1659,
"body": "This is a good idea.",
"attachment": null,
"author": {
"id": 1,
"username": "pipin",
"email": "admin@example.com",
"name": "Pip",
"state": "active",
"created_at": "2013-09-30T13:46:01Z",
"avatar_url": "http://www.gravatar.com/avatar/5224fd70153710e92fb8bcf79ac29d67?s=80&d=identicon",
"web_url": "https://gitlab.example.com/pipin"
},
"created_at": "2016-04-06T16:51:53.239Z",
"system": false,
"noteable_id": 52,
"noteable_type": "Snippet"
}
```
## Merge Requests ## Merge Requests
### List all merge request notes ### List all merge request notes
...@@ -369,27 +321,3 @@ Parameters: ...@@ -369,27 +321,3 @@ Parameters:
```bash ```bash
curl --request DELETE --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" https://gitlab.example.com/api/v4/projects/5/merge_requests/7/notes/1602 curl --request DELETE --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" https://gitlab.example.com/api/v4/projects/5/merge_requests/7/notes/1602
``` ```
Example Response:
```json
{
"id": 1602,
"body": "This is a good idea.",
"attachment": null,
"author": {
"id": 1,
"username": "pipin",
"email": "admin@example.com",
"name": "Pip",
"state": "active",
"created_at": "2013-09-30T13:46:01Z",
"avatar_url": "http://www.gravatar.com/avatar/5224fd70153710e92fb8bcf79ac29d67?s=80&d=identicon",
"web_url": "https://gitlab.example.com/pipin"
},
"created_at": "2016-04-05T22:11:59.923Z",
"system": false,
"noteable_id": 7,
"noteable_type": "MergeRequest"
}
```
...@@ -436,8 +436,8 @@ Parameters: ...@@ -436,8 +436,8 @@ Parameters:
| Attribute | Type | Required | Description | | Attribute | Type | Required | Description |
| --------- | ---- | -------- | ----------- | | --------- | ---- | -------- | ----------- |
| `name` | string | yes | The name of the new project | | `name` | string | yes if path is not provided | The name of the new project. Equals path if not provided. |
| `path` | string | no | Custom repository name for new project. By default generated based on name | | `path` | string | yes if name is not provided | Repository name for new project. Generated based on name if not provided (generated lowercased with dashes). |
| `namespace_id` | integer | no | Namespace for the new project (defaults to the current user's namespace) | | `namespace_id` | integer | no | Namespace for the new project (defaults to the current user's namespace) |
| `default_branch` | string | no | `master` by default | | `default_branch` | string | no | `master` by default |
| `description` | string | no | Short project description | | `description` | string | no | Short project description |
......
...@@ -210,18 +210,6 @@ DELETE /runners/:id ...@@ -210,18 +210,6 @@ DELETE /runners/:id
curl --request DELETE --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" "https://gitlab.example.com/api/v4/runners/6" curl --request DELETE --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" "https://gitlab.example.com/api/v4/runners/6"
``` ```
Example response:
```json
{
"active": true,
"description": "test-1-20150125-test",
"id": 6,
"is_shared": false,
"name": null,
}
```
## List project's runners ## List project's runners
List all runners (specific and shared) available in the project. Shared runners List all runners (specific and shared) available in the project. Shared runners
...@@ -308,15 +296,3 @@ DELETE /projects/:id/runners/:runner_id ...@@ -308,15 +296,3 @@ DELETE /projects/:id/runners/:runner_id
``` ```
curl --request DELETE --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" "https://gitlab.example.com/api/v4/projects/9/runners/9" curl --request DELETE --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" "https://gitlab.example.com/api/v4/projects/9/runners/9"
``` ```
Example response:
```json
{
"active": true,
"description": "test-2016-02-01",
"id": 9,
"is_shared": false,
"name": null
}
```
...@@ -125,22 +125,3 @@ Example request: ...@@ -125,22 +125,3 @@ Example request:
```bash ```bash
curl --request DELETE --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" https://gitlab.example.com/api/v4/hooks/2 curl --request DELETE --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" https://gitlab.example.com/api/v4/hooks/2
``` ```
Example response:
```json
{
"note_events" : false,
"project_id" : null,
"enable_ssl_verification" : true,
"url" : "https://gitlab.example.com/hook",
"updated_at" : "2015-11-04T20:12:15.931Z",
"issues_events" : false,
"merge_requests_events" : false,
"created_at" : "2015-11-04T20:12:15.931Z",
"service_id" : null,
"id" : 2,
"push_events" : true,
"tag_push_events" : false
}
```
...@@ -141,11 +141,6 @@ Parameters: ...@@ -141,11 +141,6 @@ Parameters:
- `id` (required) - The ID of a project - `id` (required) - The ID of a project
- `tag_name` (required) - The name of a tag - `tag_name` (required) - The name of a tag
```json
{
"tag_name": "v4.3.0"
}
```
## Create a new release ## Create a new release
......
...@@ -238,6 +238,9 @@ readability. ...@@ -238,6 +238,9 @@ readability.
See the relevant style guides for our guidelines and for information on linting: See the relevant style guides for our guidelines and for information on linting:
- [SCSS][scss-style-guide] - [SCSS][scss-style-guide]
- JavaScript - We defer to [AirBnb][airbnb-js-style-guide] on most style-related
conventions and enforce them with eslint. See [our current .eslintrc][eslistrc]
for specific rules and patterns.
## Testing ## Testing
...@@ -434,3 +437,5 @@ Scenario: Developer can approve merge request ...@@ -434,3 +437,5 @@ Scenario: Developer can approve merge request
[state-management]: https://vuejs.org/v2/guide/state-management.html#Simple-State-Management-from-Scratch [state-management]: https://vuejs.org/v2/guide/state-management.html#Simple-State-Management-from-Scratch
[vue-resource-repo]: https://github.com/pagekit/vue-resource [vue-resource-repo]: https://github.com/pagekit/vue-resource
[issue-boards-service]: https://gitlab.com/gitlab-org/gitlab-ce/blob/master/app/assets/javascripts/boards/services/board_service.js.es6 [issue-boards-service]: https://gitlab.com/gitlab-org/gitlab-ce/blob/master/app/assets/javascripts/boards/services/board_service.js.es6
[airbnb-js-style-guide]: https://github.com/airbnb/javascript
[eslintrc]: https://gitlab.com/gitlab-org/gitlab-ce/blob/master/.eslintrc
...@@ -50,6 +50,12 @@ Notes: ...@@ -50,6 +50,12 @@ Notes:
asking a GitLab developer to do it once the merge request is merged. asking a GitLab developer to do it once the merge request is merged.
- If you branch is more than 500 commits behind `master`, the job will fail and - If you branch is more than 500 commits behind `master`, the job will fail and
you should rebase your branch upon latest `master`. you should rebase your branch upon latest `master`.
- Code reviews for merge requests often consist of multiple iterations of
feedback and fixes. There is no need to update your EE MR after each
iteration. Instead, create an EE MR as soon as you see the
`rake ee_compat_check` job failing and update it after the CE MR is merged.
This helps to identify significant conflicts sooner, but also reduces the
number of times you have to resolve conflicts.
## Possible type of conflicts ## Possible type of conflicts
......
...@@ -35,5 +35,6 @@ do. ...@@ -35,5 +35,6 @@ do.
| <code>/spend &lt;1h 30m &#124; -1h 5m&gt;</code> | Add or subtract spent time | | <code>/spend &lt;1h 30m &#124; -1h 5m&gt;</code> | Add or subtract spent time |
| `/remove_time_spent` | Remove time spent | | `/remove_time_spent` | Remove time spent |
| `/target_branch <Branch Name>` | Set target branch for current merge request | | `/target_branch <Branch Name>` | Set target branch for current merge request |
| `/award :emoji:` | Toggle award for :emoji: |
| `/weight <1-9>` | Set the weight of the issue | | `/weight <1-9>` | Set the weight of the issue |
| `/clear_weight` | Clears the issue weight | | `/clear_weight` | Clears the issue weight |
...@@ -203,7 +203,7 @@ But the advantages of having stable identifiers outweigh this drawback. ...@@ -203,7 +203,7 @@ But the advantages of having stable identifiers outweigh this drawback.
And to understand a change in context one can always look at the merge commit that groups all the commits together when the code is merged into the master branch. And to understand a change in context one can always look at the merge commit that groups all the commits together when the code is merged into the master branch.
After you merge multiple commits from a feature branch into the master branch this is harder to undo. After you merge multiple commits from a feature branch into the master branch this is harder to undo.
If you would have squashed all the commits into one you could have just reverted this commit but as we indicated you should not rebase commits after they are pushed. If you had squashed all the commits into one you could have just reverted this commit but as we indicated you should not rebase commits after they are pushed.
Fortunately [reverting a merge made some time ago](https://git-scm.com/blog/2010/03/02/undoing-merges.html) can be done with git. Fortunately [reverting a merge made some time ago](https://git-scm.com/blog/2010/03/02/undoing-merges.html) can be done with git.
This however, requires having specific merge commits for the commits your want to revert. This however, requires having specific merge commits for the commits your want to revert.
If you revert a merge and you change your mind, revert the revert instead of merging again since git will not allow you to merge the code again otherwise. If you revert a merge and you change your mind, revert the revert instead of merging again since git will not allow you to merge the code again otherwise.
......
...@@ -42,4 +42,4 @@ Feature: Award Emoji ...@@ -42,4 +42,4 @@ Feature: Award Emoji
@javascript @javascript
Scenario: I add award emoji using regular comment Scenario: I add award emoji using regular comment
Given I leave comment with a single emoji Given I leave comment with a single emoji
Then I have award added Then I have new comment with emoji added
...@@ -44,6 +44,10 @@ class Spinach::Features::AwardEmoji < Spinach::FeatureSteps ...@@ -44,6 +44,10 @@ class Spinach::Features::AwardEmoji < Spinach::FeatureSteps
end end
end end
step 'I have new comment with emoji added' do
expect(page).to have_selector ".emoji[title=':smile:']"
end
step 'I have award added' do step 'I have award added' do
page.within '.awards' do page.within '.awards' do
expect(page).to have_selector '.js-emoji-btn' expect(page).to have_selector '.js-emoji-btn'
......
...@@ -5,10 +5,13 @@ module API ...@@ -5,10 +5,13 @@ module API
version %w(v3 v4), using: :path version %w(v3 v4), using: :path
version 'v3', using: :path do version 'v3', using: :path do
mount ::API::V3::AwardEmoji
mount ::API::V3::Boards mount ::API::V3::Boards
mount ::API::V3::Branches mount ::API::V3::Branches
mount ::API::V3::BroadcastMessages
mount ::API::V3::Commits mount ::API::V3::Commits
mount ::API::V3::DeployKeys mount ::API::V3::DeployKeys
mount ::API::V3::Environments
mount ::API::V3::Files mount ::API::V3::Files
mount ::API::V3::Groups mount ::API::V3::Groups
mount ::API::V3::Issues mount ::API::V3::Issues
...@@ -19,16 +22,21 @@ module API ...@@ -19,16 +22,21 @@ module API
mount ::API::V3::Notes mount ::API::V3::Notes
mount ::API::V3::ProjectGitHook mount ::API::V3::ProjectGitHook
mount ::API::V3::ProjectHooks mount ::API::V3::ProjectHooks
mount ::API::V3::ProjectPushRule
mount ::API::V3::Projects mount ::API::V3::Projects
mount ::API::V3::ProjectSnippets mount ::API::V3::ProjectSnippets
mount ::API::V3::Repositories mount ::API::V3::Repositories
mount ::API::V3::Runners
mount ::API::V3::Services
mount ::API::V3::Settings mount ::API::V3::Settings
mount ::API::V3::Subscriptions mount ::API::V3::Subscriptions
mount ::API::V3::SystemHooks mount ::API::V3::SystemHooks
mount ::API::V3::Tags mount ::API::V3::Tags
mount ::API::V3::Todos
mount ::API::V3::Templates mount ::API::V3::Templates
mount ::API::V3::Todos
mount ::API::V3::Triggers
mount ::API::V3::Users mount ::API::V3::Users
mount ::API::V3::Variables
end end
before { allow_access_with_scope :api } before { allow_access_with_scope :api }
......
...@@ -83,7 +83,6 @@ module API ...@@ -83,7 +83,6 @@ module API
unauthorized! unless award.user == current_user || current_user.admin? unauthorized! unless award.user == current_user || current_user.admin?
award.destroy award.destroy
present award, with: Entities::AwardEmoji
end end
end end
end end
......
...@@ -121,9 +121,7 @@ module API ...@@ -121,9 +121,7 @@ module API
service = ::Boards::Lists::DestroyService.new(user_project, current_user) service = ::Boards::Lists::DestroyService.new(user_project, current_user)
if service.execute(list) unless service.execute(list)
present list, with: Entities::List
else
render_api_error!({ error: 'List could not be deleted!' }, 400) render_api_error!({ error: 'List could not be deleted!' }, 400)
end end
end end
......
...@@ -124,11 +124,7 @@ module API ...@@ -124,11 +124,7 @@ module API
result = DeleteBranchService.new(user_project, current_user). result = DeleteBranchService.new(user_project, current_user).
execute(params[:branch]) execute(params[:branch])
if result[:status] == :success if result[:status] != :success
{
branch: params[:branch]
}
else
render_api_error!(result[:message], result[:return_code]) render_api_error!(result[:message], result[:return_code])
end end
end end
......
...@@ -91,7 +91,7 @@ module API ...@@ -91,7 +91,7 @@ module API
delete ':id' do delete ':id' do
message = find_message message = find_message
present message.destroy, with: Entities::BroadcastMessage message.destroy
end end
end end
end end
......
...@@ -447,7 +447,8 @@ module API ...@@ -447,7 +447,8 @@ module API
expose :target_type expose :target_type
expose :target do |todo, options| expose :target do |todo, options|
Entities.const_get(todo.target_type).represent(todo.target, options) target = todo.target_type == 'Commit' ? 'RepoCommit' : todo.target_type
Entities.const_get(target).represent(todo.target, options)
end end
expose :target_url do |todo, options| expose :target_url do |todo, options|
......
...@@ -79,7 +79,7 @@ module API ...@@ -79,7 +79,7 @@ module API
environment = user_project.environments.find(params[:environment_id]) environment = user_project.environments.find(params[:environment_id])
present environment.destroy, with: Entities::Environment environment.destroy
end end
end end
end end
......
...@@ -118,10 +118,7 @@ module API ...@@ -118,10 +118,7 @@ module API
file_params = declared_params(include_missing: false) file_params = declared_params(include_missing: false)
result = ::Files::DestroyService.new(user_project, current_user, commit_params(file_params)).execute result = ::Files::DestroyService.new(user_project, current_user, commit_params(file_params)).execute
if result[:status] == :success if result[:status] != :success
status(200)
commit_response(file_params)
else
render_api_error!(result[:message], 400) render_api_error!(result[:message], 400)
end end
end end
......
module API module API
class Labels < Grape::API class Labels < Grape::API
include PaginationParams include PaginationParams
before { authenticate! } before { authenticate! }
params do params do
...@@ -56,7 +56,7 @@ module API ...@@ -56,7 +56,7 @@ module API
label = user_project.labels.find_by(title: params[:name]) label = user_project.labels.find_by(title: params[:name])
not_found!('Label') unless label not_found!('Label') unless label
present label.destroy, with: Entities::Label, current_user: current_user, project: user_project label.destroy
end end
desc 'Update an existing label. At least one optional parameter is required.' do desc 'Update an existing label. At least one optional parameter is required.' do
......
...@@ -99,24 +99,10 @@ module API ...@@ -99,24 +99,10 @@ module API
end end
delete ":id/members/:user_id" do delete ":id/members/:user_id" do
source = find_source(source_type, params[:id]) source = find_source(source_type, params[:id])
# Ensure that memeber exists
source.members.find_by!(user_id: params[:user_id])
# This is to ensure back-compatibility but find_by! should be used ::Members::DestroyService.new(source, current_user, declared_params).execute
# in that casse in 9.0!
member = source.members.find_by(user_id: params[:user_id])
# This is to ensure back-compatibility but this should be removed in
# favor of find_by! in 9.0!
not_found!("Member: user_id:#{params[:user_id]}") if source_type == 'group' && member.nil?
# This is to ensure back-compatibility but 204 behavior should be used
# for all DELETE endpoints in 9.0!
if member.nil?
{ message: "Access revoked", id: params[:user_id].to_i }
else
::Members::DestroyService.new(source, current_user, declared_params).execute
present member.user, with: Entities::Member, member: member
end
end end
end end
end end
......
...@@ -132,8 +132,6 @@ module API ...@@ -132,8 +132,6 @@ module API
authorize! :admin_note, note authorize! :admin_note, note
::Notes::DestroyService.new(user_project, current_user).execute(note) ::Notes::DestroyService.new(user_project, current_user).execute(note)
present note, with: Entities::Note
end end
end end
end end
......
...@@ -90,12 +90,9 @@ module API ...@@ -90,12 +90,9 @@ module API
requires :hook_id, type: Integer, desc: 'The ID of the hook to delete' requires :hook_id, type: Integer, desc: 'The ID of the hook to delete'
end end
delete ":id/hooks/:hook_id" do delete ":id/hooks/:hook_id" do
begin hook = user_project.hooks.find(params.delete(:hook_id))
present user_project.hooks.destroy(params[:hook_id]), with: Entities::ProjectHook
rescue hook.destroy
# ProjectHook can raise Error if hook_id not found
not_found!("Error deleting hook #{params[:hook_id]}")
end
end end
end end
end end
......
...@@ -98,8 +98,9 @@ module API ...@@ -98,8 +98,9 @@ module API
success Entities::Project success Entities::Project
end end
params do params do
requires :name, type: String, desc: 'The name of the project' optional :name, type: String, desc: 'The name of the project'
optional :path, type: String, desc: 'The path of the repository' optional :path, type: String, desc: 'The path of the repository'
at_least_one_of :name, :path
use :optional_params use :optional_params
use :create_params use :create_params
end end
...@@ -359,7 +360,6 @@ module API ...@@ -359,7 +360,6 @@ module API
not_found!('Group Link') unless link not_found!('Group Link') unless link
link.destroy link.destroy
no_content!
end end
desc 'Upload a file' desc 'Upload a file'
......
...@@ -38,7 +38,7 @@ module API ...@@ -38,7 +38,7 @@ module API
end end
desc 'Deletes a registered Runner' do desc 'Deletes a registered Runner' do
http_codes [[200, 'Runner was deleted'], [403, 'Forbidden']] http_codes [[204, 'Runner was deleted'], [403, 'Forbidden']]
end end
params do params do
requires :token, type: String, desc: %q(Runner's authentication token) requires :token, type: String, desc: %q(Runner's authentication token)
......
...@@ -78,9 +78,8 @@ module API ...@@ -78,9 +78,8 @@ module API
delete ':id' do delete ':id' do
runner = get_runner(params[:id]) runner = get_runner(params[:id])
authenticate_delete_runner!(runner) authenticate_delete_runner!(runner)
runner.destroy!
present runner, with: Entities::Runner runner.destroy!
end end
end end
...@@ -136,8 +135,6 @@ module API ...@@ -136,8 +135,6 @@ module API
forbidden!("Only one project associated with the runner. Please remove the runner instead") if runner.projects.count == 1 forbidden!("Only one project associated with the runner. Please remove the runner instead") if runner.projects.count == 1
runner_project.destroy runner_project.destroy
present runner, with: Entities::Runner
end end
end end
......
...@@ -702,9 +702,7 @@ module API ...@@ -702,9 +702,7 @@ module API
hash.merge!(key => nil) hash.merge!(key => nil)
end end
if service.update_attributes(attrs.merge(active: false)) unless service.update_attributes(attrs.merge(active: false))
true
else
render_api_error!('400 Bad Request', 400) render_api_error!('400 Bad Request', 400)
end end
end end
......
...@@ -118,9 +118,10 @@ module API ...@@ -118,9 +118,10 @@ module API
delete ':id' do delete ':id' do
snippet = snippets_for_current_user.find_by(id: params.delete(:id)) snippet = snippets_for_current_user.find_by(id: params.delete(:id))
return not_found!('Snippet') unless snippet return not_found!('Snippet') unless snippet
authorize! :destroy_personal_snippet, snippet authorize! :destroy_personal_snippet, snippet
snippet.destroy snippet.destroy
no_content!
end end
desc 'Get a raw snippet' do desc 'Get a raw snippet' do
......
...@@ -66,7 +66,7 @@ module API ...@@ -66,7 +66,7 @@ module API
hook = SystemHook.find_by(id: params[:id]) hook = SystemHook.find_by(id: params[:id])
not_found!('System hook') unless hook not_found!('System hook') unless hook
present hook.destroy, with: Entities::Hook hook.destroy
end end
end end
end end
......
...@@ -66,11 +66,7 @@ module API ...@@ -66,11 +66,7 @@ module API
result = ::Tags::DestroyService.new(user_project, current_user). result = ::Tags::DestroyService.new(user_project, current_user).
execute(params[:tag_name]) execute(params[:tag_name])
if result[:status] == :success if result[:status] != :success
{
tag_name: params[:tag_name]
}
else
render_api_error!(result[:message], result[:return_code]) render_api_error!(result[:message], result[:return_code])
end end
end end
......
...@@ -93,8 +93,6 @@ module API ...@@ -93,8 +93,6 @@ module API
return not_found!('Trigger') unless trigger return not_found!('Trigger') unless trigger
trigger.destroy trigger.destroy
present trigger, with: Entities::Trigger
end end
end end
end end
......
...@@ -238,7 +238,7 @@ module API ...@@ -238,7 +238,7 @@ module API
key = user.keys.find_by(id: params[:key_id]) key = user.keys.find_by(id: params[:key_id])
not_found!('Key') unless key not_found!('Key') unless key
present key.destroy, with: Entities::SSHKey key.destroy
end end
desc 'Add an email address to a specified user. Available only for admins.' do desc 'Add an email address to a specified user. Available only for admins.' do
...@@ -424,7 +424,7 @@ module API ...@@ -424,7 +424,7 @@ module API
key = current_user.keys.find_by(id: params[:key_id]) key = current_user.keys.find_by(id: params[:key_id])
not_found!('Key') unless key not_found!('Key') unless key
present key.destroy, with: Entities::SSHKey key.destroy
end end
desc "Get the currently authenticated user's email addresses" do desc "Get the currently authenticated user's email addresses" do
......
module API
module V3
class AwardEmoji < Grape::API
include PaginationParams
before { authenticate! }
AWARDABLES = %w[issue merge_request snippet].freeze
resource :projects do
AWARDABLES.each do |awardable_type|
awardable_string = awardable_type.pluralize
awardable_id_string = "#{awardable_type}_id"
params do
requires :id, type: String, desc: 'The ID of a project'
requires :"#{awardable_id_string}", type: Integer, desc: "The ID of an Issue, Merge Request or Snippet"
end
[":id/#{awardable_string}/:#{awardable_id_string}/award_emoji",
":id/#{awardable_string}/:#{awardable_id_string}/notes/:note_id/award_emoji"].each do |endpoint|
desc 'Delete a +awardables+ award emoji' do
detail 'This feature was introduced in 8.9'
success ::API::Entities::AwardEmoji
end
params do
requires :award_id, type: Integer, desc: 'The ID of an award emoji'
end
delete "#{endpoint}/:award_id" do
award = awardable.award_emoji.find(params[:award_id])
unauthorized! unless award.user == current_user || current_user.admin?
present award.destroy, with: ::API::Entities::AwardEmoji
end
end
end
end
helpers do
def awardable
@awardable ||=
begin
if params.include?(:note_id)
note_id = params.delete(:note_id)
awardable.notes.find(note_id)
elsif params.include?(:issue_id)
user_project.issues.find(params[:issue_id])
elsif params.include?(:merge_request_id)
user_project.merge_requests.find(params[:merge_request_id])
else
user_project.snippets.find(params[:snippet_id])
end
end
end
end
end
end
end
...@@ -44,6 +44,27 @@ module API ...@@ -44,6 +44,27 @@ module API
authorize!(:read_board, user_project) authorize!(:read_board, user_project)
present board_lists, with: ::API::Entities::List present board_lists, with: ::API::Entities::List
end end
desc 'Delete a board list' do
detail 'This feature was introduced in 8.13'
success ::API::Entities::List
end
params do
requires :list_id, type: Integer, desc: 'The ID of a board list'
end
delete "/lists/:list_id" do
authorize!(:admin_list, user_project)
list = board_lists.find(params[:list_id])
service = ::Boards::Lists::DestroyService.new(user_project, current_user)
if service.execute(list)
present list, with: ::API::Entities::List
else
render_api_error!({ error: 'List could not be deleted!' }, 400)
end
end
end end
end end
end end
......
...@@ -19,6 +19,26 @@ module API ...@@ -19,6 +19,26 @@ module API
present branches, with: ::API::Entities::RepoBranch, project: user_project present branches, with: ::API::Entities::RepoBranch, project: user_project
end end
desc 'Delete a branch'
params do
requires :branch, type: String, desc: 'The name of the branch'
end
delete ":id/repository/branches/:branch", requirements: { branch: /.+/ } do
authorize_push_project
result = DeleteBranchService.new(user_project, current_user).
execute(params[:branch])
if result[:status] == :success
status(200)
{
branch_name: params[:branch]
}
else
render_api_error!(result[:message], result[:return_code])
end
end
desc 'Delete all merged branches' desc 'Delete all merged branches'
delete ":id/repository/merged_branches" do delete ":id/repository/merged_branches" do
DeleteMergedBranchesService.new(user_project, current_user).async_execute DeleteMergedBranchesService.new(user_project, current_user).async_execute
......
module API
module V3
class BroadcastMessages < Grape::API
include PaginationParams
before { authenticate! }
before { authenticated_as_admin! }
resource :broadcast_messages do
helpers do
def find_message
BroadcastMessage.find(params[:id])
end
end
desc 'Delete a broadcast message' do
detail 'This feature was introduced in GitLab 8.12.'
success ::API::Entities::BroadcastMessage
end
params do
requires :id, type: Integer, desc: 'Broadcast message ID'
end
delete ':id' do
message = find_message
present message.destroy, with: ::API::Entities::BroadcastMessage
end
end
end
end
end
module API
module V3
class Environments < Grape::API
include PaginationParams
before { authenticate! }
params do
requires :id, type: String, desc: 'The project ID'
end
resource :projects do
desc 'Deletes an existing environment' do
detail 'This feature was introduced in GitLab 8.11.'
success ::API::Entities::Environment
end
params do
requires :environment_id, type: Integer, desc: 'The environment ID'
end
delete ':id/environments/:environment_id' do
authorize! :update_environment, user_project
environment = user_project.environments.find(params[:environment_id])
present environment.destroy, with: ::API::Entities::Environment
end
end
end
end
end
...@@ -228,6 +228,8 @@ module API ...@@ -228,6 +228,8 @@ module API
not_found!('Issue') unless issue not_found!('Issue') unless issue
authorize!(:destroy_issue, issue) authorize!(:destroy_issue, issue)
status(200)
issue.destroy issue.destroy
end end
end end
......
...@@ -13,6 +13,21 @@ module API ...@@ -13,6 +13,21 @@ module API
get ':id/labels' do get ':id/labels' do
present available_labels, with: ::API::Entities::Label, current_user: current_user, project: user_project present available_labels, with: ::API::Entities::Label, current_user: current_user, project: user_project
end end
desc 'Delete an existing label' do
success ::API::Entities::Label
end
params do
requires :name, type: String, desc: 'The name of the label to be deleted'
end
delete ':id/labels' do
authorize! :admin_label, user_project
label = user_project.labels.find_by(title: params[:name])
not_found!('Label') unless label
present label.destroy, with: ::API::Entities::Label, current_user: current_user, project: user_project
end
end end
end end
end end
......
...@@ -119,6 +119,7 @@ module API ...@@ -119,6 +119,7 @@ module API
# This is to ensure back-compatibility but 204 behavior should be used # This is to ensure back-compatibility but 204 behavior should be used
# for all DELETE endpoints in 9.0! # for all DELETE endpoints in 9.0!
if member.nil? if member.nil?
status(200 )
{ message: "Access revoked", id: params[:user_id].to_i } { message: "Access revoked", id: params[:user_id].to_i }
else else
::Members::DestroyService.new(source, current_user, declared_params).execute ::Members::DestroyService.new(source, current_user, declared_params).execute
......
...@@ -106,6 +106,8 @@ module API ...@@ -106,6 +106,8 @@ module API
merge_request = find_project_merge_request(params[:merge_request_id]) merge_request = find_project_merge_request(params[:merge_request_id])
authorize!(:destroy_merge_request, merge_request) authorize!(:destroy_merge_request, merge_request)
status(200)
merge_request.destroy merge_request.destroy
end end
......
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