Commit 2b3319e8 authored by Yorick Peterse's avatar Yorick Peterse

Merge branch 'master' of gitlab.com:gitlab-org/gitlab-ce

parents 0f57aaaa 14491285
......@@ -2,8 +2,10 @@ Please view this file on the master branch, on stable branches it's out of date.
v 8.7.0 (unreleased)
- All images in discussions and wikis now link to their source files !3464 (Connor Shea).
- Return status code 303 after a branch DELETE operation to avoid project deletion (Stan Hu)
- Improved Markdown rendering performance !3389 (Yorick Peterse)
- Don't attempt to look up an avatar in repo if repo directory does not exist (Stan Hu)
- Expose project badges in project settings
- Preserve time notes/comments have been updated at when moving issue
- Make HTTP(s) label consistent on clone bar (Stan Hu)
- Expose label description in API (Mariusz Jachimowicz)
......@@ -16,6 +18,7 @@ v 8.7.0 (unreleased)
- Handle nil descriptions in Slack issue messages (Stan Hu)
- Add default scope to projects to exclude projects pending deletion
- Ensure empty recipients are rejected in BuildsEmailService
- API: Ability to filter milestones by state `active` and `closed` (Robert Schilling)
- Implement 'Groups View' as an option for dashboard preferences !3379 (Elias W.)
- Implement 'TODOs View' as an option for dashboard preferences !3379 (Elias W.)
- Gracefully handle notes on deleted commits in merge requests (Stan Hu)
......@@ -23,11 +26,13 @@ v 8.7.0 (unreleased)
- Fall back to `In-Reply-To` and `References` headers when sub-addressing is not available (David Padilla)
- Remove "Congratulations!" tweet button on newly-created project. (Connor Shea)
- Improved UX of the navigation sidebar
- Fix admin/projects when using visibility levels on search (PotHix)
- Build status notifications
- Update GitLab Pages to 0.2.2: fixes content-type of predefined 404 page
- API: Expose user location (Robert Schilling)
v 8.6.5 (unreleased)
- Only update repository language if it is not set to improve performance
- Check permissions when user attempts to import members from another project
v 8.6.4
......
......@@ -300,7 +300,7 @@ group :development, :test do
gem 'rubocop', '~> 0.38.0', require: false
gem 'scss_lint', '~> 0.47.0', require: false
gem 'coveralls', '~> 0.8.2', require: false
gem 'simplecov', '~> 0.10.0', require: false
gem 'simplecov', '~> 0.11.0', require: false
gem 'flog', require: false
gem 'flay', require: false
gem 'bundler-audit', require: false
......
......@@ -136,10 +136,9 @@ GEM
colorize (0.7.7)
concurrent-ruby (1.0.0)
connection_pool (2.2.0)
coveralls (0.8.9)
coveralls (0.8.13)
json (~> 1.8)
rest-client (>= 1.6.8, < 2)
simplecov (~> 0.10.0)
simplecov (~> 0.11.0)
term-ansicolor (~> 1.3)
thor (~> 0.19.1)
tins (~> 1.6.0)
......@@ -176,8 +175,6 @@ GEM
diff-lcs (1.2.5)
diffy (3.0.7)
docile (1.1.5)
domain_name (0.5.25)
unf (>= 0.0.5, < 1.0.0)
doorkeeper (2.2.2)
railties (>= 3.2)
dropzonejs-rails (0.7.2)
......@@ -445,8 +442,6 @@ GEM
nokogiri (~> 1.6.0)
ruby_parser (~> 3.5)
htmlentities (4.3.4)
http-cookie (1.0.2)
domain_name (~> 0.5)
http_parser.rb (0.5.3)
httparty (0.13.7)
json (~> 1.8)
......@@ -504,7 +499,6 @@ GEM
nested_form (0.3.2)
net-ldap (0.12.1)
net-ssh (3.0.1)
netrc (0.11.0)
newrelic_rpm (3.14.1.311)
nokogiri (1.6.7.2)
mini_portile2 (~> 2.0.0.rc2)
......@@ -681,10 +675,6 @@ GEM
listen (~> 3.0)
responders (2.1.1)
railties (>= 4.2.0, < 5.1)
rest-client (1.8.0)
http-cookie (>= 1.0.2, < 2.0)
mime-types (>= 1.16, < 3.0)
netrc (~> 0.7)
rinku (1.7.3)
rotp (2.1.1)
rouge (1.10.1)
......@@ -778,7 +768,7 @@ GEM
rufus-scheduler (>= 2.0.24)
sidekiq (>= 4.0.0)
simple_oauth (0.1.9)
simplecov (0.10.0)
simplecov (0.11.2)
docile (~> 1.1.0)
json (~> 1.8)
simplecov-html (~> 0.10.0)
......@@ -869,7 +859,7 @@ GEM
underscore-rails (1.8.3)
unf (0.1.4)
unf_ext
unf_ext (0.0.7.1)
unf_ext (0.0.7.2)
unicode-display_width (1.0.2)
unicorn (4.9.0)
kgio (~> 2.6)
......@@ -1065,7 +1055,7 @@ DEPENDENCIES
shoulda-matchers (~> 2.8.0)
sidekiq (~> 4.0)
sidekiq-cron (~> 0.4.0)
simplecov (~> 0.10.0)
simplecov (~> 0.11.0)
sinatra (~> 1.4.4)
six (~> 0.2.0)
slack-notifier (~> 1.2.0)
......
......@@ -5,7 +5,7 @@ class Admin::ProjectsController < Admin::ApplicationController
def index
@projects = Project.all
@projects = @projects.in_namespace(params[:namespace_id]) if params[:namespace_id].present?
@projects = @projects.where("visibility_level IN (?)", params[:visibility_levels]) if params[:visibility_levels].present?
@projects = @projects.where("projects.visibility_level IN (?)", params[:visibility_levels]) if params[:visibility_levels].present?
@projects = @projects.with_push if params[:with_push].present?
@projects = @projects.abandoned if params[:abandoned].present?
@projects = @projects.non_archived unless params[:with_archived].present?
......
......@@ -68,7 +68,9 @@ class Projects::ApplicationController < ApplicationController
end
def require_non_empty_project
redirect_to namespace_project_path(@project.namespace, @project) if @project.empty_repo?
# Be sure to return status code 303 to avoid a double DELETE:
# http://api.rubyonrails.org/classes/ActionController/Redirecting.html
redirect_to namespace_project_path(@project.namespace, @project), status: 303 if @project.empty_repo?
end
def require_branch_head
......
class Projects::BadgesController < Projects::ApplicationController
before_action :no_cache_headers
layout 'project_settings'
before_action :authorize_admin_project!, only: [:index]
before_action :no_cache_headers, except: [:index]
def index
@ref = params[:ref] || @project.default_branch || 'master'
@build_badge = Gitlab::Badge::Build.new(@project, @ref)
end
def build
badge = Gitlab::Badge::Build.new(project, params[:ref])
......
......@@ -48,7 +48,7 @@ class Projects::BranchesController < Projects::ApplicationController
respond_to do |format|
format.html do
redirect_to namespace_project_branches_path(@project.namespace,
@project)
@project), status: 303
end
format.js { render status: status[:return_code] }
end
......
......@@ -24,6 +24,8 @@ class Projects::RefsController < Projects::ApplicationController
namespace_project_find_file_path(@project.namespace, @project, @id)
when "graphs_commits"
commits_namespace_project_graph_path(@project.namespace, @project, @id)
when "badges"
namespace_project_badges_path(@project.namespace, @project, ref: @id)
else
namespace_project_commits_path(@project.namespace, @project, @id)
end
......
......@@ -55,15 +55,15 @@ class GitPushService < BaseService
end
def update_main_language
# Performance can be bad so for now only check main_language once
# See https://gitlab.com/gitlab-org/gitlab-ce/issues/14937
return if @project.main_language.present?
return unless is_default_branch?
return unless push_to_new_branch? || push_to_existing_branch?
current_language = @project.repository.main_language
unless current_language == @project.main_language
return @project.update_attributes(main_language: current_language)
end
@project.update_attributes(main_language: current_language)
true
end
......
......@@ -71,8 +71,13 @@
= icon('code fw')
%span
Variables
= nav_link path: 'triggers#index' do
= nav_link(controller: :triggers) do
= link_to namespace_project_triggers_path(@project.namespace, @project), title: 'Triggers' do
= icon('retweet fw')
%span
Triggers
= nav_link(controller: :badges) do
= link_to namespace_project_badges_path(@project.namespace, @project), title: 'Badges' do
= icon('star-half-empty fw')
%span
Badges
- page_title 'Badges'
- badges_path = namespace_project_badges_path(@project.namespace, @project)
- header_title project_title(@project, 'Badges', badges_path)
.prepend-top-10
.panel.panel-default
.panel-heading
%b Builds badge &middot;
= @build_badge.to_html
.pull-right
= render 'shared/ref_switcher', destination: 'badges'
.panel-body
.row
.col-md-2.text-center
Markdown
.col-md-10.code.js-syntax-highlight
= highlight('.md', @build_badge.to_markdown)
.row
%hr
.row
.col-md-2.text-center
HTML
.col-md-10.code.js-syntax-highlight
= highlight('.html', @build_badge.to_html)
......@@ -802,10 +802,11 @@ Rails.application.routes.draw do
resources :approvers, only: :destroy
resources :runner_projects, only: [:create, :destroy]
resources :badges, only: [], path: 'badges/*ref',
constraints: { ref: Gitlab::Regex.git_reference_regex } do
resources :badges, only: [:index] do
collection do
get :build, constraints: { format: /svg/ }
scope '*ref', constraints: { ref: Gitlab::Regex.git_reference_regex } do
get :build, constraints: { format: /svg/ }
end
end
end
resources :audit_events, only: [:index]
......
......@@ -7,8 +7,24 @@ Returns a list of project milestones.
```
GET /projects/:id/milestones
GET /projects/:id/milestones?iid=42
GET /projects/:id/milestones?state=active
GET /projects/:id/milestones?state=closed
```
Parameters:
| Attribute | Type | Required | Description |
| --------- | ---- | -------- | ----------- |
| `id` | integer | yes | The ID of a project |
| `iid` | integer | optional | Return only the milestone having the given `iid` |
| `state` | string | optional | Return only `active` or `closed` milestones` |
```bash
curl -H "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" https://gitlab.example.com/api/v3/projects/5/milestones
```
Example Response:
```json
[
{
......@@ -25,10 +41,6 @@ GET /projects/:id/milestones?iid=42
]
```
Parameters:
- `id` (required) - The ID of a project
- `iid` (optional) - Return the milestone having the given `iid`
## Get single milestone
......
......@@ -38,7 +38,7 @@ services:
- postgres
before_script:
- bundle_install
- bundle install
stages:
- build
......
......@@ -64,7 +64,7 @@ module API
authorize_admin_project
@branch = user_project.repository.find_branch(params[:branch])
not_found!("Branch does not exist") unless @branch
not_found!("Branch") unless @branch
protected_branch = user_project.protected_branches.find_by(name: @branch.name)
protected_branch.destroy if protected_branch
......
......@@ -3,17 +3,33 @@ module API
class Milestones < Grape::API
before { authenticate! }
helpers do
def filter_milestones_state(milestones, state)
case state
when 'active' then milestones.active
when 'closed' then milestones.closed
else milestones
end
end
end
resource :projects do
# Get a list of project milestones
#
# Parameters:
# id (required) - The ID of a project
# id (required) - The ID of a project
# state (optional) - Return "active" or "closed" milestones
# Example Request:
# GET /projects/:id/milestones
# GET /projects/:id/milestones?state=active
# GET /projects/:id/milestones?state=closed
get ":id/milestones" do
authorize! :read_milestone, user_project
present paginate(user_project.milestones), with: Entities::Milestone
milestones = user_project.milestones
milestones = filter_milestones_state(milestones, params[:state])
present paginate(milestones), with: Entities::Milestone
end
# Get a single project milestone
......
......@@ -4,14 +4,15 @@ module Gitlab
# Build badge
#
class Build
include Gitlab::Application.routes.url_helpers
include ActionView::Helpers::AssetTagHelper
include ActionView::Helpers::UrlHelper
def initialize(project, ref)
@project, @ref = project, ref
@image = ::Ci::ImageForBuildService.new.execute(project, ref: ref)
end
def to_s
@image[:name].sub(/\.svg$/, '')
end
def type
'image/svg+xml'
end
......@@ -19,6 +20,27 @@ module Gitlab
def data
File.read(@image[:path])
end
def to_s
@image[:name].sub(/\.svg$/, '')
end
def to_html
link_to(image_tag(image_url, alt: 'build status'), link_url)
end
def to_markdown
"[![build status](#{image_url})](#{link_url})"
end
def image_url
build_namespace_project_badges_url(@project.namespace,
@project, @ref, format: :svg)
end
def link_url
namespace_project_commits_url(@project.namespace, @project, id: @ref)
end
end
end
end
require 'spec_helper'
describe Admin::ProjectsController do
let!(:project) { create(:project, visibility_level: Gitlab::VisibilityLevel::PUBLIC) }
before do
sign_in(create(:admin))
end
describe 'GET /projects' do
render_views
it 'retrieves the project for the given visibility level' do
get :index, visibility_levels: [Gitlab::VisibilityLevel::PUBLIC]
expect(response.body).to match(project.name)
end
it 'does not retrieve the project' do
get :index, visibility_levels: [Gitlab::VisibilityLevel::INTERNAL]
expect(response.body).to_not match(project.name)
end
end
end
......@@ -93,6 +93,20 @@ describe Projects::BranchesController do
end
end
describe "POST destroy with HTML format" do
render_views
it 'returns 303' do
post :destroy,
format: :html,
id: 'foo/bar/baz',
namespace_id: project.namespace.to_param,
project_id: project.to_param
expect(response.status).to eq(303)
end
end
describe "POST destroy" do
render_views
......
require 'spec_helper'
feature 'list of badges' do
include Select2Helper
background do
user = create(:user)
project = create(:project)
project.team << [user, :master]
login_as(user)
visit edit_namespace_project_path(project.namespace, project)
end
scenario 'user displays list of badges' do
click_link 'Badges'
expect(page).to have_content 'build status'
expect(page).to have_content 'Markdown'
expect(page).to have_content 'HTML'
expect(page).to have_css('.highlight', count: 2)
expect(page).to have_xpath("//img[@alt='build status']")
page.within('.highlight', match: :first) do
expect(page).to have_content 'badges/master/build.svg'
end
end
scenario 'user changes current ref on badges list page', js: true do
click_link 'Badges'
select2('improve/awesome', from: '#ref')
expect(page).to have_content 'badges/improve/awesome/build.svg'
end
end
......@@ -3,13 +3,44 @@ require 'spec_helper'
describe Gitlab::Badge::Build do
let(:project) { create(:project) }
let(:sha) { project.commit.sha }
let(:badge) { described_class.new(project, 'master') }
let(:branch) { 'master' }
let(:badge) { described_class.new(project, branch) }
describe '#type' do
subject { badge.type }
it { is_expected.to eq 'image/svg+xml' }
end
describe '#to_html' do
let(:html) { Nokogiri::HTML.parse(badge.to_html) }
let(:a_href) { html.at('a') }
it 'points to link' do
expect(a_href[:href]).to eq badge.link_url
end
it 'contains clickable image' do
expect(a_href.children.first.name).to eq 'img'
end
end
describe '#to_markdown' do
subject { badge.to_markdown }
it { is_expected.to include badge.image_url }
it { is_expected.to include badge.link_url }
end
describe '#image_url' do
subject { badge.image_url }
it { is_expected.to include "badges/#{branch}/build.svg" }
end
describe '#link_url' do
subject { badge.link_url }
it { is_expected.to include "commits/#{branch}" }
end
context 'build exists' do
let(:ci_commit) { create(:ci_commit, project: project, sha: sha) }
let!(:build) { create(:ci_build, commit: ci_commit) }
......
......@@ -4,6 +4,7 @@ describe API::API, api: true do
include ApiHelpers
let(:user) { create(:user) }
let!(:project) { create(:project, namespace: user.namespace ) }
let!(:closed_milestone) { create(:closed_milestone, project: project) }
let!(:milestone) { create(:milestone, project: project) }
before { project.team << [user, :developer] }
......@@ -20,6 +21,24 @@ describe API::API, api: true do
get api("/projects/#{project.id}/milestones")
expect(response.status).to eq(401)
end
it 'returns an array of active milestones' do
get api("/projects/#{project.id}/milestones?state=active", user)
expect(response.status).to eq(200)
expect(json_response).to be_an Array
expect(json_response.length).to eq(1)
expect(json_response.first['id']).to eq(milestone.id)
end
it 'returns an array of closed milestones' do
get api("/projects/#{project.id}/milestones?state=closed", user)
expect(response.status).to eq(200)
expect(json_response).to be_an Array
expect(json_response.length).to eq(1)
expect(json_response.first['id']).to eq(closed_milestone.id)
end
end
describe 'GET /projects/:id/milestones/:milestone_id' do
......
......@@ -180,21 +180,37 @@ describe GitPushService, services: true do
end
context "after push" do
before do
@service = execute_service(project, user, @oldrev, @newrev, ref)
def execute
execute_service(project, user, @oldrev, @newrev, ref)
end
context "to master" do
let(:ref) { @ref }
it { expect(@service.update_main_language).to eq(true) }
it { expect(project.main_language).to eq("Ruby") }
context 'when main_language is nil' do
it 'obtains the language from the repository' do
expect(project.repository).to receive(:main_language)
execute
end
it 'sets the project main language' do
execute
expect(project.main_language).to eq("Ruby")
end
end
context 'when main_language is already set' do
it 'does not check the repository' do
execute # do an initial run to simulate lang being preset
expect(project.repository).not_to receive(:main_language)
execute
end
end
end
context "to other branch" do
let(:ref) { 'refs/heads/feature/branch' }
it { expect(@service.update_main_language).to eq(nil) }
it { expect(project.main_language).to eq(nil) }
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