Commit 93621543 authored by Filipa Lacerda's avatar Filipa Lacerda

Merge branch 'master' into add-svg-loader

* master: (21 commits)
  Move `Group -> Members` to top-level, fix missing sub-nav for Subgroups
  Left align logo; increase max width of title
  Add newline to end of frontend.md.
  Clone nested objects from default data. Checks if key is present before accessing it
  Update CHANGELOG.md for 8.17.1
  Document use of AirBnb js styleguide and eslint.
  Don't allow a project to be shared with an ancestor of the group it is in
  Fix access to projects shared with a nested group
  Ignore builds dir when run rubocop check
  Remove hidden-xs classes from last columns in environments and pipelines table. Transform pipelines table css to match structure of pipelines table Make environments table overflow
  Use exceptions for MergeService error handling
  Clarify when to create EE compatibility MR in code review process
  New runner API returns 204
  Backport new behavior to CI API
  Backport API to V3
  Update documentation
  Return 204 for delete endpoints
  API project create: Make name or path required
  Only create unmergeable todos once
  Put back the new project button
  ...
parents 6862e788 05c8ec6c
...@@ -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:
......
...@@ -2,6 +2,21 @@ ...@@ -2,6 +2,21 @@
documentation](doc/development/changelog.md) for instructions on adding your own documentation](doc/development/changelog.md) for instructions on adding your own
entry. entry.
## 8.17.1 (2017-02-28)
- Replace setInterval with setTimeout to prevent highly frequent requests. !9271 (Takuya Noguchi)
- Disable unused tags count cache for Projects, Builds and Runners.
- Spam check and reCAPTCHA improvements.
- Allow searching issues for strings containing colons.
- Disabled tooltip on add issues button in usse boards.
- Fixed commit search UI.
- Fix MR changes tab size count when there are over 100 files in the diff.
- Disable invalid service templates.
- Use default branch as target_branch when parameter is missing.
- Upgrade GitLab Pages to v0.3.2.
- Add performance query regression fix for !9088 affecting #27267.
- Chat slash commands show labels correctly.
## 8.17.0 (2017-02-22) ## 8.17.0 (2017-02-22)
- API: Fix file downloading. !0 (8267) - API: Fix file downloading. !0 (8267)
......
...@@ -68,7 +68,7 @@ gem 'gollum-rugged_adapter', '~> 0.4.2', require: false ...@@ -68,7 +68,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'
......
...@@ -304,7 +304,7 @@ GEM ...@@ -304,7 +304,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)
...@@ -353,8 +353,8 @@ GEM ...@@ -353,8 +353,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
...@@ -417,7 +417,7 @@ GEM ...@@ -417,7 +417,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)
...@@ -758,7 +758,7 @@ GEM ...@@ -758,7 +758,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)
...@@ -886,7 +886,7 @@ DEPENDENCIES ...@@ -886,7 +886,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)
haml_lint (~> 0.21.0) haml_lint (~> 0.21.0)
hamlit (~> 2.6.1) hamlit (~> 2.6.1)
...@@ -1011,4 +1011,4 @@ DEPENDENCIES ...@@ -1011,4 +1011,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;
......
...@@ -142,7 +142,7 @@ module.exports = Vue.component('environment-component', { ...@@ -142,7 +142,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>
...@@ -174,12 +174,12 @@ module.exports = Vue.component('environment-component', { ...@@ -174,12 +174,12 @@ module.exports = Vue.component('environment-component', {
:environments="state.environments" :environments="state.environments"
:can-create-deployment="canCreateDeploymentParsed" :can-create-deployment="canCreateDeploymentParsed"
:can-read-environment="canReadEnvironmentParsed"/> :can-read-environment="canReadEnvironmentParsed"/>
<table-pagination v-if="state.paginationInformation && state.paginationInformation.totalPages > 1"
: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>
`, `,
......
...@@ -486,8 +486,8 @@ module.exports = Vue.component('environment-item', { ...@@ -486,8 +486,8 @@ 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" 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"
:actions="manualActions"/> :actions="manualActions"/>
......
...@@ -31,7 +31,7 @@ module.exports = Vue.component('environment-table-component', { ...@@ -31,7 +31,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>
...@@ -39,7 +39,7 @@ module.exports = Vue.component('environment-table-component', { ...@@ -39,7 +39,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>
......
...@@ -38,7 +38,7 @@ const playIconSvg = require('icons/_icon_play.svg'); ...@@ -38,7 +38,7 @@ const playIconSvg = require('icons/_icon_play.svg');
}, },
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">
......
...@@ -36,7 +36,7 @@ require('./pipelines_table_row'); ...@@ -36,7 +36,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>
......
...@@ -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 {
margin-right: 3px;
color: $gl-text-color-secondary;
display: inline-block;
.fa:nth-child(1) { .folder-icon {
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;
......
...@@ -91,10 +91,6 @@ class MergeRequest < ActiveRecord::Base ...@@ -91,10 +91,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?]
......
...@@ -33,8 +33,15 @@ class ProjectGroupLink < ActiveRecord::Base ...@@ -33,8 +33,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
......
...@@ -474,7 +474,7 @@ class User < ActiveRecord::Base ...@@ -474,7 +474,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
......
...@@ -6,6 +6,8 @@ module MergeRequests ...@@ -6,6 +6,8 @@ module MergeRequests
# Executed when you do merge via GitLab UI # Executed when you do merge via GitLab UI
# #
class MergeService < MergeRequests::BaseService class MergeService < MergeRequests::BaseService
MergeError = Class.new(StandardError)
attr_reader :merge_request, :source attr_reader :merge_request, :source
def execute(merge_request) def execute(merge_request)
...@@ -27,6 +29,8 @@ module MergeRequests ...@@ -27,6 +29,8 @@ module MergeRequests
success success
end end
end end
rescue MergeError => e
log_merge_error(e.message, save_message_on_model: true)
end end
private private
...@@ -42,19 +46,13 @@ module MergeRequests ...@@ -42,19 +46,13 @@ module MergeRequests
commit_id = repository.merge(current_user, source, merge_request, options) commit_id = repository.merge(current_user, source, merge_request, options)
if commit_id raise MergeError, 'Conflicts detected during merge' unless commit_id
merge_request.update(merge_commit_sha: commit_id)
else merge_request.update(merge_commit_sha: commit_id)
log_merge_error('Conflicts detected during merge', save_message_on_model: true)
false
end
rescue GitHooksService::PreReceiveError => e rescue GitHooksService::PreReceiveError => e
log_merge_error(e.message, save_message_on_model: true) raise MergeError, e.message
false
rescue StandardError => e rescue StandardError => e
merge_request.update(merge_error: "Something went wrong during merge: #{e.message}") raise MergeError, "Something went wrong during merge: #{e.message}"
log_merge_error(e.message)
false
ensure ensure
merge_request.update(in_progress_merge_commit_sha: nil) merge_request.update(in_progress_merge_commit_sha: nil)
end end
......
...@@ -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_build_succeeds? next unless merge_request.merge_when_build_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
......
...@@ -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 }
......
...@@ -36,6 +36,10 @@ ...@@ -36,6 +36,10 @@
= icon('bell fw') = icon('bell fw')
%span.badge.todos-pending-count{ class: ("hidden" if todos_pending_count == 0) } %span.badge.todos-pending-count{ class: ("hidden" if todos_pending_count == 0) }
= todos_count_format(todos_pending_count) = todos_count_format(todos_pending_count)
- if current_user.can_create_project?
%li
= link_to new_project_path, title: 'New project', aria: { label: "New project" }, data: {toggle: 'tooltip', placement: 'bottom', container: 'body'} do
= icon('plus fw')
- if Gitlab::Sherlock.enabled? - if Gitlab::Sherlock.enabled?
%li %li
= link_to sherlock_transactions_path, title: 'Sherlock Transactions', = link_to sherlock_transactions_path, title: 'Sherlock Transactions',
...@@ -61,12 +65,12 @@ ...@@ -61,12 +65,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'
......
...@@ -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,3 +21,7 @@ ...@@ -21,3 +21,7 @@
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
...@@ -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 performance query regression fix for !9088 affecting #27267'
merge_request:
author:
--- ---
title: Disable invalid service templates title: Re-add the New Project button in nav bar
merge_request: merge_request:
author: author:
--- ---
title: Fixed commit search UI title: Left align logo
merge_request: merge_request:
author: author:
---
title: Disable unused tags count cache for Projects, Builds and Runners
merge_request:
author:
---
title: Spam check and reCAPTCHA improvements
merge_request:
author:
---
title: Replace setInterval with setTimeout to prevent highly frequent requests
merge_request: 9271
author: Takuya Noguchi
---
title: Allow searching issues for strings containing colons
merge_request:
author:
---
title: 'API project create: Make name or path required'
merge_request: 9416
author:
---
title: Disabled tooltip on add issues button in usse boards
merge_request:
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: Use default branch as target_branch when parameter is missing
merge_request:
author:
---
title: Only create unmergeable todos once when MR fails to merge
merge_request:
author:
---
title: Upgrade GitLab Pages to v0.3.2
merge_request:
author:
---
title: Chat slash commands show labels correctly
merge_request:
author:
...@@ -159,6 +159,7 @@ The following table shows the possible return codes for API requests. ...@@ -159,6 +159,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" http://gitlab.example.com/api/v3/projects/1/issues/80/award_emoji/344 curl --request DELETE --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" http://gitlab.example.com/api/v3/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" http://gitlab.example.com/api/v3/projects/1/issues/80/award_emoji/345 curl --request DELETE --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" http://gitlab.example.com/api/v3/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/v3/projects/5/boards/1/lists/1 curl --request DELETE --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" https://gitlab.example.com/api/v3/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/v3/projects/5/repository/branches/newbranch" curl --request DELETE --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" "https://gitlab.example.com/api/v3/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/v3/broadcast_messages/1 curl --request DELETE --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" https://gitlab.example.com/api/v3/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/v3/projects/1/triggers/7b9148c158980bbd9bcea92c17522d" curl --request DELETE --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" "https://gitlab.example.com/api/v3/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/v3/projects/1/variables/VARIABLE_1" curl --request DELETE --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" "https://gitlab.example.com/api/v3/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/v3/projects/5/deploy_keys/13" curl --request DELETE --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" "https://gitlab.example.com/api/v3/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/v3/projects/1/environments/1" curl --request DELETE --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" "https://gitlab.example.com/api/v3/projects/1/environments/1"
``` ```
Example response:
```json
{
"id": 1,
"name": "deploy",
"slug": "deploy",
"external_url": "https://deploy.example.gitlab.com"
}
```
...@@ -581,43 +581,6 @@ POST /projects/:id/issues/:issue_id/unsubscribe ...@@ -581,43 +581,6 @@ POST /projects/:id/issues/:issue_id/unsubscribe
curl --request POST --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" https://gitlab.example.com/api/v3/projects/5/issues/93/unsubscribe curl --request POST --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" https://gitlab.example.com/api/v3/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
}
```
## 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/v3/projects/1/labels?name=bug" curl --request DELETE --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" "https://gitlab.example.com/api/v3/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/v3/projects/5/labels/1/unsubscribe curl --request POST --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" https://gitlab.example.com/api/v3/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/v3/projects/5/issues/11/notes/636 curl --request DELETE --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" https://gitlab.example.com/api/v3/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/v3/projects/5/snippets/52/notes/1659 curl --request DELETE --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" https://gitlab.example.com/api/v3/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/v3/projects/5/merge_requests/7/notes/1602 curl --request DELETE --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" https://gitlab.example.com/api/v3/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"
}
```
...@@ -435,8 +435,8 @@ Parameters: ...@@ -435,8 +435,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) |
| `description` | string | no | Short project description | | `description` | string | no | Short project description |
| `issues_enabled` | boolean | no | Enable issues for this project | | `issues_enabled` | boolean | no | Enable issues for this project |
......
...@@ -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/v3/runners/6" curl --request DELETE --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" "https://gitlab.example.com/api/v3/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/v3/projects/9/runners/9" curl --request DELETE --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" "https://gitlab.example.com/api/v3/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/v3/hooks/2 curl --request DELETE --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" https://gitlab.example.com/api/v3/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
......
...@@ -11,6 +11,7 @@ Feature: Dashboard ...@@ -11,6 +11,7 @@ Feature: Dashboard
And I visit dashboard page And I visit dashboard page
Scenario: I should see projects list Scenario: I should see projects list
Then I should see "New Project" link
Then I should see "Shop" project link Then I should see "Shop" project link
Then I should see "Shop" project CI status Then I should see "Shop" project CI status
......
...@@ -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
...@@ -21,12 +24,16 @@ module API ...@@ -21,12 +24,16 @@ module API
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::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
......
...@@ -127,9 +127,7 @@ module API ...@@ -127,9 +127,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
......
...@@ -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
......
...@@ -93,24 +93,10 @@ module API ...@@ -93,24 +93,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
......
...@@ -94,8 +94,9 @@ module API ...@@ -94,8 +94,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
...@@ -353,7 +354,6 @@ module API ...@@ -353,7 +354,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
......
...@@ -654,9 +654,7 @@ module API ...@@ -654,9 +654,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
......
...@@ -236,7 +236,7 @@ module API ...@@ -236,7 +236,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
...@@ -422,7 +422,7 @@ module API ...@@ -422,7 +422,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
...@@ -226,6 +226,8 @@ module API ...@@ -226,6 +226,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
......
...@@ -103,6 +103,8 @@ module API ...@@ -103,6 +103,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
......
...@@ -121,6 +121,8 @@ module API ...@@ -121,6 +121,8 @@ module API
authorize! :admin_project_snippet, snippet authorize! :admin_project_snippet, snippet
snippet.destroy snippet.destroy
status(200)
end end
desc 'Get a raw project snippet' desc 'Get a raw project snippet'
......
...@@ -172,8 +172,9 @@ module API ...@@ -172,8 +172,9 @@ module API
success ::API::Entities::Project success ::API::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,6 +360,8 @@ module API ...@@ -359,6 +360,8 @@ module API
desc 'Remove a project' desc 'Remove a project'
delete ":id" do delete ":id" do
authorize! :remove_project, user_project authorize! :remove_project, user_project
status(200)
::Projects::DestroyService.new(user_project, current_user, {}).async_execute ::Projects::DestroyService.new(user_project, current_user, {}).async_execute
end end
...@@ -384,6 +387,7 @@ module API ...@@ -384,6 +387,7 @@ module API
authorize! :remove_fork_project, user_project authorize! :remove_fork_project, user_project
if user_project.forked? if user_project.forked?
status(200)
user_project.forked_project_link.destroy user_project.forked_project_link.destroy
else else
not_modified! not_modified!
......
module API
module V3
class Runners < Grape::API
include PaginationParams
before { authenticate! }
resource :runners do
desc 'Remove a runner' do
success ::API::Entities::Runner
end
params do
requires :id, type: Integer, desc: 'The ID of the runner'
end
delete ':id' do
runner = Ci::Runner.find(params[:id])
not_found!('Runner') unless runner
authenticate_delete_runner!(runner)
status(200)
runner.destroy
end
end
params do
requires :id, type: String, desc: 'The ID of a project'
end
resource :projects do
before { authorize_admin_project }
desc "Disable project's runner" do
success ::API::Entities::Runner
end
params do
requires :runner_id, type: Integer, desc: 'The ID of the runner'
end
delete ':id/runners/:runner_id' do
runner_project = user_project.runner_projects.find_by(runner_id: params[:runner_id])
not_found!('Runner') unless runner_project
runner = runner_project.runner
forbidden!("Only one project associated with the runner. Please remove the runner instead") if runner.projects.count == 1
runner_project.destroy
present runner, with: ::API::Entities::Runner
end
end
helpers do
def authenticate_delete_runner!(runner)
return if current_user.is_admin?
forbidden!("Runner is shared") if runner.is_shared?
forbidden!("Runner associated with more than one project") if runner.projects.count > 1
forbidden!("No access granted") unless user_can_access_runner?(runner)
end
def user_can_access_runner?(runner)
current_user.ci_authorized_runners.exists?(runner.id)
end
end
end
end
end
This diff is collapsed.
...@@ -13,6 +13,19 @@ module API ...@@ -13,6 +13,19 @@ module API
get do get do
present SystemHook.all, with: ::API::Entities::Hook present SystemHook.all, with: ::API::Entities::Hook
end end
desc 'Delete a hook' do
success ::API::Entities::Hook
end
params do
requires :id, type: Integer, desc: 'The ID of the system hook'
end
delete ":id" do
hook = SystemHook.find_by(id: params[:id])
not_found!('System hook') unless hook
present hook.destroy, with: ::API::Entities::Hook
end
end end
end end
end end
......
...@@ -14,6 +14,26 @@ module API ...@@ -14,6 +14,26 @@ module API
tags = user_project.repository.tags.sort_by(&:name).reverse tags = user_project.repository.tags.sort_by(&:name).reverse
present tags, with: ::API::Entities::RepoTag, project: user_project present tags, with: ::API::Entities::RepoTag, project: user_project
end end
desc 'Delete a repository tag'
params do
requires :tag_name, type: String, desc: 'The name of the tag'
end
delete ":id/repository/tags/:tag_name", requirements: { tag_name: /.+/ } do
authorize_push_project
result = ::Tags::DestroyService.new(user_project, current_user).
execute(params[:tag_name])
if result[:status] == :success
status(200)
{
tag_name: params[:tag_name]
}
else
render_api_error!(result[:message], result[:return_code])
end
end
end end
end end
end end
......
...@@ -19,6 +19,8 @@ module API ...@@ -19,6 +19,8 @@ module API
desc 'Mark all todos as done' desc 'Mark all todos as done'
delete do delete do
status(200)
todos = TodosFinder.new(current_user, params).execute todos = TodosFinder.new(current_user, params).execute
TodoService.new.mark_todos_as_done(todos, current_user) TodoService.new.mark_todos_as_done(todos, current_user)
end end
......
module API
module V3
class Triggers < Grape::API
include PaginationParams
params do
requires :id, type: String, desc: 'The ID of a project'
end
resource :projects do
desc 'Delete a trigger' do
success ::API::Entities::Trigger
end
params do
requires :token, type: String, desc: 'The unique token of trigger'
end
delete ':id/triggers/:token' do
authenticate!
authorize! :admin_build, user_project
trigger = user_project.triggers.find_by(token: params[:token].to_s)
return not_found!('Trigger') unless trigger
trigger.destroy
present trigger, with: ::API::Entities::Trigger
end
end
end
end
end
...@@ -92,6 +92,25 @@ module API ...@@ -92,6 +92,25 @@ module API
present paginate(events), with: ::API::V3::Entities::Event present paginate(events), with: ::API::V3::Entities::Event
end end
desc 'Delete an existing SSH key from a specified user. Available only for admins.' do
success ::API::Entities::SSHKey
end
params do
requires :id, type: Integer, desc: 'The ID of the user'
requires :key_id, type: Integer, desc: 'The ID of the SSH key'
end
delete ':id/keys/:key_id' do
authenticated_as_admin!
user = User.find_by(id: params[:id])
not_found!('User') unless user
key = user.keys.find_by(id: params[:key_id])
not_found!('Key') unless key
present key.destroy, with: ::API::Entities::SSHKey
end
end end
resource :user do resource :user do
...@@ -111,6 +130,19 @@ module API ...@@ -111,6 +130,19 @@ module API
get "emails" do get "emails" do
present current_user.emails, with: ::API::Entities::Email present current_user.emails, with: ::API::Entities::Email
end end
desc 'Delete an SSH key from the currently authenticated user' do
success ::API::Entities::SSHKey
end
params do
requires :key_id, type: Integer, desc: 'The ID of the SSH key'
end
delete "keys/:key_id" do
key = current_user.keys.find_by(id: params[:key_id])
not_found!('Key') unless key
present key.destroy, with: ::API::Entities::SSHKey
end
end end
end end
end end
......
module API
module V3
class Variables < Grape::API
include PaginationParams
before { authenticate! }
before { authorize! :admin_build, user_project }
params do
requires :id, type: String, desc: 'The ID of a project'
end
resource :projects do
desc 'Delete an existing variable from a project' do
success ::API::Entities::Variable
end
params do
requires :key, type: String, desc: 'The key of the variable'
end
delete ':id/variables/:key' do
variable = user_project.variables.find_by(key: params[:key])
not_found!('Variable') unless variable
present variable.destroy, with: ::API::Entities::Variable
end
end
end
end
end
module API module API
# Projects variables API
class Variables < Grape::API class Variables < Grape::API
include PaginationParams include PaginationParams
...@@ -81,10 +80,9 @@ module API ...@@ -81,10 +80,9 @@ module API
end end
delete ':id/variables/:key' do delete ':id/variables/:key' do
variable = user_project.variables.find_by(key: params[:key]) variable = user_project.variables.find_by(key: params[:key])
not_found!('Variable') unless variable
return not_found!('Variable') unless variable variable.destroy
present variable.destroy, with: Entities::Variable
end end
end end
end end
......
...@@ -217,6 +217,7 @@ module Ci ...@@ -217,6 +217,7 @@ module Ci
build = Ci::Build.find_by_id(params[:id]) build = Ci::Build.find_by_id(params[:id])
authenticate_build!(build) authenticate_build!(build)
status(200)
build.erase_artifacts! build.erase_artifacts!
end end
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.
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