Commit 0eee2195 authored by Filipa Lacerda's avatar Filipa Lacerda

Merge branch 'ce-to-ee-2018-05-31' into 'master'

CE upstream - 2018-05-31 21:32 UTC

See merge request gitlab-org/gitlab-ee!5925
parents 239dbdf5 fe55ece9
......@@ -126,7 +126,6 @@ export default {
</div>
<form
v-if="!isCompact"
class="form-horizontal"
@submit.prevent.stop="commitChanges"
ref="formEl"
>
......
......@@ -59,7 +59,7 @@ export default {
ref="form"
:action="deleteWikiUrl"
method="post"
class="form-horizontal js-requires-input"
class="js-requires-input"
>
<input
ref="method"
......
......@@ -79,12 +79,13 @@ export default {
};
</script>
<template>
<div class="ci-job-dropdown-container dropdown">
<div class="ci-job-dropdown-container dropdown dropright">
<button
v-tooltip
type="button"
data-toggle="dropdown"
data-container="body"
data-boundary="viewport"
class="dropdown-menu-toggle build-content"
:title="tooltipText"
>
......
......@@ -87,7 +87,8 @@ table {
display: none;
}
.dropdown-toggle::after {
.dropdown-toggle::after,
.dropright .dropdown-menu-toggle::after {
// Remove bootstrap's dropdown caret
display: none;
}
......@@ -148,8 +149,14 @@ table {
}
}
.nav-tabs .nav-link {
border: 0;
.nav-tabs {
.nav-link {
border: 0;
}
.nav-item {
margin-bottom: 0;
}
}
pre code {
......
/*
* This is a minimal stylesheet, meant to be used for error pages.
*/
@import 'framework/variables';
@import '../../../node_modules/bootstrap/scss/functions';
@import '../../../node_modules/bootstrap/scss/variables';
@import '../../../node_modules/bootstrap/scss/mixins';
@import '../../../node_modules/bootstrap/scss/reboot';
@import '../../../node_modules/bootstrap/scss/buttons';
@import '../../../node_modules/bootstrap/scss/forms';
$body-color: #666;
$header-color: #456;
body {
color: $body-color;
text-align: center;
font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
margin: auto;
font-size: 14px;
}
h1 {
font-size: 56px;
line-height: 100px;
font-weight: 400;
color: $header-color;
}
h2 {
font-size: 24px;
color: $body-color;
line-height: 1.5em;
}
h3 {
color: $header-color;
font-size: 20px;
font-weight: 400;
line-height: 28px;
}
img {
max-width: 80vw;
display: block;
margin: 40px auto;
}
a {
text-decoration: none;
color: $blue-600;
}
.page-container {
margin: auto 20px;
}
.container {
margin: auto;
max-width: 600px;
border-bottom: 1px solid $border-color;
padding-bottom: 1em;
}
.action-container {
padding: 0.5em 0;
}
.form-inline-flex {
display: flex;
flex-wrap: wrap;
button {
display: block;
width: 100%;
}
.field {
display: block;
width: 100%;
margin-bottom: 1em;
}
@include media-breakpoint-up(sm) {
flex-wrap: nowrap;
button {
width: auto;
}
.field {
margin-bottom: 0;
margin-right: 0.5em;
}
}
}
.error-nav {
padding: 0;
text-align: center;
li {
display: block;
padding-bottom: 1em;
}
@include media-breakpoint-up(sm) {
li {
display: inline-block;
padding-bottom: 0;
&:not(:first-child)::before {
content: '\00B7';
display: inline-block;
padding: 0 1em;
}
}
}
}
......@@ -169,11 +169,14 @@
color: $color-800;
}
.nav-links li a.active {
border-bottom: 2px solid $color-500;
.nav-links li {
&.active a,
a.active {
border-bottom: 2px solid $color-500;
.badge.badge-pill {
font-weight: $gl-font-weight-bold;
.badge.badge-pill {
font-weight: $gl-font-weight-bold;
}
}
}
......
......@@ -31,14 +31,15 @@
color: $black;
}
}
}
&.active {
color: $black;
font-weight: $gl-font-weight-bold;
&.active a,
a.active {
color: $black;
font-weight: $gl-font-weight-bold;
.badge.badge-pill {
color: $black;
}
.badge.badge-pill {
color: $black;
}
}
}
......
......@@ -382,6 +382,7 @@ $dropdown-chevron-size: 10px;
$dropdown-toggle-active-border-color: darken($border-color, 14%);
$dropdown-item-hover-bg: $gray-darker;
$dropdown-fade-mask-height: 32px;
$dropdown-member-form-control-width: 163px;
/*
* Filtered Search
......
......@@ -42,13 +42,12 @@
}
}
.form-horizontal {
margin-top: 20px;
.form-group {
margin-bottom: 0;
@include media-breakpoint-up(sm) {
display: -webkit-flex;
display: flex;
margin-top: 3px;
@include media-breakpoint-down(sm) {
display: block;
margin-left: 5px;
}
}
......@@ -68,10 +67,15 @@
}
.member-form-control {
@include media-breakpoint-down(xs) {
padding-bottom: 5px;
@include media-breakpoint-down(sm) {
width: $dropdown-member-form-control-width;
margin-left: 0;
padding-bottom: 5px;
}
@include media-breakpoint-down(xs) {
margin-right: 0;
width: auto;
}
}
......@@ -257,10 +261,6 @@
align-self: flex-start;
}
.form-horizontal ~ .btn {
margin-right: 0;
}
@include media-breakpoint-down(xs) {
display: block;
......@@ -270,6 +270,12 @@
display: block;
}
.controls > .btn:last-child {
margin-left: 5px;
margin-right: 5px;
width: auto;
}
.form-control {
width: 100%;
}
......@@ -282,10 +288,6 @@
.member-controls {
margin-top: 5px;
}
.form-horizontal {
margin-top: 10px;
}
}
}
......@@ -309,10 +311,6 @@
margin-top: 0;
}
.form-horizontal {
display: block;
}
.member-form-control {
margin: 5px 0;
}
......
......@@ -154,14 +154,15 @@ class ApplicationController < ActionController::Base
end
def render_403
head :forbidden
respond_to do |format|
format.any { head :forbidden }
format.html { render "errors/access_denied", layout: "errors", status: 403 }
end
end
def render_404
respond_to do |format|
format.html do
render file: Rails.root.join("public", "404"), layout: false, status: "404"
end
format.html { render "errors/not_found", layout: "errors", status: 404 }
# Prevent the Rails CSRF protector from thinking a missing .js file is a JavaScript file
format.js { render json: '', status: :not_found, content_type: 'application/json' }
format.any { head :not_found }
......
......@@ -39,7 +39,7 @@ class ProfilesController < Profiles::ApplicationController
user.reset_feed_token!
end
flash[:notice] = "Feed token was successfully reset"
flash[:notice] = 'Feed token was successfully reset'
redirect_to profile_personal_access_tokens_path
end
......
......@@ -100,8 +100,6 @@ module Issuable
strip_attributes :title
after_save :ensure_metrics, unless: :imported?
# We want to use optimistic lock for cases when only title or description are involved
# http://api.rubyonrails.org/classes/ActiveRecord/Locking/Optimistic.html
def locking_enabled?
......
......@@ -69,6 +69,7 @@ class Issue < ActiveRecord::Base
scope :public_only, -> { where(confidential: false) }
after_save :expire_etag_cache
after_save :ensure_metrics, unless: :imported?
attr_spammable :title, spam_title: true
attr_spammable :description, spam_description: true
......
......@@ -62,6 +62,7 @@ class MergeRequest < ActiveRecord::Base
after_create :ensure_merge_request_diff, unless: :importing?
after_update :clear_memoized_shas
after_update :reload_diff_if_branch_changed
after_save :ensure_metrics
# When this attribute is true some MR validation is ignored
# It allows us to close or modify broken merge requests
......
class CommitStatusPresenter < Gitlab::View::Presenter::Delegated
CALLOUT_FAILURE_MESSAGES = {
unknown_failure: 'There is an unknown failure, please try again',
script_failure: 'There has been a script failure. Check the job log for more information',
api_failure: 'There has been an API failure, please try again',
stuck_or_timeout_failure: 'There has been a timeout failure or the job got stuck. Check your timeout limits or try again',
runner_system_failure: 'There has been a runner system failure, please try again',
missing_dependency_failure: 'There has been a missing dependency failure, check the job log for more information'
missing_dependency_failure: 'There has been a missing dependency failure'
}.freeze
presents :build
......
......@@ -26,7 +26,7 @@ class JobEntity < Grape::Entity
expose :created_at
expose :updated_at
expose :detailed_status, as: :status, with: StatusEntity
expose :callout_message, if: -> (*) { failed? }
expose :callout_message, if: -> (*) { failed? && !build.script_failure? }
expose :recoverable, if: -> (*) { failed? }
private
......
= form_for @application_setting, url: admin_application_settings_path, html: { class: 'form-horizontal fieldset-form' } do |f|
= form_for @application_setting, url: admin_application_settings_path do |f|
= form_errors(@application_setting)
%fieldset
.form-group
= f.label :mirror_available, 'Enable mirror configuration', class: 'control-label col-sm-2'
.col-sm-10
.form-group.row
= f.label :mirror_available, 'Enable mirror configuration', class: 'control-label col-sm-4'
.col-sm-8
.form-check
= f.check_box :mirror_available, class: 'form-check-input'
= f.label :mirror_available, class: 'form-check-label' do
......
= form_for @application_setting, url: admin_application_settings_path, html: { class: 'form-horizontal fieldset-form' } do |f|
= form_for @application_setting, url: admin_application_settings_path do |f|
= form_errors(@application_setting)
%fieldset
.form-group
.form-group.row
.col-sm-12
.form-check
= f.check_box :enforce_terms, class: 'form-check-input'
......@@ -10,7 +10,7 @@
= _("Require all users to accept Terms of Service when they access GitLab.")
.form-text.text-muted
= _("When enabled, users cannot use GitLab until the terms have been accepted.")
.form-group
.form-group.row
.col-sm-12
= f.label :terms do
= _("Terms of Service Agreement")
......
= form_for [:admin, @application], url: @url, html: {role: 'form'} do |f|
= form_errors(application)
= content_tag :div, class: 'form-group' do
= content_tag :div, class: 'form-group row' do
= f.label :name, class: 'col-sm-2 col-form-label'
.col-sm-10
= f.text_field :name, class: 'form-control'
= doorkeeper_errors_for application, :name
= content_tag :div, class: 'form-group' do
= content_tag :div, class: 'form-group row' do
= f.label :redirect_uri, class: 'col-sm-2 col-form-label'
.col-sm-10
= f.text_area :redirect_uri, class: 'form-control'
......@@ -20,7 +20,7 @@
%code= Doorkeeper.configuration.native_redirect_uri
for local tests
= content_tag :div, class: 'form-group' do
= content_tag :div, class: 'form-group row' do
= f.label :trusted, class: 'col-sm-2 col-form-label'
.col-sm-10
= f.check_box :trusted
......
%nav
%ul.error-nav
%li
= link_to s_('Nav|Home'), root_path
%li
- if current_user
= link_to s_('Nav|Sign out and sign in with a different account'), destroy_user_session_path
- else
= link_to s_('Nav|Sign In / Register'), new_session_path(:user, redirect_to_referer: 'yes')
%li
= link_to s_('Nav|Help'), help_path
- message = local_assigns.fetch(:message)
- content_for(:title, 'Access Denied')
%img{ :alt => "GitLab Logo", :src => image_path('logo.svg') }
%h1
403
= image_tag('illustrations/error-403.svg', alt: '403', lazy: false)
.container
%h3 Access Denied
%hr
%h3
= s_("403|You don't have the permission to access this page.")
- if message
%p
= message
- else
%p You are not allowed to access this page.
%p Read more about project permissions #{link_to "here", help_page_path("user/permissions"), class: "vlink"}
%p
= s_('403|Please contact your GitLab administrator to get the permission.')
.action-container.js-go-back{ style: 'display: none' }
%a{ href: 'javascript:history.back()', class: 'btn btn-success' }
= s_('Go Back')
= render "errors/footer"
- content_for(:title, 'Not Found')
%img{ :alt => "GitLab Logo", :src => image_path('logo.svg') }
%h1
404
= image_tag('illustrations/error-404.svg', alt: '404', lazy: false)
.container
%h3 The resource you were looking for doesn't exist.
%hr
%p You may have mistyped the address or the page may have moved.
%h3
= s_('404|Page Not Found')
%p
= s_("404|Make sure the address is correct and the page hasn't moved.")
%p
= s_('404|Please contact your GitLab administrator if you think this is a mistake.')
.action-container
= form_tag search_path, method: :get, class: 'form-inline-flex' do |f|
.field
= search_field_tag :search, '', placeholder: _('Search for projects, issues, etc.'), class: 'form-control'
= button_tag 'Search', class: 'btn btn-success', name: nil, type: 'submit'
= render 'errors/footer'
......@@ -3,57 +3,17 @@
%head
%meta{ :content => "width=device-width, initial-scale=1, maximum-scale=1", :name => "viewport" }
%title= yield(:title)
:css
body {
color: #666;
text-align: center;
font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
margin: auto;
font-size: 14px;
}
%style
= Rails.application.assets_manifest.find_sources('errors.css').first.to_s.html_safe
%body
.page-container
= yield
-# haml-lint:disable InlineJavaScript
:javascript
(function(){
var goBackElement = document.querySelector('.js-go-back');
h1 {
font-size: 56px;
line-height: 100px;
font-weight: 400;
color: #456;
}
h2 {
font-size: 24px;
color: #666;
line-height: 1.5em;
}
h3 {
color: #456;
font-size: 20px;
font-weight: 400;
line-height: 28px;
}
hr {
max-width: 800px;
margin: 18px auto;
border: 0;
border-top: 1px solid #EEE;
border-bottom: 1px solid white;
}
img {
max-width: 40vw;
display: block;
margin: 40px auto;
}
.container {
margin: auto 20px;
}
ul {
margin: auto;
text-align: left;
display:inline-block;
}
%body
= yield
if (goBackElement && history.length > 1) {
goBackElement.style.display = 'block';
}
}());
......@@ -12,8 +12,8 @@
= label_tag 'merge_request[force_remove_source_branch]', class: 'form-check-label' do
Remove source branch when merge request is accepted.
.form-group
.col-sm-10.col-sm-offset-2
.form-group.row
.col-sm-10.offset-sm-2
.form-check
= hidden_field_tag 'merge_request[squash]', '0', id: nil
= check_box_tag 'merge_request[squash]', '1', issuable.squash, class: 'form-check-input'
......
......@@ -62,7 +62,7 @@
title: 'Resend invite'
- if user != current_user && member.can_update?
= form_for member, remote: true, html: { class: 'js-edit-member-form form-horizontal' } do |f|
= form_for member, remote: true, html: { class: 'js-edit-member-form form-group row append-right-5' } do |f|
= f.hidden_field :access_level
.member-form-control.dropdown.append-right-5
%button.dropdown-menu-toggle.js-member-permissions-dropdown{ type: "button",
......
......@@ -5,25 +5,25 @@
.fade-right= icon('angle-right')
%ul.nav-links.scrolling-tabs.js-milestone-tabs.nav.nav-tabs
- if issues_accessible
%li.active
= link_to '#tab-issues', 'data-toggle' => 'tab', 'data-show' => '.tab-issues-buttons' do
%li.nav-item
= link_to '#tab-issues', class: 'nav-link active', 'data-toggle' => 'tab', 'data-show' => '.tab-issues-buttons' do
Issues
%span.badge.badge-pill= milestone.issues_visible_to_user(current_user).size
%li
= link_to '#tab-merge-requests', 'data-toggle' => 'tab', 'data-endpoint': milestone_merge_request_tab_path(milestone) do
%li.nav-item
= link_to '#tab-merge-requests', class: 'nav-link', 'data-toggle' => 'tab', 'data-endpoint': milestone_merge_request_tab_path(milestone) do
Merge Requests
%span.badge.badge-pill= milestone.merge_requests.size
- else
%li.active
= link_to '#tab-merge-requests', 'data-toggle' => 'tab', 'data-endpoint': milestone_merge_request_tab_path(milestone) do
%li.nav-item
= link_to '#tab-merge-requests', class: 'nav-link active', 'data-toggle' => 'tab', 'data-endpoint': milestone_merge_request_tab_path(milestone) do
Merge Requests
%span.badge.badge-pill= milestone.merge_requests.size
%li
= link_to '#tab-participants', 'data-toggle' => 'tab', 'data-endpoint': milestone_participants_tab_path(milestone) do
%li.nav-item
= link_to '#tab-participants', class: 'nav-link', 'data-toggle' => 'tab', 'data-endpoint': milestone_participants_tab_path(milestone) do
Participants
%span.badge.badge-pill= milestone.participants.count
%li
= link_to '#tab-labels', 'data-toggle' => 'tab', 'data-endpoint': milestone_labels_tab_path(milestone) do
%li.nav-item
= link_to '#tab-labels', class: 'nav-link', 'data-toggle' => 'tab', 'data-endpoint': milestone_labels_tab_path(milestone) do
Labels
%span.badge.badge-pill= milestone.labels.count
......
---
title: Update 404 and 403 pages with helpful actions.
merge_request: 19096
author:
type: changed
---
title: Take two for MR metrics population background migration
merge_request: 19097
author:
type: other
---
title: Removes redundant script failure message from Job page
merge_request: 19138
author:
type: changed
---
title: Add merge requests list endpoint for groups
merge_request:
author:
type: other
---
title: Make ActiveRecordSubscriber rails 5 compatible
merge_request:
author:
type: other
---
title: Eliminate cached N+1 queries for projects in Issue API
merge_request:
author:
type: performance
......@@ -130,6 +130,7 @@ module Gitlab
config.assets.precompile << "snippets.css"
config.assets.precompile << "locale/**/app.js"
config.assets.precompile << "emoji_sprites.css"
config.assets.precompile << "errors.css"
# Import gitlab-svgs directly from vendored directory
config.assets.paths << "#{config.root}/node_modules/@gitlab-org/gitlab-svgs/dist"
......
class MigrateRemainingMrMetricsPopulatingBackgroundMigration < ActiveRecord::Migration
include Gitlab::Database::MigrationHelpers
DOWNTIME = false
BATCH_SIZE = 5_000
MIGRATION = 'PopulateMergeRequestMetricsWithEventsData'
DELAY_INTERVAL = 10.minutes
disable_ddl_transaction!
class MergeRequest < ActiveRecord::Base
self.table_name = 'merge_requests'
include ::EachBatch
end
def up
# Perform any ongoing background migration that might still be running. This
# avoids scheduling way too many of the same jobs on self-hosted instances
# if they're updating GitLab across multiple versions. The "Take one"
# migration was executed on 10.4 on
# SchedulePopulateMergeRequestMetricsWithEventsData.
Gitlab::BackgroundMigration.steal(MIGRATION)
metrics_not_exists_clause = <<~SQL
NOT EXISTS (SELECT 1 FROM merge_request_metrics
WHERE merge_request_metrics.merge_request_id = merge_requests.id)
SQL
relation = MergeRequest.where(metrics_not_exists_clause)
# We currently have ~400_000 MR records without metrics on GitLab.com.
# This means it'll schedule ~80 jobs (5000 MRs each) with a 10 minutes gap,
# so this should take ~14 hours for all background migrations to complete.
#
queue_background_migration_jobs_by_range_at_intervals(relation,
MIGRATION,
DELAY_INTERVAL,
batch_size: BATCH_SIZE)
end
def down
end
end
......@@ -241,6 +241,112 @@ Parameters:
]
```
## List group merge requests
Get all merge requests for this group and its subgroups.
The `state` parameter can be used to get only merge requests with a given state (`opened`, `closed`, or `merged`) or all of them (`all`).
The pagination parameters `page` and `per_page` can be used to restrict the list of merge requests.
```
GET /groups/:id/merge_requests
GET /groups/:id/merge_requests?state=opened
GET /groups/:id/merge_requests?state=all
GET /groups/:id/merge_requests?milestone=release
GET /groups/:id/merge_requests?labels=bug,reproduced
GET /groups/:id/merge_requests?my_reaction_emoji=star
```
`group_id` represents the ID of the group which contains the project where the MR resides.
Parameters:
| Attribute | Type | Required | Description |
| ------------------- | -------------- | -------- | ------------------------------------------------------------------------------------------------------------------------------ |
| `id` | integer | yes | The ID of a group |
| `state` | string | no | Return all merge requests or just those that are `opened`, `closed`, or `merged` |
| `order_by` | string | no | Return merge requests ordered by `created_at` or `updated_at` fields. Default is `created_at` |
| `sort` | string | no | Return merge requests sorted in `asc` or `desc` order. Default is `desc` |
| `milestone` | string | no | Return merge requests for a specific milestone |
| `view` | string | no | If `simple`, returns the `iid`, URL, title, description, and basic state of merge request |
| `labels` | string | no | Return merge requests matching a comma separated list of labels |
| `created_after` | datetime | no | Return merge requests created on or after the given time |
| `created_before` | datetime | no | Return merge requests created on or before the given time |
| `updated_after` | datetime | no | Return merge requests updated on or after the given time |
| `updated_before` | datetime | no | Return merge requests updated on or before the given time |
| `scope` | string | no | Return merge requests for the given scope: `created_by_me`, `assigned_to_me` or `all`.<br> |
| `author_id` | integer | no | Returns merge requests created by the given user `id` _([Introduced][ce-13060] in GitLab 9.5)_ |
| `assignee_id` | integer | no | Returns merge requests assigned to the given user `id` _([Introduced][ce-13060] in GitLab 9.5)_ |
| `my_reaction_emoji` | string | no | Return merge requests reacted by the authenticated user by the given `emoji` _([Introduced][ce-14016] in GitLab 10.0)_ |
| `source_branch` | string | no | Return merge requests with the given source branch |
| `target_branch` | string | no | Return merge requests with the given target branch |
| `search` | string | no | Search merge requests against their `title` and `description` |
```json
[
{
"id": 1,
"iid": 1,
"target_branch": "master",
"source_branch": "test1",
"project_id": 3,
"title": "test1",
"state": "opened",
"created_at": "2017-04-29T08:46:00Z",
"updated_at": "2017-04-29T08:46:00Z",
"upvotes": 0,
"downvotes": 0,
"author": {
"id": 1,
"username": "admin",
"email": "admin@example.com",
"name": "Administrator",
"state": "active",
"created_at": "2012-04-29T08:46:00Z"
},
"assignee": {
"id": 1,
"username": "admin",
"email": "admin@example.com",
"name": "Administrator",
"state": "active",
"created_at": "2012-04-29T08:46:00Z"
},
"source_project_id": 2,
"target_project_id": 3,
"labels": [ ],
"description": "fixed login page css paddings",
"work_in_progress": false,
"milestone": {
"id": 5,
"iid": 1,
"project_id": 3,
"title": "v2.0",
"description": "Assumenda aut placeat expedita exercitationem labore sunt enim earum.",
"state": "closed",
"created_at": "2015-02-02T19:49:26.013Z",
"updated_at": "2015-02-02T19:49:26.013Z",
"due_date": null
},
"merge_when_pipeline_succeeds": true,
"merge_status": "can_be_merged",
"sha": "8888888888888888888888888888888888888888",
"merge_commit_sha": null,
"user_notes_count": 1,
"changes_count": "1",
"should_remove_source_branch": true,
"force_remove_source_branch": false,
"web_url": "http://example.com/example/example/merge_requests/1",
"discussion_locked": false,
"time_stats": {
"time_estimate": 0,
"total_time_spent": 0,
"human_time_estimate": null,
"human_total_time_spent": null
}
}
]
```
## Get single MR
Shows information about a single merge request.
......
# Tips
> TODO: Add tips
## Clearing production compiled assets
To clear production compiled assets created with `yarn webpack-prod` you can run:
```
yarn clean
```
......@@ -120,6 +120,10 @@ Add `screenshot_and_save_page` in a `:js` spec to screenshot what Capybara
Add `screenshot_and_open_image` in a `:js` spec to screenshot what Capybara
"sees", and automatically open the image.
The HTML dumps created by this are missing CSS.
This results in them looking very different from the actual application.
There is a [small hack](https://gitlab.com/gitlab-org/gitlab-ce/snippets/1718469) to add CSS which makes debugging easier.
### Fast unit tests
Some classes are well-isolated from Rails and you should be able to test them
......
......@@ -16,7 +16,7 @@ module API
args[:scope] = args[:scope].underscore if args[:scope]
issues = IssuesFinder.new(current_user, args).execute
.preload(:assignees, :labels, :notes, :timelogs)
.preload(:assignees, :labels, :notes, :timelogs, :project)
issues.reorder(args[:order_by] => args[:sort])
end
......
......@@ -61,6 +61,18 @@ module API
end
end
def serializer_options_for(merge_requests)
options = { with: Entities::MergeRequestBasic, current_user: current_user }
if params[:view] == 'simple'
options[:with] = Entities::MergeRequestSimple
else
options[:issuable_metadata] = issuable_meta_data(merge_requests, 'MergeRequest')
end
options
end
params :merge_requests_params do
optional :state, type: String, values: %w[opened closed merged all], default: 'all',
desc: 'Return opened, closed, merged, or all merge requests'
......@@ -100,16 +112,26 @@ module API
authenticate! unless params[:scope] == 'all'
merge_requests = find_merge_requests
options = { with: Entities::MergeRequestBasic,
current_user: current_user }
present merge_requests, serializer_options_for(merge_requests)
end
end
if params[:view] == 'simple'
options[:with] = Entities::MergeRequestSimple
else
options[:issuable_metadata] = issuable_meta_data(merge_requests, 'MergeRequest')
end
params do
requires :id, type: String, desc: 'The ID of a group'
end
resource :groups, requirements: API::PROJECT_ENDPOINT_REQUIREMENTS do
desc 'Get a list of group merge requests' do
success Entities::MergeRequestBasic
end
params do
use :merge_requests_params
end
get ":id/merge_requests" do
group = find_group!(params[:id])
present merge_requests, options
merge_requests = find_merge_requests(group_id: group.id, include_subgroups: true)
present merge_requests, serializer_options_for(merge_requests)
end
end
......@@ -161,15 +183,8 @@ module API
merge_requests = find_merge_requests(project_id: user_project.id)
options = { with: Entities::MergeRequestBasic,
current_user: current_user,
project: user_project }
if params[:view] == 'simple'
options[:with] = Entities::MergeRequestSimple
else
options[:issuable_metadata] = issuable_meta_data(merge_requests, 'MergeRequest')
end
options = serializer_options_for(merge_requests)
options[:project] = user_project
present merge_requests, options
end
......
......@@ -28,6 +28,7 @@ project_tree:
- project_members:
- :user
- merge_requests:
- :metrics
- notes:
- :author
- events:
......
......@@ -19,9 +19,10 @@ module Gitlab
label: :project_label,
custom_attributes: 'ProjectCustomAttribute',
project_badges: 'Badge',
metrics: 'MergeRequest::Metrics',
ci_cd_settings: 'ProjectCiCdSetting' }.freeze
USER_REFERENCES = %w[author_id assignee_id updated_by_id user_id created_by_id last_edited_by_id merge_user_id resolved_by_id closed_by_id].freeze
USER_REFERENCES = %w[author_id assignee_id updated_by_id merged_by_id latest_closed_by_id user_id created_by_id last_edited_by_id merge_user_id resolved_by_id closed_by_id].freeze
PROJECT_REFERENCES = %w[project_id source_project_id target_project_id].freeze
......
......@@ -4,7 +4,7 @@ module Gitlab
attach_to :active_record
def sql(event)
unless event.payload[:name] == 'CACHE'
unless event.payload.fetch(:cached, event.payload[:name] == 'CACHE')
Transaction.current&.increment
end
end
......
......@@ -8,8 +8,8 @@ msgid ""
msgstr ""
"Project-Id-Version: gitlab 1.0.0\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2018-05-30 10:16-0400\n"
"PO-Revision-Date: 2018-05-30 10:16-0400\n"
"POT-Creation-Date: 2018-06-01 01:47-0500\n"
"PO-Revision-Date: 2018-06-01 01:47-0500\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n"
"Language: \n"
......@@ -201,6 +201,21 @@ msgstr ""
msgid "2FA enabled"
msgstr ""
msgid "403|Please contact your GitLab administrator to get the permission."
msgstr ""
msgid "403|You don't have the permission to access this page."
msgstr ""
msgid "404|Make sure the address is correct and the page hasn't moved."
msgstr ""
msgid "404|Page Not Found"
msgstr ""
msgid "404|Please contact your GitLab administrator if you think this is a mistake."
msgstr ""
msgid "<strong>Removes</strong> source branch"
msgstr ""
......@@ -741,9 +756,6 @@ msgstr ""
msgid "BillingPlans|per user"
msgstr ""
msgid "Blame"
msgstr ""
msgid "Branch (%{branch_count})"
msgid_plural "Branches (%{branch_count})"
msgstr[0] ""
......@@ -1187,6 +1199,12 @@ msgstr ""
msgid "ClusterIntegration|Advanced options on this Kubernetes cluster's integration"
msgstr ""
msgid "ClusterIntegration|An error occured while trying to fetch project zones: %{error}"
msgstr ""
msgid "ClusterIntegration|An error occured while trying to fetch your projects: %{error}"
msgstr ""
msgid "ClusterIntegration|Applications"
msgstr ""
......@@ -1247,6 +1265,15 @@ msgstr ""
msgid "ClusterIntegration|Every new Google Cloud Platform (GCP) account receives $300 in credit upon %{sign_up_link}. In partnership with Google, GitLab is able to offer an additional $200 for new GCP accounts to get started with GitLab's Google Kubernetes Engine Integration."
msgstr ""
msgid "ClusterIntegration|Fetching machine types"
msgstr ""
msgid "ClusterIntegration|Fetching projects"
msgstr ""
msgid "ClusterIntegration|Fetching zones"
msgstr ""
msgid "ClusterIntegration|GitLab Integration"
msgstr ""
......@@ -1355,6 +1382,18 @@ msgstr ""
msgid "ClusterIntegration|Multiple Kubernetes clusters are available in GitLab Enterprise Edition Premium and Ultimate"
msgstr ""
msgid "ClusterIntegration|No machine types matched your search"
msgstr ""
msgid "ClusterIntegration|No projects found"
msgstr ""
msgid "ClusterIntegration|No projects matched your search"
msgstr ""
msgid "ClusterIntegration|No zones matched your search"
msgstr ""
msgid "ClusterIntegration|Note:"
msgstr ""
......@@ -1367,9 +1406,6 @@ msgstr ""
msgid "ClusterIntegration|Please make sure that your Google account meets the following requirements:"
msgstr ""
msgid "ClusterIntegration|Project ID"
msgstr ""
msgid "ClusterIntegration|Project namespace"
msgstr ""
......@@ -1400,19 +1436,40 @@ msgstr ""
msgid "ClusterIntegration|Save changes"
msgstr ""
msgid "ClusterIntegration|Search machine types"
msgstr ""
msgid "ClusterIntegration|Search projects"
msgstr ""
msgid "ClusterIntegration|Search zones"
msgstr ""
msgid "ClusterIntegration|Security"
msgstr ""
msgid "ClusterIntegration|See and edit the details for your Kubernetes cluster"
msgstr ""
msgid "ClusterIntegration|See machine types"
msgid "ClusterIntegration|See zones"
msgstr ""
msgid "ClusterIntegration|See your projects"
msgid "ClusterIntegration|Select machine type"
msgstr ""
msgid "ClusterIntegration|See zones"
msgid "ClusterIntegration|Select project"
msgstr ""
msgid "ClusterIntegration|Select project and zone to choose machine type"
msgstr ""
msgid "ClusterIntegration|Select project to choose zone"
msgstr ""
msgid "ClusterIntegration|Select zone"
msgstr ""
msgid "ClusterIntegration|Select zone to choose machine type"
msgstr ""
msgid "ClusterIntegration|Service token"
......@@ -1445,6 +1502,9 @@ msgstr ""
msgid "ClusterIntegration|Token"
msgstr ""
msgid "ClusterIntegration|Validating project billing status"
msgstr ""
msgid "ClusterIntegration|With a Kubernetes cluster associated to this project, you can use review apps, deploy your applications, run your pipelines, and much more in an easy way."
msgstr ""
......@@ -1725,6 +1785,9 @@ msgstr ""
msgid "Copy reference to clipboard"
msgstr ""
msgid "Copy to clipboard"
msgstr ""
msgid "Create"
msgstr ""
......@@ -2665,6 +2728,9 @@ msgstr ""
msgid "Gitaly Servers"
msgstr ""
msgid "Go Back"
msgstr ""
msgid "Go back"
msgstr ""
......@@ -2835,6 +2901,9 @@ msgstr ""
msgid "IDE|Go back"
msgstr ""
msgid "IDE|Open in file view"
msgstr ""
msgid "IDE|Review"
msgstr ""
......@@ -3331,6 +3400,18 @@ msgstr ""
msgid "Name new label"
msgstr ""
msgid "Nav|Help"
msgstr ""
msgid "Nav|Home"
msgstr ""
msgid "Nav|Sign In / Register"
msgstr ""
msgid "Nav|Sign out and sign in with a different account"
msgstr ""
msgid "New Issue"
msgid_plural "New Issues"
msgstr[0] ""
......@@ -3624,9 +3705,6 @@ msgstr ""
msgid "Performance optimization"
msgstr ""
msgid "Permalink"
msgstr ""
msgid "Permissions"
msgstr ""
......@@ -3798,9 +3876,6 @@ msgstr ""
msgid "Play"
msgstr ""
msgid "Please <a href=%{link_to_billing} target=\"_blank\" rel=\"noopener noreferrer\">enable billing for one of your projects to be able to create a Kubernetes cluster</a>, then try again."
msgstr ""
msgid "Please accept the Terms of Service before continuing."
msgstr ""
......@@ -4146,9 +4221,6 @@ msgstr ""
msgid "Quick actions can be used in the issues description and comment boxes."
msgstr ""
msgid "Raw"
msgstr ""
msgid "Read more"
msgstr ""
......@@ -4370,6 +4442,9 @@ msgstr ""
msgid "Search files"
msgstr ""
msgid "Search for projects, issues, etc."
msgstr ""
msgid "Search milestones"
msgstr ""
......@@ -4388,6 +4463,9 @@ msgstr ""
msgid "Security report"
msgstr ""
msgid "Select"
msgstr ""
msgid "Select Archive Format"
msgstr ""
......@@ -4406,6 +4484,15 @@ msgstr ""
msgid "Select branch/tag"
msgstr ""
msgid "Select project"
msgstr ""
msgid "Select project and zone to choose machine type"
msgstr ""
msgid "Select project to choose zone"
msgstr ""
msgid "Select source branch"
msgstr ""
......@@ -4687,6 +4774,9 @@ msgstr ""
msgid "Specify the following URL during the Runner setup:"
msgstr ""
msgid "Squash commits"
msgstr ""
msgid "Stage all"
msgstr ""
......@@ -5494,9 +5584,6 @@ msgstr ""
msgid "Want to see the data? Please ask an administrator for access."
msgstr ""
msgid "We could not verify that one of your projects on GCP has billing enabled. Please try again."
msgstr ""
msgid "We don't have enough data to show this stage."
msgstr ""
......
{
"private": true,
"scripts": {
"clean": "rm -rf public/assets tmp/cache/*-loader",
"dev-server": "nodemon -w 'config/webpack.config.js' --exec 'webpack-dev-server --config config/webpack.config.js'",
"eslint": "eslint --max-warnings 0 --ext .js,.vue .",
"eslint-fix": "eslint --max-warnings 0 --ext .js,.vue --fix .",
......
......@@ -147,7 +147,7 @@ describe ApplicationController do
end
describe '#authenticate_sessionless_user!' do
describe "authenticating a user from a feed token" do
describe 'authenticating a user from a feed token' do
controller(described_class) do
def index
render text: 'authenticated'
......@@ -182,7 +182,7 @@ describe ApplicationController do
context "when the 'feed_token' param is populated with an invalid feed token" do
it "doesn't log the user" do
get :index, feed_token: "token", format: :atom
get :index, feed_token: 'token', format: :atom
expect(response.status).not_to eq 200
expect(response.body).not_to eq 'authenticated'
end
......
require 'spec_helper'
describe 'Error Pages' do
let(:user) { create(:user) }
let(:project) { create(:project, :public) }
before do
sign_in(user)
end
shared_examples 'shows nav links' do
it 'shows nav links' do
expect(page).to have_link("Home", href: root_path)
expect(page).to have_link("Help", href: help_path)
expect(page).to have_link(nil, href: destroy_user_session_path)
end
end
describe '404' do
before do
visit '/not-a-real-page'
end
it 'allows user to search' do
fill_in 'search', with: 'something'
click_button 'Search'
expect(page).to have_current_path(%r{^/search\?.*search=something.*})
end
it_behaves_like 'shows nav links'
end
describe '403' do
before do
visit '/'
visit edit_project_path(project)
end
it_behaves_like 'shows nav links'
end
end
......@@ -17,8 +17,8 @@ feature 'Project milestone' do
it 'shows issues tab' do
within('#content-body') do
expect(page).to have_link 'Issues', href: '#tab-issues'
expect(page).to have_selector '.nav-links li.active', count: 1
expect(find('.nav-links li.active')).to have_content 'Issues'
expect(page).to have_selector '.nav-links li a.active', count: 1
expect(find('.nav-links li a.active')).to have_content 'Issues'
end
end
......@@ -44,8 +44,8 @@ feature 'Project milestone' do
it 'hides issues tab' do
within('#content-body') do
expect(page).not_to have_link 'Issues', href: '#tab-issues'
expect(page).to have_selector '.nav-links li.active', count: 1
expect(find('.nav-links li.active')).to have_content 'Merge Requests'
expect(page).to have_selector '.nav-links li a.active', count: 1
expect(find('.nav-links li a.active')).to have_content 'Merge Requests'
end
end
......
......@@ -379,7 +379,7 @@ describe 'Pipeline', :js do
end
it 'fails to access the page' do
expect(page).to have_content('Access Denied')
expect(page).to have_title('Access Denied')
end
end
end
......
......@@ -353,3 +353,8 @@ lfs_file_locks:
- user
project_badges:
- project
metrics:
- merge_request
- latest_closed_by
- merged_by
- pipeline
......@@ -119,6 +119,25 @@ describe Gitlab::ImportExport::RelationFactory do
end
end
context 'overrided model with pluralized name' do
let(:relation_sym) { :metrics }
let(:relation_hash) do
{
'id' => 99,
'merge_request_id' => 99,
'merged_at' => Time.now,
'merged_by_id' => 99,
'latest_closed_at' => nil,
'latest_closed_by_id' => nil
}
end
it 'does not raise errors' do
expect { created_object }.not_to raise_error
end
end
context 'Project references' do
let(:relation_sym) { :project_foo_model }
let(:relation_hash) do
......
......@@ -208,6 +208,19 @@ MergeRequestDiffFile:
- b_mode
- too_large
- binary
MergeRequest::Metrics:
- id
- created_at
- updated_at
- merge_request_id
- pipeline_id
- latest_closed_by_id
- latest_closed_at
- merged_by_id
- merged_at
- latest_build_started_at
- latest_build_finished_at
- first_deployed_to_production_at
Ci::Pipeline:
- id
- project_id
......
require 'spec_helper'
require Rails.root.join('db', 'post_migrate', '20180521162137_migrate_remaining_mr_metrics_populating_background_migration.rb')
describe MigrateRemainingMrMetricsPopulatingBackgroundMigration, :migration, :sidekiq do
let(:namespaces) { table(:namespaces) }
let(:projects) { table(:projects) }
let(:mrs) { table(:merge_requests) }
before do
namespaces.create!(id: 1, name: 'foo', path: 'foo')
projects.create!(id: 123, name: 'gitlab1', path: 'gitlab1', namespace_id: 1)
projects.create!(id: 456, name: 'gitlab2', path: 'gitlab2', namespace_id: 1)
projects.create!(id: 789, name: 'gitlab3', path: 'gitlab3', namespace_id: 1)
mrs.create!(title: 'foo', target_branch: 'target', source_branch: 'source', target_project_id: 123)
mrs.create!(title: 'bar', target_branch: 'target', source_branch: 'source', target_project_id: 456)
mrs.create!(title: 'kux', target_branch: 'target', source_branch: 'source', target_project_id: 789)
end
it 'correctly schedules background migrations' do
stub_const("#{described_class.name}::BATCH_SIZE", 2)
Sidekiq::Testing.fake! do
Timecop.freeze do
migrate!
expect(described_class::MIGRATION)
.to be_scheduled_delayed_migration(10.minutes, mrs.first.id, mrs.second.id)
expect(described_class::MIGRATION)
.to be_scheduled_delayed_migration(20.minutes, mrs.third.id, mrs.third.id)
expect(BackgroundMigrationWorker.jobs.size).to eq(2)
end
end
end
end
......@@ -219,11 +219,11 @@ describe Ci::BuildPresenter do
end
describe '#callout_failure_message' do
let(:build) { create(:ci_build, :failed, :script_failure) }
let(:build) { create(:ci_build, :failed, :api_failure) }
it 'returns a verbose failure reason' do
description = subject.callout_failure_message
expect(description).to eq('There has been a script failure. Check the job log for more information')
expect(description).to eq('There has been an API failure, please try again')
end
end
......
This diff is collapsed.
......@@ -131,7 +131,7 @@ describe JobEntity do
end
context 'when job failed' do
let(:job) { create(:ci_build, :script_failure) }
let(:job) { create(:ci_build, :api_failure) }
it 'contains details' do
expect(subject[:status]).to include :icon, :favicon, :text, :label, :tooltip
......@@ -142,20 +142,20 @@ describe JobEntity do
end
it 'should indicate the failure reason on tooltip' do
expect(subject[:status][:tooltip]).to eq('failed <br> (script failure)')
expect(subject[:status][:tooltip]).to eq('failed <br> (API failure)')
end
it 'should include a callout message with a verbose output' do
expect(subject[:callout_message]).to eq('There has been a script failure. Check the job log for more information')
expect(subject[:callout_message]).to eq('There has been an API failure, please try again')
end
it 'should state that it is not recoverable' do
expect(subject[:recoverable]).to be_falsy
expect(subject[:recoverable]).to be_truthy
end
end
context 'when job is allowed to fail' do
let(:job) { create(:ci_build, :allowed_to_fail, :script_failure) }
let(:job) { create(:ci_build, :allowed_to_fail, :api_failure) }
it 'contains details' do
expect(subject[:status]).to include :icon, :favicon, :text, :label, :tooltip
......@@ -166,15 +166,24 @@ describe JobEntity do
end
it 'should indicate the failure reason on tooltip' do
expect(subject[:status][:tooltip]).to eq('failed <br> (script failure) (allowed to fail)')
expect(subject[:status][:tooltip]).to eq('failed <br> (API failure) (allowed to fail)')
end
it 'should include a callout message with a verbose output' do
expect(subject[:callout_message]).to eq('There has been a script failure. Check the job log for more information')
expect(subject[:callout_message]).to eq('There has been an API failure, please try again')
end
it 'should state that it is not recoverable' do
expect(subject[:recoverable]).to be_falsy
expect(subject[:recoverable]).to be_truthy
end
end
context 'when the job failed with a script failure' do
let(:job) { create(:ci_build, :failed, :script_failure) }
it 'should not include callout message or recoverable keys' do
expect(subject).not_to include('callout_message')
expect(subject).not_to include('recoverable')
end
end
......
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