Commit ce881513 authored by Sean Packham's avatar Sean Packham

Merge branch 'master' into add-university-content

parents 8e741e2b 90578f4a
Please view this file on the master branch, on stable branches it's out of date. Please view this file on the master branch, on stable branches it's out of date.
v 8.13.0 (unreleased) v 8.13.0 (unreleased)
- Use gitlab-shell v3.6.2 (GIT TRACE logging)
- Speed-up group milestones show page - Speed-up group milestones show page
- Add more tests for calendar contribution (ClemMakesApps)
- Fix robots.txt disallowing access to groups starting with "s" (Matt Harrison) - Fix robots.txt disallowing access to groups starting with "s" (Matt Harrison)
- Revoke button in Applications Settings underlines on hover. - Revoke button in Applications Settings underlines on hover.
- Add organization field to user profile - Add organization field to user profile
...@@ -12,6 +14,8 @@ v 8.12.2 (unreleased) ...@@ -12,6 +14,8 @@ v 8.12.2 (unreleased)
- Fix snippets pagination - Fix snippets pagination
- Fix List-Unsubscribe header in emails - Fix List-Unsubscribe header in emails
- Fix an issue with the "Commits" section of the cycle analytics summary. !6513 - Fix an issue with the "Commits" section of the cycle analytics summary. !6513
- Fix errors importing project feature and milestone models using GitLab project import
- Make JWT messages Docker-compatible
v 8.12.1 v 8.12.1
- Fix a memory leak in HTML::Pipeline::SanitizationFilter::WHITELIST - Fix a memory leak in HTML::Pipeline::SanitizationFilter::WHITELIST
...@@ -118,6 +122,7 @@ v 8.12.0 ...@@ -118,6 +122,7 @@ v 8.12.0
- Change pipeline duration to be jobs running time instead of simple wall time from start to end !6084 - Change pipeline duration to be jobs running time instead of simple wall time from start to end !6084
- Show queued time when showing a pipeline !6084 - Show queued time when showing a pipeline !6084
- Remove unused mixins (ClemMakesApps) - Remove unused mixins (ClemMakesApps)
- Fix issue board label filtering appending already filtered labels
- Add search to all issue board lists - Add search to all issue board lists
- Scroll active tab into view on mobile - Scroll active tab into view on mobile
- Fix groups sort dropdown alignment (ClemMakesApps) - Fix groups sort dropdown alignment (ClemMakesApps)
......
...@@ -280,12 +280,12 @@ ...@@ -280,12 +280,12 @@
if (page === 'projects:boards:show') { if (page === 'projects:boards:show') {
if (label.isAny) { if (label.isAny) {
gl.issueBoards.BoardsStore.state.filters['label_name'] = []; gl.issueBoards.BoardsStore.state.filters['label_name'] = [];
} else if (label.title) { } else if ($el.hasClass('is-active')) {
gl.issueBoards.BoardsStore.state.filters['label_name'].push(label.title); gl.issueBoards.BoardsStore.state.filters['label_name'].push(label.title);
} else { } else {
var filters = gl.issueBoards.BoardsStore.state.filters['label_name']; var filters = gl.issueBoards.BoardsStore.state.filters['label_name'];
filters = filters.filter(function (label) { filters = filters.filter(function (filteredLabel) {
return label !== $el.text().trim(); return filteredLabel !== label.title;
}); });
gl.issueBoards.BoardsStore.state.filters['label_name'] = filters; gl.issueBoards.BoardsStore.state.filters['label_name'] = filters;
} }
......
...@@ -25,7 +25,7 @@ class JwtController < ApplicationController ...@@ -25,7 +25,7 @@ class JwtController < ApplicationController
authenticate_with_http_basic do |login, password| authenticate_with_http_basic do |login, password|
@authentication_result = Gitlab::Auth.find_for_git_client(login, password, project: nil, ip: request.ip) @authentication_result = Gitlab::Auth.find_for_git_client(login, password, project: nil, ip: request.ip)
render_403 unless @authentication_result.success? && render_unauthorized unless @authentication_result.success? &&
(@authentication_result.actor.nil? || @authentication_result.actor.is_a?(User)) (@authentication_result.actor.nil? || @authentication_result.actor.is_a?(User))
end end
rescue Gitlab::Auth::MissingPersonalTokenError rescue Gitlab::Auth::MissingPersonalTokenError
...@@ -33,10 +33,21 @@ class JwtController < ApplicationController ...@@ -33,10 +33,21 @@ class JwtController < ApplicationController
end end
def render_missing_personal_token def render_missing_personal_token
render plain: "HTTP Basic: Access denied\n" \ render json: {
errors: [
{ code: 'UNAUTHORIZED',
message: "HTTP Basic: Access denied\n" \
"You have 2FA enabled, please use a personal access token for Git over HTTP.\n" \ "You have 2FA enabled, please use a personal access token for Git over HTTP.\n" \
"You can generate one at #{profile_personal_access_tokens_url}", "You can generate one at #{profile_personal_access_tokens_url}" }
status: 401 ] }, status: 401
end
def render_unauthorized
render json: {
errors: [
{ code: 'UNAUTHORIZED',
message: 'HTTP Basic: Access denied' }
] }, status: 401
end end
def auth_params def auth_params
......
...@@ -7,10 +7,10 @@ module Auth ...@@ -7,10 +7,10 @@ module Auth
def execute(authentication_abilities:) def execute(authentication_abilities:)
@authentication_abilities = authentication_abilities @authentication_abilities = authentication_abilities
return error('not found', 404) unless registry.enabled return error('UNAVAILABLE', status: 404, message: 'registry not enabled') unless registry.enabled
unless current_user || project unless current_user || project
return error('forbidden', 403) unless scope return error('DENIED', status: 403, message: 'access forbidden') unless scope
end end
{ token: authorized_token(scope).encoded } { token: authorized_token(scope).encoded }
...@@ -111,5 +111,12 @@ module Auth ...@@ -111,5 +111,12 @@ module Auth
@authentication_abilities.include?(:create_container_image) && @authentication_abilities.include?(:create_container_image) &&
can?(current_user, :create_container_image, requested_project) can?(current_user, :create_container_image, requested_project)
end end
def error(code, status:, message: '')
{
errors: [{ code: code, message: message }],
http_status: status
}
end
end end
end end
# Model relationships to be included in the project import/export # Model relationships to be included in the project import/export
project_tree: project_tree:
- :labels
- milestones:
- :events
- issues: - issues:
- :events - :events
- notes: - notes:
...@@ -39,9 +42,6 @@ project_tree: ...@@ -39,9 +42,6 @@ project_tree:
- protected_branches: - protected_branches:
- :merge_access_levels - :merge_access_levels
- :push_access_levels - :push_access_levels
- :labels
- milestones:
- :events
- :project_feature - :project_feature
# Only include the following attributes for the models specified. # Only include the following attributes for the models specified.
......
...@@ -61,11 +61,17 @@ module Gitlab ...@@ -61,11 +61,17 @@ module Gitlab
def restore_project def restore_project
return @project unless @tree_hash return @project unless @tree_hash
project_params = @tree_hash.reject { |_key, value| value.is_a?(Array) }
@project.update(project_params) @project.update(project_params)
@project @project
end end
def project_params
@tree_hash.reject do |key, value|
# return params that are not 1 to many or 1 to 1 relations
value.is_a?(Array) || key == key.singularize
end
end
# Given a relation hash containing one or more models and its relationships, # Given a relation hash containing one or more models and its relationships,
# loops through each model and each object from a model type and # loops through each model and each object from a model type and
# and assigns its correspondent attributes hash from +tree_hash+ # and assigns its correspondent attributes hash from +tree_hash+
......
...@@ -466,6 +466,29 @@ describe 'Issue Boards', feature: true, js: true do ...@@ -466,6 +466,29 @@ describe 'Issue Boards', feature: true, js: true do
end end
end end
it 'removes filtered labels' do
wait_for_vue_resource
page.within '.labels-filter' do
click_button('Label')
wait_for_ajax
page.within '.dropdown-menu-labels' do
click_link(testing.title)
wait_for_vue_resource(spinner: false)
end
expect(page).to have_css('input[name="label_name[]"]', visible: false)
page.within '.dropdown-menu-labels' do
click_link(testing.title)
wait_for_vue_resource(spinner: false)
end
expect(page).not_to have_css('input[name="label_name[]"]', visible: false)
end
end
it 'infinite scrolls list with label filter' do it 'infinite scrolls list with label filter' do
50.times do 50.times do
create(:labeled_issue, project: project, labels: [testing]) create(:labeled_issue, project: project, labels: [testing])
......
...@@ -5,13 +5,41 @@ feature 'Contributions Calendar', js: true, feature: true do ...@@ -5,13 +5,41 @@ feature 'Contributions Calendar', js: true, feature: true do
let(:contributed_project) { create(:project, :public) } let(:contributed_project) { create(:project, :public) }
before do date_format = '%A %b %d, %Y'
login_as :user issue_title = 'Bug in old browser'
issue_params = { title: issue_title }
issue_params = { title: 'Bug in old browser' } def get_cell_color_selector(contributions)
Issues::CreateService.new(contributed_project, @user, issue_params).execute contribution_cell = '.user-contrib-cell'
activity_colors = Array['#ededed', '#acd5f2', '#7fa8c9', '#527ba0', '#254e77']
activity_colors_index = 0
if contributions > 0 && contributions < 10
activity_colors_index = 1
elsif contributions >= 10 && contributions < 20
activity_colors_index = 2
elsif contributions >= 20 && contributions < 30
activity_colors_index = 3
elsif contributions >= 30
activity_colors_index = 4
end
"#{contribution_cell}[fill='#{activity_colors[activity_colors_index]}']"
end
# Push code contribution def get_cell_date_selector(contributions, date)
contribution_text = 'No contributions'
if contributions === 1
contribution_text = '1 contribution'
elsif contributions > 1
contribution_text = "#{contributions} contributions"
end
"#{get_cell_color_selector(contributions)}[data-original-title='#{contribution_text}<br />#{date}']"
end
def push_code_contribution
push_params = { push_params = {
project: contributed_project, project: contributed_project,
action: Event::PUSHED, action: Event::PUSHED,
...@@ -20,7 +48,10 @@ feature 'Contributions Calendar', js: true, feature: true do ...@@ -20,7 +48,10 @@ feature 'Contributions Calendar', js: true, feature: true do
} }
Event.create(push_params) Event.create(push_params)
end
before do
login_as :user
visit @user.username visit @user.username
wait_for_ajax wait_for_ajax
end end
...@@ -29,11 +60,71 @@ feature 'Contributions Calendar', js: true, feature: true do ...@@ -29,11 +60,71 @@ feature 'Contributions Calendar', js: true, feature: true do
expect(page).to have_css('.js-contrib-calendar') expect(page).to have_css('.js-contrib-calendar')
end end
describe '1 calendar activity' do
before do
Issues::CreateService.new(contributed_project, @user, issue_params).execute
visit @user.username
wait_for_ajax
end
it 'displays calendar activity log', js: true do it 'displays calendar activity log', js: true do
expect(find('.content_list .event-note')).to have_content "Bug in old browser" expect(find('.content_list .event-note')).to have_content issue_title
end
it 'displays calendar activity square color for 1 contribution', js: true do
expect(page).to have_selector(get_cell_color_selector(1), count: 1)
end
it 'displays calendar activity square on the correct date', js: true do
today = Date.today.strftime(date_format)
expect(page).to have_selector(get_cell_date_selector(1, today), count: 1)
end
end end
it 'displays calendar activity square color', js: true do describe '10 calendar activities' do
expect(page).to have_selector('.user-contrib-cell[fill=\'#acd5f2\']', count: 1) before do
(0..9).each do |i|
push_code_contribution()
end
visit @user.username
wait_for_ajax
end
it 'displays calendar activity square color for 10 contributions', js: true do
expect(page).to have_selector(get_cell_color_selector(10), count: 1)
end
it 'displays calendar activity square on the correct date', js: true do
today = Date.today.strftime(date_format)
expect(page).to have_selector(get_cell_date_selector(10, today), count: 1)
end
end
describe 'calendar activity on two days' do
before do
push_code_contribution()
Timecop.freeze(Date.yesterday)
Issues::CreateService.new(contributed_project, @user, issue_params).execute
Timecop.return
visit @user.username
wait_for_ajax
end
it 'displays calendar activity squares for both days', js: true do
expect(page).to have_selector(get_cell_color_selector(1), count: 2)
end
it 'displays calendar activity square for yesterday', js: true do
yesterday = Date.yesterday.strftime(date_format)
expect(page).to have_selector(get_cell_date_selector(1, yesterday), count: 1)
end
it 'displays calendar activity square for today', js: true do
today = Date.today.strftime(date_format)
expect(page).to have_selector(get_cell_date_selector(1, today), count: 1)
end
end end
end end
...@@ -2231,6 +2231,31 @@ ...@@ -2231,6 +2231,31 @@
], ],
"milestones": [ "milestones": [
{
"id": 1,
"title": "test milestone",
"project_id": 8,
"description": "test milestone",
"due_date": null,
"created_at": "2016-06-14T15:02:04.415Z",
"updated_at": "2016-06-14T15:02:04.415Z",
"state": "active",
"iid": 1,
"events": [
{
"id": 487,
"target_type": "Milestone",
"target_id": 1,
"title": null,
"data": null,
"project_id": 46,
"created_at": "2016-06-14T15:02:04.418Z",
"updated_at": "2016-06-14T15:02:04.418Z",
"action": 1,
"author_id": 18
}
]
},
{ {
"id": 20, "id": 20,
"title": "v4.0", "title": "v4.0",
...@@ -7373,5 +7398,16 @@ ...@@ -7373,5 +7398,16 @@
} }
] ]
} }
] ],
"project_feature": {
"builds_access_level": 0,
"created_at": "2014-12-26T09:26:45.000Z",
"id": 2,
"issues_access_level": 0,
"merge_requests_access_level": 20,
"project_id": 4,
"snippets_access_level": 20,
"updated_at": "2016-09-23T11:58:28.000Z",
"wiki_access_level": 20
}
} }
\ No newline at end of file
...@@ -107,6 +107,12 @@ describe Gitlab::ImportExport::ProjectTreeRestorer, services: true do ...@@ -107,6 +107,12 @@ describe Gitlab::ImportExport::ProjectTreeRestorer, services: true do
expect(Label.first.label_links.first.target).not_to be_nil expect(Label.first.label_links.first.target).not_to be_nil
end end
it 'has a project feature' do
restored_project_json
expect(project.project_feature).not_to be_nil
end
it 'restores the correct service' do it 'restores the correct service' do
restored_project_json restored_project_json
......
...@@ -39,7 +39,7 @@ describe JwtController do ...@@ -39,7 +39,7 @@ describe JwtController do
subject! { get '/jwt/auth', parameters, headers } subject! { get '/jwt/auth', parameters, headers }
it { expect(response).to have_http_status(403) } it { expect(response).to have_http_status(401) }
end end
end end
...@@ -77,7 +77,7 @@ describe JwtController do ...@@ -77,7 +77,7 @@ describe JwtController do
subject! { get '/jwt/auth', parameters, headers } subject! { get '/jwt/auth', parameters, headers }
it { expect(response).to have_http_status(403) } it { expect(response).to have_http_status(401) }
end end
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