From 7f7d39858f87d5920137d63e5d6005a0989ca392 Mon Sep 17 00:00:00 2001 From: Iman Mohamadi Date: Wed, 14 Oct 2015 11:14:59 +0330 Subject: ugly outlines removed form sidebar --- app/assets/stylesheets/framework/sidebar.scss | 3 +++ 1 file changed, 3 insertions(+) diff --git a/app/assets/stylesheets/framework/sidebar.scss b/app/assets/stylesheets/framework/sidebar.scss index c5ea3aca7ca..1c42ba2fd75 100644 --- a/app/assets/stylesheets/framework/sidebar.scss +++ b/app/assets/stylesheets/framework/sidebar.scss @@ -64,6 +64,7 @@ text-decoration: none; padding-left: 22px; font-weight: normal; + outline: none; &:hover { text-decoration: none; @@ -176,6 +177,7 @@ text-align: center; line-height: 40px; transition-duration: .3s; + outline: none; } .collapse-nav a:hover { @@ -238,6 +240,7 @@ width: 100%; padding: 10px 22px; overflow: hidden; + outline: none; img { width: 36px; -- cgit v1.2.1 From 5a5069969ce8e9184e36abbb7623bf474d5869e9 Mon Sep 17 00:00:00 2001 From: Jonathan Schoeffling Date: Sun, 14 Jun 2015 18:04:20 -0400 Subject: Add support for searching commit log messages Include the log messages of recent commits in project-level search results, providing functionality similar to 'git log --grep'. Update repository model rspec tests to validate the output of Repository#commits_with_log_matching. --- CHANGELOG | 1 + app/controllers/search_controller.rb | 4 ++-- app/models/repository.rb | 6 ++++++ app/views/layouts/_search.html.haml | 2 ++ app/views/search/_category.html.haml | 7 +++++++ app/views/search/results/_commits.html.haml | 32 +++++++++++++++++++++++++++++ lib/gitlab/project_search_results.rb | 12 ++++++++++- spec/models/repository_spec.rb | 11 ++++++++++ 8 files changed, 72 insertions(+), 3 deletions(-) create mode 100644 app/views/search/results/_commits.html.haml diff --git a/CHANGELOG b/CHANGELOG index 0d89fca9fc1..3975f236a58 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -208,6 +208,7 @@ v 8.0.0 - Fix references to target project issues in Merge Requests markdown preview and textareas (Francesco Levorato) - Redirect from incorrectly cased group or project path to correct one (Francesco Levorato) - Removed API calls from CE to CI + - Include commit logs in project search v 7.14.3 - No changes diff --git a/app/controllers/search_controller.rb b/app/controllers/search_controller.rb index eb0408a95e5..9bb42ec86b3 100644 --- a/app/controllers/search_controller.rb +++ b/app/controllers/search_controller.rb @@ -23,8 +23,8 @@ class SearchController < ApplicationController @search_results = if @project - unless %w(blobs notes issues merge_requests milestones wiki_blobs). - include?(@scope) + unless %w(blobs notes issues merge_requests milestones wiki_blobs + commits).include?(@scope) @scope = 'blobs' end diff --git a/app/models/repository.rb b/app/models/repository.rb index a3ba5f4c18a..39451f7da7f 100644 --- a/app/models/repository.rb +++ b/app/models/repository.rb @@ -87,6 +87,12 @@ class Repository commits end + def commits_with_log_matching(query) + list = Gitlab::Git::Commit.where(repo: raw_repository, limit: 1000) + list = Commit.decorate(list, @project) if list.present? + list.select! { |c| c.message.match /#{query}/i } + end + def find_branch(name) branches.find { |branch| branch.name == name } end diff --git a/app/views/layouts/_search.html.haml b/app/views/layouts/_search.html.haml index ceb64ce3157..d1aa8f62463 100644 --- a/app/views/layouts/_search.html.haml +++ b/app/views/layouts/_search.html.haml @@ -11,6 +11,8 @@ = hidden_field_tag :scope, 'merge_requests' - elsif current_controller?(:wikis) = hidden_field_tag :scope, 'wiki_blobs' + - elsif current_controller?(:commits) + = hidden_field_tag :scope, 'commits' - else = hidden_field_tag :search_code, true diff --git a/app/views/search/_category.html.haml b/app/views/search/_category.html.haml index d637abfa76b..ef43f727d8b 100644 --- a/app/views/search/_category.html.haml +++ b/app/views/search/_category.html.haml @@ -42,6 +42,13 @@ Wiki %span.badge = @search_results.wiki_blobs_count + %li{class: ("active" if @scope == 'commits')} + = link_to search_filter_path(scope: 'commits') do + = icon('history fw') + %span + Commit Logs + %span.badge + = @search_results.commits_count - elsif @show_snippets %li{class: ("active" if @scope == 'snippet_blobs')} diff --git a/app/views/search/results/_commits.html.haml b/app/views/search/results/_commits.html.haml new file mode 100644 index 00000000000..8076174e59d --- /dev/null +++ b/app/views/search/results/_commits.html.haml @@ -0,0 +1,32 @@ +.search-result-row + .commits-row-title + %strong.str-truncated + = link_to commits.title, namespace_project_commit_path(@project.namespace, @project, commits.id), class: "commit_short_id" + + .pull-right + = link_to commits.short_id, namespace_project_commit_path(@project.namespace, @project, commits.id), class: "commit_short_id" + + .notes_count + - if @note_counts + - note_count = @note_counts.fetch(commits.id, 0) + - else + - notes = commits.notes + - note_count = notes.user.count + + - if note_count > 0 + %span.light + %i.fa.fa-comments + = note_count + + - if commits.description? + .commits-row-description + %pre + = preserve(gfm(escape_once(commits.description))) + + .commits-row-info + = commit_author_link(commits, avatar: true, size: 24) + authored + .committed_ago + #{time_ago_with_tooltip(commits.committed_date)}   + = link_to_browse_code(@project, commits) + %br diff --git a/lib/gitlab/project_search_results.rb b/lib/gitlab/project_search_results.rb index 0a2be605af9..3bf98699bcb 100644 --- a/lib/gitlab/project_search_results.rb +++ b/lib/gitlab/project_search_results.rb @@ -20,6 +20,8 @@ module Gitlab Kaminari.paginate_array(blobs).page(page).per(per_page) when 'wiki_blobs' Kaminari.paginate_array(wiki_blobs).page(page).per(per_page) + when 'commits' + Kaminari.paginate_array(commits).page(page).per(per_page) else super end @@ -27,7 +29,7 @@ module Gitlab def total_count @total_count ||= issues_count + merge_requests_count + blobs_count + - notes_count + wiki_blobs_count + notes_count + wiki_blobs_count + commits_count end def blobs_count @@ -42,6 +44,10 @@ module Gitlab @wiki_blobs_count ||= wiki_blobs.count end + def commits_count + @commits_count ||= commits.count + end + private def blobs @@ -70,6 +76,10 @@ module Gitlab Note.where(project_id: limit_project_ids).user.search(query).order('updated_at DESC') end + def commits + project.repository.commits_with_log_matching(query) + end + def limit_project_ids [project.id] end diff --git a/spec/models/repository_spec.rb b/spec/models/repository_spec.rb index 05e51532eb8..ceffd5a8617 100644 --- a/spec/models/repository_spec.rb +++ b/spec/models/repository_spec.rb @@ -26,6 +26,17 @@ describe Repository do it { is_expected.to eq('c1acaa58bbcbc3eafe538cb8274ba387047b69f8') } end + describe :commits_with_log_matching do + subject { repository.commits_with_log_matching('submodule'). + map{|k| k.id} + } + + it { is_expected.to include('5937ac0a7beb003549fc5fd26fc247adbce4a52e') } + it { is_expected.to include('6f6d7e7ed97bb5f0054f2b1df789b39ca89b6ff9') } + it { is_expected.to include('cfe32cf61b73a0d5e9f13e774abde7ff789b1660') } + it { is_expected.not_to include('913c66a37b4a45b9769037c55c2d238bd0942d2e') } + end + describe :blob_at do context 'blank sha' do subject { repository.blob_at(Gitlab::Git::BLANK_SHA, '.gitignore') } -- cgit v1.2.1 From 091aa95dbfec0b062ed706fb55589ce10e5bd9d0 Mon Sep 17 00:00:00 2001 From: Mike Chmielewski Date: Wed, 21 Oct 2015 00:59:52 +0000 Subject: Make subject of spec line up on one line to satisfy rubocop requirements --- spec/models/repository_spec.rb | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/spec/models/repository_spec.rb b/spec/models/repository_spec.rb index ceffd5a8617..9d5859f1476 100644 --- a/spec/models/repository_spec.rb +++ b/spec/models/repository_spec.rb @@ -27,9 +27,7 @@ describe Repository do end describe :commits_with_log_matching do - subject { repository.commits_with_log_matching('submodule'). - map{|k| k.id} - } + subject { repository.commits_with_log_matching('submodule').map{|k| k.id} } it { is_expected.to include('5937ac0a7beb003549fc5fd26fc247adbce4a52e') } it { is_expected.to include('6f6d7e7ed97bb5f0054f2b1df789b39ca89b6ff9') } @@ -102,4 +100,4 @@ describe Repository do it { expect(subject.data.lines[2]).to eq(" - Feature: Replace teams with group membership\n") } end end -end +end \ No newline at end of file -- cgit v1.2.1 From afdb53baecb2ef6d57f8ed957213260825c67805 Mon Sep 17 00:00:00 2001 From: Mike Chmielewski Date: Wed, 21 Oct 2015 01:04:19 +0000 Subject: Added @commits to list of tags. --- lib/tasks/spinach.rake | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/tasks/spinach.rake b/lib/tasks/spinach.rake index c8881be0954..d5a96fd38f4 100644 --- a/lib/tasks/spinach.rake +++ b/lib/tasks/spinach.rake @@ -5,7 +5,7 @@ namespace :spinach do task :project do cmds = [ %W(rake gitlab:setup), - %W(spinach --tags ~@admin,~@dashboard,~@profile,~@public,~@snippets), + %W(spinach --tags ~@admin,~@dashboard,~@profile,~@public,~@snippets,~@commits), ] run_commands(cmds) end @@ -14,7 +14,7 @@ namespace :spinach do task :other do cmds = [ %W(rake gitlab:setup), - %W(spinach --tags @admin,@dashboard,@profile,@public,@snippets), + %W(spinach --tags @admin,@dashboard,@profile,@public,@snippets,@commits), ] run_commands(cmds) end @@ -33,4 +33,4 @@ def run_commands(cmds) cmds.each do |cmd| system({'RAILS_ENV' => 'test', 'force' => 'yes'}, *cmd) or raise("#{cmd} failed!") end -end +end \ No newline at end of file -- cgit v1.2.1 From 8e3a316121ba0814997cc66a8ef00fb97ea0f200 Mon Sep 17 00:00:00 2001 From: Michael Chmielewski Date: Tue, 20 Oct 2015 21:44:39 -0400 Subject: Moved changelog entry to 8.2 --- CHANGELOG | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/CHANGELOG b/CHANGELOG index 3975f236a58..b573d40317e 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -29,6 +29,9 @@ v 8.1.0 - Ensure MySQL CI limits DB migrations occur after the fields have been created (Stan Hu) - Fix duplicate repositories in GitHub import page (Stan Hu) - Redirect to a default path if HTTP_REFERER is not set (Stan Hu) + - Include commit logs in project search + +v 8.1.0 (unreleased) - Send an email to admin email when a user is reported for spam (Jonathan Rochkind) - Show notifications button when user is member of group rather than project (Grzegorz Bizon) - Fix bug preventing mentioned issued from being closed when MR is merged using fast-forward merge. @@ -208,7 +211,6 @@ v 8.0.0 - Fix references to target project issues in Merge Requests markdown preview and textareas (Francesco Levorato) - Redirect from incorrectly cased group or project path to correct one (Francesco Levorato) - Removed API calls from CE to CI - - Include commit logs in project search v 7.14.3 - No changes -- cgit v1.2.1 From 8e8fb87d4091f05a75929d6daa3bbe6862e2dda1 Mon Sep 17 00:00:00 2001 From: Michael Chmielewski Date: Sat, 24 Oct 2015 22:41:51 -0400 Subject: Trailing new lines at ends of files are important. --- spec/models/repository_spec.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spec/models/repository_spec.rb b/spec/models/repository_spec.rb index 9d5859f1476..a6973ea8fcb 100644 --- a/spec/models/repository_spec.rb +++ b/spec/models/repository_spec.rb @@ -100,4 +100,4 @@ describe Repository do it { expect(subject.data.lines[2]).to eq(" - Feature: Replace teams with group membership\n") } end end -end \ No newline at end of file +end -- cgit v1.2.1 From b1f4aaa5e753e6e7cdefd84226839123df59b382 Mon Sep 17 00:00:00 2001 From: Michael Chmielewski Date: Tue, 27 Oct 2015 21:16:56 -0400 Subject: Trying to incorporate suggestions from comments on Merge Request 1661 --- app/models/repository.rb | 9 +++++---- lib/gitlab/project_search_results.rb | 2 +- spec/models/repository_spec.rb | 4 ++-- 3 files changed, 8 insertions(+), 7 deletions(-) diff --git a/app/models/repository.rb b/app/models/repository.rb index 39451f7da7f..ed7ed9fd261 100644 --- a/app/models/repository.rb +++ b/app/models/repository.rb @@ -87,10 +87,11 @@ class Repository commits end - def commits_with_log_matching(query) - list = Gitlab::Git::Commit.where(repo: raw_repository, limit: 1000) - list = Commit.decorate(list, @project) if list.present? - list.select! { |c| c.message.match /#{query}/i } + def find_commits_with_matching_log(query) + # Limited to 1000 commits for now, could be parameterized? + args = %W(git log --pretty=%H --max-count 1000 --grep=#{query}) + + Gitlab::Popen.popen(args, path_to_repo) end def find_branch(name) diff --git a/lib/gitlab/project_search_results.rb b/lib/gitlab/project_search_results.rb index 3bf98699bcb..54389f7d662 100644 --- a/lib/gitlab/project_search_results.rb +++ b/lib/gitlab/project_search_results.rb @@ -77,7 +77,7 @@ module Gitlab end def commits - project.repository.commits_with_log_matching(query) + project.repository.find_commits_with_matching_log(query) end def limit_project_ids diff --git a/spec/models/repository_spec.rb b/spec/models/repository_spec.rb index a6973ea8fcb..26c92af31ed 100644 --- a/spec/models/repository_spec.rb +++ b/spec/models/repository_spec.rb @@ -26,8 +26,8 @@ describe Repository do it { is_expected.to eq('c1acaa58bbcbc3eafe538cb8274ba387047b69f8') } end - describe :commits_with_log_matching do - subject { repository.commits_with_log_matching('submodule').map{|k| k.id} } + describe :find_commits_with_matching_log do + subject { repository.find_commits_with_matching_log('submodule').map{|k| k.id} } it { is_expected.to include('5937ac0a7beb003549fc5fd26fc247adbce4a52e') } it { is_expected.to include('6f6d7e7ed97bb5f0054f2b1df789b39ca89b6ff9') } -- cgit v1.2.1 From 7b62791afc8e98f8ccd7d85dbae0cf2128883c13 Mon Sep 17 00:00:00 2001 From: Michael Chmielewski Date: Tue, 27 Oct 2015 23:24:43 -0400 Subject: Fixed method to use git log via Popen as recommended, and made output match test (and thus system) expectations. --- app/models/repository.rb | 7 ++++++- spec/models/repository_spec.rb | 2 +- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/app/models/repository.rb b/app/models/repository.rb index ed7ed9fd261..112ad05c188 100644 --- a/app/models/repository.rb +++ b/app/models/repository.rb @@ -91,7 +91,12 @@ class Repository # Limited to 1000 commits for now, could be parameterized? args = %W(git log --pretty=%H --max-count 1000 --grep=#{query}) - Gitlab::Popen.popen(args, path_to_repo) + git_log_results = Gitlab::Popen.popen(args, path_to_repo) + + # 1. Get result, which is 1-element array + # 2. Split on lines + # 3. Recreate array, but remove trailing newline characters on each element + git_log_results.first.lines.map{ |l| l.chomp } end def find_branch(name) diff --git a/spec/models/repository_spec.rb b/spec/models/repository_spec.rb index 26c92af31ed..17b5f28891b 100644 --- a/spec/models/repository_spec.rb +++ b/spec/models/repository_spec.rb @@ -27,7 +27,7 @@ describe Repository do end describe :find_commits_with_matching_log do - subject { repository.find_commits_with_matching_log('submodule').map{|k| k.id} } + subject { repository.find_commits_with_matching_log('submodule') } it { is_expected.to include('5937ac0a7beb003549fc5fd26fc247adbce4a52e') } it { is_expected.to include('6f6d7e7ed97bb5f0054f2b1df789b39ca89b6ff9') } -- cgit v1.2.1 From a0d0a0179134c16c84dfa18da9db78b375cd7cd0 Mon Sep 17 00:00:00 2001 From: Michael Chmielewski Date: Wed, 28 Oct 2015 22:12:22 -0400 Subject: Actually converted code to following suggestions. --- app/models/repository.rb | 9 +++------ spec/models/repository_spec.rb | 2 +- 2 files changed, 4 insertions(+), 7 deletions(-) diff --git a/app/models/repository.rb b/app/models/repository.rb index 112ad05c188..a0f2b3fb765 100644 --- a/app/models/repository.rb +++ b/app/models/repository.rb @@ -91,12 +91,9 @@ class Repository # Limited to 1000 commits for now, could be parameterized? args = %W(git log --pretty=%H --max-count 1000 --grep=#{query}) - git_log_results = Gitlab::Popen.popen(args, path_to_repo) - - # 1. Get result, which is 1-element array - # 2. Split on lines - # 3. Recreate array, but remove trailing newline characters on each element - git_log_results.first.lines.map{ |l| l.chomp } + git_log_results = Gitlab::Popen.popen(args, path_to_repo).first.lines.map{ |l| l.chomp } + commits = git_log_results.map{ |c| commit(c) } + commits end def find_branch(name) diff --git a/spec/models/repository_spec.rb b/spec/models/repository_spec.rb index 17b5f28891b..aedbfa04d88 100644 --- a/spec/models/repository_spec.rb +++ b/spec/models/repository_spec.rb @@ -27,7 +27,7 @@ describe Repository do end describe :find_commits_with_matching_log do - subject { repository.find_commits_with_matching_log('submodule') } + subject { repository.find_commits_with_matching_log('submodule').map{ |k| k.id } } it { is_expected.to include('5937ac0a7beb003549fc5fd26fc247adbce4a52e') } it { is_expected.to include('6f6d7e7ed97bb5f0054f2b1df789b39ca89b6ff9') } -- cgit v1.2.1 From 7fc95d805dd2a4b997bbc3ad24a1a3a7d64ef305 Mon Sep 17 00:00:00 2001 From: Yorick Peterse Date: Tue, 20 Oct 2015 16:56:29 +0200 Subject: Added index on services.template This column is queried when creating a new project, without an index this query would lead to a sequence scan. --- db/migrate/20151020145526_add_services_template_index.rb | 5 +++++ db/schema.rb | 1 + 2 files changed, 6 insertions(+) create mode 100644 db/migrate/20151020145526_add_services_template_index.rb diff --git a/db/migrate/20151020145526_add_services_template_index.rb b/db/migrate/20151020145526_add_services_template_index.rb new file mode 100644 index 00000000000..1b04f313565 --- /dev/null +++ b/db/migrate/20151020145526_add_services_template_index.rb @@ -0,0 +1,5 @@ +class AddServicesTemplateIndex < ActiveRecord::Migration + def change + add_index :services, :template + end +end diff --git a/db/schema.rb b/db/schema.rb index 4bde9f0b748..73fc83c3d6b 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -667,6 +667,7 @@ ActiveRecord::Schema.define(version: 20151026182941) do add_index "services", ["created_at", "id"], name: "index_services_on_created_at_and_id", using: :btree add_index "services", ["project_id"], name: "index_services_on_project_id", using: :btree + add_index "services", ["template"], name: "index_services_on_template", using: :btree create_table "snippets", force: true do |t| t.string "title" -- cgit v1.2.1 From 6369c992a6d9279f4aa38c60c350c966f3926df1 Mon Sep 17 00:00:00 2001 From: Yorick Peterse Date: Tue, 20 Oct 2015 17:44:15 +0200 Subject: Added benchmark for Projects::CreateService This benchmark currently runs at ~0.6 iterations per second and is unlikely to perform any better any time soon. --- .../services/projects/create_service_spec.rb | 28 ++++++++++++++++++++++ 1 file changed, 28 insertions(+) create mode 100644 spec/benchmarks/services/projects/create_service_spec.rb diff --git a/spec/benchmarks/services/projects/create_service_spec.rb b/spec/benchmarks/services/projects/create_service_spec.rb new file mode 100644 index 00000000000..25ed48c34fd --- /dev/null +++ b/spec/benchmarks/services/projects/create_service_spec.rb @@ -0,0 +1,28 @@ +require 'spec_helper' + +describe Projects::CreateService, benchmark: true do + describe '#execute' do + let(:user) { create(:user, :admin) } + + let(:group) do + group = create(:group) + + create(:group_member, group: group, user: user) + + group + end + + benchmark_subject do + name = SecureRandom.hex + service = described_class.new(user, + name: name, + path: name, + namespace_id: group.id, + visibility_level: Gitlab::VisibilityLevel::PUBLIC) + + service.execute + end + + it { is_expected.to iterate_per_second(0.5) } + end +end -- cgit v1.2.1 From 29b3ce56ac45afc2c4dcd7055b53d8c06ef9faf2 Mon Sep 17 00:00:00 2001 From: Yorick Peterse Date: Wed, 21 Oct 2015 16:19:05 +0200 Subject: Removed extra activity update for new projects When a project is created the last activity timestamp is already set so there's no need for another update. --- app/services/projects/create_service.rb | 2 -- 1 file changed, 2 deletions(-) diff --git a/app/services/projects/create_service.rb b/app/services/projects/create_service.rb index faf1ee008e7..5b84527eccf 100644 --- a/app/services/projects/create_service.rb +++ b/app/services/projects/create_service.rb @@ -94,8 +94,6 @@ module Projects @project.team << [current_user, :master, current_user] end - @project.update_column(:last_activity_at, @project.created_at) - if @project.import? @project.import_start end -- cgit v1.2.1 From 72ececfab18d4577fbd7e57d44b771576eb204bf Mon Sep 17 00:00:00 2001 From: Thirumal S Date: Fri, 30 Oct 2015 17:27:22 +0530 Subject: form-control class to select box --- app/views/profiles/notifications/_settings.html.haml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/views/profiles/notifications/_settings.html.haml b/app/views/profiles/notifications/_settings.html.haml index 2c85d2a9b2b..742c5c4b68d 100644 --- a/app/views/profiles/notifications/_settings.html.haml +++ b/app/views/profiles/notifications/_settings.html.haml @@ -14,4 +14,4 @@ = form_tag profile_notifications_path, method: :put, remote: true, class: 'update-notifications' do = hidden_field_tag :notification_type, type, id: dom_id(membership, 'notification_type') = hidden_field_tag :notification_id, membership.id, id: dom_id(membership, 'notification_id') - = select_tag :notification_level, options_for_select(Notification.options_with_labels, notification.level), class: 'trigger-submit' + = select_tag :notification_level, options_for_select(Notification.options_with_labels, notification.level), class: 'form-control trigger-submit' -- cgit v1.2.1 From 74416daa660a047d3a7cb00e11e1d775b4ea0937 Mon Sep 17 00:00:00 2001 From: Thirumal S Date: Fri, 30 Oct 2015 19:26:56 +0530 Subject: form group alignment issue fixed in webhook index page --- app/assets/stylesheets/pages/projects.scss | 4 ++++ app/views/projects/hooks/index.html.haml | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/app/assets/stylesheets/pages/projects.scss b/app/assets/stylesheets/pages/projects.scss index f7a22849003..b384e3fae6c 100644 --- a/app/assets/stylesheets/pages/projects.scss +++ b/app/assets/stylesheets/pages/projects.scss @@ -511,3 +511,7 @@ pre.light-well { margin-top: -1px; } } + +.form-control-padding-top { + padding-top: 10px; +} diff --git a/app/views/projects/hooks/index.html.haml b/app/views/projects/hooks/index.html.haml index 85dbfd67862..65e00b38ad4 100644 --- a/app/views/projects/hooks/index.html.haml +++ b/app/views/projects/hooks/index.html.haml @@ -19,7 +19,7 @@ = f.text_field :url, class: "form-control", placeholder: 'http://example.com/trigger-ci.json' .form-group = f.label :url, "Trigger", class: 'control-label' - .col-sm-10 + .col-sm-10.form-control-padding-top %div = f.check_box :push_events, class: 'pull-left' .prepend-left-20 -- cgit v1.2.1 From 31723eb9f0f9490d873a6ecddc897fef3ea1885c Mon Sep 17 00:00:00 2001 From: KON YUICHI Date: Sat, 31 Oct 2015 22:32:06 +0900 Subject: fix deprecated --- app/controllers/projects_controller.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/controllers/projects_controller.rb b/app/controllers/projects_controller.rb index 05c7d3de8bc..00d13a83ce8 100644 --- a/app/controllers/projects_controller.rb +++ b/app/controllers/projects_controller.rb @@ -1,7 +1,7 @@ class ProjectsController < ApplicationController include ExtractsPath - prepend_before_filter :render_go_import, only: [:show] + prepend_before_action :render_go_import, only: [:show] skip_before_action :authenticate_user!, only: [:show, :activity] before_action :project, except: [:new, :create] before_action :repository, except: [:new, :create] -- cgit v1.2.1 From c03da1caade637298ca96e59cea990b0827539c9 Mon Sep 17 00:00:00 2001 From: Kamil Trzcinski Date: Mon, 2 Nov 2015 14:44:06 +0100 Subject: Extend yml syntax for only and except to support specifying repository path --- CHANGELOG | 1 + app/models/ci/commit.rb | 2 +- doc/ci/yaml/README.md | 14 +- lib/ci/gitlab_ci_yaml_processor.rb | 64 +++--- spec/lib/ci/gitlab_ci_yaml_processor_spec.rb | 303 ++++++++++++++++++++------- 5 files changed, 273 insertions(+), 111 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index 6bec4f606e7..eec74e5c5f7 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -13,6 +13,7 @@ v 8.2.0 (unreleased) - Fix: Inability to reply to code comments in the MR view, if the MR comes from a fork - Use git follow flag for commits page when retrieve history for file or directory - Show merge request CI status on merge requests index page + - Extend yml syntax for only and except to support specifying repository path - Fix: 500 error returned if destroy request without HTTP referer (Kazuki Shimizu) - Remove deprecated CI events from project settings page - Use issue editor as cross reference comment author when issue is edited with a new mention. diff --git a/app/models/ci/commit.rb b/app/models/ci/commit.rb index 13437b2483f..e58420d82d4 100644 --- a/app/models/ci/commit.rb +++ b/app/models/ci/commit.rb @@ -187,7 +187,7 @@ module Ci end def config_processor - @config_processor ||= Ci::GitlabCiYamlProcessor.new(ci_yaml_file) + @config_processor ||= Ci::GitlabCiYamlProcessor.new(ci_yaml_file, gl_project.path_with_namespace) rescue Ci::GitlabCiYamlProcessor::ValidationError => e save_yaml_error(e.message) nil diff --git a/doc/ci/yaml/README.md b/doc/ci/yaml/README.md index ea8f72bc135..0c1d8cfdff6 100644 --- a/doc/ci/yaml/README.md +++ b/doc/ci/yaml/README.md @@ -169,7 +169,7 @@ This are two parameters that allow for setting a refs policy to limit when jobs There are a few rules that apply to usage of refs policy: -1. `only` and `except` are exclusive. If both `only` and `except` are defined in job specification only `only` is taken into account. +1. `only` and `except` are inclusive. If both `only` and `except` are defined in job specification the ref is filtered by `only` and `except`. 1. `only` and `except` allow for using the regexp expressions. 1. `only` and `except` allow for using special keywords: `branches` and `tags`. These names can be used for example to exclude all tags and all branches. @@ -182,6 +182,18 @@ job: - branches # use special keyword ``` +1. `only` and `except` allow for specify repository path to filter jobs for forks. +The repository path can be used to have jobs executed only for parent repository. + +```yaml +job: + only: + - branches@gitlab-org/gitlab-ce + except: + - master@gitlab-org/gitlab-ce +``` +The above will run `job` for all branches, except master on `gitlab-org/gitlab-ce` repository only. + ### tags `tags` is used to select specific runners from the list of all runners that are allowed to run this project. diff --git a/lib/ci/gitlab_ci_yaml_processor.rb b/lib/ci/gitlab_ci_yaml_processor.rb index efcd2faffc7..0f57a4f53ab 100644 --- a/lib/ci/gitlab_ci_yaml_processor.rb +++ b/lib/ci/gitlab_ci_yaml_processor.rb @@ -7,10 +7,11 @@ module Ci ALLOWED_YAML_KEYS = [:before_script, :image, :services, :types, :stages, :variables] ALLOWED_JOB_KEYS = [:tags, :script, :only, :except, :type, :image, :services, :allow_failure, :type, :stage, :when] - attr_reader :before_script, :image, :services, :variables + attr_reader :before_script, :image, :services, :variables, :path - def initialize(config) + def initialize(config, path = nil) @config = YAML.load(config) + @path = path unless @config.is_a? Hash raise ValidationError, "YAML should be a hash" @@ -63,26 +64,6 @@ module Ci end end - def process?(only_params, except_params, ref, tag) - return true if only_params.nil? && except_params.nil? - - if only_params - return true if tag && only_params.include?("tags") - return true if !tag && only_params.include?("branches") - - only_params.find do |pattern| - match_ref?(pattern, ref) - end - else - return false if tag && except_params.include?("tags") - return false if !tag && except_params.include?("branches") - - except_params.each do |pattern| - return false if match_ref?(pattern, ref) - end - end - end - def build_job(name, job) { stage_idx: stages.index(job[:stage]), @@ -101,14 +82,6 @@ module Ci } end - def match_ref?(pattern, ref) - if pattern.first == "/" && pattern.last == "/" - Regexp.new(pattern[1...-1]) =~ ref - else - pattern == ref - end - end - def normalize_script(script) if script.is_a? Array script.join("\n") @@ -208,5 +181,36 @@ module Ci def validate_string(value) value.is_a?(String) || value.is_a?(Symbol) end + + def process?(only_params, except_params, ref, tag) + if only_params.present? + return false unless matching?(only_params, ref, tag) + end + + if except_params.present? + return false if matching?(except_params, ref, tag) + end + + true + end + + def matching?(patterns, ref, tag) + patterns.any? do |pattern| + match_ref?(pattern, ref, tag) + end + end + + def match_ref?(pattern, ref, tag) + pattern, path = pattern.split('@', 2) + return false if path && path != self.path + return true if tag && pattern == 'tags' + return true if !tag && pattern == 'branches' + + if pattern.first == "/" && pattern.last == "/" + Regexp.new(pattern[1...-1]) =~ ref + else + pattern == ref + end + end end end diff --git a/spec/lib/ci/gitlab_ci_yaml_processor_spec.rb b/spec/lib/ci/gitlab_ci_yaml_processor_spec.rb index abdb6b89ac5..a141a459ba3 100644 --- a/spec/lib/ci/gitlab_ci_yaml_processor_spec.rb +++ b/spec/lib/ci/gitlab_ci_yaml_processor_spec.rb @@ -2,7 +2,8 @@ require 'spec_helper' module Ci describe GitlabCiYamlProcessor do - + let(:path) { 'path' } + describe "#builds_for_ref" do let(:type) { 'test' } @@ -12,7 +13,7 @@ module Ci rspec: { script: "rspec" } }) - config_processor = GitlabCiYamlProcessor.new(config) + config_processor = GitlabCiYamlProcessor.new(config, path) expect(config_processor.builds_for_stage_and_ref(type, "master").size).to eq(1) expect(config_processor.builds_for_stage_and_ref(type, "master").first).to eq({ @@ -28,78 +29,222 @@ module Ci when: "on_success" }) end + + describe :only do + it "does not return builds if only has another branch" do + config = YAML.dump({ + before_script: ["pwd"], + rspec: { script: "rspec", only: ["deploy"] } + }) - it "does not return builds if only has another branch" do - config = YAML.dump({ - before_script: ["pwd"], - rspec: { script: "rspec", only: ["deploy"] } - }) + config_processor = GitlabCiYamlProcessor.new(config, path) - config_processor = GitlabCiYamlProcessor.new(config) + expect(config_processor.builds_for_stage_and_ref(type, "master").size).to eq(0) + end - expect(config_processor.builds_for_stage_and_ref(type, "master").size).to eq(0) - end + it "does not return builds if only has regexp with another branch" do + config = YAML.dump({ + before_script: ["pwd"], + rspec: { script: "rspec", only: ["/^deploy$/"] } + }) - it "does not return builds if only has regexp with another branch" do - config = YAML.dump({ - before_script: ["pwd"], - rspec: { script: "rspec", only: ["/^deploy$/"] } - }) + config_processor = GitlabCiYamlProcessor.new(config, path) - config_processor = GitlabCiYamlProcessor.new(config) + expect(config_processor.builds_for_stage_and_ref(type, "master").size).to eq(0) + end - expect(config_processor.builds_for_stage_and_ref(type, "master").size).to eq(0) - end + it "returns builds if only has specified this branch" do + config = YAML.dump({ + before_script: ["pwd"], + rspec: { script: "rspec", only: ["master"] } + }) - it "returns builds if only has specified this branch" do - config = YAML.dump({ - before_script: ["pwd"], - rspec: { script: "rspec", only: ["master"] } - }) + config_processor = GitlabCiYamlProcessor.new(config, path) - config_processor = GitlabCiYamlProcessor.new(config) + expect(config_processor.builds_for_stage_and_ref(type, "master").size).to eq(1) + end - expect(config_processor.builds_for_stage_and_ref(type, "master").size).to eq(1) - end + it "returns builds if only has a list of branches including specified" do + config = YAML.dump({ + before_script: ["pwd"], + rspec: { script: "rspec", type: type, only: ["master", "deploy"] } + }) - it "does not build tags" do - config = YAML.dump({ - before_script: ["pwd"], - rspec: { script: "rspec", except: ["tags"] } - }) + config_processor = GitlabCiYamlProcessor.new(config, path) - config_processor = GitlabCiYamlProcessor.new(config) + expect(config_processor.builds_for_stage_and_ref(type, "deploy").size).to eq(1) + end - expect(config_processor.builds_for_stage_and_ref(type, "0-1", true).size).to eq(0) - end + it "returns builds if only has a branches keyword specified" do + config = YAML.dump({ + before_script: ["pwd"], + rspec: { script: "rspec", type: type, only: ["branches"] } + }) - it "returns builds if only has a list of branches including specified" do - config = YAML.dump({ - before_script: ["pwd"], - rspec: { script: "rspec", type: type, only: ["master", "deploy"] } - }) + config_processor = GitlabCiYamlProcessor.new(config, path) + + expect(config_processor.builds_for_stage_and_ref(type, "deploy").size).to eq(1) + end + + it "does not return builds if only has a tags keyword" do + config = YAML.dump({ + before_script: ["pwd"], + rspec: { script: "rspec", type: type, only: ["tags"] } + }) + + config_processor = GitlabCiYamlProcessor.new(config, path) + + expect(config_processor.builds_for_stage_and_ref(type, "deploy").size).to eq(0) + end + + it "returns builds if only has current repository path" do + config = YAML.dump({ + before_script: ["pwd"], + rspec: { script: "rspec", type: type, only: ["branches@path"] } + }) + + config_processor = GitlabCiYamlProcessor.new(config, path) + + expect(config_processor.builds_for_stage_and_ref(type, "deploy").size).to eq(1) + end + + it "does not return builds if only has different repository path" do + config = YAML.dump({ + before_script: ["pwd"], + rspec: { script: "rspec", type: type, only: ["branches@fork"] } + }) + + config_processor = GitlabCiYamlProcessor.new(config, path) + + expect(config_processor.builds_for_stage_and_ref(type, "deploy").size).to eq(0) + end + + it "returns build only for specified type" do + + config = YAML.dump({ + before_script: ["pwd"], + build: { script: "build", type: "build", only: ["master", "deploy"] }, + rspec: { script: "rspec", type: type, only: ["master", "deploy"] }, + staging: { script: "deploy", type: "deploy", only: ["master", "deploy"] }, + production: { script: "deploy", type: "deploy", only: ["master", "deploy"] }, + production: { script: "deploy", type: "deploy", only: ["master@path", "deploy"] }, + }) - config_processor = GitlabCiYamlProcessor.new(config) + config_processor = GitlabCiYamlProcessor.new(config, path) - expect(config_processor.builds_for_stage_and_ref(type, "deploy").size).to eq(1) + expect(config_processor.builds_for_stage_and_ref("production", "deploy").size).to eq(0) + expect(config_processor.builds_for_stage_and_ref(type, "deploy").size).to eq(1) + expect(config_processor.builds_for_stage_and_ref("deploy", "deploy").size).to eq(2) + end end - it "returns build only for specified type" do + describe :except do + it "returns builds if except has another branch" do + config = YAML.dump({ + before_script: ["pwd"], + rspec: { script: "rspec", except: ["deploy"] } + }) - config = YAML.dump({ - before_script: ["pwd"], - build: { script: "build", type: "build", only: ["master", "deploy"] }, - rspec: { script: "rspec", type: type, only: ["master", "deploy"] }, - staging: { script: "deploy", type: "deploy", only: ["master", "deploy"] }, - production: { script: "deploy", type: "deploy", only: ["master", "deploy"] }, - }) + config_processor = GitlabCiYamlProcessor.new(config, path) - config_processor = GitlabCiYamlProcessor.new(config) + expect(config_processor.builds_for_stage_and_ref(type, "master").size).to eq(1) + end + + it "returns builds if except has regexp with another branch" do + config = YAML.dump({ + before_script: ["pwd"], + rspec: { script: "rspec", except: ["/^deploy$/"] } + }) + + config_processor = GitlabCiYamlProcessor.new(config, path) + + expect(config_processor.builds_for_stage_and_ref(type, "master").size).to eq(1) + end - expect(config_processor.builds_for_stage_and_ref("production", "deploy").size).to eq(0) - expect(config_processor.builds_for_stage_and_ref(type, "deploy").size).to eq(1) - expect(config_processor.builds_for_stage_and_ref("deploy", "deploy").size).to eq(2) + it "does not return builds if except has specified this branch" do + config = YAML.dump({ + before_script: ["pwd"], + rspec: { script: "rspec", except: ["master"] } + }) + + config_processor = GitlabCiYamlProcessor.new(config, path) + + expect(config_processor.builds_for_stage_and_ref(type, "master").size).to eq(0) + end + + it "does not return builds if except has a list of branches including specified" do + config = YAML.dump({ + before_script: ["pwd"], + rspec: { script: "rspec", type: type, except: ["master", "deploy"] } + }) + + config_processor = GitlabCiYamlProcessor.new(config, path) + + expect(config_processor.builds_for_stage_and_ref(type, "deploy").size).to eq(0) + end + + it "does not return builds if except has a branches keyword specified" do + config = YAML.dump({ + before_script: ["pwd"], + rspec: { script: "rspec", type: type, except: ["branches"] } + }) + + config_processor = GitlabCiYamlProcessor.new(config, path) + + expect(config_processor.builds_for_stage_and_ref(type, "deploy").size).to eq(0) + end + + it "returns builds if except has a tags keyword" do + config = YAML.dump({ + before_script: ["pwd"], + rspec: { script: "rspec", type: type, except: ["tags"] } + }) + + config_processor = GitlabCiYamlProcessor.new(config, path) + + expect(config_processor.builds_for_stage_and_ref(type, "deploy").size).to eq(1) + end + + it "does not return builds if except has current repository path" do + config = YAML.dump({ + before_script: ["pwd"], + rspec: { script: "rspec", type: type, except: ["branches@path"] } + }) + + config_processor = GitlabCiYamlProcessor.new(config, path) + + expect(config_processor.builds_for_stage_and_ref(type, "deploy").size).to eq(0) + end + + it "returns builds if except has different repository path" do + config = YAML.dump({ + before_script: ["pwd"], + rspec: { script: "rspec", type: type, except: ["branches@fork"] } + }) + + config_processor = GitlabCiYamlProcessor.new(config, path) + + expect(config_processor.builds_for_stage_and_ref(type, "deploy").size).to eq(1) + end + + it "returns build except specified type" do + config = YAML.dump({ + before_script: ["pwd"], + build: { script: "build", type: "build", except: ["master", "deploy"] }, + rspec: { script: "rspec", type: type, except: ["master", "deploy", "test@fork"] }, + staging: { script: "deploy", type: "deploy", except: ["master", "deploy"] }, + production: { script: "deploy", type: "deploy", except: ["master", "deploy"] }, + production: { script: "deploy", type: "deploy", except: ["master@path", "deploy"] }, + }) + + config_processor = GitlabCiYamlProcessor.new(config, path) + + expect(config_processor.builds_for_stage_and_ref("production", "deploy").size).to eq(0) + expect(config_processor.builds_for_stage_and_ref(type, "test").size).to eq(1) + expect(config_processor.builds_for_stage_and_ref("deploy", "master").size).to eq(2) + end end + end describe "Image and service handling" do @@ -111,7 +256,7 @@ module Ci rspec: { script: "rspec" } }) - config_processor = GitlabCiYamlProcessor.new(config) + config_processor = GitlabCiYamlProcessor.new(config, path) expect(config_processor.builds_for_stage_and_ref("test", "master").size).to eq(1) expect(config_processor.builds_for_stage_and_ref("test", "master").first).to eq({ @@ -139,7 +284,7 @@ module Ci rspec: { image: "ruby:2.5", services: ["postgresql"], script: "rspec" } }) - config_processor = GitlabCiYamlProcessor.new(config) + config_processor = GitlabCiYamlProcessor.new(config, path) expect(config_processor.builds_for_stage_and_ref("test", "master").size).to eq(1) expect(config_processor.builds_for_stage_and_ref("test", "master").first).to eq({ @@ -172,7 +317,7 @@ module Ci rspec: { script: "rspec" } }) - config_processor = GitlabCiYamlProcessor.new(config) + config_processor = GitlabCiYamlProcessor.new(config, path) expect(config_processor.variables).to eq(variables) end end @@ -184,7 +329,7 @@ module Ci rspec: { script: "rspec", when: when_state } }) - config_processor = GitlabCiYamlProcessor.new(config) + config_processor = GitlabCiYamlProcessor.new(config, path) builds = config_processor.builds_for_stage_and_ref("test", "master") expect(builds.size).to eq(1) expect(builds.first[:when]).to eq(when_state) @@ -200,154 +345,154 @@ module Ci it "returns errors if tags parameter is invalid" do config = YAML.dump({ rspec: { script: "test", tags: "mysql" } }) expect do - GitlabCiYamlProcessor.new(config) + GitlabCiYamlProcessor.new(config, path) end.to raise_error(GitlabCiYamlProcessor::ValidationError, "rspec job: tags parameter should be an array of strings") end it "returns errors if before_script parameter is invalid" do config = YAML.dump({ before_script: "bundle update", rspec: { script: "test" } }) expect do - GitlabCiYamlProcessor.new(config) + GitlabCiYamlProcessor.new(config, path) end.to raise_error(GitlabCiYamlProcessor::ValidationError, "before_script should be an array of strings") end it "returns errors if image parameter is invalid" do config = YAML.dump({ image: ["test"], rspec: { script: "test" } }) expect do - GitlabCiYamlProcessor.new(config) + GitlabCiYamlProcessor.new(config, path) end.to raise_error(GitlabCiYamlProcessor::ValidationError, "image should be a string") end it "returns errors if job name is blank" do config = YAML.dump({ '' => { script: "test" } }) expect do - GitlabCiYamlProcessor.new(config) + GitlabCiYamlProcessor.new(config, path) end.to raise_error(GitlabCiYamlProcessor::ValidationError, "job name should be non-empty string") end it "returns errors if job name is non-string" do config = YAML.dump({ 10 => { script: "test" } }) expect do - GitlabCiYamlProcessor.new(config) + GitlabCiYamlProcessor.new(config, path) end.to raise_error(GitlabCiYamlProcessor::ValidationError, "job name should be non-empty string") end it "returns errors if job image parameter is invalid" do config = YAML.dump({ rspec: { script: "test", image: ["test"] } }) expect do - GitlabCiYamlProcessor.new(config) + GitlabCiYamlProcessor.new(config, path) end.to raise_error(GitlabCiYamlProcessor::ValidationError, "rspec job: image should be a string") end it "returns errors if services parameter is not an array" do config = YAML.dump({ services: "test", rspec: { script: "test" } }) expect do - GitlabCiYamlProcessor.new(config) + GitlabCiYamlProcessor.new(config, path) end.to raise_error(GitlabCiYamlProcessor::ValidationError, "services should be an array of strings") end it "returns errors if services parameter is not an array of strings" do config = YAML.dump({ services: [10, "test"], rspec: { script: "test" } }) expect do - GitlabCiYamlProcessor.new(config) + GitlabCiYamlProcessor.new(config, path) end.to raise_error(GitlabCiYamlProcessor::ValidationError, "services should be an array of strings") end it "returns errors if job services parameter is not an array" do config = YAML.dump({ rspec: { script: "test", services: "test" } }) expect do - GitlabCiYamlProcessor.new(config) + GitlabCiYamlProcessor.new(config, path) end.to raise_error(GitlabCiYamlProcessor::ValidationError, "rspec job: services should be an array of strings") end it "returns errors if job services parameter is not an array of strings" do config = YAML.dump({ rspec: { script: "test", services: [10, "test"] } }) expect do - GitlabCiYamlProcessor.new(config) + GitlabCiYamlProcessor.new(config, path) end.to raise_error(GitlabCiYamlProcessor::ValidationError, "rspec job: services should be an array of strings") end it "returns errors if there are unknown parameters" do config = YAML.dump({ extra: "bundle update" }) expect do - GitlabCiYamlProcessor.new(config) + GitlabCiYamlProcessor.new(config, path) end.to raise_error(GitlabCiYamlProcessor::ValidationError, "Unknown parameter: extra") end it "returns errors if there are unknown parameters that are hashes, but doesn't have a script" do config = YAML.dump({ extra: { services: "test" } }) expect do - GitlabCiYamlProcessor.new(config) + GitlabCiYamlProcessor.new(config, path) end.to raise_error(GitlabCiYamlProcessor::ValidationError, "Unknown parameter: extra") end it "returns errors if there is no any jobs defined" do config = YAML.dump({ before_script: ["bundle update"] }) expect do - GitlabCiYamlProcessor.new(config) + GitlabCiYamlProcessor.new(config, path) end.to raise_error(GitlabCiYamlProcessor::ValidationError, "Please define at least one job") end it "returns errors if job allow_failure parameter is not an boolean" do config = YAML.dump({ rspec: { script: "test", allow_failure: "string" } }) expect do - GitlabCiYamlProcessor.new(config) + GitlabCiYamlProcessor.new(config, path) end.to raise_error(GitlabCiYamlProcessor::ValidationError, "rspec job: allow_failure parameter should be an boolean") end it "returns errors if job stage is not a string" do config = YAML.dump({ rspec: { script: "test", type: 1, allow_failure: "string" } }) expect do - GitlabCiYamlProcessor.new(config) + GitlabCiYamlProcessor.new(config, path) end.to raise_error(GitlabCiYamlProcessor::ValidationError, "rspec job: stage parameter should be build, test, deploy") end it "returns errors if job stage is not a pre-defined stage" do config = YAML.dump({ rspec: { script: "test", type: "acceptance", allow_failure: "string" } }) expect do - GitlabCiYamlProcessor.new(config) + GitlabCiYamlProcessor.new(config, path) end.to raise_error(GitlabCiYamlProcessor::ValidationError, "rspec job: stage parameter should be build, test, deploy") end it "returns errors if job stage is not a defined stage" do config = YAML.dump({ types: ["build", "test"], rspec: { script: "test", type: "acceptance", allow_failure: "string" } }) expect do - GitlabCiYamlProcessor.new(config) + GitlabCiYamlProcessor.new(config, path) end.to raise_error(GitlabCiYamlProcessor::ValidationError, "rspec job: stage parameter should be build, test") end it "returns errors if stages is not an array" do config = YAML.dump({ types: "test", rspec: { script: "test" } }) expect do - GitlabCiYamlProcessor.new(config) + GitlabCiYamlProcessor.new(config, path) end.to raise_error(GitlabCiYamlProcessor::ValidationError, "stages should be an array of strings") end it "returns errors if stages is not an array of strings" do config = YAML.dump({ types: [true, "test"], rspec: { script: "test" } }) expect do - GitlabCiYamlProcessor.new(config) + GitlabCiYamlProcessor.new(config, path) end.to raise_error(GitlabCiYamlProcessor::ValidationError, "stages should be an array of strings") end it "returns errors if variables is not a map" do config = YAML.dump({ variables: "test", rspec: { script: "test" } }) expect do - GitlabCiYamlProcessor.new(config) + GitlabCiYamlProcessor.new(config, path) end.to raise_error(GitlabCiYamlProcessor::ValidationError, "variables should be a map of key-valued strings") end it "returns errors if variables is not a map of key-valued strings" do config = YAML.dump({ variables: { test: false }, rspec: { script: "test" } }) expect do - GitlabCiYamlProcessor.new(config) + GitlabCiYamlProcessor.new(config, path) end.to raise_error(GitlabCiYamlProcessor::ValidationError, "variables should be a map of key-valued strings") end it "returns errors if job when is not on_success, on_failure or always" do config = YAML.dump({ rspec: { script: "test", when: 1 } }) expect do - GitlabCiYamlProcessor.new(config) + GitlabCiYamlProcessor.new(config, path) end.to raise_error(GitlabCiYamlProcessor::ValidationError, "rspec job: when parameter should be on_success, on_failure or always") end end -- cgit v1.2.1 From 2dec5ec99042cd8da6c127d4bcfa7f5f84ef94eb Mon Sep 17 00:00:00 2001 From: Jeroen van Baarsen Date: Wed, 28 Oct 2015 17:39:22 +0100 Subject: Only redirect to homepage url when its not the root url It was possible to create an infi redirect when the user set up the `home_page_url` to redirect to the main URL of the gitlab instance. This fix makes sure this redirect is not possible. Fixes !1020 Signed-off-by: Jeroen van Baarsen --- app/controllers/application_controller.rb | 22 +++++++++++++++------- 1 file changed, 15 insertions(+), 7 deletions(-) diff --git a/app/controllers/application_controller.rb b/app/controllers/application_controller.rb index 1b0609e279e..0d182e8eb04 100644 --- a/app/controllers/application_controller.rb +++ b/app/controllers/application_controller.rb @@ -59,13 +59,8 @@ class ApplicationController < ActionController::Base end def authenticate_user!(*args) - # If user is not signed-in and tries to access root_path - redirect him to landing page - # Don't redirect to the default URL to prevent endless redirections - if current_application_settings.home_page_url.present? && - current_application_settings.home_page_url.chomp('/') != Gitlab.config.gitlab['url'].chomp('/') - if current_user.nil? && root_path == request.path - redirect_to current_application_settings.home_page_url and return - end + if redirect_to_home_page_url? + redirect_to current_application_settings.home_page_url and return end super(*args) @@ -346,4 +341,17 @@ class ApplicationController < ActionController::Base def git_import_enabled? current_application_settings.import_sources.include?('git') end + + def redirect_to_home_page_url? + # If user is not signed-in and tries to access root_path - redirect him to landing page + # Don't redirect to the default URL to prevent endless redirections + return false unless current_application_settings.home_page_url.present? + + home_page_url = current_application_settings.home_page_url.chomp('/') + root_urls = [Gitlab.config.gitlab['url'].chomp('/'), root_url.chomp('/')] + + return false if root_urls.include?(home_page_url) + + current_user.nil? && root_path == request.path + end end -- cgit v1.2.1 From 1056c9d2d2481ee4fe3a55e0d9acb3691c1a019c Mon Sep 17 00:00:00 2001 From: Kamil Trzcinski Date: Mon, 2 Nov 2015 15:49:54 +0100 Subject: Spelling --- doc/ci/yaml/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/ci/yaml/README.md b/doc/ci/yaml/README.md index 0c1d8cfdff6..d117a2969be 100644 --- a/doc/ci/yaml/README.md +++ b/doc/ci/yaml/README.md @@ -192,7 +192,7 @@ job: except: - master@gitlab-org/gitlab-ce ``` -The above will run `job` for all branches, except master on `gitlab-org/gitlab-ce` repository only. +The above will run `job` for all branches on `gitlab-org/gitlab-ce`, except master . ### tags `tags` is used to select specific runners from the list of all runners that are allowed to run this project. -- cgit v1.2.1 From e032a7288f4103a6d5980da6af4040bc9271bd99 Mon Sep 17 00:00:00 2001 From: Jacob Vosmaer Date: Mon, 2 Nov 2015 16:02:47 +0100 Subject: Spread out runner contacted_at updates --- lib/ci/api/helpers.rb | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/lib/ci/api/helpers.rb b/lib/ci/api/helpers.rb index e602cda81d6..7e4986b6af3 100644 --- a/lib/ci/api/helpers.rb +++ b/lib/ci/api/helpers.rb @@ -16,7 +16,9 @@ module Ci end def update_runner_last_contact - if current_runner.contacted_at.nil? || Time.now - current_runner.contacted_at >= UPDATE_RUNNER_EVERY + # Use a random threshold to prevent beating DB updates + contacted_at_max_age = UPDATE_RUNNER_EVERY + Random.rand(UPDATE_RUNNER_EVERY) + if current_runner.contacted_at.nil? || Time.now - current_runner.contacted_at >= contacted_at_max_age current_runner.update_attributes(contacted_at: Time.now) end end -- cgit v1.2.1 From 810c91fe35db6a83c9c517e03d07dc1795922646 Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Mon, 2 Nov 2015 16:39:24 +0100 Subject: Refactor search by commits message Signed-off-by: Dmitriy Zaporozhets --- CHANGELOG | 4 +--- app/assets/stylesheets/pages/commits.scss | 2 ++ app/models/repository.rb | 6 +++--- app/views/search/_category.html.haml | 2 +- app/views/search/results/_commits.html.haml | 32 +---------------------------- lib/gitlab/project_search_results.rb | 2 +- spec/models/repository_spec.rb | 4 ++-- 7 files changed, 11 insertions(+), 41 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index b573d40317e..78e0891e822 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -14,6 +14,7 @@ v 8.2.0 (unreleased) - Fix: 500 error returned if destroy request without HTTP referer (Kazuki Shimizu) - Remove deprecated CI events from project settings page - Use issue editor as cross reference comment author when issue is edited with a new mention. + - Include commit logs in project search v 8.1.1 - Fix cloning Wiki repositories via HTTP (Stan Hu) @@ -29,9 +30,6 @@ v 8.1.0 - Ensure MySQL CI limits DB migrations occur after the fields have been created (Stan Hu) - Fix duplicate repositories in GitHub import page (Stan Hu) - Redirect to a default path if HTTP_REFERER is not set (Stan Hu) - - Include commit logs in project search - -v 8.1.0 (unreleased) - Send an email to admin email when a user is reported for spam (Jonathan Rochkind) - Show notifications button when user is member of group rather than project (Grzegorz Bizon) - Fix bug preventing mentioned issued from being closed when MR is merged using fast-forward merge. diff --git a/app/assets/stylesheets/pages/commits.scss b/app/assets/stylesheets/pages/commits.scss index 4e121b95d13..e485487bcfd 100644 --- a/app/assets/stylesheets/pages/commits.scss +++ b/app/assets/stylesheets/pages/commits.scss @@ -33,6 +33,8 @@ } li.commit { + list-style: none; + .commit-row-title { font-size: $list-font-size; line-height: 20px; diff --git a/app/models/repository.rb b/app/models/repository.rb index a0f2b3fb765..c6d904339e4 100644 --- a/app/models/repository.rb +++ b/app/models/repository.rb @@ -87,12 +87,12 @@ class Repository commits end - def find_commits_with_matching_log(query) + def find_commits_by_message(query) # Limited to 1000 commits for now, could be parameterized? args = %W(git log --pretty=%H --max-count 1000 --grep=#{query}) - git_log_results = Gitlab::Popen.popen(args, path_to_repo).first.lines.map{ |l| l.chomp } - commits = git_log_results.map{ |c| commit(c) } + git_log_results = Gitlab::Popen.popen(args, path_to_repo).first.lines.map(&:chomp) + commits = git_log_results.map { |c| commit(c) } commits end diff --git a/app/views/search/_category.html.haml b/app/views/search/_category.html.haml index ef43f727d8b..481451edb23 100644 --- a/app/views/search/_category.html.haml +++ b/app/views/search/_category.html.haml @@ -46,7 +46,7 @@ = link_to search_filter_path(scope: 'commits') do = icon('history fw') %span - Commit Logs + Commits %span.badge = @search_results.commits_count diff --git a/app/views/search/results/_commits.html.haml b/app/views/search/results/_commits.html.haml index 8076174e59d..7cff694350f 100644 --- a/app/views/search/results/_commits.html.haml +++ b/app/views/search/results/_commits.html.haml @@ -1,32 +1,2 @@ .search-result-row - .commits-row-title - %strong.str-truncated - = link_to commits.title, namespace_project_commit_path(@project.namespace, @project, commits.id), class: "commit_short_id" - - .pull-right - = link_to commits.short_id, namespace_project_commit_path(@project.namespace, @project, commits.id), class: "commit_short_id" - - .notes_count - - if @note_counts - - note_count = @note_counts.fetch(commits.id, 0) - - else - - notes = commits.notes - - note_count = notes.user.count - - - if note_count > 0 - %span.light - %i.fa.fa-comments - = note_count - - - if commits.description? - .commits-row-description - %pre - = preserve(gfm(escape_once(commits.description))) - - .commits-row-info - = commit_author_link(commits, avatar: true, size: 24) - authored - .committed_ago - #{time_ago_with_tooltip(commits.committed_date)}   - = link_to_browse_code(@project, commits) - %br + = render 'projects/commits/commit', project: @project, commit: commits diff --git a/lib/gitlab/project_search_results.rb b/lib/gitlab/project_search_results.rb index 54389f7d662..c873ef3771e 100644 --- a/lib/gitlab/project_search_results.rb +++ b/lib/gitlab/project_search_results.rb @@ -77,7 +77,7 @@ module Gitlab end def commits - project.repository.find_commits_with_matching_log(query) + project.repository.find_commits_by_message(query) end def limit_project_ids diff --git a/spec/models/repository_spec.rb b/spec/models/repository_spec.rb index aedbfa04d88..319fa0a7c8d 100644 --- a/spec/models/repository_spec.rb +++ b/spec/models/repository_spec.rb @@ -26,8 +26,8 @@ describe Repository do it { is_expected.to eq('c1acaa58bbcbc3eafe538cb8274ba387047b69f8') } end - describe :find_commits_with_matching_log do - subject { repository.find_commits_with_matching_log('submodule').map{ |k| k.id } } + describe :find_commits_by_message do + subject { repository.find_commits_by_message('submodule').map{ |k| k.id } } it { is_expected.to include('5937ac0a7beb003549fc5fd26fc247adbce4a52e') } it { is_expected.to include('6f6d7e7ed97bb5f0054f2b1df789b39ca89b6ff9') } -- cgit v1.2.1 From 63cafdb8e5f9481539beaf2b6eac11cf8148daf1 Mon Sep 17 00:00:00 2001 From: Jacob Vosmaer Date: Mon, 2 Nov 2015 17:04:28 +0100 Subject: Add changelog entry for contacted_at --- CHANGELOG | 3 +++ 1 file changed, 3 insertions(+) diff --git a/CHANGELOG b/CHANGELOG index 6bec4f606e7..b67f010c6a0 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -17,6 +17,9 @@ v 8.2.0 (unreleased) - Remove deprecated CI events from project settings page - Use issue editor as cross reference comment author when issue is edited with a new mention. +v 8.1.3 + - Spread out runner contacted_at updates + v 8.1.1 - Fix cloning Wiki repositories via HTTP (Stan Hu) - Add migration to remove satellites directory -- cgit v1.2.1 From 60c5b52ee906639e8bc0408a4a63d50862580fc8 Mon Sep 17 00:00:00 2001 From: Robert Speicher Date: Mon, 2 Nov 2015 15:04:43 -0500 Subject: Explicitly require backup/files --- lib/backup/builds.rb | 2 ++ lib/backup/uploads.rb | 2 ++ 2 files changed, 4 insertions(+) diff --git a/lib/backup/builds.rb b/lib/backup/builds.rb index 800f30c2144..635967f4bd4 100644 --- a/lib/backup/builds.rb +++ b/lib/backup/builds.rb @@ -1,3 +1,5 @@ +require 'backup/files' + module Backup class Builds < Files def initialize diff --git a/lib/backup/uploads.rb b/lib/backup/uploads.rb index 0a0ec564ba4..9261f77f3c9 100644 --- a/lib/backup/uploads.rb +++ b/lib/backup/uploads.rb @@ -1,3 +1,5 @@ +require 'backup/files' + module Backup class Uploads < Files -- cgit v1.2.1 From f61aa9acdc54306f22bbf4209bdae75b35d7df0c Mon Sep 17 00:00:00 2001 From: Takuya Noguchi Date: Tue, 3 Nov 2015 14:01:27 +0900 Subject: Update links in CI docs after GitLab 8.1 --- doc/ci/examples/README.md | 6 +++--- doc/ci/examples/test-and-deploy-python-application-to-heroku.md | 2 +- doc/ci/examples/test-and-deploy-ruby-application-to-heroku.md | 4 ++-- doc/ci/examples/test-clojure-application.md | 4 ++-- 4 files changed, 8 insertions(+), 8 deletions(-) diff --git a/doc/ci/examples/README.md b/doc/ci/examples/README.md index c8122fc63b3..1cf41aea391 100644 --- a/doc/ci/examples/README.md +++ b/doc/ci/examples/README.md @@ -1,5 +1,5 @@ # Build script examples -+ [Test and deploy Ruby applications to Heroku](test-and-deploy-ruby-application-to-heroku.md) -+ [Test and deploy Python applications to Heroku](test-and-deploy-python-application-to-heroku.md) -+ [Test Clojure applications](test-clojure-application.md) ++ [Test and deploy a Ruby application to Heroku](test-and-deploy-ruby-application-to-heroku.md) ++ [Test and deploy a Python application to Heroku](test-and-deploy-python-application-to-heroku.md) ++ [Test a Clojure application](test-clojure-application.md) diff --git a/doc/ci/examples/test-and-deploy-python-application-to-heroku.md b/doc/ci/examples/test-and-deploy-python-application-to-heroku.md index 036b03dd6b9..a236da53fe9 100644 --- a/doc/ci/examples/test-and-deploy-python-application-to-heroku.md +++ b/doc/ci/examples/test-and-deploy-python-application-to-heroku.md @@ -1,7 +1,7 @@ ## Test and Deploy a python application This example will guide you how to run tests in your Python application and deploy it automatically as Heroku application. -You can checkout the example [source](https://gitlab.com/ayufan/python-getting-started) and check [CI status](https://ci.gitlab.com/projects/4080). +You can checkout the example [source](https://gitlab.com/ayufan/python-getting-started) and check [CI status](https://gitlab.com/ayufan/python-getting-started/builds?scope=all). ### Configure project This is what the `.gitlab-ci.yml` file looks like for this project: diff --git a/doc/ci/examples/test-and-deploy-ruby-application-to-heroku.md b/doc/ci/examples/test-and-deploy-ruby-application-to-heroku.md index d2a872f1934..e52e1547461 100644 --- a/doc/ci/examples/test-and-deploy-ruby-application-to-heroku.md +++ b/doc/ci/examples/test-and-deploy-ruby-application-to-heroku.md @@ -1,7 +1,7 @@ ## Test and Deploy a ruby application This example will guide you how to run tests in your Ruby application and deploy it automatiacally as Heroku application. -You can checkout the example [source](https://gitlab.com/ayufan/ruby-getting-started) and check [CI status](https://ci.gitlab.com/projects/4050). +You can checkout the example [source](https://gitlab.com/ayufan/ruby-getting-started) and check [CI status](https://gitlab.com/ayufan/ruby-getting-started/builds?scope=all). ### Configure project This is what the `.gitlab-ci.yml` file looks like for this project: @@ -64,4 +64,4 @@ gitlab-ci-multi-runner register \ With the command above, you create a runner that uses [ruby:2.1](https://registry.hub.docker.com/u/library/ruby/) image and uses [postgres](https://registry.hub.docker.com/u/library/postgres/) database. -To access PostgreSQL database you need to connect to `host: postgres` as user `postgres` without password. \ No newline at end of file +To access PostgreSQL database you need to connect to `host: postgres` as user `postgres` without password. diff --git a/doc/ci/examples/test-clojure-application.md b/doc/ci/examples/test-clojure-application.md index eaee94a10f1..56b746ce025 100644 --- a/doc/ci/examples/test-clojure-application.md +++ b/doc/ci/examples/test-clojure-application.md @@ -1,8 +1,8 @@ -## Test Clojure applications +## Test a Clojure application This example will guide you how to run tests in your Clojure application. -You can checkout the example [source](https://gitlab.com/dzaporozhets/clojure-web-application) and check [CI status](https://ci.gitlab.com/projects/6306). +You can checkout the example [source](https://gitlab.com/dzaporozhets/clojure-web-application) and check [CI status](https://gitlab.com/dzaporozhets/clojure-web-application/builds?scope=all). ### Configure project -- cgit v1.2.1 From d0398514b8b8eda7d03ba89b250554ff60a29ed4 Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Mon, 2 Nov 2015 15:36:04 +0100 Subject: Add 'New file' link to dropdown on project page Signed-off-by: Dmitriy Zaporozhets --- CHANGELOG | 1 + app/views/projects/buttons/_dropdown.html.haml | 4 ++++ 2 files changed, 5 insertions(+) diff --git a/CHANGELOG b/CHANGELOG index 588909d2578..c2bf3bf559b 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -17,6 +17,7 @@ v 8.2.0 (unreleased) - Remove deprecated CI events from project settings page - Use issue editor as cross reference comment author when issue is edited with a new mention. - [API] Add ability to fetch the commit ID of the last commit that actually touched a file + - Add "New file" link to dropdown on project page v 8.1.1 - Fix cloning Wiki repositories via HTTP (Stan Hu) diff --git a/app/views/projects/buttons/_dropdown.html.haml b/app/views/projects/buttons/_dropdown.html.haml index 4580c912692..bed2b16249e 100644 --- a/app/views/projects/buttons/_dropdown.html.haml +++ b/app/views/projects/buttons/_dropdown.html.haml @@ -20,6 +20,10 @@ New snippet - if can?(current_user, :push_code, @project) %li.divider + %li + = link_to namespace_project_new_blob_path(@project.namespace, @project, @project.default_branch || 'master'), title: 'New file' do + = icon('file fw') + New file %li = link_to new_namespace_project_branch_path(@project.namespace, @project) do = icon('code-fork fw') -- cgit v1.2.1 From 28f6fba97cb9753c43d109ef4f43439413d4eb69 Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Tue, 3 Nov 2015 10:16:09 +0100 Subject: Fix commits search for empty repository Signed-off-by: Dmitriy Zaporozhets --- lib/gitlab/project_search_results.rb | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/lib/gitlab/project_search_results.rb b/lib/gitlab/project_search_results.rb index c873ef3771e..70de6a74e76 100644 --- a/lib/gitlab/project_search_results.rb +++ b/lib/gitlab/project_search_results.rb @@ -77,7 +77,11 @@ module Gitlab end def commits - project.repository.find_commits_by_message(query) + if project.empty_repo? || query.blank? + [] + else + project.repository.find_commits_by_message(query).compact + end end def limit_project_ids -- cgit v1.2.1 From fe34b745e71a3e4ebb18d77a186d24de23b50863 Mon Sep 17 00:00:00 2001 From: Kamil Trzcinski Date: Tue, 3 Nov 2015 11:05:54 +0100 Subject: Fix tests --- spec/lib/ci/gitlab_ci_yaml_processor_spec.rb | 26 +++++++++++--------------- 1 file changed, 11 insertions(+), 15 deletions(-) diff --git a/spec/lib/ci/gitlab_ci_yaml_processor_spec.rb b/spec/lib/ci/gitlab_ci_yaml_processor_spec.rb index a141a459ba3..9963f76f993 100644 --- a/spec/lib/ci/gitlab_ci_yaml_processor_spec.rb +++ b/spec/lib/ci/gitlab_ci_yaml_processor_spec.rb @@ -123,18 +123,16 @@ module Ci config = YAML.dump({ before_script: ["pwd"], - build: { script: "build", type: "build", only: ["master", "deploy"] }, - rspec: { script: "rspec", type: type, only: ["master", "deploy"] }, + rspec: { script: "rspec", type: "test", only: ["master", "deploy"] }, staging: { script: "deploy", type: "deploy", only: ["master", "deploy"] }, - production: { script: "deploy", type: "deploy", only: ["master", "deploy"] }, production: { script: "deploy", type: "deploy", only: ["master@path", "deploy"] }, }) - config_processor = GitlabCiYamlProcessor.new(config, path) + config_processor = GitlabCiYamlProcessor.new(config, 'fork') - expect(config_processor.builds_for_stage_and_ref("production", "deploy").size).to eq(0) - expect(config_processor.builds_for_stage_and_ref(type, "deploy").size).to eq(1) expect(config_processor.builds_for_stage_and_ref("deploy", "deploy").size).to eq(2) + expect(config_processor.builds_for_stage_and_ref("test", "deploy").size).to eq(1) + expect(config_processor.builds_for_stage_and_ref("deploy", "master").size).to eq(1) end end @@ -230,18 +228,16 @@ module Ci it "returns build except specified type" do config = YAML.dump({ before_script: ["pwd"], - build: { script: "build", type: "build", except: ["master", "deploy"] }, - rspec: { script: "rspec", type: type, except: ["master", "deploy", "test@fork"] }, - staging: { script: "deploy", type: "deploy", except: ["master", "deploy"] }, - production: { script: "deploy", type: "deploy", except: ["master", "deploy"] }, - production: { script: "deploy", type: "deploy", except: ["master@path", "deploy"] }, + rspec: { script: "rspec", type: "test", except: ["master", "deploy", "test@fork"] }, + staging: { script: "deploy", type: "deploy", except: ["master"] }, + production: { script: "deploy", type: "deploy", except: ["master@fork"] }, }) - config_processor = GitlabCiYamlProcessor.new(config, path) + config_processor = GitlabCiYamlProcessor.new(config, 'fork') - expect(config_processor.builds_for_stage_and_ref("production", "deploy").size).to eq(0) - expect(config_processor.builds_for_stage_and_ref(type, "test").size).to eq(1) - expect(config_processor.builds_for_stage_and_ref("deploy", "master").size).to eq(2) + expect(config_processor.builds_for_stage_and_ref("deploy", "deploy").size).to eq(2) + expect(config_processor.builds_for_stage_and_ref("test", "test").size).to eq(0) + expect(config_processor.builds_for_stage_and_ref("deploy", "master").size).to eq(0) end end -- cgit v1.2.1 From 9479496f7584336788fc61121c096dfbcb3f6e4a Mon Sep 17 00:00:00 2001 From: Valery Sizov Date: Mon, 2 Nov 2015 16:56:44 +0200 Subject: Add added, modified and removed properties to commit object in webhook --- CHANGELOG | 1 + doc/web_hooks/web_hooks.md | 5 ++++- lib/gitlab/push_data_builder.rb | 33 +++++++++++++++++++++++++++++-- spec/lib/gitlab/push_data_builder_spec.rb | 6 ++++++ 4 files changed, 42 insertions(+), 3 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index 588909d2578..78f72ccc1e5 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -17,6 +17,7 @@ v 8.2.0 (unreleased) - Remove deprecated CI events from project settings page - Use issue editor as cross reference comment author when issue is edited with a new mention. - [API] Add ability to fetch the commit ID of the last commit that actually touched a file + - Add "added", "modified" and "removed" properties to commit object in webhook v 8.1.1 - Fix cloning Wiki repositories via HTTP (Stan Hu) diff --git a/doc/web_hooks/web_hooks.md b/doc/web_hooks/web_hooks.md index ef99a69f60a..7d838187a26 100644 --- a/doc/web_hooks/web_hooks.md +++ b/doc/web_hooks/web_hooks.md @@ -69,7 +69,10 @@ X-Gitlab-Event: Push Hook } } ], - "total_commits_count": 4 + "total_commits_count": 4, + "added": ["CHANGELOG"], + "modified": ["app/controller/application.rb"], + "removed": [] } ``` diff --git a/lib/gitlab/push_data_builder.rb b/lib/gitlab/push_data_builder.rb index d010ade704e..fa068d50763 100644 --- a/lib/gitlab/push_data_builder.rb +++ b/lib/gitlab/push_data_builder.rb @@ -18,7 +18,10 @@ module Gitlab # homepage: String, # }, # commits: Array, - # total_commits_count: Fixnum + # total_commits_count: Fixnum, + # added: ["CHANGELOG"], + # modified: [], + # removed: ["tmp/file.txt"] # } # def build(project, user, oldrev, newrev, ref, commits = [], message = nil) @@ -33,6 +36,8 @@ module Gitlab commit_attrs = commits_limited.map(&:hook_attrs) type = Gitlab::Git.tag_ref?(ref) ? "tag_push" : "push" + + repo_changes = repo_changes(project, newrev, oldrev) # Hash to be passed as post_receive_data data = { object_kind: type, @@ -55,7 +60,10 @@ module Gitlab visibility_level: project.visibility_level }, commits: commit_attrs, - total_commits_count: commits_count + total_commits_count: commits_count, + added: repo_changes[:added], + modified: repo_changes[:modified], + removed: repo_changes[:removed] } data @@ -86,6 +94,27 @@ module Gitlab newrev end end + + def repo_changes(project, newrev, oldrev) + changes = { added: [], modified: [], removed: [] } + compare_result = CompareService.new. + execute(project, newrev, project, oldrev) + + if compare_result + compare_result.diffs.each do |diff| + case true + when diff.deleted_file + changes[:removed] << diff.old_path + when diff.renamed_file, diff.new_file + changes[:added] << diff.new_path + else + changes[:modified] << diff.new_path + end + end + end + + changes + end end end end diff --git a/spec/lib/gitlab/push_data_builder_spec.rb b/spec/lib/gitlab/push_data_builder_spec.rb index 1b8ba7b4d43..02710742625 100644 --- a/spec/lib/gitlab/push_data_builder_spec.rb +++ b/spec/lib/gitlab/push_data_builder_spec.rb @@ -17,6 +17,9 @@ describe 'Gitlab::PushDataBuilder' do it { expect(data[:repository][:git_ssh_url]).to eq(project.ssh_url_to_repo) } it { expect(data[:repository][:visibility_level]).to eq(project.visibility_level) } it { expect(data[:total_commits_count]).to eq(3) } + it { expect(data[:added]).to eq(["gitlab-grack"]) } + it { expect(data[:modified]).to eq([".gitmodules", "files/ruby/popen.rb", "files/ruby/regex.rb"]) } + it { expect(data[:removed]).to eq([]) } end describe :build do @@ -35,5 +38,8 @@ describe 'Gitlab::PushDataBuilder' do it { expect(data[:ref]).to eq('refs/tags/v1.1.0') } it { expect(data[:commits]).to be_empty } it { expect(data[:total_commits_count]).to be_zero } + it { expect(data[:added]).to eq([]) } + it { expect(data[:modified]).to eq([]) } + it { expect(data[:removed]).to eq([]) } end end -- cgit v1.2.1 From 8a22b5bf544bd258b5cacca78b9f241849418d16 Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Mon, 2 Nov 2015 16:59:00 +0100 Subject: Remove inflector rule that makes commits uncountable Signed-off-by: Dmitriy Zaporozhets --- config/initializers/inflections.rb | 21 --------------------- 1 file changed, 21 deletions(-) diff --git a/config/initializers/inflections.rb b/config/initializers/inflections.rb index 5d46ece1e1b..9e8b0131f8f 100644 --- a/config/initializers/inflections.rb +++ b/config/initializers/inflections.rb @@ -8,24 +8,3 @@ # inflect.irregular 'person', 'people' # inflect.uncountable %w( fish sheep ) # end - -# Mark "commits" as uncountable. -# -# Without this change, the routes -# -# resources :commit, only: [:show], constraints: {id: /[[:alnum:]]{6,40}/} -# resources :commits, only: [:show], constraints: {id: /.+/} -# -# would generate identical route helper methods (`project_commit_path`), resulting -# in one of them not getting a helper method at all. -# -# After this change, the helper methods are: -# -# project_commit_path(@project, @project.commit) -# # => "/gitlabhq/commit/bcf03b5de6c33f3869ef70d68cf06e679d1d7f9a -# -# project_commits_path(@project, 'stable/README.md') -# # => "/gitlabhq/commits/stable/README.md" -ActiveSupport::Inflector.inflections do |inflect| - inflect.uncountable %w(commits) -end -- cgit v1.2.1 From 0df65909eff560f2d313c4034ed21a65d643a0c3 Mon Sep 17 00:00:00 2001 From: Yorick Peterse Date: Tue, 3 Nov 2015 11:47:23 +0100 Subject: Added benchmark for User.all This benchmark exists to test if ordering has any noticeable impact in the test environment. --- spec/benchmarks/models/user_spec.rb | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/spec/benchmarks/models/user_spec.rb b/spec/benchmarks/models/user_spec.rb index 4cdba66939b..1be7a8d3ed9 100644 --- a/spec/benchmarks/models/user_spec.rb +++ b/spec/benchmarks/models/user_spec.rb @@ -1,6 +1,16 @@ require 'spec_helper' describe User, benchmark: true do + describe '.all' do + before do + 10.times { create(:user) } + end + + benchmark_subject { User.all.to_a } + + it { is_expected.to iterate_per_second(500) } + end + describe '.by_login' do before do %w{Alice Bob Eve}.each do |name| -- cgit v1.2.1 From 732f5380af5d688a152de9c5b4bb14ffb935dd2a Mon Sep 17 00:00:00 2001 From: Yorick Peterse Date: Tue, 3 Nov 2015 11:54:43 +0100 Subject: Only sort by IDs by default Sorting by both "created_at" and "id" in descending order is not needed as simply sorting by "id" in descending order will already sort rows from new to old. Depending on the query and data involved sorting twice can also introduce significant overhead. --- app/models/concerns/sortable.rb | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/app/models/concerns/sortable.rb b/app/models/concerns/sortable.rb index 0ad2654867d..913c747a1c3 100644 --- a/app/models/concerns/sortable.rb +++ b/app/models/concerns/sortable.rb @@ -8,12 +8,12 @@ module Sortable included do # By default all models should be ordered # by created_at field starting from newest - default_scope { order(created_at: :desc, id: :desc) } + default_scope { order(id: :desc) } - scope :order_created_desc, -> { reorder(created_at: :desc, id: :desc) } - scope :order_created_asc, -> { reorder(created_at: :asc, id: :asc) } - scope :order_updated_desc, -> { reorder(updated_at: :desc, id: :desc) } - scope :order_updated_asc, -> { reorder(updated_at: :asc, id: :asc) } + scope :order_created_desc, -> { reorder(created_at: :desc) } + scope :order_created_asc, -> { reorder(created_at: :asc) } + scope :order_updated_desc, -> { reorder(updated_at: :desc) } + scope :order_updated_asc, -> { reorder(updated_at: :asc) } scope :order_name_asc, -> { reorder(name: :asc) } scope :order_name_desc, -> { reorder(name: :desc) } end -- cgit v1.2.1 From a2f8f9ad3da777869ba702ebf3c5b85b18991c28 Mon Sep 17 00:00:00 2001 From: Yorick Peterse Date: Tue, 3 Nov 2015 11:56:04 +0100 Subject: Fixed User sorting specs The descriptions were not accurate and one particular spec seemingly expected the wrong User row to be returned. --- spec/models/user_spec.rb | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/spec/models/user_spec.rb b/spec/models/user_spec.rb index c71cfb3ebe3..49e0bfdd2ec 100644 --- a/spec/models/user_spec.rb +++ b/spec/models/user_spec.rb @@ -663,24 +663,24 @@ describe User do @user1 = create :user, created_at: Date.today - 1, last_sign_in_at: Date.today - 1, name: 'Omega' end - it "sorts users as recently_signed_in" do + it "sorts users by the recent sign-in time" do expect(User.sort('recent_sign_in').first).to eq(@user) end - it "sorts users as late_signed_in" do + it "sorts users by the oldest sign-in time" do expect(User.sort('oldest_sign_in').first).to eq(@user1) end - it "sorts users as recently_created" do + it "sorts users in descending order by their creation time" do expect(User.sort('created_desc').first).to eq(@user) end - it "sorts users as late_created" do + it "sorts users in ascending order by their creation time" do expect(User.sort('created_asc').first).to eq(@user1) end - it "sorts users by name when nil is passed" do - expect(User.sort(nil).first).to eq(@user) + it "sorts users by id in descending order when nil is passed" do + expect(User.sort(nil).first).to eq(@user1) end end -- cgit v1.2.1 From d23ffc832c465c873ad5a70117a57bf32f0b4735 Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Tue, 3 Nov 2015 12:00:27 +0100 Subject: Fix code that depends on incorrect inflector behavior Signed-off-by: Dmitriy Zaporozhets --- app/views/search/results/_commit.html.haml | 2 ++ app/views/search/results/_commits.html.haml | 2 -- spec/mailers/notify_spec.rb | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) create mode 100644 app/views/search/results/_commit.html.haml delete mode 100644 app/views/search/results/_commits.html.haml diff --git a/app/views/search/results/_commit.html.haml b/app/views/search/results/_commit.html.haml new file mode 100644 index 00000000000..4e6c3965dc6 --- /dev/null +++ b/app/views/search/results/_commit.html.haml @@ -0,0 +1,2 @@ +.search-result-row + = render 'projects/commits/commit', project: @project, commit: commit diff --git a/app/views/search/results/_commits.html.haml b/app/views/search/results/_commits.html.haml deleted file mode 100644 index 7cff694350f..00000000000 --- a/app/views/search/results/_commits.html.haml +++ /dev/null @@ -1,2 +0,0 @@ -.search-result-row - = render 'projects/commits/commit', project: @project, commit: commits diff --git a/spec/mailers/notify_spec.rb b/spec/mailers/notify_spec.rb index cb67ec95d57..47863d54579 100644 --- a/spec/mailers/notify_spec.rb +++ b/spec/mailers/notify_spec.rb @@ -468,7 +468,7 @@ describe Notify do subject { Notify.note_commit_email(recipient.id, note.id) } it_behaves_like 'a note email' - it_behaves_like 'an answer to an existing thread', 'commits' + it_behaves_like 'an answer to an existing thread', 'commit' it 'has the correct subject' do is_expected.to have_subject /#{commit.title} \(#{commit.short_id}\)/ -- cgit v1.2.1 From 8d2758e02d634fd8518893f39dcc3359284e890f Mon Sep 17 00:00:00 2001 From: Kamil Trzcinski Date: Wed, 21 Oct 2015 11:29:47 +0200 Subject: Cleanup stuck CI builds daily --- CHANGELOG | 1 + app/workers/stuck_ci_builds_worker.rb | 18 ++++++++++++ spec/workers/stuck_ci_builds_worker_spec.rb | 44 +++++++++++++++++++++++++++++ 3 files changed, 63 insertions(+) create mode 100644 app/workers/stuck_ci_builds_worker.rb create mode 100644 spec/workers/stuck_ci_builds_worker_spec.rb diff --git a/CHANGELOG b/CHANGELOG index 08c85072633..e4f235fc3de 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -35,6 +35,7 @@ v 8.1.0 - Fix duplicate repositories in GitHub import page (Stan Hu) - Redirect to a default path if HTTP_REFERER is not set (Stan Hu) - Adds ability to create directories using the web editor (Ben Ford) + - Cleanup stuck CI builds v 8.1.0 (unreleased) - Send an email to admin email when a user is reported for spam (Jonathan Rochkind) diff --git a/app/workers/stuck_ci_builds_worker.rb b/app/workers/stuck_ci_builds_worker.rb new file mode 100644 index 00000000000..ad02a3b16d9 --- /dev/null +++ b/app/workers/stuck_ci_builds_worker.rb @@ -0,0 +1,18 @@ +class StuckCiBuildsWorker + include Sidekiq::Worker + include Sidetiq::Schedulable + + BUILD_STUCK_TIMEOUT = 1.day + + recurrence { daily } + + def perform + Rails.logger.info 'Cleaning stuck builds' + + builds = Ci::Build.running_or_pending.where('updated_at < ?', BUILD_STUCK_TIMEOUT.ago) + builds.find_each(batch_size: 50).each do |build| + Rails.logger.debug "Dropping stuck #{build.status} build #{build.id} for runner #{build.runner_id}" + build.drop + end + end +end diff --git a/spec/workers/stuck_ci_builds_worker_spec.rb b/spec/workers/stuck_ci_builds_worker_spec.rb new file mode 100644 index 00000000000..f9d87d97014 --- /dev/null +++ b/spec/workers/stuck_ci_builds_worker_spec.rb @@ -0,0 +1,44 @@ +require "spec_helper" + +describe StuckCiBuildsWorker do + let!(:build) { create :ci_build } + + subject do + build.reload + build.status + end + + %w(pending running).each do |status| + context "#{status} build" do + before do + build.update!(status: status) + end + + it 'gets dropped if it was updated over 2 days ago' do + build.update!(updated_at: 2.day.ago) + StuckCiBuildsWorker.new.perform + is_expected.to eq('failed') + end + + it "is still #{status}" do + build.update!(updated_at: 1.minute.ago) + StuckCiBuildsWorker.new.perform + is_expected.to eq(status) + end + end + end + + %w(success failed canceled).each do |status| + context "#{status} build" do + before do + build.update!(status: status) + end + + it "is still #{status}" do + build.update!(updated_at: 2.day.ago) + StuckCiBuildsWorker.new.perform + is_expected.to eq(status) + end + end + end +end -- cgit v1.2.1 From e3aed9121948c8124ddf128af3841986d69dafd5 Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Tue, 3 Nov 2015 13:22:11 +0100 Subject: Better name for up-level links Signed-off-by: Dmitriy Zaporozhets --- CHANGELOG | 1 + app/views/layouts/nav/_group.html.haml | 4 ++-- app/views/layouts/nav/_group_settings.html.haml | 4 ++-- app/views/layouts/nav/_profile.html.haml | 4 ++-- app/views/layouts/nav/_project.html.haml | 8 ++++---- app/views/layouts/nav/_project_settings.html.haml | 4 ++-- features/steps/groups.rb | 2 +- features/steps/project/project.rb | 4 ++-- features/steps/shared/project_tab.rb | 2 +- 9 files changed, 17 insertions(+), 16 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index 08c85072633..f178db46263 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -19,6 +19,7 @@ v 8.2.0 (unreleased) - [API] Add ability to fetch the commit ID of the last commit that actually touched a file - Add "New file" link to dropdown on project page - Include commit logs in project search + - Rename "Back to" links to "Go to" because its not always a case it point to place user come from v 8.1.1 - Fix cloning Wiki repositories via HTTP (Stan Hu) diff --git a/app/views/layouts/nav/_group.html.haml b/app/views/layouts/nav/_group.html.haml index eb35af22b93..319352876b4 100644 --- a/app/views/layouts/nav/_group.html.haml +++ b/app/views/layouts/nav/_group.html.haml @@ -1,9 +1,9 @@ %ul.nav.nav-sidebar = nav_link do - = link_to root_path, title: 'Back to dashboard', data: {placement: 'right'}, class: 'back-link' do + = link_to root_path, title: 'Go to dashboard', data: {placement: 'right'}, class: 'back-link' do = icon('caret-square-o-left fw') %span - Back to dashboard + Go to dashboard %li.separate-item diff --git a/app/views/layouts/nav/_group_settings.html.haml b/app/views/layouts/nav/_group_settings.html.haml index 8075fe32fbc..c8411521f36 100644 --- a/app/views/layouts/nav/_group_settings.html.haml +++ b/app/views/layouts/nav/_group_settings.html.haml @@ -1,9 +1,9 @@ %ul.nav.nav-sidebar = nav_link do - = link_to group_path(@group), title: 'Back to group', data: {placement: 'right'}, class: 'back-link' do + = link_to group_path(@group), title: 'Go to group', data: {placement: 'right'}, class: 'back-link' do = icon('caret-square-o-left fw') %span - Back to group + Go to group %li.separate-item diff --git a/app/views/layouts/nav/_profile.html.haml b/app/views/layouts/nav/_profile.html.haml index 5a47b8e6db2..0f3a793e30b 100644 --- a/app/views/layouts/nav/_profile.html.haml +++ b/app/views/layouts/nav/_profile.html.haml @@ -1,9 +1,9 @@ %ul.nav.nav-sidebar = nav_link do - = link_to root_path, title: 'Back to dashboard', data: {placement: 'right'}, class: 'back-link' do + = link_to root_path, title: 'Go to dashboard', data: {placement: 'right'}, class: 'back-link' do = icon('caret-square-o-left fw') %span - Back to dashboard + Go to dashboard %li.separate-item diff --git a/app/views/layouts/nav/_project.html.haml b/app/views/layouts/nav/_project.html.haml index 53a913fe8f3..20db2866d1f 100644 --- a/app/views/layouts/nav/_project.html.haml +++ b/app/views/layouts/nav/_project.html.haml @@ -1,16 +1,16 @@ %ul.nav.nav-sidebar - if @project.group = nav_link do - = link_to group_path(@project.group), title: 'Back to group', data: {placement: 'right'}, class: 'back-link' do + = link_to group_path(@project.group), title: 'Go to group', data: {placement: 'right'}, class: 'back-link' do = icon('caret-square-o-left fw') %span - Back to group + Go to group - else = nav_link do - = link_to root_path, title: 'Back to dashboard', data: {placement: 'right'}, class: 'back-link' do + = link_to root_path, title: 'Go to dashboard', data: {placement: 'right'}, class: 'back-link' do = icon('caret-square-o-left fw') %span - Back to dashboard + Go to dashboard %li.separate-item diff --git a/app/views/layouts/nav/_project_settings.html.haml b/app/views/layouts/nav/_project_settings.html.haml index 356ce09c3d7..a59939ccd31 100644 --- a/app/views/layouts/nav/_project_settings.html.haml +++ b/app/views/layouts/nav/_project_settings.html.haml @@ -1,9 +1,9 @@ %ul.nav.nav-sidebar = nav_link do - = link_to project_path(@project), title: 'Back to project', data: {placement: 'right'}, class: 'back-link' do + = link_to project_path(@project), title: 'Go to project', data: {placement: 'right'}, class: 'back-link' do = icon('caret-square-o-left fw') %span - Back to project + Go to project %li.separate-item diff --git a/features/steps/groups.rb b/features/steps/groups.rb index 69ddfa42c06..70388c18fcf 100644 --- a/features/steps/groups.rb +++ b/features/steps/groups.rb @@ -6,7 +6,7 @@ class Spinach::Features::Groups < Spinach::FeatureSteps include Select2Helper step 'I should see back to dashboard button' do - expect(page).to have_content 'Back to dashboard' + expect(page).to have_content 'Go to dashboard' end step 'gitlab user "Mike"' do diff --git a/features/steps/project/project.rb b/features/steps/project/project.rb index d76891d5bde..9ca7c8ebbc7 100644 --- a/features/steps/project/project.rb +++ b/features/steps/project/project.rb @@ -124,11 +124,11 @@ class Spinach::Features::Project < Spinach::FeatureSteps end step 'I should see back to dashboard button' do - expect(page).to have_content 'Back to dashboard' + expect(page).to have_content 'Go to dashboard' end step 'I should see back to group button' do - expect(page).to have_content 'Back to group' + expect(page).to have_content 'Go to group' end step 'I click notifications drop down button' do diff --git a/features/steps/shared/project_tab.rb b/features/steps/shared/project_tab.rb index c67e5e4a06a..33ff7084e30 100644 --- a/features/steps/shared/project_tab.rb +++ b/features/steps/shared/project_tab.rb @@ -46,7 +46,7 @@ module SharedProjectTab step 'the active main tab should be Settings' do page.within '.nav-sidebar' do - expect(page).to have_content('Back to project') + expect(page).to have_content('Go to project') end end -- cgit v1.2.1 From ab129f7b235527d28068a3fd6ca1fc6eed5ebac5 Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Tue, 3 Nov 2015 14:00:41 +0100 Subject: Improve profile page UI Signed-off-by: Dmitriy Zaporozhets --- app/assets/stylesheets/pages/profile.scss | 22 ++++++++++++++++++++++ app/views/users/show.html.haml | 27 ++++++++++++++++----------- 2 files changed, 38 insertions(+), 11 deletions(-) diff --git a/app/assets/stylesheets/pages/profile.scss b/app/assets/stylesheets/pages/profile.scss index b7391e5303b..1d6ca0dfc13 100644 --- a/app/assets/stylesheets/pages/profile.scss +++ b/app/assets/stylesheets/pages/profile.scss @@ -53,3 +53,25 @@ float: right; font-size: 12px; } + +.profile-link-holder { + display: inline; + + &:after { + content: "\00B7"; + padding: 0px 6px; + font-weight: bold; + } + + &:last-child { + &:after { + content: ""; + padding: 0; + } + } + + a { + color: $blue-dark; + text-decoration: none; + } +} diff --git a/app/views/users/show.html.haml b/app/views/users/show.html.haml index 4ea4a1f92c2..3766d8cd673 100644 --- a/app/views/users/show.html.haml +++ b/app/views/users/show.html.haml @@ -24,22 +24,27 @@ .cover-desc - unless @user.public_email.blank? - = link_to @user.public_email, "mailto:#{@user.public_email}" + .profile-link-holder + = link_to @user.public_email, "mailto:#{@user.public_email}" - unless @user.skype.blank? - · - = link_to "Skype", "skype:#{@user.skype}" + .profile-link-holder + = link_to "skype:#{@user.skype}", title: "Skype" do + = icon('skype') - unless @user.linkedin.blank? - · - = link_to "LinkedIn", "http://www.linkedin.com/in/#{@user.linkedin}" + .profile-link-holder + = link_to "http://www.linkedin.com/in/#{@user.linkedin}", title: "LinkedIn" do + = icon('linkedin-square') - unless @user.twitter.blank? - · - = link_to "Twitter", "http://www.twitter.com/#{@user.twitter}" + .profile-link-holder + = link_to "http://www.twitter.com/#{@user.twitter}", title: "Twitter" do + = icon('twitter-square') - unless @user.website_url.blank? - · - = link_to @user.short_website_url, @user.full_website_url + .profile-link-holder + = link_to @user.short_website_url, @user.full_website_url - unless @user.location.blank? - · - = @user.location + .profile-link-holder + = icon('map-marker') + = @user.location .cover-controls -- cgit v1.2.1 From 4d7f00fdeae074ae26f2629c78064d6eaa21ace1 Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Tue, 3 Nov 2015 15:32:40 +0100 Subject: Apply new design for user profile page Signed-off-by: Dmitriy Zaporozhets --- CHANGELOG | 1 + app/assets/javascripts/calendar.js.coffee | 2 +- app/assets/stylesheets/framework/common.scss | 10 +++++ app/assets/stylesheets/pages/profile.scss | 4 ++ app/views/users/_projects.html.haml | 13 ------ app/views/users/show.html.haml | 62 +++++++++++++++++++--------- 6 files changed, 59 insertions(+), 33 deletions(-) delete mode 100644 app/views/users/_projects.html.haml diff --git a/CHANGELOG b/CHANGELOG index ae3613cc330..4c43a377fd9 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -20,6 +20,7 @@ v 8.2.0 (unreleased) - [API] Add ability to fetch the commit ID of the last commit that actually touched a file - Add "New file" link to dropdown on project page - Include commit logs in project search + - New design for user profile page v 8.1.1 - Fix cloning Wiki repositories via HTTP (Stan Hu) diff --git a/app/assets/javascripts/calendar.js.coffee b/app/assets/javascripts/calendar.js.coffee index 4c4bc3d66ed..2b1e20d3225 100644 --- a/app/assets/javascripts/calendar.js.coffee +++ b/app/assets/javascripts/calendar.js.coffee @@ -25,7 +25,7 @@ class @Calendar 30 ] legendCellPadding: 3 - cellSize: $('.user-calendar').width() / 80 + cellSize: $('.user-calendar').width() / 76 onClick: (date, count) -> formated_date = date.getFullYear() + "-" + (date.getMonth()+1) + "-" + date.getDate() $.ajax diff --git a/app/assets/stylesheets/framework/common.scss b/app/assets/stylesheets/framework/common.scss index e1a1793be9c..3d0b71e066e 100644 --- a/app/assets/stylesheets/framework/common.scss +++ b/app/assets/stylesheets/framework/common.scss @@ -387,6 +387,16 @@ table { } } +.center-middle-menu { + @include nav-menu; + text-align: center; + margin: -$gl-padding; + height: auto; + margin-top: 0; + margin-bottom: 0; + border-bottom: 1px solid $border-color; +} + .dropzone .dz-preview .dz-progress { border-color: $border-color !important; } diff --git a/app/assets/stylesheets/pages/profile.scss b/app/assets/stylesheets/pages/profile.scss index 1d6ca0dfc13..bc1ad21305a 100644 --- a/app/assets/stylesheets/pages/profile.scss +++ b/app/assets/stylesheets/pages/profile.scss @@ -75,3 +75,7 @@ text-decoration: none; } } + +.cal-heatmap-container { + margin: 0 auto; +} diff --git a/app/views/users/_projects.html.haml b/app/views/users/_projects.html.haml deleted file mode 100644 index a126a858ea8..00000000000 --- a/app/views/users/_projects.html.haml +++ /dev/null @@ -1,13 +0,0 @@ -- if local_assigns.has_key?(:contributed_projects) && contributed_projects.present? - .panel.panel-default.contributed-projects - .panel-heading Projects contributed to - = render 'shared/projects/list', - projects: contributed_projects.sort_by(&:star_count).reverse, - projects_limit: 5, stars: true, avatar: false - -- if local_assigns.has_key?(:projects) && projects.present? - .panel.panel-default - .panel-heading Personal projects - = render 'shared/projects/list', - projects: projects.sort_by(&:star_count).reverse, - projects_limit: 10, stars: true, avatar: false diff --git a/app/views/users/show.html.haml b/app/views/users/show.html.haml index 3766d8cd673..e22d93aae84 100644 --- a/app/views/users/show.html.haml +++ b/app/views/users/show.html.haml @@ -52,7 +52,7 @@ = link_to profile_path, class: 'btn btn-gray' do = icon('pencil') - elsif current_user - .report-abuse + %span.report-abuse - if @user.abuse_report %button.btn.btn-danger{ title: 'Already reported for abuse', data: { toggle: 'tooltip', placement: 'left', container: 'body' }} @@ -61,6 +61,10 @@ = link_to new_abuse_report_path(user_id: @user.id), class: 'btn btn-gray', title: 'Report abuse', data: {toggle: 'tooltip', placement: 'left', container: 'body'} do = icon('exclamation-circle') + - if current_user +   + = link_to user_path(@user, :atom, { private_token: current_user.private_token }), class: 'btn btn-gray' do + = icon('rss') .gray-content-block.second-block .user-calendar @@ -69,27 +73,47 @@ .user-calendar-activities -.row.prepend-top-20 - %section.col-md-7 - - if @groups.any? - .prepend-top-20 - %h4 Groups - = render 'groups', groups: @groups - %hr - - %h4 - User Activity - - - if current_user - %span.rss-icon.pull-right - = link_to user_path(@user, :atom, { private_token: current_user.private_token }) do - %strong - %i.fa.fa-rss +%ul.nav.center-middle-menu + %li.active + = link_to "#activity", 'data-toggle' => 'tab' do + Activity + - if @groups.any? + %li + = link_to "#groups", 'data-toggle' => 'tab' do + Groups + - if @contributed_projects.present? + %li + = link_to "#contributed", 'data-toggle' => 'tab' do + Contributed projects + - if @projects.present? + %li + = link_to "#personal", 'data-toggle' => 'tab' do + Personal projects +.tab-content + .tab-pane.active#activity .content_list = spinner - %aside.col-md-5 - = render 'projects', projects: @projects, contributed_projects: @contributed_projects + + - if @groups.any? + .tab-pane#groups + %ul.content-list + - @groups.each do |group| + = render 'shared/groups/group', group: group + + - if @contributed_projects.present? + .tab-pane#contributed + .contributed-projects + = render 'shared/projects/list', + projects: @contributed_projects.sort_by(&:star_count).reverse, + projects_limit: 5, stars: true, avatar: false + + - if @projects.present? + .tab-pane#personal + .personal-projects + = render 'shared/projects/list', + projects: @projects.sort_by(&:star_count).reverse, + projects_limit: 10, stars: true, avatar: false :coffeescript $(".user-calendar").load("#{user_calendar_path}") -- cgit v1.2.1 From 00ac792cfba52dffbbfd1bf304059fcd63d7e688 Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Tue, 3 Nov 2015 15:44:52 +0100 Subject: Fix clipboard button overflow Signed-off-by: Dmitriy Zaporozhets --- app/assets/stylesheets/framework/buttons.scss | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/app/assets/stylesheets/framework/buttons.scss b/app/assets/stylesheets/framework/buttons.scss index 04024419584..fe56266284b 100644 --- a/app/assets/stylesheets/framework/buttons.scss +++ b/app/assets/stylesheets/framework/buttons.scss @@ -180,3 +180,7 @@ } } } + +.btn-clipboard { + border: none; +} -- cgit v1.2.1 From e0edc01d1477d463d2ecf8137c966859d32c1302 Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Tue, 3 Nov 2015 16:39:09 +0100 Subject: Fix tests Signed-off-by: Dmitriy Zaporozhets --- features/profile/profile.feature | 1 + features/steps/profile/profile.rb | 15 ++++++++++----- 2 files changed, 11 insertions(+), 5 deletions(-) diff --git a/features/profile/profile.feature b/features/profile/profile.feature index 27c0bde364e..168d9d30b50 100644 --- a/features/profile/profile.feature +++ b/features/profile/profile.feature @@ -7,6 +7,7 @@ Feature: Profile Given I visit profile page Then I should see my profile info + @javascript Scenario: I can see groups I belong to Given I have group with projects When I visit profile page diff --git a/features/steps/profile/profile.rb b/features/steps/profile/profile.rb index 8cf24705a5e..40b2aa7c357 100644 --- a/features/steps/profile/profile.rb +++ b/features/steps/profile/profile.rb @@ -59,7 +59,7 @@ class Spinach::Features::Profile < Spinach::FeatureSteps step 'I should not see the "Remove avatar" button' do expect(page).not_to have_link("Remove avatar") end - + step 'I should see the gravatar host link' do expect(page).to have_link("gravatar.com") end @@ -159,10 +159,9 @@ class Spinach::Features::Profile < Spinach::FeatureSteps end step 'I should see my user page' do - expect(page).to have_content "User Activity" - - page.within '.navbar-gitlab' do + page.within ".cover-block" do expect(page).to have_content current_user.name + expect(page).to have_content current_user.username end end @@ -176,7 +175,13 @@ class Spinach::Features::Profile < Spinach::FeatureSteps end step 'I should see groups I belong to' do - expect(page).to have_css('.profile-groups-avatars', visible: true) + page.within ".content" do + click_link "Groups" + end + + page.within "#groups" do + expect(page).to have_content @group.name + end end step 'I click on new application button' do -- cgit v1.2.1 From ef6f6f80ec6242790d54a57445fd7e4915b36ed1 Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Tue, 3 Nov 2015 16:42:02 +0100 Subject: Add extra padding between user description and links on profile page Signed-off-by: Dmitriy Zaporozhets --- app/assets/stylesheets/framework/blocks.scss | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/assets/stylesheets/framework/blocks.scss b/app/assets/stylesheets/framework/blocks.scss index 5949a0fd5ad..8917c53b1f5 100644 --- a/app/assets/stylesheets/framework/blocks.scss +++ b/app/assets/stylesheets/framework/blocks.scss @@ -100,7 +100,7 @@ } .cover-desc { - padding: 0 $gl-padding; + padding: 0 $gl-padding 3px; color: $gl-text-color; } -- cgit v1.2.1 From 700909d56726e23c500a2b55e2e68d14cbe3a161 Mon Sep 17 00:00:00 2001 From: Robert Speicher Date: Mon, 2 Nov 2015 15:33:56 -0500 Subject: Bump stamp to ~> 0.6.0 Closes #2801 --- Gemfile | 2 +- Gemfile.lock | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Gemfile b/Gemfile index bb31c147b26..df260633091 100644 --- a/Gemfile +++ b/Gemfile @@ -63,7 +63,7 @@ gem 'rack-cors', '~> 0.4.0', require: 'rack/cors' # Format dates and times # based on human-friendly examples -gem "stamp", '~> 0.5.0' +gem "stamp", '~> 0.6.0' # Enumeration fields gem 'enumerize', '~> 0.7.0' diff --git a/Gemfile.lock b/Gemfile.lock index 65abc45ff19..030191fb80c 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -689,7 +689,7 @@ GEM actionpack (>= 3.0) activesupport (>= 3.0) sprockets (>= 2.8, < 4.0) - stamp (0.5.0) + stamp (0.6.0) state_machine (1.2.0) stringex (2.5.2) systemu (2.6.5) @@ -909,7 +909,7 @@ DEPENDENCIES spring-commands-spinach (~> 1.0.0) spring-commands-teaspoon (~> 0.0.2) sprockets (~> 2.12.3) - stamp (~> 0.5.0) + stamp (~> 0.6.0) state_machine (~> 1.2.0) task_list (~> 1.0.2) teaspoon (~> 1.0.0) -- cgit v1.2.1 From 4773d98e835dd14bd73e7bde0d5bcf4754355976 Mon Sep 17 00:00:00 2001 From: Douwe Maan Date: Tue, 3 Nov 2015 17:58:12 +0100 Subject: Add Facebook authentication --- CHANGELOG | 1 + Gemfile | 1 + Gemfile.lock | 3 + app/assets/images/auth_buttons/facebook_64.png | Bin 0 -> 2970 bytes app/helpers/auth_helper.rb | 2 +- config/gitlab.yml.example | 23 +++--- doc/integration/facebook.md | 96 +++++++++++++++++++++++++ doc/integration/facebook_api_keys.png | Bin 0 -> 125921 bytes doc/integration/facebook_app_settings.png | Bin 0 -> 134387 bytes doc/integration/facebook_website_url.png | Bin 0 -> 42292 bytes doc/integration/omniauth.md | 3 +- 11 files changed, 116 insertions(+), 13 deletions(-) create mode 100644 app/assets/images/auth_buttons/facebook_64.png create mode 100644 doc/integration/facebook.md create mode 100644 doc/integration/facebook_api_keys.png create mode 100644 doc/integration/facebook_app_settings.png create mode 100644 doc/integration/facebook_website_url.png diff --git a/CHANGELOG b/CHANGELOG index 16055208db5..0ec6030b130 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -26,6 +26,7 @@ v 8.2.0 (unreleased) v 8.1.3 - Spread out runner contacted_at updates - New design for user profile page + - Add Facebook authentication v 8.1.1 - Fix cloning Wiki repositories via HTTP (Stan Hu) diff --git a/Gemfile b/Gemfile index bb31c147b26..8379e5eea17 100644 --- a/Gemfile +++ b/Gemfile @@ -19,6 +19,7 @@ gem 'devise-async', '~> 0.9.0' gem 'doorkeeper', '~> 2.1.3' gem 'omniauth', '~> 1.2.2' gem 'omniauth-bitbucket', '~> 0.0.2' +gem 'omniauth-facebook', '~> 3.0.0' gem 'omniauth-github', '~> 1.1.1' gem 'omniauth-gitlab', '~> 1.0.0' gem 'omniauth-google-oauth2', '~> 0.2.0' diff --git a/Gemfile.lock b/Gemfile.lock index 65abc45ff19..c9ba4959ddf 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -423,6 +423,8 @@ GEM multi_json (~> 1.7) omniauth (~> 1.1) omniauth-oauth (~> 1.0) + omniauth-facebook (3.0.0) + omniauth-oauth2 (~> 1.2) omniauth-github (1.1.2) omniauth (~> 1.0) omniauth-oauth2 (~> 1.1) @@ -859,6 +861,7 @@ DEPENDENCIES octokit (~> 3.7.0) omniauth (~> 1.2.2) omniauth-bitbucket (~> 0.0.2) + omniauth-facebook (~> 3.0.0) omniauth-github (~> 1.1.1) omniauth-gitlab (~> 1.0.0) omniauth-google-oauth2 (~> 0.2.0) diff --git a/app/assets/images/auth_buttons/facebook_64.png b/app/assets/images/auth_buttons/facebook_64.png new file mode 100644 index 00000000000..1f1a80d7368 Binary files /dev/null and b/app/assets/images/auth_buttons/facebook_64.png differ diff --git a/app/helpers/auth_helper.rb b/app/helpers/auth_helper.rb index cd99a232403..2c81ea1623c 100644 --- a/app/helpers/auth_helper.rb +++ b/app/helpers/auth_helper.rb @@ -1,5 +1,5 @@ module AuthHelper - PROVIDERS_WITH_ICONS = %w(twitter github gitlab bitbucket google_oauth2).freeze + PROVIDERS_WITH_ICONS = %w(twitter github gitlab bitbucket google_oauth2 facebook).freeze FORM_BASED_PROVIDERS = [/\Aldap/, 'crowd'].freeze def ldap_enabled? diff --git a/config/gitlab.yml.example b/config/gitlab.yml.example index e297f393e3d..20894ebcdc9 100644 --- a/config/gitlab.yml.example +++ b/config/gitlab.yml.example @@ -274,27 +274,28 @@ production: &base # arguments, followed by optional 'args' which can be either a hash or an array. # Documentation for this is available at http://doc.gitlab.com/ce/integration/omniauth.html providers: - # - { name: 'google_oauth2', - # label: 'Google', - # app_id: 'YOUR_APP_ID', - # app_secret: 'YOUR_APP_SECRET', - # args: { access_type: 'offline', approval_prompt: '' } } - # - { name: 'twitter', - # app_id: 'YOUR_APP_ID', - # app_secret: 'YOUR_APP_SECRET' } # - { name: 'github', - # label: 'GitHub', # app_id: 'YOUR_APP_ID', # app_secret: 'YOUR_APP_SECRET', # args: { scope: 'user:email' } } + # - { name: 'bitbucket', + # app_id: 'YOUR_APP_ID', + # app_secret: 'YOUR_APP_SECRET' } # - { name: 'gitlab', - # label: 'GitLab.com', # app_id: 'YOUR_APP_ID', # app_secret: 'YOUR_APP_SECRET', # args: { scope: 'api' } } - # - { name: 'bitbucket', + # - { name: 'google_oauth2', + # app_id: 'YOUR_APP_ID', + # app_secret: 'YOUR_APP_SECRET', + # args: { access_type: 'offline', approval_prompt: '' } } + # - { name: 'facebook', # app_id: 'YOUR_APP_ID', # app_secret: 'YOUR_APP_SECRET' } + # - { name: 'twitter', + # app_id: 'YOUR_APP_ID', + # app_secret: 'YOUR_APP_SECRET' } + # # - { name: 'saml', # label: 'Our SAML Provider', # args: { diff --git a/doc/integration/facebook.md b/doc/integration/facebook.md new file mode 100644 index 00000000000..5880b5baf76 --- /dev/null +++ b/doc/integration/facebook.md @@ -0,0 +1,96 @@ +# Facebook OAuth2 OmniAuth Provider + +To enable the Facebook OmniAuth provider you must register your application with Facebook. Facebook will generate an app ID and secret key for you to use. + +1. Sign in to the [Facebook Developer Platform](https://developers.facebook.com/). + +1. Choose "My Apps" > "Add a New App" + +1. Select the type "Website" + +1. Enter a name for your app. This can be anything. Consider something like "<Organization>'s GitLab" or "<Your Name>'s GitLab" or +something else descriptive. + +1. Choose "Create New Facebook App ID" + +1. Select a Category, for example "Productivity" + +1. Choose "Create App ID" + +1. Enter the address of your GitLab installation at the bottom of the package + + ![Facebook Website URL](facebook_website_url.png) + +1. Choose "Next" + +1. Choose "Skip Quick Start" in the upper right corner + +1. Choose "Settings" in the menu on the left + +1. Fill in a contact email for your app + ![Facebook App Settings](facebook_app_settings.png) + +1. Choose "Save Changes" + +1. Choose "Status & Review" in the menu on the left + +1. Change the switch on the right from No to Yes + +1. Choose "Confirm" when prompted to make the app public + +1. Choose "Dashboard" in the menu on the left + +1. Choose "Show" next to the hidden "App Secret" + +1. You should now see an app key and app secret (see screenshot). Keep this page open as you continue configuration. + + ![Facebook API Keys](facebook_api_keys.png) + +1. On your GitLab server, open the configuration file. + + For omnibus package: + + ```sh + sudo editor /etc/gitlab/gitlab.rb + ``` + + For installations from source: + + ```sh + cd /home/git/gitlab + + sudo -u git -H editor config/gitlab.yml + ``` + +1. See [Initial OmniAuth Configuration](omniauth.md#initial-omniauth-configuration) for initial settings. + +1. Add the provider configuration: + + For omnibus package: + + ```ruby + gitlab_rails['omniauth_providers'] = [ + { + "name" => "facebook", + "app_id" => "YOUR_APP_ID", + "app_secret" => "YOUR_APP_SECRET" + } + ] + ``` + + For installations from source: + + ``` + - { name: 'facebook', app_id: 'YOUR_APP_ID', + app_secret: 'YOUR_APP_SECRET' } + ``` + +1. Change 'YOUR_APP_ID' to the API key from Facebook page in step 10. + +1. Change 'YOUR_APP_SECRET' to the API secret from the Facebook page in step 10. + +1. Save the configuration file. + +1. Restart GitLab for the changes to take effect. + +On the sign in page there should now be a Facebook icon below the regular sign in form. Click the icon to begin the authentication process. Facebook will ask the user to sign in and authorize the GitLab application. If everything goes well the user will be returned to GitLab and will be signed in. diff --git a/doc/integration/facebook_api_keys.png b/doc/integration/facebook_api_keys.png new file mode 100644 index 00000000000..d6c44ac0f11 Binary files /dev/null and b/doc/integration/facebook_api_keys.png differ diff --git a/doc/integration/facebook_app_settings.png b/doc/integration/facebook_app_settings.png new file mode 100644 index 00000000000..30dd21e198a Binary files /dev/null and b/doc/integration/facebook_app_settings.png differ diff --git a/doc/integration/facebook_website_url.png b/doc/integration/facebook_website_url.png new file mode 100644 index 00000000000..dc3088bb2fa Binary files /dev/null and b/doc/integration/facebook_website_url.png differ diff --git a/doc/integration/omniauth.md b/doc/integration/omniauth.md index c5cecbc2f2d..bd9550c6ddb 100644 --- a/doc/integration/omniauth.md +++ b/doc/integration/omniauth.md @@ -73,8 +73,9 @@ Now we can choose one or more of the Supported Providers below to continue confi - [Bitbucket](bitbucket.md) - [GitLab.com](gitlab.md) - [Google](google.md) -- [Shibboleth](shibboleth.md) +- [Facebook](facebook.md) - [Twitter](twitter.md) +- [Shibboleth](shibboleth.md) - [SAML](saml.md) - [Crowd](crowd.md) -- cgit v1.2.1 From 98dcad2762930b0dc967ff8e67f9f795228d2342 Mon Sep 17 00:00:00 2001 From: Douwe Maan Date: Tue, 3 Nov 2015 17:58:26 +0100 Subject: Use proper labels for OAuth providers --- lib/gitlab/o_auth/provider.rb | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/lib/gitlab/o_auth/provider.rb b/lib/gitlab/o_auth/provider.rb index 90c3fe8da33..9ad7a38d505 100644 --- a/lib/gitlab/o_auth/provider.rb +++ b/lib/gitlab/o_auth/provider.rb @@ -1,6 +1,12 @@ module Gitlab module OAuth class Provider + LABELS = { + "github" => "GitHub", + "gitlab" => "GitLab.com", + "google_oauth2" => "Google" + }.freeze + def self.providers Devise.omniauth_providers end @@ -23,8 +29,9 @@ module Gitlab end def self.label_for(name) + name = name.to_s config = config_for(name) - (config && config['label']) || name.to_s.titleize + (config && config['label']) || LABELS[name] || name.titleize end end end -- cgit v1.2.1 From 05eb9e7884a1a1eb4144f84e7f586d26b011f4f1 Mon Sep 17 00:00:00 2001 From: Robert Speicher Date: Tue, 3 Nov 2015 16:16:15 -0500 Subject: Minor reformatting for Facebook integration doc [ci skip] --- doc/integration/facebook.md | 27 ++++++++++++++------------- 1 file changed, 14 insertions(+), 13 deletions(-) diff --git a/doc/integration/facebook.md b/doc/integration/facebook.md index 5880b5baf76..bc1f1673086 100644 --- a/doc/integration/facebook.md +++ b/doc/integration/facebook.md @@ -19,7 +19,7 @@ something else descriptive. 1. Enter the address of your GitLab installation at the bottom of the package - ![Facebook Website URL](facebook_website_url.png) + ![Facebook Website URL](facebook_website_url.png) 1. Choose "Next" @@ -28,6 +28,7 @@ something else descriptive. 1. Choose "Settings" in the menu on the left 1. Fill in a contact email for your app + ![Facebook App Settings](facebook_app_settings.png) 1. Choose "Save Changes" @@ -51,15 +52,15 @@ something else descriptive. For omnibus package: ```sh - sudo editor /etc/gitlab/gitlab.rb + sudo editor /etc/gitlab/gitlab.rb ``` For installations from source: ```sh - cd /home/git/gitlab + cd /home/git/gitlab - sudo -u git -H editor config/gitlab.yml + sudo -u git -H editor config/gitlab.yml ``` 1. See [Initial OmniAuth Configuration](omniauth.md#initial-omniauth-configuration) for initial settings. @@ -69,20 +70,20 @@ something else descriptive. For omnibus package: ```ruby - gitlab_rails['omniauth_providers'] = [ - { - "name" => "facebook", - "app_id" => "YOUR_APP_ID", - "app_secret" => "YOUR_APP_SECRET" - } - ] + gitlab_rails['omniauth_providers'] = [ + { + "name" => "facebook", + "app_id" => "YOUR_APP_ID", + "app_secret" => "YOUR_APP_SECRET" + } + ] ``` For installations from source: ``` - - { name: 'facebook', app_id: 'YOUR_APP_ID', - app_secret: 'YOUR_APP_SECRET' } + - { name: 'facebook', app_id: 'YOUR_APP_ID', + app_secret: 'YOUR_APP_SECRET' } ``` 1. Change 'YOUR_APP_ID' to the API key from Facebook page in step 10. -- cgit v1.2.1 From 312375ac7c7d6619740899cd185a8dde1d653955 Mon Sep 17 00:00:00 2001 From: Robert Speicher Date: Tue, 3 Nov 2015 17:10:17 -0500 Subject: Update Shell Commands doc for configurable git binary path --- doc/development/shell_commands.md | 20 +++++++++++++++----- 1 file changed, 15 insertions(+), 5 deletions(-) diff --git a/doc/development/shell_commands.md b/doc/development/shell_commands.md index 2d1d0fb4154..65cdd74bdb6 100644 --- a/doc/development/shell_commands.md +++ b/doc/development/shell_commands.md @@ -35,6 +35,16 @@ Gitlab::Popen.popen(%W(find /some/path -not -path /some/path -mmin +120 -delete) This coding style could have prevented CVE-2013-4490. +## Always use the configurable git binary path for git commands + +```ruby +# Wrong +system(*%W(git branch -d -- #{branch_name})) + +# Correct +system(*%W(#{Gitlab.config.git.bin_path} branch -d -- #{branch_name})) +``` + ## Bypass the shell by splitting commands into separate tokens When we pass shell commands as a single string to Ruby, Ruby will let `/bin/sh` evaluate the entire string. Essentially, we are asking the shell to evaluate a one-line script. This creates a risk for shell injection attacks. It is better to split the shell command into tokens ourselves. Sometimes we use the scripting capabilities of the shell to change the working directory or set environment variables. All of this can also be achieved securely straight from Ruby @@ -81,9 +91,9 @@ In the GitLab codebase, we avoid the option/argument ambiguity by _always_ using ```ruby # Wrong -system(*%W(git branch -d #{branch_name})) +system(*%W(#{Gitlab.config.git.bin_path} branch -d #{branch_name})) # Correct -system(*%W(git branch -d -- #{branch_name})) +system(*%W(#{Gitlab.config.git.bin_path} branch -d -- #{branch_name})) ``` This coding style could have prevented CVE-2013-4582. @@ -94,9 +104,9 @@ Capturing the output of shell commands with backticks reads nicely, but you are ```ruby # Wrong -logs = `cd #{repo_dir} && git log` +logs = `cd #{repo_dir} && #{Gitlab.config.git.bin_path} log` # Correct -logs, exit_status = Gitlab::Popen.popen(%W(git log), repo_dir) +logs, exit_status = Gitlab::Popen.popen(%W(#{Gitlab.config.git.bin_path} log), repo_dir) # Wrong user = `whoami` @@ -108,7 +118,7 @@ In other repositories, such as gitlab-shell you can also use `IO.popen`. ```ruby # Safe IO.popen example -logs = IO.popen(%W(git log), chdir: repo_dir) { |p| p.read } +logs = IO.popen(%W(#{Gitlab.config.git.bin_path} log), chdir: repo_dir) { |p| p.read } ``` Note that unlike `Gitlab::Popen.popen`, `IO.popen` does not capture standard error. -- cgit v1.2.1 From d09d62b6b875102b7a334fcf9e689537e1f25013 Mon Sep 17 00:00:00 2001 From: Robert Speicher Date: Tue, 3 Nov 2015 17:10:38 -0500 Subject: Replace all usages of `git` command with configurable binary path Closes #3311 --- app/models/repository.rb | 12 ++++++------ config/initializers/2_app.rb | 6 +++--- lib/backup/repository.rb | 6 +++--- lib/gitlab/force_push_check.rb | 2 +- lib/gitlab/git_ref_validator.rb | 2 +- lib/gitlab/upgrader.rb | 8 ++++---- lib/tasks/gitlab/check.rake | 2 +- lib/tasks/gitlab/shell.rake | 10 +++++----- spec/models/project_wiki_spec.rb | 2 +- spec/requests/api/repositories_spec.rb | 4 ++-- spec/support/test_env.rb | 8 ++++---- 11 files changed, 31 insertions(+), 31 deletions(-) diff --git a/app/models/repository.rb b/app/models/repository.rb index 9266ba27f0a..f8c4cb1387b 100644 --- a/app/models/repository.rb +++ b/app/models/repository.rb @@ -89,7 +89,7 @@ class Repository def find_commits_by_message(query) # Limited to 1000 commits for now, could be parameterized? - args = %W(git log --pretty=%H --max-count 1000 --grep=#{query}) + args = %W(#{Gitlab.config.git.bin_path} log --pretty=%H --max-count 1000 --grep=#{query}) git_log_results = Gitlab::Popen.popen(args, path_to_repo).first.lines.map(&:chomp) commits = git_log_results.map { |c| commit(c) } @@ -296,7 +296,7 @@ class Repository end def last_commit_for_path(sha, path) - args = %W(git rev-list --max-count=1 #{sha} -- #{path}) + args = %W(#{Gitlab.config.git.bin_path} rev-list --max-count=1 #{sha} -- #{path}) sha = Gitlab::Popen.popen(args, path_to_repo).first.strip commit(sha) end @@ -347,7 +347,7 @@ class Repository end def branch_names_contains(sha) - args = %W(git branch --contains #{sha}) + args = %W(#{Gitlab.config.git.bin_path} branch --contains #{sha}) names = Gitlab::Popen.popen(args, path_to_repo).first if names.respond_to?(:split) @@ -364,7 +364,7 @@ class Repository end def tag_names_contains(sha) - args = %W(git tag --contains #{sha}) + args = %W(#{Gitlab.config.git.bin_path} tag --contains #{sha}) names = Gitlab::Popen.popen(args, path_to_repo).first if names.respond_to?(:split) @@ -505,7 +505,7 @@ class Repository def search_files(query, ref) offset = 2 - args = %W(git grep -i -n --before-context #{offset} --after-context #{offset} -e #{query} #{ref || root_ref}) + args = %W(#{Gitlab.config.git.bin_path} grep -i -n --before-context #{offset} --after-context #{offset} -e #{query} #{ref || root_ref}) Gitlab::Popen.popen(args, path_to_repo).first.scrub.split(/^--$/) end @@ -537,7 +537,7 @@ class Repository end def fetch_ref(source_path, source_ref, target_ref) - args = %W(git fetch -f #{source_path} #{source_ref}:#{target_ref}) + args = %W(#{Gitlab.config.git.bin_path} fetch -f #{source_path} #{source_ref}:#{target_ref}) Gitlab::Popen.popen(args, path_to_repo) end diff --git a/config/initializers/2_app.rb b/config/initializers/2_app.rb index 688cdf5f4b0..35b150c9929 100644 --- a/config/initializers/2_app.rb +++ b/config/initializers/2_app.rb @@ -1,8 +1,8 @@ module Gitlab - VERSION = File.read(Rails.root.join("VERSION")).strip - REVISION = Gitlab::Popen.popen(%W(git log --pretty=format:%h -n 1)).first.chomp - def self.config Settings end + + VERSION = File.read(Rails.root.join("VERSION")).strip + REVISION = Gitlab::Popen.popen(%W(#{config.git.bin_path} log --pretty=format:%h -n 1)).first.chomp end diff --git a/lib/backup/repository.rb b/lib/backup/repository.rb index 4d70f7883dd..a82a7e1f7bf 100644 --- a/lib/backup/repository.rb +++ b/lib/backup/repository.rb @@ -35,7 +35,7 @@ module Backup if wiki.repository.empty? $progress.puts " [SKIPPED]".cyan else - cmd = %W(git --git-dir=#{path_to_repo(wiki)} bundle create #{path_to_bundle(wiki)} --all) + cmd = %W(#{Gitlab.config.git.bin_path} --git-dir=#{path_to_repo(wiki)} bundle create #{path_to_bundle(wiki)} --all) output, status = Gitlab::Popen.popen(cmd) if status.zero? $progress.puts " [DONE]".green @@ -67,7 +67,7 @@ module Backup FileUtils.mkdir_p(path_to_repo(project)) cmd = %W(tar -xf #{path_to_bundle(project)} -C #{path_to_repo(project)}) else - cmd = %W(git init --bare #{path_to_repo(project)}) + cmd = %W(#{Gitlab.config.git.bin_path} init --bare #{path_to_repo(project)}) end if system(*cmd, silent) @@ -87,7 +87,7 @@ module Backup # that was initialized with ProjectWiki.new() and then # try to restore with 'git clone --bare'. FileUtils.rm_rf(path_to_repo(wiki)) - cmd = %W(git clone --bare #{path_to_bundle(wiki)} #{path_to_repo(wiki)}) + cmd = %W(#{Gitlab.config.git.bin_path} clone --bare #{path_to_bundle(wiki)} #{path_to_repo(wiki)}) if system(*cmd, silent) $progress.puts " [DONE]".green diff --git a/lib/gitlab/force_push_check.rb b/lib/gitlab/force_push_check.rb index fdb6a35c78d..93c6a5bb7f5 100644 --- a/lib/gitlab/force_push_check.rb +++ b/lib/gitlab/force_push_check.rb @@ -7,7 +7,7 @@ module Gitlab if Gitlab::Git.blank_ref?(oldrev) || Gitlab::Git.blank_ref?(newrev) false else - missed_refs, _ = Gitlab::Popen.popen(%W(git --git-dir=#{project.repository.path_to_repo} rev-list #{oldrev} ^#{newrev})) + missed_refs, _ = Gitlab::Popen.popen(%W(#{Gitlab.config.git.bin_path} --git-dir=#{project.repository.path_to_repo} rev-list #{oldrev} ^#{newrev})) missed_refs.split("\n").size > 0 end end diff --git a/lib/gitlab/git_ref_validator.rb b/lib/gitlab/git_ref_validator.rb index 39d17def930..4d83d8e72a8 100644 --- a/lib/gitlab/git_ref_validator.rb +++ b/lib/gitlab/git_ref_validator.rb @@ -6,7 +6,7 @@ module Gitlab # Returns true for a valid reference name, false otherwise def validate(ref_name) Gitlab::Utils.system_silent( - %W(git check-ref-format refs/#{ref_name})) + %W(#{Gitlab.config.git.bin_path} check-ref-format refs/#{ref_name})) end end end diff --git a/lib/gitlab/upgrader.rb b/lib/gitlab/upgrader.rb index cf040971c6e..f3567f3ef85 100644 --- a/lib/gitlab/upgrader.rb +++ b/lib/gitlab/upgrader.rb @@ -50,15 +50,15 @@ module Gitlab end def fetch_git_tags - remote_tags, _ = Gitlab::Popen.popen(%W(git ls-remote --tags https://gitlab.com/gitlab-org/gitlab-ce.git)) + remote_tags, _ = Gitlab::Popen.popen(%W(#{Gitlab.config.git.bin_path} ls-remote --tags https://gitlab.com/gitlab-org/gitlab-ce.git)) remote_tags.split("\n").grep(/tags\/v#{current_version.major}/) end def update_commands { - "Stash changed files" => %W(git stash), - "Get latest code" => %W(git fetch), - "Switch to new version" => %W(git checkout v#{latest_version}), + "Stash changed files" => %W(#{Gitlab.config.git.bin_path} stash), + "Get latest code" => %W(#{Gitlab.config.git.bin_path} fetch), + "Switch to new version" => %W(#{Gitlab.config.git.bin_path} checkout v#{latest_version}), "Install gems" => %W(bundle), "Migrate DB" => %W(bundle exec rake db:migrate), "Recompile assets" => %W(bundle exec rake assets:clean assets:precompile), diff --git a/lib/tasks/gitlab/check.rake b/lib/tasks/gitlab/check.rake index 2e73f792a9d..a25fac62cfc 100644 --- a/lib/tasks/gitlab/check.rake +++ b/lib/tasks/gitlab/check.rake @@ -824,7 +824,7 @@ namespace :gitlab do repo_dirs = Dir.glob(File.join(namespace_dir, '*')) repo_dirs.each do |dir| puts "\nChecking repo at #{dir}" - system(*%w(git fsck), chdir: dir) + system(*%W(#{Gitlab.config.git.bin_path} fsck), chdir: dir) end end end diff --git a/lib/tasks/gitlab/shell.rake b/lib/tasks/gitlab/shell.rake index 3c0cc763d17..dd61632e557 100644 --- a/lib/tasks/gitlab/shell.rake +++ b/lib/tasks/gitlab/shell.rake @@ -17,7 +17,7 @@ namespace :gitlab do # Clone if needed unless File.directory?(target_dir) - system(*%W(git clone -- #{args.repo} #{target_dir})) + system(*%W(#{Gitlab.config.git.bin_path} clone -- #{args.repo} #{target_dir})) end # Make sure we're on the right tag @@ -27,7 +27,7 @@ namespace :gitlab do reseted = reset_to_commit(args) unless reseted - system(*%W(git fetch origin)) + system(*%W(#{Gitlab.config.git.bin_path} fetch origin)) reset_to_commit(args) end @@ -128,14 +128,14 @@ namespace :gitlab do end def reset_to_commit(args) - tag, status = Gitlab::Popen.popen(%W(git describe -- #{args.tag})) + tag, status = Gitlab::Popen.popen(%W(#{Gitlab.config.git.bin_path} describe -- #{args.tag})) unless status.zero? - tag, status = Gitlab::Popen.popen(%W(git describe -- origin/#{args.tag})) + tag, status = Gitlab::Popen.popen(%W(#{Gitlab.config.git.bin_path} describe -- origin/#{args.tag})) end tag = tag.strip - system(*%W(git reset --hard #{tag})) + system(*%W(#{Gitlab.config.git.bin_path} reset --hard #{tag})) end end diff --git a/spec/models/project_wiki_spec.rb b/spec/models/project_wiki_spec.rb index 94802dcfb79..9f6cdeeaa96 100644 --- a/spec/models/project_wiki_spec.rb +++ b/spec/models/project_wiki_spec.rb @@ -223,7 +223,7 @@ describe ProjectWiki do def create_temp_repo(path) FileUtils.mkdir_p path - system(*%W(git init --quiet --bare -- #{path})) + system(*%W(#{Gitlab.config.git.bin_path} init --quiet --bare -- #{path})) end def remove_temp_repo(path) diff --git a/spec/requests/api/repositories_spec.rb b/spec/requests/api/repositories_spec.rb index 1149f7e7989..faf6b77a462 100644 --- a/spec/requests/api/repositories_spec.rb +++ b/spec/requests/api/repositories_spec.rb @@ -36,8 +36,8 @@ describe API::API, api: true do it 'should create a new annotated tag' do # Identity must be set in .gitconfig to create annotated tag. repo_path = project.repository.path_to_repo - system(*%W(git --git-dir=#{repo_path} config user.name #{user.name})) - system(*%W(git --git-dir=#{repo_path} config user.email #{user.email})) + system(*%W(#{Gitlab.config.git.bin_path} --git-dir=#{repo_path} config user.name #{user.name})) + system(*%W(#{Gitlab.config.git.bin_path} --git-dir=#{repo_path} config user.email #{user.email})) post api("/projects/#{project.id}/repository/tags", user), tag_name: 'v7.1.0', diff --git a/spec/support/test_env.rb b/spec/support/test_env.rb index d12ba25b71b..787670e9297 100644 --- a/spec/support/test_env.rb +++ b/spec/support/test_env.rb @@ -96,15 +96,15 @@ module TestEnv clone_url = "https://gitlab.com/gitlab-org/#{repo_name}.git" unless File.directory?(repo_path) - system(*%W(git clone -q #{clone_url} #{repo_path})) + system(*%W(#{Gitlab.config.git.bin_path} clone -q #{clone_url} #{repo_path})) end Dir.chdir(repo_path) do branch_sha.each do |branch, sha| # Try to reset without fetching to avoid using the network. - reset = %W(git update-ref refs/heads/#{branch} #{sha}) + reset = %W(#{Gitlab.config.git.bin_path} update-ref refs/heads/#{branch} #{sha}) unless system(*reset) - if system(*%w(git fetch origin)) + if system(*%W(#{Gitlab.config.git.bin_path} fetch origin)) unless system(*reset) raise 'The fetched test seed '\ 'does not contain the required revision.' @@ -117,7 +117,7 @@ module TestEnv end # We must copy bare repositories because we will push to them. - system(git_env, *%W(git clone -q --bare #{repo_path} #{repo_path_bare})) + system(git_env, *%W(#{Gitlab.config.git.bin_path} clone -q --bare #{repo_path} #{repo_path_bare})) end def copy_repo(project) -- cgit v1.2.1 From 5f94e130d11adf4398058d1c558de6f44b11675a Mon Sep 17 00:00:00 2001 From: mozillazg Date: Wed, 4 Nov 2015 11:41:44 +0800 Subject: update example of regex for pytest-cov --- app/views/projects/ci_settings/_form.html.haml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/views/projects/ci_settings/_form.html.haml b/app/views/projects/ci_settings/_form.html.haml index d711413c6b9..20bdccc9027 100644 --- a/app/views/projects/ci_settings/_form.html.haml +++ b/app/views/projects/ci_settings/_form.html.haml @@ -102,7 +102,7 @@ %code \(\d+.\d+\%\) covered %li pytest-cov (Python) - - %code \d+\%$ + %code \d+\%\s*$ -- cgit v1.2.1 From 91cbf9db0c5c95381e7d422fd684e623d58fadab Mon Sep 17 00:00:00 2001 From: Stan Hu Date: Mon, 26 Oct 2015 07:26:03 +0100 Subject: Add allow_failure field to commit status API Closes #3196 --- CHANGELOG | 1 + doc/api/commits.md | 6 ++++-- lib/api/entities.rb | 2 +- spec/requests/api/commit_status_spec.rb | 4 +++- 4 files changed, 9 insertions(+), 4 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index 16055208db5..e7238c45662 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -3,6 +3,7 @@ Please view this file on the master branch, on stable branches it's out of date. v 8.2.0 (unreleased) - Force update refs/merge-requests/X/head upon a push to the source branch of a merge request (Stan Hu) - Improved performance of finding users by one of their Email addresses + - Add allow_failure field to commit status API (Stan Hu) - Improved performance of replacing references in comments - Show last project commit to default branch on project home page - Highlight comment based on anchor in URL diff --git a/doc/api/commits.md b/doc/api/commits.md index 9f72adc6ed9..8e4a0ee1b82 100644 --- a/doc/api/commits.md +++ b/doc/api/commits.md @@ -22,7 +22,8 @@ Parameters: "author_name": "Dmitriy Zaporozhets", "author_email": "dzaporozhets@sphereconsultinginc.com", "created_at": "2012-09-20T11:50:22+03:00", - "message": "Replace sanitize with escape once" + "message": "Replace sanitize with escape once", + "allow_failure": false }, { "id": "6104942438c14ec7bd21c6cd5bd995272b3faff6", @@ -31,7 +32,8 @@ Parameters: "author_name": "randx", "author_email": "dmitriy.zaporozhets@gmail.com", "created_at": "2012-09-20T09:06:12+03:00", - "message": "Sanitize for network graph" + "message": "Sanitize for network graph", + "allow_failure": false } ] ``` diff --git a/lib/api/entities.rb b/lib/api/entities.rb index 883a5e14b17..20cadae2291 100644 --- a/lib/api/entities.rb +++ b/lib/api/entities.rb @@ -231,7 +231,7 @@ module API class CommitStatus < Grape::Entity expose :id, :sha, :ref, :status, :name, :target_url, :description, - :created_at, :started_at, :finished_at + :created_at, :started_at, :finished_at, :allow_failure expose :author, using: Entities::UserBasic end diff --git a/spec/requests/api/commit_status_spec.rb b/spec/requests/api/commit_status_spec.rb index b9e6dfc15a7..a28607bd240 100644 --- a/spec/requests/api/commit_status_spec.rb +++ b/spec/requests/api/commit_status_spec.rb @@ -18,7 +18,7 @@ describe API::API, api: true do before do @status1 = create(:commit_status, commit: ci_commit, status: 'running') @status2 = create(:commit_status, commit: ci_commit, name: 'coverage', status: 'pending') - @status3 = create(:commit_status, commit: ci_commit, name: 'coverage', ref: 'develop', status: 'running') + @status3 = create(:commit_status, commit: ci_commit, name: 'coverage', ref: 'develop', status: 'running', allow_failure: true) @status4 = create(:commit_status, commit: ci_commit, name: 'coverage', status: 'success') @status5 = create(:commit_status, commit: ci_commit, ref: 'develop', status: 'success') @status6 = create(:commit_status, commit: ci_commit, status: 'success') @@ -30,6 +30,8 @@ describe API::API, api: true do expect(json_response).to be_an Array expect(statuses_id).to contain_exactly(@status3.id, @status4.id, @status5.id, @status6.id) + json_response.sort_by!{ |status| status['id'] } + expect(json_response.map{ |status| status['allow_failure'] }).to eq([true, false, false, false]) end it "should return all commit statuses" do -- cgit v1.2.1 From bdb45360e76a272c275690cb11227a737c56e934 Mon Sep 17 00:00:00 2001 From: Tim Jabs Date: Thu, 8 Oct 2015 18:06:51 +0200 Subject: Changed documentation of converting a MySQL-Database with Gitlab to a Postgresdatatabase. The instructions were missleading. See -> https://gitlab.com/gitlab-org/gitlab-ce/issues/2904 --- doc/update/mysql_to_postgresql.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/doc/update/mysql_to_postgresql.md b/doc/update/mysql_to_postgresql.md index a596ea38456..a7de5648c0e 100644 --- a/doc/update/mysql_to_postgresql.md +++ b/doc/update/mysql_to_postgresql.md @@ -60,6 +60,9 @@ sudo -u git -H python mysql-postgresql-converter/db_converter.py gitlabhq_produc sudo -u git -H ed -s db/database.sql < mysql-postgresql-converter/move_drop_indexes.ed # Compress database backup +# Warning: If you have Gitlab 7.12.0 or older skip this step and import the database.sql directly into the backup with: +# sudo -u git -H tar rf TIMESTAMP_gitlab_backup.tar db/database.sql +# The compressed databasedump is not supported at 7.12.0 and older. sudo -u git -H gzip db/database.sql # Replace the MySQL dump in TIMESTAMP_gitlab_backup.tar. @@ -71,4 +74,5 @@ sudo -u git -H tar rf TIMESTAMP_gitlab_backup.tar db/database.sql.gz # Done! TIMESTAMP_gitlab_backup.tar can now be restored into a Postgres GitLab # installation. +# See https://gitlab.com/gitlab-org/gitlab-ce/blob/master/doc/raketasks/backup_restore.md for more information about backups. ``` -- cgit v1.2.1 From c5d637b2cad3ad760f54d4aaa398847b4e251524 Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Wed, 4 Nov 2015 14:13:25 +0100 Subject: Improvements to profile page UI * add separator between tabs * show project avatars * fix tooltip offset on user calendar * remove gray hover for tabs Signed-off-by: Dmitriy Zaporozhets --- app/assets/javascripts/calendar.js.coffee | 2 +- app/assets/stylesheets/framework/common.scss | 22 +++++++++++++++++++++- app/assets/stylesheets/framework/mixins.scss | 1 + app/assets/stylesheets/pages/profile.scss | 4 ---- app/views/users/show.html.haml | 6 +++--- 5 files changed, 26 insertions(+), 9 deletions(-) diff --git a/app/assets/javascripts/calendar.js.coffee b/app/assets/javascripts/calendar.js.coffee index 2b1e20d3225..97621236924 100644 --- a/app/assets/javascripts/calendar.js.coffee +++ b/app/assets/javascripts/calendar.js.coffee @@ -25,7 +25,7 @@ class @Calendar 30 ] legendCellPadding: 3 - cellSize: $('.user-calendar').width() / 76 + cellSize: $('.user-calendar').width() / 73 onClick: (date, count) -> formated_date = date.getFullYear() + "-" + (date.getMonth()+1) + "-" + date.getDate() $.ajax diff --git a/app/assets/stylesheets/framework/common.scss b/app/assets/stylesheets/framework/common.scss index 3d0b71e066e..41287d52f69 100644 --- a/app/assets/stylesheets/framework/common.scss +++ b/app/assets/stylesheets/framework/common.scss @@ -389,12 +389,32 @@ table { .center-middle-menu { @include nav-menu; + padding: 0; text-align: center; margin: -$gl-padding; - height: auto; margin-top: 0; margin-bottom: 0; + height: 58px; border-bottom: 1px solid $border-color; + + li { + &:after { + content: "|"; + color: $border-gray-light; + } + + &:last-child { + &:after { + content: none; + } + } + + > a { + display: inline-block; + text-transform: uppercase; + font-size: 13px; + } + } } .dropzone .dz-preview .dz-progress { diff --git a/app/assets/stylesheets/framework/mixins.scss b/app/assets/stylesheets/framework/mixins.scss index fe078d016d7..b9c179f2881 100644 --- a/app/assets/stylesheets/framework/mixins.scss +++ b/app/assets/stylesheets/framework/mixins.scss @@ -137,6 +137,7 @@ &:hover, &:active, &:focus { text-decoration: none; + outline: none; } } diff --git a/app/assets/stylesheets/pages/profile.scss b/app/assets/stylesheets/pages/profile.scss index bc1ad21305a..1d6ca0dfc13 100644 --- a/app/assets/stylesheets/pages/profile.scss +++ b/app/assets/stylesheets/pages/profile.scss @@ -75,7 +75,3 @@ text-decoration: none; } } - -.cal-heatmap-container { - margin: 0 auto; -} diff --git a/app/views/users/show.html.haml b/app/views/users/show.html.haml index e22d93aae84..5a15c6c244a 100644 --- a/app/views/users/show.html.haml +++ b/app/views/users/show.html.haml @@ -73,7 +73,7 @@ .user-calendar-activities -%ul.nav.center-middle-menu +%ul.center-middle-menu %li.active = link_to "#activity", 'data-toggle' => 'tab' do Activity @@ -106,14 +106,14 @@ .contributed-projects = render 'shared/projects/list', projects: @contributed_projects.sort_by(&:star_count).reverse, - projects_limit: 5, stars: true, avatar: false + projects_limit: 5, stars: true, avatar: true - if @projects.present? .tab-pane#personal .personal-projects = render 'shared/projects/list', projects: @projects.sort_by(&:star_count).reverse, - projects_limit: 10, stars: true, avatar: false + projects_limit: 10, stars: true, avatar: true :coffeescript $(".user-calendar").load("#{user_calendar_path}") -- cgit v1.2.1 From 8508be74d2063bb86e39d1cc8667e8adb9dfe63e Mon Sep 17 00:00:00 2001 From: Kjel Delaey Date: Wed, 4 Nov 2015 15:55:19 +0100 Subject: Style inline event items with titles containing long words properly.. On a tablet in portrait mode with a width of 768px the event-title isn't aligned properly when the title contains a long string. This also happens when resizing your browser viewport on a desktop. Example string: Administrator pushed new branch feature-branch-with-a-very-long-name at Gitlab Org / Gitlab Test In the UI it would look like the example below: ---------- | | | AVATAR | less than a minute ago | | ---------- Administrator pushed new branch feature-branch-with-a-very-long-name at... --- app/assets/stylesheets/pages/events.scss | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/app/assets/stylesheets/pages/events.scss b/app/assets/stylesheets/pages/events.scss index dfb901652bf..d2ca106cc8d 100644 --- a/app/assets/stylesheets/pages/events.scss +++ b/app/assets/stylesheets/pages/events.scss @@ -11,9 +11,12 @@ color: #7f8fa4; &.event-inline { + padding-left: $gl-padding + $gl-avatar-size; + .avatar { position: relative; top: -2px; + margin-left: -$gl-avatar-size; } .event-title { @@ -155,6 +158,10 @@ @media (max-width: $screen-xs-max) { .event-item { + &.event-inline { + padding-left: $gl-padding; + } + .event-title { white-space: normal; overflow: visible; -- cgit v1.2.1 From 8b0906c86d10ff02865e99400f2c0e3bdd1ac6fe Mon Sep 17 00:00:00 2001 From: Kjel Delaey Date: Wed, 4 Nov 2015 16:22:27 +0100 Subject: Apply the same rules to block event items.. Try to avoid alignment issues as well. --- app/assets/stylesheets/pages/events.scss | 13 +++---------- 1 file changed, 3 insertions(+), 10 deletions(-) diff --git a/app/assets/stylesheets/pages/events.scss b/app/assets/stylesheets/pages/events.scss index d2ca106cc8d..02401c7c73a 100644 --- a/app/assets/stylesheets/pages/events.scss +++ b/app/assets/stylesheets/pages/events.scss @@ -4,19 +4,16 @@ */ .event-item { font-size: $gl-font-size; - padding: $gl-padding; + padding: $gl-padding $gl-padding $gl-padding ($gl-padding + $gl-avatar-size); margin-left: -$gl-padding; margin-right: -$gl-padding; border-bottom: 1px solid $table-border-color; color: #7f8fa4; &.event-inline { - padding-left: $gl-padding + $gl-avatar-size; - .avatar { position: relative; top: -2px; - margin-left: -$gl-avatar-size; } .event-title { @@ -33,6 +30,7 @@ } .avatar { + margin-left: -$gl-avatar-size; margin-right: 15px; } @@ -46,9 +44,6 @@ } .event-body { - margin-left: 63px; - margin-right: 80px; - .event-note { margin-top: 5px; word-wrap: break-word; @@ -158,9 +153,7 @@ @media (max-width: $screen-xs-max) { .event-item { - &.event-inline { - padding-left: $gl-padding; - } + padding-left: $gl-padding; .event-title { white-space: normal; -- cgit v1.2.1 From 3f2955de3bf08ef1ec378d323fb2360547a4ca16 Mon Sep 17 00:00:00 2001 From: Kjel Delaey Date: Wed, 4 Nov 2015 16:23:39 +0100 Subject: Combine selectors because the same style is being applied --- app/assets/stylesheets/pages/events.scss | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/app/assets/stylesheets/pages/events.scss b/app/assets/stylesheets/pages/events.scss index 02401c7c73a..f8d1afda73e 100644 --- a/app/assets/stylesheets/pages/events.scss +++ b/app/assets/stylesheets/pages/events.scss @@ -16,10 +16,7 @@ top: -2px; } - .event-title { - line-height: 44px; - } - + .event-title, .event-item-timestamp { line-height: 44px; } -- cgit v1.2.1 From 530c9519d4d0760848daf5026f93fbcbff348656 Mon Sep 17 00:00:00 2001 From: Kjel Delaey Date: Wed, 4 Nov 2015 16:40:22 +0100 Subject: Make sure that multi-commit rows inside event bodies are aligned properly.. Prevent the second, third, ... rows from having a different indentation than the first commit row. Adding the extra "15px padding" to the event item prevents this. Having a 15px margin on the avatar only doesn't prevent this from happening. --- app/assets/stylesheets/pages/events.scss | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/app/assets/stylesheets/pages/events.scss b/app/assets/stylesheets/pages/events.scss index f8d1afda73e..c150b4ac19f 100644 --- a/app/assets/stylesheets/pages/events.scss +++ b/app/assets/stylesheets/pages/events.scss @@ -4,7 +4,7 @@ */ .event-item { font-size: $gl-font-size; - padding: $gl-padding $gl-padding $gl-padding ($gl-padding + $gl-avatar-size); + padding: $gl-padding $gl-padding $gl-padding ($gl-padding + $gl-avatar-size + 15px); margin-left: -$gl-padding; margin-right: -$gl-padding; border-bottom: 1px solid $table-border-color; @@ -27,8 +27,7 @@ } .avatar { - margin-left: -$gl-avatar-size; - margin-right: 15px; + margin-left: -($gl-avatar-size + 15px); } .event-title { -- cgit v1.2.1 From 07821839d0616c06180388b91e3131bc008522a0 Mon Sep 17 00:00:00 2001 From: mutec Date: Wed, 4 Nov 2015 17:49:23 +0100 Subject: Update installation.md --- doc/install/installation.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/install/installation.md b/doc/install/installation.md index 599d2541f2c..e31448263c7 100644 --- a/doc/install/installation.md +++ b/doc/install/installation.md @@ -332,7 +332,7 @@ GitLab Shell is an SSH access and repository management software developed speci # Go to Gitlab installation folder - cd /home/git/gilab + cd /home/git/gitlab sudo -u git -H bundle exec rake gitlab:setup RAILS_ENV=production -- cgit v1.2.1 From 95da91a66de5820a44989aa708338c24177cd10c Mon Sep 17 00:00:00 2001 From: Sytse Sijbrandij Date: Wed, 4 Nov 2015 17:07:21 +0000 Subject: Use single spaces --- doc_styleguide.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/doc_styleguide.md b/doc_styleguide.md index 656bb1d17ff..cceb449a854 100644 --- a/doc_styleguide.md +++ b/doc_styleguide.md @@ -15,6 +15,8 @@ For subtitles, use '##', '###' and so on. - Do not duplicate information. - Be brief and clear. - Whenever it applies, add documents in alphabetical order. +- Write in US English +- Use [single spaces](http://www.slate.com/articles/technology/technology/2011/01/space_invaders.html) instead of double spaces. ## Images -- cgit v1.2.1 From dfccc28e38b6298eff8eeedf1ba91a93c0182353 Mon Sep 17 00:00:00 2001 From: Vincent Lequertier Date: Wed, 4 Nov 2015 19:04:20 +0100 Subject: It makes more sense like this --- doc/install/installation.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/install/installation.md b/doc/install/installation.md index 599d2541f2c..5a09cf7c965 100644 --- a/doc/install/installation.md +++ b/doc/install/installation.md @@ -253,8 +253,8 @@ We recommend using a PostgreSQL database. For MySQL check [MySQL setup guide](da nproc # Enable cluster mode if you expect to have a high load instance - # Ex. change amount of workers to 3 for 2GB RAM server # Set the number of workers to at least the number of cores + # Ex. change amount of workers to 3 for 2GB RAM server sudo -u git -H editor config/unicorn.rb # Copy the example Rack attack config -- cgit v1.2.1 From b6f89c3490f8c31607073c9761de3ebb30ae244e Mon Sep 17 00:00:00 2001 From: Kjel Delaey Date: Thu, 5 Nov 2015 09:56:51 +0100 Subject: Add right margin to event-body.. Otherwise text will flow under the "timeago" element. The original value was 80px (see commit 8b0906c8), but a value of 174px makes more sense. (see event-title `calc` function). --- app/assets/stylesheets/pages/events.scss | 2 ++ 1 file changed, 2 insertions(+) diff --git a/app/assets/stylesheets/pages/events.scss b/app/assets/stylesheets/pages/events.scss index c150b4ac19f..282aaf2219b 100644 --- a/app/assets/stylesheets/pages/events.scss +++ b/app/assets/stylesheets/pages/events.scss @@ -40,6 +40,8 @@ } .event-body { + margin-right: 174px; + .event-note { margin-top: 5px; word-wrap: break-word; -- cgit v1.2.1 From 33b8f002636ad6171637108b53732c74d90b14ad Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Thu, 5 Nov 2015 10:51:12 +0100 Subject: Add edit/update tag actions for future release notes Signed-off-by: Dmitriy Zaporozhets --- app/controllers/projects/tags_controller.rb | 8 ++++++++ app/views/projects/tags/_tag.html.haml | 2 ++ app/views/projects/tags/edit.html.haml | 0 config/routes.rb | 2 +- 4 files changed, 11 insertions(+), 1 deletion(-) create mode 100644 app/views/projects/tags/edit.html.haml diff --git a/app/controllers/projects/tags_controller.rb b/app/controllers/projects/tags_controller.rb index f565fbbbbc3..a30c284c41f 100644 --- a/app/controllers/projects/tags_controller.rb +++ b/app/controllers/projects/tags_controller.rb @@ -10,6 +10,14 @@ class Projects::TagsController < Projects::ApplicationController @tags = Kaminari.paginate_array(sorted).page(params[:page]).per(PER_PAGE) end + def edit + # TODO: implement + end + + def update + # TODO: implement + end + def create result = CreateTagService.new(@project, current_user). execute(params[:tag_name], params[:ref], params[:message]) diff --git a/app/views/projects/tags/_tag.html.haml b/app/views/projects/tags/_tag.html.haml index 2ca295fc5f3..887f3ab075b 100644 --- a/app/views/projects/tags/_tag.html.haml +++ b/app/views/projects/tags/_tag.html.haml @@ -9,6 +9,8 @@   = strip_gpg_signature(tag.message) .controls + = link_to edit_namespace_project_tag_path(@project.namespace, @project, tag.name), class: 'btn-grouped btn' do + = icon("pencil") - if can? current_user, :download_code, @project = render 'projects/repositories/download_archive', ref: tag.name, btn_class: 'btn-grouped btn-group-xs' - if can?(current_user, :admin_project, @project) diff --git a/app/views/projects/tags/edit.html.haml b/app/views/projects/tags/edit.html.haml new file mode 100644 index 00000000000..e69de29bb2d diff --git a/config/routes.rb b/config/routes.rb index 0458f538eb6..8dc167cbbde 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -569,7 +569,7 @@ Gitlab::Application.routes.draw do end resources :branches, only: [:index, :new, :create, :destroy], constraints: { id: Gitlab::Regex.git_reference_regex } - resources :tags, only: [:index, :new, :create, :destroy], constraints: { id: Gitlab::Regex.git_reference_regex } + resources :tags, constraints: { id: Gitlab::Regex.git_reference_regex } resources :protected_branches, only: [:index, :create, :update, :destroy], constraints: { id: Gitlab::Regex.git_reference_regex } resource :variables, only: [:show, :update] resources :triggers, only: [:index, :create, :destroy] -- cgit v1.2.1 From 1c4d1c3bd69a6f9ec43cce4ab59de4ba47f73229 Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Thu, 5 Nov 2015 11:03:02 +0100 Subject: Add release model Signed-off-by: Dmitriy Zaporozhets --- app/models/release.rb | 2 ++ db/migrate/20151105094515_create_releases.rb | 14 ++++++++++++++ db/schema.rb | 13 ++++++++++++- spec/factories/releases.rb | 9 +++++++++ spec/models/release_spec.rb | 5 +++++ 5 files changed, 42 insertions(+), 1 deletion(-) create mode 100644 app/models/release.rb create mode 100644 db/migrate/20151105094515_create_releases.rb create mode 100644 spec/factories/releases.rb create mode 100644 spec/models/release_spec.rb diff --git a/app/models/release.rb b/app/models/release.rb new file mode 100644 index 00000000000..1dc9ce6dd4f --- /dev/null +++ b/app/models/release.rb @@ -0,0 +1,2 @@ +class Release < ActiveRecord::Base +end diff --git a/db/migrate/20151105094515_create_releases.rb b/db/migrate/20151105094515_create_releases.rb new file mode 100644 index 00000000000..fe4608c6662 --- /dev/null +++ b/db/migrate/20151105094515_create_releases.rb @@ -0,0 +1,14 @@ +class CreateReleases < ActiveRecord::Migration + def change + create_table :releases do |t| + t.string :tag + t.text :description + t.integer :project_id + + t.timestamps + end + + add_index :releases, :project_id + add_index :releases, [:project_id, :tag] + end +end diff --git a/db/schema.rb b/db/schema.rb index 73fc83c3d6b..34449024478 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -11,7 +11,7 @@ # # It's strongly recommended that you check this file into your version control system. -ActiveRecord::Schema.define(version: 20151026182941) do +ActiveRecord::Schema.define(version: 20151105094515) do # These are extensions that must be enabled in order to support this database enable_extension "plpgsql" @@ -637,6 +637,17 @@ ActiveRecord::Schema.define(version: 20151026182941) do add_index "protected_branches", ["project_id"], name: "index_protected_branches_on_project_id", using: :btree + create_table "releases", force: true do |t| + t.string "tag" + t.text "description" + t.integer "project_id" + t.datetime "created_at" + t.datetime "updated_at" + end + + add_index "releases", ["project_id", "tag"], name: "index_releases_on_project_id_and_tag", using: :btree + add_index "releases", ["project_id"], name: "index_releases_on_project_id", using: :btree + create_table "sent_notifications", force: true do |t| t.integer "project_id" t.integer "noteable_id" diff --git a/spec/factories/releases.rb b/spec/factories/releases.rb new file mode 100644 index 00000000000..067d8138e41 --- /dev/null +++ b/spec/factories/releases.rb @@ -0,0 +1,9 @@ +# Read about factories at https://github.com/thoughtbot/factory_girl + +FactoryGirl.define do + factory :release do + tag "MyString" + description "MyText" + project_id 1 + end +end diff --git a/spec/models/release_spec.rb b/spec/models/release_spec.rb new file mode 100644 index 00000000000..e533734ba0d --- /dev/null +++ b/spec/models/release_spec.rb @@ -0,0 +1,5 @@ +require 'rails_helper' + +RSpec.describe Release, type: :model do + pending "add some examples to (or delete) #{__FILE__}" +end -- cgit v1.2.1 From ba67af79a9ec0d37d08e51af034dd6c21170713c Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Thu, 5 Nov 2015 11:16:41 +0100 Subject: More release related logic to separate resource Signed-off-by: Dmitriy Zaporozhets --- app/controllers/projects/releases_controller.rb | 32 +++++++++++++++++++++++++ app/controllers/projects/tags_controller.rb | 8 ------- app/models/project.rb | 3 ++- app/views/projects/releases/edit.html.haml | 6 +++++ app/views/projects/releases/show.html.haml | 1 + app/views/projects/tags/_tag.html.haml | 2 +- app/views/projects/tags/edit.html.haml | 0 config/routes.rb | 5 +++- 8 files changed, 46 insertions(+), 11 deletions(-) create mode 100644 app/controllers/projects/releases_controller.rb create mode 100644 app/views/projects/releases/edit.html.haml create mode 100644 app/views/projects/releases/show.html.haml delete mode 100644 app/views/projects/tags/edit.html.haml diff --git a/app/controllers/projects/releases_controller.rb b/app/controllers/projects/releases_controller.rb new file mode 100644 index 00000000000..877cc0f3674 --- /dev/null +++ b/app/controllers/projects/releases_controller.rb @@ -0,0 +1,32 @@ +class Projects::ReleasesController < Projects::ApplicationController + # Authorize + before_action :require_non_empty_project + before_action :authorize_download_code! + before_action :authorize_push_code! + before_action :tag + before_action :release + + def show + end + + def edit + end + + def update + description = params[:release][:description] + release.update_attributes(description: description) + release.save + + redirect_to namespace_project_tag_release_path(@project.namespace, @project, @tag.name) + end + + private + + def tag + @tag ||= @repository.find_tag(params[:tag_id]) + end + + def release + @release ||= @project.releases.find_or_initialize_by(tag: @tag.name) + end +end diff --git a/app/controllers/projects/tags_controller.rb b/app/controllers/projects/tags_controller.rb index a30c284c41f..f565fbbbbc3 100644 --- a/app/controllers/projects/tags_controller.rb +++ b/app/controllers/projects/tags_controller.rb @@ -10,14 +10,6 @@ class Projects::TagsController < Projects::ApplicationController @tags = Kaminari.paginate_array(sorted).page(params[:page]).per(PER_PAGE) end - def edit - # TODO: implement - end - - def update - # TODO: implement - end - def create result = CreateTagService.new(@project, current_user). execute(params[:tag_name], params[:ref], params[:message]) diff --git a/app/models/project.rb b/app/models/project.rb index 74b89aad499..cd3de01a95f 100644 --- a/app/models/project.rb +++ b/app/models/project.rb @@ -121,6 +121,7 @@ class Project < ActiveRecord::Base has_many :starrers, through: :users_star_projects, source: :user has_many :ci_commits, dependent: :destroy, class_name: 'Ci::Commit', foreign_key: :gl_project_id has_many :ci_builds, through: :ci_commits, source: :builds, dependent: :destroy, class_name: 'Ci::Build' + has_many :releases, dependent: :destroy has_one :import_data, dependent: :destroy, class_name: "ProjectImportData" has_one :gitlab_ci_project, dependent: :destroy, class_name: "Ci::Project", foreign_key: :gitlab_id @@ -247,7 +248,7 @@ class Project < ActiveRecord::Base joins(:namespace). iwhere('namespaces.path' => namespace_path) - projects.where('projects.path' => project_path).take || + projects.where('projects.path' => project_path).take || projects.iwhere('projects.path' => project_path).take end diff --git a/app/views/projects/releases/edit.html.haml b/app/views/projects/releases/edit.html.haml new file mode 100644 index 00000000000..3b4a5e72238 --- /dev/null +++ b/app/views/projects/releases/edit.html.haml @@ -0,0 +1,6 @@ += form_for(@release, method: :put, url: namespace_project_tag_release_path(@project.namespace, @project, @tag.name), html: { class: 'form-horizontal gfm-form' }) do |f| + = render layout: 'projects/md_preview', locals: { preview_class: "md-preview", referenced_users: true } do + = render 'projects/zen', f: f, attr: :description, classes: 'js-quick-submit' + = render 'projects/notes/hints' + .error-alert + = f.submit 'Save changes', class: 'btn btn-save' diff --git a/app/views/projects/releases/show.html.haml b/app/views/projects/releases/show.html.haml new file mode 100644 index 00000000000..bd831500086 --- /dev/null +++ b/app/views/projects/releases/show.html.haml @@ -0,0 +1 @@ += debug @release diff --git a/app/views/projects/tags/_tag.html.haml b/app/views/projects/tags/_tag.html.haml index 887f3ab075b..526dd3f580b 100644 --- a/app/views/projects/tags/_tag.html.haml +++ b/app/views/projects/tags/_tag.html.haml @@ -9,7 +9,7 @@   = strip_gpg_signature(tag.message) .controls - = link_to edit_namespace_project_tag_path(@project.namespace, @project, tag.name), class: 'btn-grouped btn' do + = link_to edit_namespace_project_tag_release_path(@project.namespace, @project, tag.name), class: 'btn-grouped btn' do = icon("pencil") - if can? current_user, :download_code, @project = render 'projects/repositories/download_archive', ref: tag.name, btn_class: 'btn-grouped btn-group-xs' diff --git a/app/views/projects/tags/edit.html.haml b/app/views/projects/tags/edit.html.haml deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/config/routes.rb b/config/routes.rb index 8dc167cbbde..5836da47eb3 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -569,7 +569,10 @@ Gitlab::Application.routes.draw do end resources :branches, only: [:index, :new, :create, :destroy], constraints: { id: Gitlab::Regex.git_reference_regex } - resources :tags, constraints: { id: Gitlab::Regex.git_reference_regex } + resources :tags, only: [:index, :new, :create, :destroy], constraints: { id: Gitlab::Regex.git_reference_regex } do + resource :release + end + resources :protected_branches, only: [:index, :create, :update, :destroy], constraints: { id: Gitlab::Regex.git_reference_regex } resource :variables, only: [:show, :update] resources :triggers, only: [:index, :create, :destroy] -- cgit v1.2.1 From a4d75e3aec2e721231bc1e01a2e5e87aefe15113 Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Thu, 5 Nov 2015 12:15:25 +0100 Subject: Add ability to edit and show release notes Signed-off-by: Dmitriy Zaporozhets --- app/assets/javascripts/dispatcher.js.coffee | 3 +++ app/assets/stylesheets/framework/common.scss | 1 + app/controllers/projects/releases_controller.rb | 1 + app/views/layouts/nav/_project.html.haml | 2 +- app/views/projects/commits/_head.html.haml | 2 +- app/views/projects/releases/edit.html.haml | 24 ++++++++++++----- app/views/projects/releases/show.html.haml | 36 ++++++++++++++++++++++++- 7 files changed, 60 insertions(+), 9 deletions(-) diff --git a/app/assets/javascripts/dispatcher.js.coffee b/app/assets/javascripts/dispatcher.js.coffee index 5bf0b302179..030826be74d 100644 --- a/app/assets/javascripts/dispatcher.js.coffee +++ b/app/assets/javascripts/dispatcher.js.coffee @@ -39,6 +39,9 @@ class Dispatcher shortcut_handler = new ShortcutsNavigation() new DropzoneInput($('.merge-request-form')) new IssuableForm($('.merge-request-form')) + when 'projects:releases:edit' + new ZenMode() + new DropzoneInput($('.release-form')) when 'projects:merge_requests:show' new Diff() shortcut_handler = new ShortcutsIssuable() diff --git a/app/assets/stylesheets/framework/common.scss b/app/assets/stylesheets/framework/common.scss index 41287d52f69..ddbacd7fd41 100644 --- a/app/assets/stylesheets/framework/common.scss +++ b/app/assets/stylesheets/framework/common.scss @@ -16,6 +16,7 @@ .append-bottom-10 { margin-bottom:10px } .append-bottom-15 { margin-bottom:15px } .append-bottom-20 { margin-bottom:20px } +.append-bottom-default { margin-bottom: $gl-padding; } .inline { display: inline-block } .center { text-align: center } diff --git a/app/controllers/projects/releases_controller.rb b/app/controllers/projects/releases_controller.rb index 877cc0f3674..7d1a011cc0a 100644 --- a/app/controllers/projects/releases_controller.rb +++ b/app/controllers/projects/releases_controller.rb @@ -7,6 +7,7 @@ class Projects::ReleasesController < Projects::ApplicationController before_action :release def show + @commit = @repository.commit(@tag.target) end def edit diff --git a/app/views/layouts/nav/_project.html.haml b/app/views/layouts/nav/_project.html.haml index 20db2866d1f..2b91d7721f9 100644 --- a/app/views/layouts/nav/_project.html.haml +++ b/app/views/layouts/nav/_project.html.haml @@ -32,7 +32,7 @@ Files - if project_nav_tab? :commits - = nav_link(controller: %w(commit commits compare repositories tags branches)) do + = nav_link(controller: %w(commit commits compare repositories tags branches releases)) do = link_to project_commits_path(@project), title: 'Commits', class: 'shortcuts-commits', data: {placement: 'right'} do = icon('history fw') %span diff --git a/app/views/projects/commits/_head.html.haml b/app/views/projects/commits/_head.html.haml index a849bf84698..f11a41cfd7b 100644 --- a/app/views/projects/commits/_head.html.haml +++ b/app/views/projects/commits/_head.html.haml @@ -12,7 +12,7 @@ Branches %span.badge.js-totalbranch-count= @repository.branches.size - = nav_link(controller: :tags) do + = nav_link(controller: [:tags, :releases]) do = link_to namespace_project_tags_path(@project.namespace, @project) do Tags %span.badge.js-totaltags-count= @repository.tags.length diff --git a/app/views/projects/releases/edit.html.haml b/app/views/projects/releases/edit.html.haml index 3b4a5e72238..612e4696226 100644 --- a/app/views/projects/releases/edit.html.haml +++ b/app/views/projects/releases/edit.html.haml @@ -1,6 +1,18 @@ -= form_for(@release, method: :put, url: namespace_project_tag_release_path(@project.namespace, @project, @tag.name), html: { class: 'form-horizontal gfm-form' }) do |f| - = render layout: 'projects/md_preview', locals: { preview_class: "md-preview", referenced_users: true } do - = render 'projects/zen', f: f, attr: :description, classes: 'js-quick-submit' - = render 'projects/notes/hints' - .error-alert - = f.submit 'Save changes', class: 'btn btn-save' += render "projects/commits/header_title" += render "projects/commits/head" + +.gray-content-block + .oneline + Release notes for #{@tag.name} + +.prepend-top-default + = form_for(@release, method: :put, url: namespace_project_tag_release_path(@project.namespace, @project, @tag.name), html: { class: 'form-horizontal gfm-form release-form' }) do |f| + = render layout: 'projects/md_preview', locals: { preview_class: "md-preview", referenced_users: true } do + = render 'projects/zen', f: f, attr: :description, classes: 'description js-quick-submit' + = render 'projects/notes/hints' + .error-alert + .prepend-top-default + = f.submit 'Save changes', class: 'btn btn-save' + - if @release.persisted? + = link_to "Cancel", namespace_project_tag_release_path(@project.namespace, @project, @tag.name), class: "btn btn-default btn-cancel" + diff --git a/app/views/projects/releases/show.html.haml b/app/views/projects/releases/show.html.haml index bd831500086..606510f132f 100644 --- a/app/views/projects/releases/show.html.haml +++ b/app/views/projects/releases/show.html.haml @@ -1 +1,35 @@ -= debug @release +- page_title @release.tag, "Releases" += render "projects/commits/header_title" += render "projects/commits/head" + +.gray-content-block + .pull-right + = link_to edit_namespace_project_tag_release_path(@project.namespace, @project, @tag.name), class: 'btn-grouped btn' do + = icon("pencil") + .oneline Release notes for #{@tag.name} + +.append-bottom-default.prepend-top-default + - if @release.description.present? + .description + .wiki + = preserve do + = markdown @release.description + - else + This tag has no release notes yet. Press edit button to add one + +.gray-content-block.middle-block.clearfix + = link_to namespace_project_tree_path(@project.namespace, @project, @tag.name), class: 'btn btn-grouped' do + Browse code + = link_to namespace_project_commits_path(@project.namespace, @project, @tag.name), class: 'btn btn-grouped' do + Commits + - if can? current_user, :download_code, @project + = render 'projects/repositories/download_archive', ref: @tag.name, btn_class: 'btn-grouped' + -#- if can?(current_user, :admin_project, @project) + = link_to namespace_project_tag_path(@project.namespace, @project, @tag.name), class: 'btn btn-remove remove-row grouped', method: :delete, data: { confirm: 'Removed tag cannot be restored. Are you sure?'}, remote: true do + %i.fa.fa-trash-o + +.gray-content-block.second-block + - if @commit + = render 'projects/commits/commit', commit: @commit, project: @project + - else + Cant find HEAD commit for this tag -- cgit v1.2.1 From 6051c28fc03b4d9928ee2f2855f210845f9c0579 Mon Sep 17 00:00:00 2001 From: Valery Sizov Date: Thu, 5 Nov 2015 12:38:00 +0200 Subject: Allow groups to appear in the search results if the group owner allows it --- CHANGELOG | 1 + app/controllers/groups_controller.rb | 6 +-- app/finders/groups_finder.rb | 57 ++++++++++++------------ app/helpers/search_helper.rb | 2 +- app/models/group.rb | 2 +- app/views/groups/edit.html.haml | 9 ++++ db/migrate/20151103001141_add_public_to_group.rb | 5 +++ db/schema.rb | 9 ++-- spec/finders/group_finder_spec.rb | 15 +++++++ spec/helpers/search_helper_spec.rb | 5 +++ spec/models/group_spec.rb | 19 ++++++++ 11 files changed, 93 insertions(+), 37 deletions(-) create mode 100644 db/migrate/20151103001141_add_public_to_group.rb create mode 100644 spec/finders/group_finder_spec.rb diff --git a/CHANGELOG b/CHANGELOG index 0ec6030b130..3a75f50e9a2 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -22,6 +22,7 @@ v 8.2.0 (unreleased) - Include commit logs in project search - Add "added", "modified" and "removed" properties to commit object in webhook - Rename "Back to" links to "Go to" because its not always a case it point to place user come from + - Allow groups to appear in the search results if the group owner allows it v 8.1.3 - Spread out runner contacted_at updates diff --git a/app/controllers/groups_controller.rb b/app/controllers/groups_controller.rb index 40fb15a5b36..fb4eb094f27 100644 --- a/app/controllers/groups_controller.rb +++ b/app/controllers/groups_controller.rb @@ -4,12 +4,12 @@ class GroupsController < Groups::ApplicationController before_action :group, except: [:new, :create] # Authorize - before_action :authorize_read_group!, except: [:show, :new, :create] + before_action :authorize_read_group!, except: [:show, :new, :create, :autocomplete] before_action :authorize_admin_group!, only: [:edit, :update, :destroy, :projects] before_action :authorize_create_group!, only: [:new, :create] # Load group projects - before_action :load_projects, except: [:new, :create, :projects, :edit, :update] + before_action :load_projects, except: [:new, :create, :projects, :edit, :update, :autocomplete] before_action :event_filter, only: :show layout :determine_layout @@ -133,7 +133,7 @@ class GroupsController < Groups::ApplicationController end def group_params - params.require(:group).permit(:name, :description, :path, :avatar) + params.require(:group).permit(:name, :description, :path, :avatar, :public) end def load_events diff --git a/app/finders/groups_finder.rb b/app/finders/groups_finder.rb index d3597ef0901..b5f3176461c 100644 --- a/app/finders/groups_finder.rb +++ b/app/finders/groups_finder.rb @@ -6,33 +6,34 @@ class GroupsFinder private def all_groups(current_user) - if current_user - if current_user.authorized_groups.any? - # User has access to groups - # - # Return only: - # groups with public projects - # groups with internal projects - # groups with joined projects - # - group_ids = Project.public_and_internal_only.pluck(:namespace_id) + - current_user.authorized_groups.pluck(:id) - Group.where(id: group_ids) - else - # User has no group membership - # - # Return only: - # groups with public projects - # groups with internal projects - # - Group.where(id: Project.public_and_internal_only.pluck(:namespace_id)) - end - else - # Not authenticated - # - # Return only: - # groups with public projects - Group.where(id: Project.public_only.pluck(:namespace_id)) - end + group_ids = if current_user + if current_user.authorized_groups.any? + # User has access to groups + # + # Return only: + # groups with public projects + # groups with internal projects + # groups with joined projects + # + Project.public_and_internal_only.pluck(:namespace_id) + + current_user.authorized_groups.pluck(:id) + else + # User has no group membership + # + # Return only: + # groups with public projects + # groups with internal projects + # + Project.public_and_internal_only.pluck(:namespace_id) + end + else + # Not authenticated + # + # Return only: + # groups with public projects + Project.public_only.pluck(:namespace_id) + end + + Group.where("public IS TRUE OR id IN(?)", group_ids) end end diff --git a/app/helpers/search_helper.rb b/app/helpers/search_helper.rb index c31a556ff7b..a6ee6880247 100644 --- a/app/helpers/search_helper.rb +++ b/app/helpers/search_helper.rb @@ -70,7 +70,7 @@ module SearchHelper # Autocomplete results for the current user's groups def groups_autocomplete(term, limit = 5) - current_user.authorized_groups.search(term).limit(limit).map do |group| + GroupsFinder.new.execute(current_user).search(term).limit(limit).map do |group| { label: "group: #{search_result_sanitize(group.name)}", url: group_path(group) diff --git a/app/models/group.rb b/app/models/group.rb index 465c22d23ac..34904af3b5b 100644 --- a/app/models/group.rb +++ b/app/models/group.rb @@ -120,7 +120,7 @@ class Group < Namespace end def public_profile? - projects.public_only.any? + self.public || projects.public_only.any? end def post_create_hook diff --git a/app/views/groups/edit.html.haml b/app/views/groups/edit.html.haml index ae8fc9f85f0..57308a661c0 100644 --- a/app/views/groups/edit.html.haml +++ b/app/views/groups/edit.html.haml @@ -25,6 +25,15 @@ %hr = link_to 'Remove avatar', group_avatar_path(@group.to_param), data: { confirm: "Group avatar will be removed. Are you sure?"}, method: :delete, class: "btn btn-remove btn-sm remove-avatar" + .form-group + %hr + = f.label :public, class: 'control-label' do + Public + .col-sm-10 + .checkbox + = f.check_box :public + %span.descr Make this group public (even if there is no any public project inside this group) + .form-actions = f.submit 'Save group', class: "btn btn-save" diff --git a/db/migrate/20151103001141_add_public_to_group.rb b/db/migrate/20151103001141_add_public_to_group.rb new file mode 100644 index 00000000000..635346300c2 --- /dev/null +++ b/db/migrate/20151103001141_add_public_to_group.rb @@ -0,0 +1,5 @@ +class AddPublicToGroup < ActiveRecord::Migration + def change + add_column :namespaces, :public, :boolean, default: false + end +end diff --git a/db/schema.rb b/db/schema.rb index 73fc83c3d6b..17d445a8baa 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -11,7 +11,7 @@ # # It's strongly recommended that you check this file into your version control system. -ActiveRecord::Schema.define(version: 20151026182941) do +ActiveRecord::Schema.define(version: 20151103001141) do # These are extensions that must be enabled in order to support this database enable_extension "plpgsql" @@ -501,14 +501,15 @@ ActiveRecord::Schema.define(version: 20151026182941) do add_index "milestones", ["project_id"], name: "index_milestones_on_project_id", using: :btree create_table "namespaces", force: true do |t| - t.string "name", null: false - t.string "path", null: false + t.string "name", null: false + t.string "path", null: false t.integer "owner_id" t.datetime "created_at" t.datetime "updated_at" t.string "type" - t.string "description", default: "", null: false + t.string "description", default: "", null: false t.string "avatar" + t.boolean "public", default: false end add_index "namespaces", ["created_at", "id"], name: "index_namespaces_on_created_at_and_id", using: :btree diff --git a/spec/finders/group_finder_spec.rb b/spec/finders/group_finder_spec.rb new file mode 100644 index 00000000000..78dc027837c --- /dev/null +++ b/spec/finders/group_finder_spec.rb @@ -0,0 +1,15 @@ +require 'spec_helper' + +describe GroupsFinder do + let(:user) { create :user } + let!(:group) { create :group } + let!(:public_group) { create :group, public: true } + + describe :execute do + it 'finds public group' do + groups = GroupsFinder.new.execute(user) + expect(groups.size).to eq(1) + expect(groups.first).to eq(public_group) + end + end +end diff --git a/spec/helpers/search_helper_spec.rb b/spec/helpers/search_helper_spec.rb index b327f4f911a..ebe9c29d91c 100644 --- a/spec/helpers/search_helper_spec.rb +++ b/spec/helpers/search_helper_spec.rb @@ -42,6 +42,11 @@ describe SearchHelper do expect(search_autocomplete_opts(project.name).size).to eq(1) end + it "includes the public group" do + group = create(:group, public: true) + expect(search_autocomplete_opts(group.name).size).to eq(1) + end + context "with a current project" do before { @project = create(:project) } diff --git a/spec/models/group_spec.rb b/spec/models/group_spec.rb index 80638fc8db2..0f23e81ace9 100644 --- a/spec/models/group_spec.rb +++ b/spec/models/group_spec.rb @@ -84,4 +84,23 @@ describe Group do expect(group.avatar_type).to eq(["only images allowed"]) end end + + describe "public_profile?" do + it "returns true for public group" do + group = create(:group, public: true) + expect(group.public_profile?).to be_truthy + end + + it "returns true for non-public group with public project" do + group = create(:group) + create(:project, :public, group: group) + expect(group.public_profile?).to be_truthy + end + + it "returns false for non-public group with no public projects" do + group = create(:group) + create(:project, group: group) + expect(group.public_profile?).to be_falsy + end + end end -- cgit v1.2.1 From 850bb21b12b21fe0cf943278bc8cadad85d48dc5 Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Thu, 5 Nov 2015 13:49:34 +0100 Subject: Create show page for tag and render release notes there and on index page Signed-off-by: Dmitriy Zaporozhets --- app/assets/stylesheets/framework/callout.scss | 6 ++-- app/assets/stylesheets/pages/commits.scss | 7 ++++ app/controllers/projects/releases_controller.rb | 6 +--- app/controllers/projects/tags_controller.rb | 7 ++++ app/views/projects/branches/_commit.html.haml | 4 +-- app/views/projects/releases/edit.html.haml | 3 +- app/views/projects/releases/show.html.haml | 35 -------------------- app/views/projects/tags/_tag.html.haml | 11 ++++++- app/views/projects/tags/show.html.haml | 44 +++++++++++++++++++++++++ config/routes.rb | 4 +-- 10 files changed, 77 insertions(+), 50 deletions(-) delete mode 100644 app/views/projects/releases/show.html.haml create mode 100644 app/views/projects/tags/show.html.haml diff --git a/app/assets/stylesheets/framework/callout.scss b/app/assets/stylesheets/framework/callout.scss index f1699d21c9b..f3ce4e3c219 100644 --- a/app/assets/stylesheets/framework/callout.scss +++ b/app/assets/stylesheets/framework/callout.scss @@ -9,9 +9,9 @@ .bs-callout { margin: 20px 0; padding: 20px; - border-left: 3px solid #eee; - color: #666; - background: #f9f9f9; + border-left: 3px solid $border-color; + color: $text-color; + background: $background-color; } .bs-callout h4 { margin-top: 0; diff --git a/app/assets/stylesheets/pages/commits.scss b/app/assets/stylesheets/pages/commits.scss index e485487bcfd..c9dfcff6290 100644 --- a/app/assets/stylesheets/pages/commits.scss +++ b/app/assets/stylesheets/pages/commits.scss @@ -115,3 +115,10 @@ li.commit { } } } + +.branch-commit { + color: $gl-gray; + .commit-id, .commit-row-message { + color: $gl-gray; + } +} diff --git a/app/controllers/projects/releases_controller.rb b/app/controllers/projects/releases_controller.rb index 7d1a011cc0a..f69a4bc729e 100644 --- a/app/controllers/projects/releases_controller.rb +++ b/app/controllers/projects/releases_controller.rb @@ -6,10 +6,6 @@ class Projects::ReleasesController < Projects::ApplicationController before_action :tag before_action :release - def show - @commit = @repository.commit(@tag.target) - end - def edit end @@ -18,7 +14,7 @@ class Projects::ReleasesController < Projects::ApplicationController release.update_attributes(description: description) release.save - redirect_to namespace_project_tag_release_path(@project.namespace, @project, @tag.name) + redirect_to namespace_project_tag_path(@project.namespace, @project, @tag.name) end private diff --git a/app/controllers/projects/tags_controller.rb b/app/controllers/projects/tags_controller.rb index f565fbbbbc3..dfc8dbe01c5 100644 --- a/app/controllers/projects/tags_controller.rb +++ b/app/controllers/projects/tags_controller.rb @@ -8,6 +8,13 @@ class Projects::TagsController < Projects::ApplicationController def index sorted = VersionSorter.rsort(@repository.tag_names) @tags = Kaminari.paginate_array(sorted).page(params[:page]).per(PER_PAGE) + @releases = project.releases.where(tag: @tags) + end + + def show + @tag = @repository.find_tag(params[:id]) + @release = @project.releases.find_or_initialize_by(tag: @tag.name) + @commit = @repository.commit(@tag.target) end def create diff --git a/app/views/projects/branches/_commit.html.haml b/app/views/projects/branches/_commit.html.haml index 68326e65d85..22d77dda938 100644 --- a/app/views/projects/branches/_commit.html.haml +++ b/app/views/projects/branches/_commit.html.haml @@ -1,5 +1,5 @@ -.branch-commit.light - = link_to commit.short_id, namespace_project_commit_path(project.namespace, project, commit), class: "commit_short_id" +.branch-commit + = link_to commit.short_id, namespace_project_commit_path(project.namespace, project, commit), class: "commit-id" · %span.str-truncated = link_to_gfm commit.title, namespace_project_commit_path(project.namespace, project, commit.id), class: "commit-row-message" diff --git a/app/views/projects/releases/edit.html.haml b/app/views/projects/releases/edit.html.haml index 612e4696226..fb841b77a25 100644 --- a/app/views/projects/releases/edit.html.haml +++ b/app/views/projects/releases/edit.html.haml @@ -13,6 +13,5 @@ .error-alert .prepend-top-default = f.submit 'Save changes', class: 'btn btn-save' - - if @release.persisted? - = link_to "Cancel", namespace_project_tag_release_path(@project.namespace, @project, @tag.name), class: "btn btn-default btn-cancel" + = link_to "Cancel", namespace_project_tag_path(@project.namespace, @project, @tag.name), class: "btn btn-default btn-cancel" diff --git a/app/views/projects/releases/show.html.haml b/app/views/projects/releases/show.html.haml deleted file mode 100644 index 606510f132f..00000000000 --- a/app/views/projects/releases/show.html.haml +++ /dev/null @@ -1,35 +0,0 @@ -- page_title @release.tag, "Releases" -= render "projects/commits/header_title" -= render "projects/commits/head" - -.gray-content-block - .pull-right - = link_to edit_namespace_project_tag_release_path(@project.namespace, @project, @tag.name), class: 'btn-grouped btn' do - = icon("pencil") - .oneline Release notes for #{@tag.name} - -.append-bottom-default.prepend-top-default - - if @release.description.present? - .description - .wiki - = preserve do - = markdown @release.description - - else - This tag has no release notes yet. Press edit button to add one - -.gray-content-block.middle-block.clearfix - = link_to namespace_project_tree_path(@project.namespace, @project, @tag.name), class: 'btn btn-grouped' do - Browse code - = link_to namespace_project_commits_path(@project.namespace, @project, @tag.name), class: 'btn btn-grouped' do - Commits - - if can? current_user, :download_code, @project - = render 'projects/repositories/download_archive', ref: @tag.name, btn_class: 'btn-grouped' - -#- if can?(current_user, :admin_project, @project) - = link_to namespace_project_tag_path(@project.namespace, @project, @tag.name), class: 'btn btn-remove remove-row grouped', method: :delete, data: { confirm: 'Removed tag cannot be restored. Are you sure?'}, remote: true do - %i.fa.fa-trash-o - -.gray-content-block.second-block - - if @commit - = render 'projects/commits/commit', commit: @commit, project: @project - - else - Cant find HEAD commit for this tag diff --git a/app/views/projects/tags/_tag.html.haml b/app/views/projects/tags/_tag.html.haml index 526dd3f580b..5d203903f8b 100644 --- a/app/views/projects/tags/_tag.html.haml +++ b/app/views/projects/tags/_tag.html.haml @@ -1,13 +1,17 @@ - commit = @repository.commit(tag.target) +- release = @releases.find { |release| release.tag == tag.name } %li %div - = link_to namespace_project_commits_path(@project.namespace, @project, tag.name), class: "" do + = link_to namespace_project_tag_path(@project.namespace, @project, tag.name) do %strong %i.fa.fa-tag = tag.name - if tag.message.present?   = strip_gpg_signature(tag.message) + - if release + %span.label.label-success release + .controls = link_to edit_namespace_project_tag_release_path(@project.namespace, @project, tag.name), class: 'btn-grouped btn' do = icon("pencil") @@ -22,3 +26,8 @@ - else %p Cant find HEAD commit for this tag + - if release && release.description.present? + .description.prepend-top-default + .wiki + = preserve do + = markdown release.description diff --git a/app/views/projects/tags/show.html.haml b/app/views/projects/tags/show.html.haml new file mode 100644 index 00000000000..d2f23b96a8c --- /dev/null +++ b/app/views/projects/tags/show.html.haml @@ -0,0 +1,44 @@ +- page_title @tag.name, "Tags" += render "projects/commits/header_title" += render "projects/commits/head" + +.gray-content-block + .pull-right + = link_to edit_namespace_project_tag_release_path(@project.namespace, @project, @tag.name), class: 'btn-grouped btn' do + = icon("pencil") + - if @tag.message.present? + .title + %strong= @tag.name + = strip_gpg_signature(@tag.message) + - else + .oneline + .title + %strong= @tag.name + +.append-bottom-default.prepend-top-default + - if @release.description.present? + .description + .wiki + = preserve do + = markdown @release.description + - else + This tag has no release notes yet. Press edit button to add one + +.gray-content-block.middle-block.clearfix + = link_to namespace_project_tree_path(@project.namespace, @project, @tag.name), class: 'btn btn-grouped' do + Browse code + = link_to namespace_project_commits_path(@project.namespace, @project, @tag.name), class: 'btn btn-grouped' do + Commits + - if can? current_user, :download_code, @project + = render 'projects/repositories/download_archive', ref: @tag.name, btn_class: 'btn-grouped' + - if can?(current_user, :admin_project, @project) + .pull-right + = link_to namespace_project_tag_path(@project.namespace, @project, @tag.name), class: 'btn btn-remove remove-row grouped', method: :delete, data: { confirm: 'Removed tag cannot be restored. Are you sure?'}, remote: true do + %i.fa.fa-trash-o + +.gray-content-block.second-block + - if @commit + = render 'projects/commits/commit', commit: @commit, project: @project + - else + Cant find HEAD commit for this tag + diff --git a/config/routes.rb b/config/routes.rb index 5836da47eb3..c7aa95118e0 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -569,8 +569,8 @@ Gitlab::Application.routes.draw do end resources :branches, only: [:index, :new, :create, :destroy], constraints: { id: Gitlab::Regex.git_reference_regex } - resources :tags, only: [:index, :new, :create, :destroy], constraints: { id: Gitlab::Regex.git_reference_regex } do - resource :release + resources :tags, only: [:index, :show, :new, :create, :destroy], constraints: { id: Gitlab::Regex.git_reference_regex } do + resource :release, only: [:edit, :update] end resources :protected_branches, only: [:index, :create, :update, :destroy], constraints: { id: Gitlab::Regex.git_reference_regex } -- cgit v1.2.1 From 312cf11b61e6bbee8283dfb267516e6b42454431 Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Thu, 5 Nov 2015 14:03:48 +0100 Subject: Add release description to new tag form Signed-off-by: Dmitriy Zaporozhets --- app/assets/javascripts/dispatcher.js.coffee | 3 +++ app/controllers/projects/tags_controller.rb | 7 +++++++ app/views/projects/tags/new.html.haml | 19 ++++++++++++++++++- 3 files changed, 28 insertions(+), 1 deletion(-) diff --git a/app/assets/javascripts/dispatcher.js.coffee b/app/assets/javascripts/dispatcher.js.coffee index 030826be74d..951173af5d5 100644 --- a/app/assets/javascripts/dispatcher.js.coffee +++ b/app/assets/javascripts/dispatcher.js.coffee @@ -39,6 +39,9 @@ class Dispatcher shortcut_handler = new ShortcutsNavigation() new DropzoneInput($('.merge-request-form')) new IssuableForm($('.merge-request-form')) + when 'projects:tags:new' + new ZenMode() + new DropzoneInput($('.tag-form')) when 'projects:releases:edit' new ZenMode() new DropzoneInput($('.release-form')) diff --git a/app/controllers/projects/tags_controller.rb b/app/controllers/projects/tags_controller.rb index dfc8dbe01c5..c4a3e3dca94 100644 --- a/app/controllers/projects/tags_controller.rb +++ b/app/controllers/projects/tags_controller.rb @@ -23,6 +23,13 @@ class Projects::TagsController < Projects::ApplicationController if result[:status] == :success @tag = result[:tag] + + if params[:release_description] + release = @project.releases.find_or_initialize_by(tag: @tag.name) + release.update_attributes(description: params[:release_description]) + release.save + end + redirect_to namespace_project_tags_path(@project.namespace, @project) else @error = result[:message] diff --git a/app/views/projects/tags/new.html.haml b/app/views/projects/tags/new.html.haml index 9f5c1be125c..9b224ff89b0 100644 --- a/app/views/projects/tags/new.html.haml +++ b/app/views/projects/tags/new.html.haml @@ -8,7 +8,7 @@ %h3.page-title %i.fa.fa-code-fork New tag -= form_tag namespace_project_tags_path, method: :post, id: "new-tag-form", class: "form-horizontal" do += form_tag namespace_project_tags_path, method: :post, id: "new-tag-form", class: "form-horizontal tag-form" do .form-group = label_tag :tag_name, 'Name for new tag', class: 'control-label' .col-sm-10 @@ -23,6 +23,23 @@ .col-sm-10 = text_field_tag :message, nil, placeholder: 'Enter message.', required: false, tabindex: 3, class: 'form-control' .light (Optional) Entering a message will create an annotated tag. + %hr + .form-group + = label_tag :release_description, 'Release description', class: 'control-label' + .col-sm-10 + = render layout: 'projects/md_preview', locals: { preview_class: "md-preview", referenced_users: true } do + .zennable + %input#zen-toggle-comment.zen-toggle-comment(tabindex="-1" type="checkbox") + .zen-backdrop + = text_area_tag :release_description, nil, class: 'js-gfm-input markdown-area description js-quick-submit form-control', placeholder: '' + %a.zen-enter-link(tabindex="-1" href="#") + = icon('expand') + Edit in fullscreen + %a.zen-leave-link(href="#") + = icon('compress') + + = render 'projects/notes/hints' + .help-block You can add release description to your tag. It will be stored in GitLab database and displayed on tags page .form-actions = button_tag 'Create tag', class: 'btn btn-create', tabindex: 3 = link_to 'Cancel', namespace_project_tags_path(@project.namespace, @project), class: 'btn btn-cancel' -- cgit v1.2.1 From 26677fbe213069a3820f9f20d528bd560d447bea Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Thu, 5 Nov 2015 14:07:55 +0100 Subject: After tag is created - redirect to tag page Signed-off-by: Dmitriy Zaporozhets --- app/controllers/projects/tags_controller.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/controllers/projects/tags_controller.rb b/app/controllers/projects/tags_controller.rb index c4a3e3dca94..055f328677f 100644 --- a/app/controllers/projects/tags_controller.rb +++ b/app/controllers/projects/tags_controller.rb @@ -30,7 +30,7 @@ class Projects::TagsController < Projects::ApplicationController release.save end - redirect_to namespace_project_tags_path(@project.namespace, @project) + redirect_to namespace_project_tag_path(@project.namespace, @project, @tag.name) else @error = result[:message] render action: 'new' -- cgit v1.2.1 From ba68facf8d744f6de49b40a2e9923e6555c92cd7 Mon Sep 17 00:00:00 2001 From: Kamil Trzcinski Date: Tue, 3 Nov 2015 11:44:07 +0100 Subject: CI details cleanup - Add page titles to CI settings. - Fix CI admin navigation. - Remove duplicated scope. - Use monospace font for commit sha. - Add page title and header title to build page. - Proper authorization for cancel/retry builds. - Use gitlab pagination theme for builds and group members. - Don't paginate builds widget on build page. - Add badges to commit page Changes/Builds tabs. - Add "Builds" to commit Builds tab page title. - Add and use Ci::Build#retryable? method. - Add CI::Build#retried? method. - Allow all failed commit builds to be retried. - Proper authorization for cancel/retry all builds. - Remove unused param. - Use time_ago_with_tooltip where appropriate. - Tweak builds index text - Remove duplication between builds/build and commit_statuses/commit_status. - Use POST rather than GET for canceling and retrying builds. - Remove redundant URL helpers. - Add build ID to build page. - Link branch name on build page. - Move commit/:sha/ci to commit/:sha/builds. --- app/controllers/projects/builds_controller.rb | 10 +-- app/controllers/projects/commit_controller.rb | 38 ++++++++---- app/helpers/builds_helper.rb | 13 ---- app/helpers/ci/gitlab_helper.rb | 19 ------ app/helpers/ci_status_helper.rb | 2 +- app/models/ci/build.rb | 10 ++- app/models/commit_status.rb | 4 +- app/models/project_services/ci/hip_chat_message.rb | 2 +- app/models/project_services/ci/slack_message.rb | 2 +- app/models/project_services/gitlab_ci_service.rb | 2 +- app/views/ci/notify/build_fail_email.html.haml | 4 +- app/views/ci/notify/build_success_email.html.haml | 4 +- app/views/dashboard/groups/index.html.haml | 2 +- app/views/layouts/ci/_nav_admin.html.haml | 18 +++--- app/views/projects/_last_commit.html.haml | 2 +- app/views/projects/builds/_build.html.haml | 53 ---------------- app/views/projects/builds/_header_title.html.haml | 1 + app/views/projects/builds/index.html.haml | 12 ++-- app/views/projects/builds/show.html.haml | 39 ++++++------ app/views/projects/ci_services/edit.html.haml | 1 + app/views/projects/ci_services/index.html.haml | 1 + app/views/projects/ci_settings/edit.html.haml | 1 + app/views/projects/ci_web_hooks/index.html.haml | 1 + app/views/projects/commit/_ci_menu.html.haml | 6 +- app/views/projects/commit/_commit_box.html.haml | 4 +- app/views/projects/commit/builds.html.haml | 72 ++++++++++++++++++++++ app/views/projects/commit/ci.html.haml | 69 --------------------- .../commit_statuses/_commit_status.html.haml | 31 +++++++--- app/views/projects/runners/edit.html.haml | 2 + app/views/projects/runners/index.html.haml | 1 + app/views/projects/runners/show.html.haml | 21 ++++--- app/views/projects/triggers/index.html.haml | 1 + app/views/projects/variables/show.html.haml | 1 + config/routes.rb | 9 +-- spec/features/builds_spec.rb | 14 +++-- spec/features/commits_spec.rb | 2 +- .../project_services/gitlab_ci_service_spec.rb | 2 +- 37 files changed, 226 insertions(+), 250 deletions(-) delete mode 100644 app/helpers/builds_helper.rb delete mode 100644 app/views/projects/builds/_build.html.haml create mode 100644 app/views/projects/builds/_header_title.html.haml create mode 100644 app/views/projects/commit/builds.html.haml delete mode 100644 app/views/projects/commit/ci.html.haml diff --git a/app/controllers/projects/builds_controller.rb b/app/controllers/projects/builds_controller.rb index 7d72e0b951b..953f30e7c03 100644 --- a/app/controllers/projects/builds_controller.rb +++ b/app/controllers/projects/builds_controller.rb @@ -30,7 +30,7 @@ class Projects::BuildsController < Projects::ApplicationController def show @builds = @ci_project.commits.find_by_sha(@build.sha).builds.order('id DESC') - @builds = @builds.where("id not in (?)", @build.id).page(params[:page]).per(20) + @builds = @builds.where("id not in (?)", @build.id) @commit = @build.commit respond_to do |format| @@ -42,17 +42,13 @@ class Projects::BuildsController < Projects::ApplicationController end def retry - if @build.commands.blank? + unless @build.retryable? return page_404 end build = Ci::Build.retry(@build) - if params[:return_to] - redirect_to URI.parse(params[:return_to]).path - else - redirect_to build_path(build) - end + redirect_to build_path(build) end def status diff --git a/app/controllers/projects/commit_controller.rb b/app/controllers/projects/commit_controller.rb index 878c3a66e7d..deefdd76667 100644 --- a/app/controllers/projects/commit_controller.rb +++ b/app/controllers/projects/commit_controller.rb @@ -7,14 +7,14 @@ class Projects::CommitController < Projects::ApplicationController before_action :authorize_download_code!, except: [:cancel_builds] before_action :authorize_manage_builds!, only: [:cancel_builds] before_action :commit + before_action :authorize_manage_builds!, only: [:cancel_builds, :retry_builds] + before_action :define_show_vars, only: [:show, :builds] def show return git_not_found! unless @commit @line_notes = commit.notes.inline - @diffs = @commit.diffs @note = @project.build_commit_note(commit) - @notes_count = commit.notes.count @notes = commit.notes.not_inline.fresh @noteable = @commit @comments_allowed = @reply_allowed = true @@ -23,8 +23,6 @@ class Projects::CommitController < Projects::ApplicationController commit_id: @commit.id } - @ci_commit = project.ci_commit(commit.sha) - respond_to do |format| format.html format.diff { render text: @commit.to_diff } @@ -32,20 +30,25 @@ class Projects::CommitController < Projects::ApplicationController end end - def ci - @ci_commit = @project.ci_commit(@commit.sha) - @builds = @ci_commit.builds if @ci_commit - @notes_count = @commit.notes.count + def builds @ci_project = @project.gitlab_ci_project end def cancel_builds - @ci_commit = @project.ci_commit(@commit.sha) - @ci_commit.builds.running_or_pending.each(&:cancel) + ci_commit.builds.running_or_pending.each(&:cancel) - redirect_to ci_namespace_project_commit_path(project.namespace, project, commit.sha) + redirect_to builds_namespace_project_commit_path(project.namespace, project, commit.sha) end + def retry_builds + ci_commit.builds.latest.failed.each do |build| + if build.retryable? + Ci::Build.retry(build) + end + end + + redirect_to builds_namespace_project_commit_path(project.namespace, project, commit.sha) + end def branches @branches = @project.repository.branch_names_contains(commit.id) @@ -53,11 +56,22 @@ class Projects::CommitController < Projects::ApplicationController render layout: false end + private + def commit @commit ||= @project.commit(params[:id]) end - private + def ci_commit + @ci_commit ||= project.ci_commit(commit.sha) + end + + def define_show_vars + @diffs = commit.diffs + @notes_count = commit.notes.count + + @builds = ci_commit.builds if ci_commit + end def authorize_manage_builds! unless can?(current_user, :manage_builds, project) diff --git a/app/helpers/builds_helper.rb b/app/helpers/builds_helper.rb deleted file mode 100644 index 1b5a2c31d74..00000000000 --- a/app/helpers/builds_helper.rb +++ /dev/null @@ -1,13 +0,0 @@ -module BuildsHelper - def build_ref_link build - gitlab_ref_link build.project, build.ref - end - - def build_commit_link build - gitlab_commit_link build.project, build.short_sha - end - - def build_url(build) - namespace_project_build_path(build.gl_project, build.project, build) - end -end diff --git a/app/helpers/ci/gitlab_helper.rb b/app/helpers/ci/gitlab_helper.rb index baddbc806f2..e34c8be1dfc 100644 --- a/app/helpers/ci/gitlab_helper.rb +++ b/app/helpers/ci/gitlab_helper.rb @@ -4,25 +4,6 @@ module Ci { :"data-no-turbolink" => "data-no-turbolink" } end - def gitlab_ref_link project, ref - gitlab_url = project.gitlab_url.dup - gitlab_url << "/commits/#{ref}" - link_to ref, gitlab_url, no_turbolink - end - - def gitlab_compare_link project, before, after - gitlab_url = project.gitlab_url.dup - gitlab_url << "/compare/#{before}...#{after}" - - link_to "#{before}...#{after}", gitlab_url, no_turbolink - end - - def gitlab_commit_link project, sha - gitlab_url = project.gitlab_url.dup - gitlab_url << "/commit/#{sha}" - link_to Ci::Commit.truncate_sha(sha), gitlab_url, no_turbolink - end - def yaml_web_editor_link(project) commits = project.commits diff --git a/app/helpers/ci_status_helper.rb b/app/helpers/ci_status_helper.rb index ed88df5dd86..0ecf77bb45e 100644 --- a/app/helpers/ci_status_helper.rb +++ b/app/helpers/ci_status_helper.rb @@ -1,7 +1,7 @@ module CiStatusHelper def ci_status_path(ci_commit) project = ci_commit.gl_project - ci_namespace_project_commit_path(project.namespace, project, ci_commit.sha) + builds_namespace_project_commit_path(project.namespace, project, ci_commit.sha) end def ci_status_icon(ci_commit) diff --git a/app/models/ci/build.rb b/app/models/ci/build.rb index b19e2ac1363..7f185ae7cc3 100644 --- a/app/models/ci/build.rb +++ b/app/models/ci/build.rb @@ -106,6 +106,14 @@ module Ci failed? && allow_failure? end + def retryable? + commands.present? + end + + def retried? + !self.commit.latest_builds_for_ref(self.ref).include?(self) + end + def trace_html html = Ci::Ansi2html::convert(trace) if trace.present? html || '' @@ -222,7 +230,7 @@ module Ci end def retry_url - if commands.present? + if retryable? Gitlab::Application.routes.url_helpers. retry_namespace_project_build_path(gl_project.namespace, gl_project, self) end diff --git a/app/models/commit_status.rb b/app/models/commit_status.rb index 0b73ab6d2eb..7d54d83974a 100644 --- a/app/models/commit_status.rb +++ b/app/models/commit_status.rb @@ -15,8 +15,8 @@ class CommitStatus < ActiveRecord::Base scope :pending, -> { where(status: 'pending') } scope :success, -> { where(status: 'success') } scope :failed, -> { where(status: 'failed') } - scope :running_or_pending, -> { where(status:[:running, :pending]) } - scope :finished, -> { where(status:[:success, :failed, :canceled]) } + scope :running_or_pending, -> { where(status: [:running, :pending]) } + scope :finished, -> { where(status: [:success, :failed, :canceled]) } scope :latest, -> { where(id: unscope(:select).select('max(id)').group(:name, :ref)) } scope :ordered, -> { order(:ref, :stage_idx, :name) } scope :for_ref, ->(ref) { where(ref: ref) } diff --git a/app/models/project_services/ci/hip_chat_message.rb b/app/models/project_services/ci/hip_chat_message.rb index cbf325cc525..d89466b689f 100644 --- a/app/models/project_services/ci/hip_chat_message.rb +++ b/app/models/project_services/ci/hip_chat_message.rb @@ -11,7 +11,7 @@ module Ci def to_s lines = Array.new lines.push("#{project.name} - ") - lines.push("Commit ##{commit.id}
") + lines.push("Commit ##{commit.id}
") lines.push("#{commit.short_sha} #{commit.git_author_name} - #{commit.git_commit_message}
") lines.push("#{humanized_status(commit_status)} in #{commit.duration} second(s).") lines.join('') diff --git a/app/models/project_services/ci/slack_message.rb b/app/models/project_services/ci/slack_message.rb index dc050a3fc59..1a6ff8e34c9 100644 --- a/app/models/project_services/ci/slack_message.rb +++ b/app/models/project_services/ci/slack_message.rb @@ -45,7 +45,7 @@ module Ci def attachment_message out = "<#{ci_project_url(project)}|#{project_name}>: " - out << "Commit <#{ci_namespace_project_commit_url(commit.gl_project.namespace, commit.gl_project, commit.sha)}|\##{commit.id}> " + out << "Commit <#{builds_namespace_project_commit_url(commit.gl_project.namespace, commit.gl_project, commit.sha)}|\##{commit.id}> " out << "(<#{commit_sha_link}|#{commit.short_sha}>) " out << "of <#{commit_ref_link}|#{commit.ref}> " out << "by #{commit.git_author_name} " if commit.git_author_name diff --git a/app/models/project_services/gitlab_ci_service.rb b/app/models/project_services/gitlab_ci_service.rb index 4dcd16ede3a..095d04e0df4 100644 --- a/app/models/project_services/gitlab_ci_service.rb +++ b/app/models/project_services/gitlab_ci_service.rb @@ -71,7 +71,7 @@ class GitlabCiService < CiService def build_page(sha, ref) if project.gitlab_ci_project.present? - ci_namespace_project_commit_url(project.namespace, project, sha) + builds_namespace_project_commit_url(project.namespace, project, sha) end end diff --git a/app/views/ci/notify/build_fail_email.html.haml b/app/views/ci/notify/build_fail_email.html.haml index 69689a75022..cefb75040e9 100644 --- a/app/views/ci/notify/build_fail_email.html.haml +++ b/app/views/ci/notify/build_fail_email.html.haml @@ -7,7 +7,7 @@ = @project.name %p - Commit link: #{gitlab_commit_link(@project, @build.commit.short_sha)} + Commit: #{link_to @build.short_sha, namespace_project_commit_path(@build.gl_project.namespace, @build.gl_project, @build.sha)} %p Author: #{@build.commit.git_author_name} %p @@ -16,4 +16,4 @@ Message: #{@build.commit.git_commit_message} %p - Url: #{link_to @build.short_sha, namespace_project_build_url(@build.gl_project.namespace, @build.gl_project, @build)} + Build details: #{link_to "Build #{@build.id}", namespace_project_build_url(@build.gl_project.namespace, @build.gl_project, @build)} diff --git a/app/views/ci/notify/build_success_email.html.haml b/app/views/ci/notify/build_success_email.html.haml index 4e3015a356b..617b88f7345 100644 --- a/app/views/ci/notify/build_success_email.html.haml +++ b/app/views/ci/notify/build_success_email.html.haml @@ -8,7 +8,7 @@ = @project.name %p - Commit link: #{gitlab_commit_link(@project, @build.commit.short_sha)} + Commit: #{link_to @build.short_sha, namespace_project_commit_path(@build.gl_project.namespace, @build.gl_project, @build.sha)} %p Author: #{@build.commit.git_author_name} %p @@ -17,4 +17,4 @@ Message: #{@build.commit.git_commit_message} %p - Url: #{link_to @build.short_sha, namespace_project_build_url(@build.gl_project.namespace, @build.gl_project, @build)} + Build details: #{link_to "Build #{@build.id}", namespace_project_build_url(@build.gl_project.namespace, @build.gl_project, @build)} diff --git a/app/views/dashboard/groups/index.html.haml b/app/views/dashboard/groups/index.html.haml index c249f5cacec..f3f3f58111e 100644 --- a/app/views/dashboard/groups/index.html.haml +++ b/app/views/dashboard/groups/index.html.haml @@ -16,4 +16,4 @@ - group = group_member.group = render 'shared/groups/group', group: group, group_member: group_member -= paginate @group_members += paginate @group_members, theme: 'gitlab' diff --git a/app/views/layouts/ci/_nav_admin.html.haml b/app/views/layouts/ci/_nav_admin.html.haml index af2545a22d8..dcda04a4638 100644 --- a/app/views/layouts/ci/_nav_admin.html.haml +++ b/app/views/layouts/ci/_nav_admin.html.haml @@ -9,23 +9,25 @@ = nav_link path: 'projects#index' do = link_to ci_admin_projects_path do = icon('list-alt fw') - Projects + %span + Projects = nav_link path: 'events#index' do = link_to ci_admin_events_path do = icon('book fw') - Events + %span + Events = nav_link path: ['runners#index', 'runners#show'] do = link_to ci_admin_runners_path do = icon('cog fw') - Runners - %small.pull-right - = Ci::Runner.count(:all) + %span + Runners + %span.count= Ci::Runner.count(:all) = nav_link path: 'builds#index' do = link_to ci_admin_builds_path do = icon('link fw') - Builds - %small.pull-right - = Ci::Build.count(:all) + %span + Builds + %span.count= Ci::Build.count(:all) = nav_link(controller: :application_settings, html_options: { class: 'separate-item'}) do = link_to ci_admin_application_settings_path do = icon('cogs fw') diff --git a/app/views/projects/_last_commit.html.haml b/app/views/projects/_last_commit.html.haml index d7b20bfc6b1..7e1ee2b7fc1 100644 --- a/app/views/projects/_last_commit.html.haml +++ b/app/views/projects/_last_commit.html.haml @@ -6,7 +6,7 @@ = ci_commit.status = link_to commit.short_id, namespace_project_commit_path(project.namespace, project, commit), class: "commit_short_id" - = link_to_gfm commit.title, namespace_project_commit_path(project.namespace, project, commit.id), class: "commit-row-message" + = link_to_gfm commit.title, namespace_project_commit_path(project.namespace, project, commit), class: "commit-row-message" · #{time_ago_with_tooltip(commit.committed_date, skip_js: true)} by = commit_author_link(commit, avatar: true, size: 24) diff --git a/app/views/projects/builds/_build.html.haml b/app/views/projects/builds/_build.html.haml deleted file mode 100644 index 4ce4ed63b40..00000000000 --- a/app/views/projects/builds/_build.html.haml +++ /dev/null @@ -1,53 +0,0 @@ -%tr.build - %td.status - = ci_status_with_icon(build.status) - - %td.commit_status-link - - if build.target_url - = link_to build.target_url do - %strong Build ##{build.id} - - else - %strong Build ##{build.id} - - - if build.show_warning? - %i.fa.fa-warning.text-warning - - %td - = link_to build.short_sha, namespace_project_commit_path(@project.namespace, @project, build.sha) - - %td - = link_to build.ref, namespace_project_commits_path(@project.namespace, @project, build.ref) - - %td - - if build.runner - = runner_link(build.runner) - - else - .light none - - %td - = build.name - - .pull-right - - if build.tags.any? - - build.tags.each do |tag| - %span.label.label-primary - = tag - - if build.trigger_request - %span.label.label-info triggered - - if build.allow_failure - %span.label.label-danger allowed to fail - - %td.duration - - if build.duration - #{duration_in_words(build.finished_at, build.started_at)} - - %td.timestamp - - if build.finished_at - %span #{time_ago_in_words build.finished_at} ago - - %td - .pull-right - - if current_user && can?(current_user, :manage_builds, @project) - - if build.cancel_url - = link_to build.cancel_url, title: 'Cancel' do - %i.fa.fa-remove.cred diff --git a/app/views/projects/builds/_header_title.html.haml b/app/views/projects/builds/_header_title.html.haml new file mode 100644 index 00000000000..082dab1f5b0 --- /dev/null +++ b/app/views/projects/builds/_header_title.html.haml @@ -0,0 +1 @@ +- header_title project_title(@project, "Builds", project_builds_path(@project)) diff --git a/app/views/projects/builds/index.html.haml b/app/views/projects/builds/index.html.haml index e08556673ed..dab7164153f 100644 --- a/app/views/projects/builds/index.html.haml +++ b/app/views/projects/builds/index.html.haml @@ -1,12 +1,12 @@ - page_title "Builds" -- header_title project_title(@project, "Builds", project_builds_path(@project)) += render "header_title" .project-issuable-filter .controls - if @ci_project && current_user && can?(current_user, :manage_builds, @project) .pull-left.hidden-xs - if @all_builds.running_or_pending.any? - = link_to 'Cancel all', cancel_all_namespace_project_builds_path(@project.namespace, @project), data: { confirm: 'Are you sure?' }, class: 'btn btn-danger' + = link_to 'Cancel all', cancel_all_namespace_project_builds_path(@project.namespace, @project), data: { confirm: 'Are you sure?' }, class: 'btn btn-danger', method: :post %ul.center-top-menu %li{class: ('active' if @scope.nil?)} @@ -25,7 +25,7 @@ %span.badge.js-totalbuilds-count= @all_builds.count(:id) .gray-content-block - List of #{@scope || 'running'} builds from this project + #{(@scope || 'running').capitalize} builds from this project %ul.content-list - if @builds.blank? @@ -40,14 +40,14 @@ %th Build ID %th Commit %th Ref - %th Runner + %th Stage %th Name %th Duration %th Finished at %th - @builds.each do |build| - = render 'projects/builds/build', build: build + = render 'projects/commit_statuses/commit_status', commit_status: build, commit_sha: true, stage: true, allow_retry: true - = paginate @builds + = paginate @builds, theme: 'gitlab' diff --git a/app/views/projects/builds/show.html.haml b/app/views/projects/builds/show.html.haml index e3d8d734913..3374d5432a5 100644 --- a/app/views/projects/builds/show.html.haml +++ b/app/views/projects/builds/show.html.haml @@ -1,10 +1,13 @@ +- page_title "#{@build.name} (#{@build.id})", "Builds" += render "header_title" + .build-page .gray-content-block - Build for commit + Build ##{@build.id} for commit %strong.monospace = link_to @build.commit.short_sha, ci_status_path(@build.commit) from - %code #{@build.ref} + = link_to @build.ref, namespace_project_commits_path(@project.namespace, @project, @build.ref) #up-build-trace - if @commit.matrix_for_ref?(@build.ref) @@ -20,7 +23,7 @@ = build.id - - unless @commit.latest_builds_for_ref(@build.ref).include?(@build) + - if @build.retried? %li.active %a Build ##{@build.id} @@ -37,7 +40,7 @@ %i.fa.fa-time #{duration_in_words(@build.finished_at, @build.started_at)} .pull-right - = @build.updated_at.stamp('19:00 Aug 27') + #{time_ago_with_tooltip(@build.finished_at) if @build.finished_at} - if @build.show_warning? - unless @build.any_runners_online? @@ -87,13 +90,13 @@ .build-widget %h4.title - Build + Build ##{@build.id} - if current_user && can?(current_user, :manage_builds, @project) .pull-right - - if @build.active? - = link_to "Cancel", cancel_namespace_project_build_path(@project.namespace, @project, @build), class: 'btn btn-sm btn-danger' - - elsif @build.commands.present? - = link_to "Retry", retry_namespace_project_build_path(@project.namespace, @project, @build), class: 'btn btn-sm btn-primary', method: :post + - if @build.cancel_url + = link_to "Cancel", @build.cancel_url, class: 'btn btn-sm btn-danger', method: :post + - elsif @build.retry_url + = link_to "Retry", @build.retry_url, class: 'btn btn-sm btn-primary', method: :post - if @build.duration %p @@ -101,15 +104,15 @@ #{duration_in_words(@build.finished_at, @build.started_at)} %p %span.attr-name Created: - #{time_ago_in_words(@build.created_at)} ago + #{time_ago_with_tooltip(@build.created_at)} - if @build.finished_at %p %span.attr-name Finished: - #{time_ago_in_words(@build.finished_at)} ago + #{time_ago_with_tooltip(@build.finished_at)} %p %span.attr-name Runner: - if @build.runner && current_user && current_user.admin - \#{link_to "##{@build.runner.id}", ci_admin_runner_path(@build.runner.id)} + = link_to "##{@build.runner.id}", ci_admin_runner_path(@build.runner.id) - elsif @build.runner \##{@build.runner.id} @@ -134,10 +137,11 @@ %h4.title Commit .pull-right - %small #{build_commit_link @build} + %small + = link_to @build.commit.short_sha, ci_status_path(@build.commit), class: "monospace" %p %span.attr-name Branch: - #{build_ref_link @build} + = link_to @build.ref, namespace_project_commits_path(@project.namespace, @project, @build.ref) %p %span.attr-name Author: #{@build.commit.git_author_name} @@ -155,7 +159,9 @@ - if @builds.present? .build-widget - %h4.title #{pluralize(@builds.count(:id), "other build")} for #{@build.short_sha}: + %h4.title #{pluralize(@builds.count(:id), "other build")} for + = succeed ":" do + = link_to @build.commit.short_sha, ci_status_path(@build.commit), class: "monospace" %table.table.builds - @builds.each_with_index do |build, i| %tr.build @@ -171,8 +177,5 @@ %td.status= build.status - = paginate @builds - - :javascript new CiBuild("#{namespace_project_build_url(@project.namespace, @project, @build)}", "#{@build.status}") diff --git a/app/views/projects/ci_services/edit.html.haml b/app/views/projects/ci_services/edit.html.haml index bcc5832792f..dacb6b4f6f4 100644 --- a/app/views/projects/ci_services/edit.html.haml +++ b/app/views/projects/ci_services/edit.html.haml @@ -1 +1,2 @@ +- page_title @service.title, "CI Services" = render 'form' diff --git a/app/views/projects/ci_services/index.html.haml b/app/views/projects/ci_services/index.html.haml index c164b2d4bc0..3f26c7851d8 100644 --- a/app/views/projects/ci_services/index.html.haml +++ b/app/views/projects/ci_services/index.html.haml @@ -1,3 +1,4 @@ +- page_title "CI Services" %h3.page-title Project services %p.light Project services allow you to integrate GitLab CI with other applications diff --git a/app/views/projects/ci_settings/edit.html.haml b/app/views/projects/ci_settings/edit.html.haml index eedf484bf00..665556f5c20 100644 --- a/app/views/projects/ci_settings/edit.html.haml +++ b/app/views/projects/ci_settings/edit.html.haml @@ -1,3 +1,4 @@ +- page_title "CI Settings" - if @ci_project.generated_yaml_config %p.alert.alert-danger CI Jobs are deprecated now, you can #{link_to "download", dumped_yaml_ci_project_path(@ci_project)} diff --git a/app/views/projects/ci_web_hooks/index.html.haml b/app/views/projects/ci_web_hooks/index.html.haml index 369086b39ed..2998fb08ff1 100644 --- a/app/views/projects/ci_web_hooks/index.html.haml +++ b/app/views/projects/ci_web_hooks/index.html.haml @@ -1,3 +1,4 @@ +- page_title "CI Web Hooks" %h3.page-title CI Web hooks diff --git a/app/views/projects/commit/_ci_menu.html.haml b/app/views/projects/commit/_ci_menu.html.haml index a634ae5dfda..c73ba74f5ef 100644 --- a/app/views/projects/commit/_ci_menu.html.haml +++ b/app/views/projects/commit/_ci_menu.html.haml @@ -2,6 +2,8 @@ = nav_link(path: 'commit#show') do = link_to namespace_project_commit_path(@project.namespace, @project, @commit.id) do Changes - = nav_link(path: 'commit#ci') do - = link_to ci_namespace_project_commit_path(@project.namespace, @project, @commit.id) do + %span.badge= @diffs.count + = nav_link(path: 'commit#builds') do + = link_to builds_namespace_project_commit_path(@project.namespace, @project, @commit.id) do Builds + %span.badge= @builds.count(:id) diff --git a/app/views/projects/commit/_commit_box.html.haml b/app/views/projects/commit/_commit_box.html.haml index fbf0a9ec0c3..a6458b84860 100644 --- a/app/views/projects/commit/_commit_box.html.haml +++ b/app/views/projects/commit/_commit_box.html.haml @@ -19,7 +19,7 @@ %p %span.light Commit - = link_to @commit.id, namespace_project_commit_path(@project.namespace, @project, @commit) + = link_to @commit.id, namespace_project_commit_path(@project.namespace, @project, @commit), class: "monospace" .commit-info-row %span.light Authored by %strong @@ -36,7 +36,7 @@ .commit-info-row %span.cgray= pluralize(@commit.parents.count, "parent") - @commit.parents.each do |parent| - = link_to parent.short_id, namespace_project_commit_path(@project.namespace, @project, parent) + = link_to parent.short_id, namespace_project_commit_path(@project.namespace, @project, parent), class: "monospace" - if @ci_commit .pull-right diff --git a/app/views/projects/commit/builds.html.haml b/app/views/projects/commit/builds.html.haml new file mode 100644 index 00000000000..f7a89232e08 --- /dev/null +++ b/app/views/projects/commit/builds.html.haml @@ -0,0 +1,72 @@ +- page_title "Builds", "#{@commit.title} (#{@commit.short_id})", "Commits" += render "projects/commits/header_title" += render "commit_box" += render "ci_menu" + + +- if @ci_commit.yaml_errors.present? + .bs-callout.bs-callout-danger + %h4 Found errors in your .gitlab-ci.yml: + %ul + - @ci_commit.yaml_errors.split(",").each do |error| + %li= error + +- unless @ci_commit.ci_yaml_file + .bs-callout.bs-callout-warning + \.gitlab-ci.yml not found in this commit + +.gray-content-block.second-block + Latest builds + + .pull-right + - if @ci_commit.duration > 0 + %i.fa.fa-time + #{time_interval_in_words @ci_commit.duration} + +   + + - if @ci_project && current_user && can?(current_user, :manage_builds, @project) + - if @ci_commit.builds.latest.failed.any?(&:retryable?) + = link_to "Retry failed", retry_builds_namespace_project_commit_path(@project.namespace, @project, @commit.sha), class: 'btn btn-xs btn-primary', method: :post + + - if @ci_commit.builds.running_or_pending.any? + = link_to "Cancel running", cancel_builds_namespace_project_commit_path(@project.namespace, @project, @commit.sha), class: 'btn btn-xs btn-danger', method: :post + +.table-holder + %table.table.builds + %thead + %tr + %th Status + %th Build ID + %th Ref + %th Stage + %th Name + %th Duration + %th Finished at + - if @ci_project && @ci_project.coverage_enabled? + %th Coverage + %th + - @ci_commit.refs.each do |ref| + = render partial: "projects/commit_statuses/commit_status", collection: @ci_commit.statuses.for_ref(ref).latest.ordered, + locals: { coverage: @ci_project.try(:coverage_enabled?), stage: true, allow_retry: true } + +- if @ci_commit.retried.any? + .gray-content-block.second-block + Retried builds + + .table-holder + %table.table.builds + %thead + %tr + %th Status + %th Build ID + %th Ref + %th Stage + %th Name + %th Duration + %th Finished at + - if @ci_project && @ci_project.coverage_enabled? + %th Coverage + %th + = render partial: "projects/commit_statuses/commit_status", collection: @ci_commit.retried, + locals: { coverage: @ci_project.try(:coverage_enabled?) } diff --git a/app/views/projects/commit/ci.html.haml b/app/views/projects/commit/ci.html.haml deleted file mode 100644 index 43033cad24c..00000000000 --- a/app/views/projects/commit/ci.html.haml +++ /dev/null @@ -1,69 +0,0 @@ -- page_title "#{@commit.title} (#{@commit.short_id})", "Commits" -= render "projects/commits/header_title" -= render "commit_box" -= render "ci_menu" - - -- if @ci_commit.yaml_errors.present? - .bs-callout.bs-callout-danger - %h4 Found errors in your .gitlab-ci.yml: - %ul - - @ci_commit.yaml_errors.split(",").each do |error| - %li= error - -- unless @ci_commit.ci_yaml_file - .bs-callout.bs-callout-warning - \.gitlab-ci.yml not found in this commit - -.gray-content-block.second-block - Latest builds - - .pull-right - - if @ci_commit.duration > 0 - %i.fa.fa-time - #{time_interval_in_words @ci_commit.duration} - -   - - - if @ci_project && current_user && can?(current_user, :manage_builds, @project) - - if @ci_commit.builds.running_or_pending.any? - = link_to "Cancel all", cancel_builds_namespace_project_commit_path(@project.namespace, @project, @commit.sha), class: 'btn btn-xs btn-danger' - -.table-holder - %table.table.builds - %thead - %tr - %th Status - %th Build ID - %th Ref - %th Stage - %th Name - %th Duration - %th Finished at - - if @ci_project && @ci_project.coverage_enabled? - %th Coverage - %th - - @ci_commit.refs.each do |ref| - = render partial: "projects/commit_statuses/commit_status", collection: @ci_commit.statuses.for_ref(ref).latest.ordered, - locals: { coverage: @ci_project.try(:coverage_enabled?), allow_retry: true } - -- if @ci_commit.retried.any? - .gray-content-block.second-block - Retried builds - - .table-holder - %table.table.builds - %thead - %tr - %th Status - %th Build ID - %th Ref - %th Stage - %th Name - %th Duration - %th Finished at - - if @ci_project && @ci_project.coverage_enabled? - %th Coverage - %th - = render partial: "projects/commit_statuses/commit_status", collection: @ci_commit.retried, - locals: { coverage: @ci_project.try(:coverage_enabled?) } diff --git a/app/views/projects/commit_statuses/_commit_status.html.haml b/app/views/projects/commit_statuses/_commit_status.html.haml index 637154f56aa..c255559b88c 100644 --- a/app/views/projects/commit_statuses/_commit_status.html.haml +++ b/app/views/projects/commit_statuses/_commit_status.html.haml @@ -12,14 +12,30 @@ - if commit_status.show_warning? %i.fa.fa-warning.text-warning - %td - = commit_status.ref + - if defined?(commit_sha) && commit_sha + %td + = link_to commit_status.short_sha, namespace_project_commit_path(@project.namespace, @project, commit_status.sha), class: "monospace" %td - = commit_status.stage + - if commit_status.ref + = link_to commit_status.ref, namespace_project_commits_path(@project.namespace, @project, commit_status.ref) + - else + .light none + + - if defined?(runner) && runner + %td + - if commit_status.try(:runner) + = runner_link(commit_status.runner) + - else + .light none + + - if defined?(stage) && stage + %td + = commit_status.stage %td = commit_status.name + .pull-right - if commit_status.tags.any? - commit_status.tags.each do |tag| @@ -36,7 +52,7 @@ %td.timestamp - if commit_status.finished_at - %span #{time_ago_in_words commit_status.finished_at} ago + %span #{time_ago_with_tooltip(commit_status.finished_at)} - if defined?(coverage) && coverage %td.coverage @@ -46,9 +62,10 @@ %td .pull-right - if current_user && can?(current_user, :manage_builds, commit_status.gl_project) - - if commit_status.cancel_url - = link_to commit_status.cancel_url, title: 'Cancel' do - %i.fa.fa-remove.cred + - if commit_status.active? + - if commit_status.cancel_url + = link_to commit_status.cancel_url, method: :post, title: 'Cancel' do + %i.fa.fa-remove.cred - elsif defined?(allow_retry) && allow_retry && commit_status.retry_url = link_to commit_status.retry_url, method: :post, title: 'Retry' do %i.fa.fa-repeat diff --git a/app/views/projects/runners/edit.html.haml b/app/views/projects/runners/edit.html.haml index 66851d38316..dde9e448cb9 100644 --- a/app/views/projects/runners/edit.html.haml +++ b/app/views/projects/runners/edit.html.haml @@ -1,3 +1,5 @@ +- page_title "Edit", "#{@runner.description} ##{@runner.id}", "Runners" + %h4 Runner ##{@runner.id} %hr = form_for @runner, url: runner_path(@runner), html: { class: 'form-horizontal' } do |f| diff --git a/app/views/projects/runners/index.html.haml b/app/views/projects/runners/index.html.haml index 529fb9c296d..315afe4a764 100644 --- a/app/views/projects/runners/index.html.haml +++ b/app/views/projects/runners/index.html.haml @@ -1,3 +1,4 @@ +- page_title "Runners" .light %p A 'runner' is a process which runs a build. diff --git a/app/views/projects/runners/show.html.haml b/app/views/projects/runners/show.html.haml index c255cd51bd2..5bf4c09ca25 100644 --- a/app/views/projects/runners/show.html.haml +++ b/app/views/projects/runners/show.html.haml @@ -1,13 +1,14 @@ -= content_for :title do - %h3.project-title - Runner ##{@runner.id} - .pull-right - - if @runner.shared? - %span.runner-state.runner-state-shared - Shared - - else - %span.runner-state.runner-state-specific - Specific +- page_title "#{@runner.description} ##{@runner.id}", "Runners" + +%h3.page-title + Runner ##{@runner.id} + .pull-right + - if @runner.shared? + %span.runner-state.runner-state-shared + Shared + - else + %span.runner-state.runner-state-specific + Specific .table-holder %table.table diff --git a/app/views/projects/triggers/index.html.haml b/app/views/projects/triggers/index.html.haml index 18a37302c3e..b3ad79a200e 100644 --- a/app/views/projects/triggers/index.html.haml +++ b/app/views/projects/triggers/index.html.haml @@ -1,3 +1,4 @@ +- page_title "Triggers" %h3.page-title Triggers diff --git a/app/views/projects/variables/show.html.haml b/app/views/projects/variables/show.html.haml index 29416a94ff6..e052da1ac43 100644 --- a/app/views/projects/variables/show.html.haml +++ b/app/views/projects/variables/show.html.haml @@ -1,3 +1,4 @@ +- page_title "Variables" %h3.page-title Secret Variables diff --git a/config/routes.rb b/config/routes.rb index 0458f538eb6..990a00e3d0b 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -472,8 +472,9 @@ Gitlab::Application.routes.draw do resources :commit, only: [:show], constraints: { id: /[[:alnum:]]{6,40}/ } do member do get :branches - get :ci - get :cancel_builds + get :builds + post :cancel_builds + post :retry_builds end end @@ -588,12 +589,12 @@ Gitlab::Application.routes.draw do resources :builds, only: [:index, :show] do collection do - get :cancel_all + post :cancel_all end member do - get :cancel get :status + post :cancel post :retry end end diff --git a/spec/features/builds_spec.rb b/spec/features/builds_spec.rb index 154857e77fe..158e85e598f 100644 --- a/spec/features/builds_spec.rb +++ b/spec/features/builds_spec.rb @@ -47,10 +47,11 @@ describe "Builds" do end end - describe "GET /:project/builds/:id/cancel_all" do + describe "POST /:project/builds/:id/cancel_all" do before do @build.run! - visit cancel_all_namespace_project_builds_path(@gl_project.namespace, @gl_project) + visit namespace_project_builds_path(@gl_project.namespace, @gl_project) + click_link "Cancel all" end it { expect(page).to have_content 'No builds to show' } @@ -67,10 +68,11 @@ describe "Builds" do it { expect(page).to have_content @commit.git_author_name } end - describe "GET /:project/builds/:id/cancel" do + describe "POST /:project/builds/:id/cancel" do before do @build.run! - visit cancel_namespace_project_build_path(@gl_project.namespace, @gl_project, @build) + visit namespace_project_build_path(@gl_project.namespace, @gl_project, @build) + click_link "Cancel" end it { expect(page).to have_content 'canceled' } @@ -79,7 +81,9 @@ describe "Builds" do describe "POST /:project/builds/:id/retry" do before do - visit cancel_namespace_project_build_path(@gl_project.namespace, @gl_project, @build) + @build.run! + visit namespace_project_build_path(@gl_project.namespace, @gl_project, @build) + click_link "Cancel" click_link 'Retry' end diff --git a/spec/features/commits_spec.rb b/spec/features/commits_spec.rb index 1adc2cdf70a..340924fafe7 100644 --- a/spec/features/commits_spec.rb +++ b/spec/features/commits_spec.rb @@ -32,7 +32,7 @@ describe "Commits" do describe "Cancel all builds" do it "cancels commit" do visit ci_status_path(@commit) - click_on "Cancel all" + click_on "Cancel running" expect(page).to have_content "canceled" end end diff --git a/spec/models/project_services/gitlab_ci_service_spec.rb b/spec/models/project_services/gitlab_ci_service_spec.rb index 842089ebe0d..b9006b693b2 100644 --- a/spec/models/project_services/gitlab_ci_service_spec.rb +++ b/spec/models/project_services/gitlab_ci_service_spec.rb @@ -39,7 +39,7 @@ describe GitlabCiService do end describe :build_page do - it { expect(@service.build_page("2ab7834c", 'master')).to eq("http://localhost/#{@ci_project.gl_project.path_with_namespace}/commit/2ab7834c/ci")} + it { expect(@service.build_page("2ab7834c", 'master')).to eq("http://localhost/#{@ci_project.gl_project.path_with_namespace}/commit/2ab7834c/builds")} end describe "execute" do -- cgit v1.2.1 From 2becd53015c5b283d8c5bfc6b8702b22416e55d2 Mon Sep 17 00:00:00 2001 From: Kamil Trzcinski Date: Tue, 3 Nov 2015 14:24:00 +0100 Subject: Add missing stage to builds view --- app/views/projects/commit/builds.html.haml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/views/projects/commit/builds.html.haml b/app/views/projects/commit/builds.html.haml index f7a89232e08..00cf9c76102 100644 --- a/app/views/projects/commit/builds.html.haml +++ b/app/views/projects/commit/builds.html.haml @@ -69,4 +69,4 @@ %th Coverage %th = render partial: "projects/commit_statuses/commit_status", collection: @ci_commit.retried, - locals: { coverage: @ci_project.try(:coverage_enabled?) } + locals: { coverage: @ci_project.try(:coverage_enabled?), stage: true } -- cgit v1.2.1 From aecc4376e20b3ad23662f6181a776ac5747baa06 Mon Sep 17 00:00:00 2001 From: Valery Sizov Date: Thu, 5 Nov 2015 16:41:03 +0200 Subject: make migrations reversible --- db/migrate/20151019111551_fix_build_tags.rb | 6 +++++- db/migrate/20151019111703_fail_build_without_names.rb | 5 ++++- db/migrate/20151023112551_fail_build_with_empty_name.rb | 5 ++++- 3 files changed, 13 insertions(+), 3 deletions(-) diff --git a/db/migrate/20151019111551_fix_build_tags.rb b/db/migrate/20151019111551_fix_build_tags.rb index 84b142183f8..299a24b0a7c 100644 --- a/db/migrate/20151019111551_fix_build_tags.rb +++ b/db/migrate/20151019111551_fix_build_tags.rb @@ -1,5 +1,9 @@ class FixBuildTags < ActiveRecord::Migration - def change + def up execute("UPDATE taggings SET taggable_type='CommitStatus' WHERE taggable_type='Ci::Build'") end + + def down + execute("UPDATE taggings SET taggable_type='Ci::Build' WHERE taggable_type='CommitStatus'") + end end diff --git a/db/migrate/20151019111703_fail_build_without_names.rb b/db/migrate/20151019111703_fail_build_without_names.rb index 546b03d8129..dcdb5d1b25d 100644 --- a/db/migrate/20151019111703_fail_build_without_names.rb +++ b/db/migrate/20151019111703_fail_build_without_names.rb @@ -1,5 +1,8 @@ class FailBuildWithoutNames < ActiveRecord::Migration - def change + def up execute("UPDATE ci_builds SET status='failed' WHERE name IS NULL AND status='pending'") end + + def down + end end diff --git a/db/migrate/20151023112551_fail_build_with_empty_name.rb b/db/migrate/20151023112551_fail_build_with_empty_name.rb index f069bc60ac7..41c0f0649cd 100644 --- a/db/migrate/20151023112551_fail_build_with_empty_name.rb +++ b/db/migrate/20151023112551_fail_build_with_empty_name.rb @@ -1,5 +1,8 @@ class FailBuildWithEmptyName < ActiveRecord::Migration - def change + def up execute("UPDATE ci_builds SET status='failed' WHERE (name IS NULL OR name='') AND status='pending'") end + + def down + end end -- cgit v1.2.1 From 6fcd5127a316ce3abf1e5c5dde5b1901e8c7941f Mon Sep 17 00:00:00 2001 From: Thirumal S Date: Thu, 5 Nov 2015 20:21:46 +0530 Subject: defined class prepend-top-10 used for alignment issue --- app/assets/stylesheets/pages/projects.scss | 4 ---- app/views/projects/hooks/index.html.haml | 2 +- 2 files changed, 1 insertion(+), 5 deletions(-) diff --git a/app/assets/stylesheets/pages/projects.scss b/app/assets/stylesheets/pages/projects.scss index 2e7ad1173a5..d3b10040022 100644 --- a/app/assets/stylesheets/pages/projects.scss +++ b/app/assets/stylesheets/pages/projects.scss @@ -552,8 +552,4 @@ pre.light-well { z-index: 100; position: relative; } -} - -.form-control-padding-top { - padding-top: 10px; } \ No newline at end of file diff --git a/app/views/projects/hooks/index.html.haml b/app/views/projects/hooks/index.html.haml index 65e00b38ad4..3702aeaecba 100644 --- a/app/views/projects/hooks/index.html.haml +++ b/app/views/projects/hooks/index.html.haml @@ -19,7 +19,7 @@ = f.text_field :url, class: "form-control", placeholder: 'http://example.com/trigger-ci.json' .form-group = f.label :url, "Trigger", class: 'control-label' - .col-sm-10.form-control-padding-top + .col-sm-10.prepend-top-10 %div = f.check_box :push_events, class: 'pull-left' .prepend-left-20 -- cgit v1.2.1 From b18671a1b2c565a87663544441000063f6b83c8e Mon Sep 17 00:00:00 2001 From: Kamil Trzcinski Date: Tue, 3 Nov 2015 14:45:41 +0100 Subject: Enable shared runners for all new projects --- CHANGELOG | 1 + app/controllers/admin/application_settings_controller.rb | 1 + app/models/application_setting.rb | 3 ++- app/models/project.rb | 5 ++++- app/views/admin/application_settings/_form.html.haml | 9 +++++++++ config/initializers/1_settings.rb | 9 +++++---- db/migrate/20151103133339_add_shared_runners_setting.rb | 5 +++++ db/schema.rb | 3 ++- lib/gitlab/current_settings.rb | 3 ++- 9 files changed, 31 insertions(+), 8 deletions(-) create mode 100644 db/migrate/20151103133339_add_shared_runners_setting.rb diff --git a/CHANGELOG b/CHANGELOG index 3a75f50e9a2..22012211164 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -14,6 +14,7 @@ v 8.2.0 (unreleased) - Use git follow flag for commits page when retrieve history for file or directory - Show merge request CI status on merge requests index page - Extend yml syntax for only and except to support specifying repository path + - Enable shared runners to all new projects - Fix: 500 error returned if destroy request without HTTP referer (Kazuki Shimizu) - Remove deprecated CI events from project settings page - Use issue editor as cross reference comment author when issue is edited with a new mention. diff --git a/app/controllers/admin/application_settings_controller.rb b/app/controllers/admin/application_settings_controller.rb index 039f18f23e0..3d9c59050ff 100644 --- a/app/controllers/admin/application_settings_controller.rb +++ b/app/controllers/admin/application_settings_controller.rb @@ -57,6 +57,7 @@ class Admin::ApplicationSettingsController < Admin::ApplicationController :version_check_enabled, :admin_notification_email, :user_oauth_applications, + :shared_runners_enabled, restricted_visibility_levels: [], import_sources: [] ) diff --git a/app/models/application_setting.rb b/app/models/application_setting.rb index 05430c2ee18..266045f7afa 100644 --- a/app/models/application_setting.rb +++ b/app/models/application_setting.rb @@ -87,7 +87,8 @@ class ApplicationSetting < ActiveRecord::Base default_project_visibility: Settings.gitlab.default_projects_features['visibility_level'], default_snippet_visibility: Settings.gitlab.default_projects_features['visibility_level'], restricted_signup_domains: Settings.gitlab['restricted_signup_domains'], - import_sources: ['github','bitbucket','gitlab','gitorious','google_code','fogbugz','git'] + import_sources: ['github','bitbucket','gitlab','gitorious','google_code','fogbugz','git'], + shared_runners_enabled: Settings.gitlab_ci['shared_runners_enabled'], ) end diff --git a/app/models/project.rb b/app/models/project.rb index 74b89aad499..57db7f9f0a4 100644 --- a/app/models/project.rb +++ b/app/models/project.rb @@ -37,6 +37,7 @@ class Project < ActiveRecord::Base include Gitlab::ConfigHelper include Gitlab::ShellAdapter include Gitlab::VisibilityLevel + include Gitlab::CurrentSettings include Referable include Sortable include AfterCommitQueue @@ -775,7 +776,9 @@ class Project < ActiveRecord::Base end def ensure_gitlab_ci_project - gitlab_ci_project || create_gitlab_ci_project + gitlab_ci_project || create_gitlab_ci_project( + shared_runners_enabled: current_application_settings.shared_runners_enabled + ) end def enable_ci diff --git a/app/views/admin/application_settings/_form.html.haml b/app/views/admin/application_settings/_form.html.haml index 7a78526e09a..7253218c2e9 100644 --- a/app/views/admin/application_settings/_form.html.haml +++ b/app/views/admin/application_settings/_form.html.haml @@ -130,5 +130,14 @@ = f.text_area :help_page_text, class: 'form-control', rows: 4 .help-block Markdown enabled + %fieldset + %legend Continuous Integration + .form-group + .col-sm-offset-2.col-sm-10 + .checkbox + = f.label :shared_runners_enabled do + = f.check_box :shared_runners_enabled + Enable shared runners for a new projects + .form-actions = f.submit 'Save', class: 'btn btn-primary' diff --git a/config/initializers/1_settings.rb b/config/initializers/1_settings.rb index c189c88bdcb..64d73d7232d 100644 --- a/config/initializers/1_settings.rb +++ b/config/initializers/1_settings.rb @@ -181,10 +181,11 @@ Settings.gitlab['import_sources'] ||= ['github','bitbucket','gitlab','gitorious' # CI # Settings['gitlab_ci'] ||= Settingslogic.new({}) -Settings.gitlab_ci['all_broken_builds'] = true if Settings.gitlab_ci['all_broken_builds'].nil? -Settings.gitlab_ci['add_pusher'] = false if Settings.gitlab_ci['add_pusher'].nil? -Settings.gitlab_ci['url'] ||= Settings.send(:build_gitlab_ci_url) -Settings.gitlab_ci['builds_path'] = File.expand_path(Settings.gitlab_ci['builds_path'] || "builds/", Rails.root) +Settings.gitlab_ci['shared_runners_enabled'] = true if Settings.gitlab_ci['shared_runners_enabled'].nil? +Settings.gitlab_ci['all_broken_builds'] = true if Settings.gitlab_ci['all_broken_builds'].nil? +Settings.gitlab_ci['add_pusher'] = false if Settings.gitlab_ci['add_pusher'].nil? +Settings.gitlab_ci['url'] ||= Settings.send(:build_gitlab_ci_url) +Settings.gitlab_ci['builds_path'] = File.expand_path(Settings.gitlab_ci['builds_path'] || "builds/", Rails.root) # # Reply by email diff --git a/db/migrate/20151103133339_add_shared_runners_setting.rb b/db/migrate/20151103133339_add_shared_runners_setting.rb new file mode 100644 index 00000000000..4231dfd5c2e --- /dev/null +++ b/db/migrate/20151103133339_add_shared_runners_setting.rb @@ -0,0 +1,5 @@ +class AddSharedRunnersSetting < ActiveRecord::Migration + def up + add_column :application_settings, :shared_runners_enabled, :boolean, default: true, null: false + end +end diff --git a/db/schema.rb b/db/schema.rb index 17d445a8baa..de896f2764b 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -11,7 +11,7 @@ # # It's strongly recommended that you check this file into your version control system. -ActiveRecord::Schema.define(version: 20151103001141) do +ActiveRecord::Schema.define(version: 20151103133339) do # These are extensions that must be enabled in order to support this database enable_extension "plpgsql" @@ -47,6 +47,7 @@ ActiveRecord::Schema.define(version: 20151103001141) do t.text "import_sources" t.text "help_page_text" t.string "admin_notification_email" + t.boolean "shared_runners_enabled", default: true, null: false end create_table "audit_events", force: true do |t| diff --git a/lib/gitlab/current_settings.rb b/lib/gitlab/current_settings.rb index 0ea1b6a2f6f..cd84afa31d5 100644 --- a/lib/gitlab/current_settings.rb +++ b/lib/gitlab/current_settings.rb @@ -23,7 +23,8 @@ module Gitlab restricted_visibility_levels: Settings.gitlab['restricted_visibility_levels'], max_attachment_size: Settings.gitlab['max_attachment_size'], session_expire_delay: Settings.gitlab['session_expire_delay'], - import_sources: Settings.gitlab['import_sources'] + import_sources: Settings.gitlab['import_sources'], + shared_runners_enabled: Settings.gitlab_ci['shared_runners_enabled'], ) end -- cgit v1.2.1 From 900419c43c5a540cde22f5488675121b3ce05d31 Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Thu, 5 Nov 2015 17:08:47 +0100 Subject: Improve UI for tags page Signed-off-by: Dmitriy Zaporozhets --- app/controllers/projects/tags_controller.rb | 10 +++------- app/views/projects/tags/_download.html.haml | 17 +++++++++++++++++ app/views/projects/tags/_tag.html.haml | 8 +++----- app/views/projects/tags/destroy.js.haml | 3 --- app/views/projects/tags/show.html.haml | 22 ++++++++++------------ 5 files changed, 33 insertions(+), 27 deletions(-) create mode 100644 app/views/projects/tags/_download.html.haml delete mode 100644 app/views/projects/tags/destroy.js.haml diff --git a/app/controllers/projects/tags_controller.rb b/app/controllers/projects/tags_controller.rb index 055f328677f..670f5d3067b 100644 --- a/app/controllers/projects/tags_controller.rb +++ b/app/controllers/projects/tags_controller.rb @@ -39,13 +39,9 @@ class Projects::TagsController < Projects::ApplicationController def destroy DeleteTagService.new(project, current_user).execute(params[:id]) + release = project.releases.find_by(tag: params[:id]) + release.destroy if release - respond_to do |format| - format.html do - redirect_to namespace_project_tags_path(@project.namespace, - @project) - end - format.js - end + redirect_to namespace_project_tags_path(@project.namespace, @project) end end diff --git a/app/views/projects/tags/_download.html.haml b/app/views/projects/tags/_download.html.haml new file mode 100644 index 00000000000..667057ef2d8 --- /dev/null +++ b/app/views/projects/tags/_download.html.haml @@ -0,0 +1,17 @@ +%span.btn-group.btn-grouped + = link_to archive_namespace_project_repository_path(project.namespace, project, ref: ref, format: 'zip'), class: 'btn btn-default', rel: 'nofollow' do + %i.fa.fa-download + %span source code + %a.btn.btn-default.dropdown-toggle{ 'data-toggle' => 'dropdown' } + %span.caret + %span.sr-only + Select Archive Format + %ul.col-xs-10.dropdown-menu{ role: 'menu' } + %li + = link_to archive_namespace_project_repository_path(project.namespace, project, ref: ref, format: 'zip'), rel: 'nofollow' do + %i.fa.fa-download + %span Download zip + %li + = link_to archive_namespace_project_repository_path(project.namespace, project, ref: ref, format: 'tar.gz'), rel: 'nofollow' do + %i.fa.fa-download + %span Download tar.gz diff --git a/app/views/projects/tags/_tag.html.haml b/app/views/projects/tags/_tag.html.haml index 5d203903f8b..f3dc314a894 100644 --- a/app/views/projects/tags/_tag.html.haml +++ b/app/views/projects/tags/_tag.html.haml @@ -4,22 +4,20 @@ %div = link_to namespace_project_tag_path(@project.namespace, @project, tag.name) do %strong - %i.fa.fa-tag + = icon('tag') = tag.name - if tag.message.present?   = strip_gpg_signature(tag.message) - if release +   %span.label.label-success release .controls = link_to edit_namespace_project_tag_release_path(@project.namespace, @project, tag.name), class: 'btn-grouped btn' do = icon("pencil") - if can? current_user, :download_code, @project - = render 'projects/repositories/download_archive', ref: tag.name, btn_class: 'btn-grouped btn-group-xs' - - if can?(current_user, :admin_project, @project) - = link_to namespace_project_tag_path(@project.namespace, @project, tag.name), class: 'btn btn-xs btn-remove remove-row grouped', method: :delete, data: { confirm: 'Removed tag cannot be restored. Are you sure?'}, remote: true do - %i.fa.fa-trash-o + = render 'projects/tags/download', ref: tag.name, project: @project - if commit = render 'projects/branches/commit', commit: commit, project: @project diff --git a/app/views/projects/tags/destroy.js.haml b/app/views/projects/tags/destroy.js.haml deleted file mode 100644 index ada6710f940..00000000000 --- a/app/views/projects/tags/destroy.js.haml +++ /dev/null @@ -1,3 +0,0 @@ -$('.js-totaltags-count').html("#{@repository.tags.size}") -- if @repository.tags.size == 0 - $('.tags').load(document.URL + ' .nothing-here-block').hide().fadeIn(1000) diff --git a/app/views/projects/tags/show.html.haml b/app/views/projects/tags/show.html.haml index d2f23b96a8c..22697464fd2 100644 --- a/app/views/projects/tags/show.html.haml +++ b/app/views/projects/tags/show.html.haml @@ -6,6 +6,16 @@ .pull-right = link_to edit_namespace_project_tag_release_path(@project.namespace, @project, @tag.name), class: 'btn-grouped btn' do = icon("pencil") + = link_to namespace_project_tree_path(@project.namespace, @project, @tag.name), class: 'btn btn-grouped' do + = icon('files-o') + = link_to namespace_project_commits_path(@project.namespace, @project, @tag.name), class: 'btn btn-grouped' do + = icon('history') + - if can? current_user, :download_code, @project + = render 'projects/tags/download', ref: @tag.name, project: @project + - if can?(current_user, :admin_project, @project) + .pull-right + = link_to namespace_project_tag_path(@project.namespace, @project, @tag.name), class: 'btn btn-remove remove-row grouped', method: :delete, data: { confirm: 'Removed tag cannot be restored. Are you sure?'} do + %i.fa.fa-trash-o - if @tag.message.present? .title %strong= @tag.name @@ -24,18 +34,6 @@ - else This tag has no release notes yet. Press edit button to add one -.gray-content-block.middle-block.clearfix - = link_to namespace_project_tree_path(@project.namespace, @project, @tag.name), class: 'btn btn-grouped' do - Browse code - = link_to namespace_project_commits_path(@project.namespace, @project, @tag.name), class: 'btn btn-grouped' do - Commits - - if can? current_user, :download_code, @project - = render 'projects/repositories/download_archive', ref: @tag.name, btn_class: 'btn-grouped' - - if can?(current_user, :admin_project, @project) - .pull-right - = link_to namespace_project_tag_path(@project.namespace, @project, @tag.name), class: 'btn btn-remove remove-row grouped', method: :delete, data: { confirm: 'Removed tag cannot be restored. Are you sure?'}, remote: true do - %i.fa.fa-trash-o - .gray-content-block.second-block - if @commit = render 'projects/commits/commit', commit: @commit, project: @project -- cgit v1.2.1 From 3c0244d3d1533dab3276465a63a26e0937aef543 Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Thu, 5 Nov 2015 18:37:31 +0100 Subject: Retyle tag show page Signed-off-by: Dmitriy Zaporozhets --- app/views/projects/tags/show.html.haml | 24 ++++++++++-------------- 1 file changed, 10 insertions(+), 14 deletions(-) diff --git a/app/views/projects/tags/show.html.haml b/app/views/projects/tags/show.html.haml index 22697464fd2..f80ba5516a0 100644 --- a/app/views/projects/tags/show.html.haml +++ b/app/views/projects/tags/show.html.haml @@ -16,14 +16,17 @@ .pull-right = link_to namespace_project_tag_path(@project.namespace, @project, @tag.name), class: 'btn btn-remove remove-row grouped', method: :delete, data: { confirm: 'Removed tag cannot be restored. Are you sure?'} do %i.fa.fa-trash-o - - if @tag.message.present? - .title - %strong= @tag.name - = strip_gpg_signature(@tag.message) + .title + %strong= @tag.name + - if @tag.message.present? + %span.light +   + = strip_gpg_signature(@tag.message) + - if @commit + = render 'projects/branches/commit', commit: @commit, project: @project - else - .oneline - .title - %strong= @tag.name + Cant find HEAD commit for this tag + .append-bottom-default.prepend-top-default - if @release.description.present? @@ -33,10 +36,3 @@ = markdown @release.description - else This tag has no release notes yet. Press edit button to add one - -.gray-content-block.second-block - - if @commit - = render 'projects/commits/commit', commit: @commit, project: @project - - else - Cant find HEAD commit for this tag - -- cgit v1.2.1 From c55b5c72e94344d138af7de198016c8ea54b80f8 Mon Sep 17 00:00:00 2001 From: Achilleas Pipinellis Date: Thu, 5 Nov 2015 21:09:02 +0200 Subject: Remove duplicate documentation links --- doc/README.md | 27 +++++++++++---------------- 1 file changed, 11 insertions(+), 16 deletions(-) diff --git a/doc/README.md b/doc/README.md index a0ff856ebb6..3cd98fab0d5 100644 --- a/doc/README.md +++ b/doc/README.md @@ -17,20 +17,20 @@ ## CI Documentation -+ [Quick Start](ci/quick_start/README.md) -+ [Configuring project (.gitlab-ci.yml)](ci/yaml/README.md) -+ [Configuring runner](ci/runners/README.md) -+ [Configuring deployment](ci/deployment/README.md) -+ [Using Docker Images](ci/docker/using_docker_images.md) -+ [Using Docker Build](ci/docker/using_docker_build.md) -+ [Using Variables](ci/variables/README.md) +- [Quick Start](ci/quick_start/README.md) +- [Configuring project (.gitlab-ci.yml)](ci/yaml/README.md) +- [Configuring runner](ci/runners/README.md) +- [Configuring deployment](ci/deployment/README.md) +- [Using Docker Images](ci/docker/using_docker_images.md) +- [Using Docker Build](ci/docker/using_docker_build.md) +- [Using Variables](ci/variables/README.md) ### CI Examples -+ [Test and deploy Ruby applications to Heroku](ci/examples/test-and-deploy-ruby-application-to-heroku.md) -+ [Test and deploy Python applications to Heroku](ci/examples/test-and-deploy-python-application-to-heroku.md) -+ [Test Clojure applications](ci/examples/test-clojure-application.md) -+ Help your favorite programming language and GitLab by sending a merge request with a guide for that language. +- [Test and deploy Ruby applications to Heroku](ci/examples/test-and-deploy-ruby-application-to-heroku.md) +- [Test and deploy Python applications to Heroku](ci/examples/test-and-deploy-python-application-to-heroku.md) +- [Test Clojure applications](ci/examples/test-clojure-application.md) +- Help your favorite programming language and GitLab by sending a merge request with a guide for that language. ## Administrator documentation @@ -49,11 +49,6 @@ - [Reply by email](incoming_email/README.md) Allow users to comment on issues and merge requests by replying to notification emails. - [Migrate GitLab CI to CE/EE](migrate_ci_to_ce/README.md) Follow this guide to migrate your existing GitLab CI data to GitLab CE/EE. -### Administrator documentation - -+ [User permissions](permissions/permissions.md) -+ [API](api/README.md) - ## Contributor documentation - [Development](development/README.md) Explains the architecture and the guidelines for shell commands. -- cgit v1.2.1 From 5f696d0c22dd367fb4687b2d18f8db92e179bbcc Mon Sep 17 00:00:00 2001 From: Achilleas Pipinellis Date: Thu, 5 Nov 2015 21:21:12 +0200 Subject: Add CI permissions and api links to README [ci skip] --- doc/README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/doc/README.md b/doc/README.md index 3cd98fab0d5..0f6866475f7 100644 --- a/doc/README.md +++ b/doc/README.md @@ -24,6 +24,8 @@ - [Using Docker Images](ci/docker/using_docker_images.md) - [Using Docker Build](ci/docker/using_docker_build.md) - [Using Variables](ci/variables/README.md) +- [User permissions](ci/permissions/README.md) +- [API](ci/api/README.md) ### CI Examples -- cgit v1.2.1 From c468461579f0dedc0ad92609e6bb54624c2e2b04 Mon Sep 17 00:00:00 2001 From: Sytse Sijbrandij Date: Thu, 5 Nov 2015 21:17:15 -0800 Subject: Only have one link in emails to make clicking it easier. --- app/views/layouts/notify.html.haml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/views/layouts/notify.html.haml b/app/views/layouts/notify.html.haml index 854cda57c39..f58b9bd6ba6 100644 --- a/app/views/layouts/notify.html.haml +++ b/app/views/layouts/notify.html.haml @@ -40,9 +40,9 @@ Reply to this email directly or #{link_to "view it on GitLab", @target_url}. - else - #{link_to "View it on GitLab", @target_url} + #{link_to "View it on GitLab", @target_url}. %br - You're receiving this email because of your account on #{link_to Gitlab.config.gitlab.host, root_url}. + You're receiving this email because of your account on #{Gitlab.config.gitlab.host}. If you'd like to receive fewer emails, you can adjust your notification settings. = email_action @target_url -- cgit v1.2.1 From 40a9b1ce00ed4e4f03431b731ca5a6716356d5a6 Mon Sep 17 00:00:00 2001 From: Stan Hu Date: Thu, 5 Nov 2015 23:47:04 -0800 Subject: Fix bug where manually merged branches in a MR would end up with an empty diff Closes #3314 --- CHANGELOG | 1 + app/services/merge_requests/refresh_service.rb | 8 ++++---- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index 16055208db5..3614d790361 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,6 +1,7 @@ Please view this file on the master branch, on stable branches it's out of date. v 8.2.0 (unreleased) + - Fix bug where manually merged branches in a MR would end up with an empty diff (Stan Hu) - Force update refs/merge-requests/X/head upon a push to the source branch of a merge request (Stan Hu) - Improved performance of finding users by one of their Email addresses - Improved performance of replacing references in comments diff --git a/app/services/merge_requests/refresh_service.rb b/app/services/merge_requests/refresh_service.rb index d68bc79ecc0..e180edb4bf3 100644 --- a/app/services/merge_requests/refresh_service.rb +++ b/app/services/merge_requests/refresh_service.rb @@ -7,17 +7,17 @@ module MergeRequests @branch_name = Gitlab::Git.ref_name(ref) find_new_commits + # Be sure to close outstanding MRs before reloading them to avoid generating an + # empty diff during a manual merge + close_merge_requests reload_merge_requests # Leave a system note if a branch was deleted/added if branch_added? || branch_removed? comment_mr_branch_presence_changed - comment_mr_with_commits - else - comment_mr_with_commits - close_merge_requests end + comment_mr_with_commits execute_mr_web_hooks true -- cgit v1.2.1 From cea2afa85ed81abfa809a622ca3a548f770ad228 Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Fri, 6 Nov 2015 14:14:43 +0100 Subject: Add changelog item and remove release labels for tags list Signed-off-by: Dmitriy Zaporozhets --- CHANGELOG | 1 + app/views/projects/tags/_tag.html.haml | 3 --- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index 0ec6030b130..a7a9e073ae7 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -22,6 +22,7 @@ v 8.2.0 (unreleased) - Include commit logs in project search - Add "added", "modified" and "removed" properties to commit object in webhook - Rename "Back to" links to "Go to" because its not always a case it point to place user come from + - Ability to add release notes (markdown text and attachments) to git tags v 8.1.3 - Spread out runner contacted_at updates diff --git a/app/views/projects/tags/_tag.html.haml b/app/views/projects/tags/_tag.html.haml index f3dc314a894..e2c5178185e 100644 --- a/app/views/projects/tags/_tag.html.haml +++ b/app/views/projects/tags/_tag.html.haml @@ -9,9 +9,6 @@ - if tag.message.present?   = strip_gpg_signature(tag.message) - - if release -   - %span.label.label-success release .controls = link_to edit_namespace_project_tag_release_path(@project.namespace, @project, tag.name), class: 'btn-grouped btn' do -- cgit v1.2.1 From ed757ef6e3aab55c8fe0f2c1efdd79d65025c550 Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Fri, 6 Nov 2015 14:44:08 +0100 Subject: Rewrite remove tag test Signed-off-by: Dmitriy Zaporozhets --- features/project/commits/tags.feature | 9 +-------- features/steps/project/commits/tags.rb | 25 ++++++------------------- 2 files changed, 7 insertions(+), 27 deletions(-) diff --git a/features/project/commits/tags.feature b/features/project/commits/tags.feature index 02f399f7cad..24fb84d1cc9 100644 --- a/features/project/commits/tags.feature +++ b/features/project/commits/tags.feature @@ -29,13 +29,6 @@ Feature: Project Commits Tags @javascript Scenario: I delete a tag + Given I visit tag 'v1.1.0' page Given I delete tag 'v1.1.0' Then I should not see tag 'v1.1.0' - - @javascript - Scenario: I delete all tags and see info message - Given I delete all tags - Then I should see tags info message - - # @wip - # Scenario: I can download project by tag diff --git a/features/steps/project/commits/tags.rb b/features/steps/project/commits/tags.rb index e6f8faf50fd..ff824c76955 100644 --- a/features/steps/project/commits/tags.rb +++ b/features/steps/project/commits/tags.rb @@ -52,11 +52,13 @@ class Spinach::Features::ProjectCommitsTags < Spinach::FeatureSteps expect(page).to have_content 'Tag already exists' end + step "I visit tag 'v1.1.0' page" do + click_link 'v1.1.0' + end + step "I delete tag 'v1.1.0'" do - page.within '.tags' do - first('.btn-remove').click - sleep 0.05 - end + first('.btn-remove').click + sleep 0.05 end step "I should not see tag 'v1.1.0'" do @@ -64,19 +66,4 @@ class Spinach::Features::ProjectCommitsTags < Spinach::FeatureSteps expect(page.all(visible: true)).not_to have_content 'v1.1.0' end end - - step 'I delete all tags' do - page.within '.tags' do - page.all('.btn-remove').each do |remove| - remove.click - sleep 0.05 - end - end - end - - step 'I should see tags info message' do - page.within '.tags' do - expect(page).to have_content 'Repository has no tags yet.' - end - end end -- cgit v1.2.1 From c1a893d91a569cf65b381e8c2b56c82824e9f593 Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Fri, 6 Nov 2015 14:44:46 +0100 Subject: Fix list rendering issue when dropdown was hidden in row Signed-off-by: Dmitriy Zaporozhets --- app/assets/stylesheets/framework/lists.scss | 2 +- app/assets/stylesheets/framework/mixins.scss | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/app/assets/stylesheets/framework/lists.scss b/app/assets/stylesheets/framework/lists.scss index f6942db5816..45f3b5849bf 100644 --- a/app/assets/stylesheets/framework/lists.scss +++ b/app/assets/stylesheets/framework/lists.scss @@ -117,7 +117,7 @@ ul.content-list { } .controls { - padding-top: 4px; + padding-top: 1px; float: right; .btn { diff --git a/app/assets/stylesheets/framework/mixins.scss b/app/assets/stylesheets/framework/mixins.scss index b9c179f2881..11c48d26ab5 100644 --- a/app/assets/stylesheets/framework/mixins.scss +++ b/app/assets/stylesheets/framework/mixins.scss @@ -72,9 +72,10 @@ list-style: none; > li { + @include clearfix; + padding: 10px 0; border-bottom: 1px solid #EEE; - overflow: hidden; display: block; margin: 0px; -- cgit v1.2.1 From b60ad399acdd753efe4f2d724c47800b6a70056b Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Fri, 6 Nov 2015 14:47:29 +0100 Subject: Fix test Signed-off-by: Dmitriy Zaporozhets --- features/project/commits/tags.feature | 1 - features/steps/project/commits/tags.rb | 7 ++++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/features/project/commits/tags.feature b/features/project/commits/tags.feature index 24fb84d1cc9..660238c2319 100644 --- a/features/project/commits/tags.feature +++ b/features/project/commits/tags.feature @@ -27,7 +27,6 @@ Feature: Project Commits Tags And I submit new tag form with tag that already exists Then I should see new an error that tag already exists - @javascript Scenario: I delete a tag Given I visit tag 'v1.1.0' page Given I delete tag 'v1.1.0' diff --git a/features/steps/project/commits/tags.rb b/features/steps/project/commits/tags.rb index ff824c76955..cb5fe20834d 100644 --- a/features/steps/project/commits/tags.rb +++ b/features/steps/project/commits/tags.rb @@ -57,13 +57,14 @@ class Spinach::Features::ProjectCommitsTags < Spinach::FeatureSteps end step "I delete tag 'v1.1.0'" do - first('.btn-remove').click - sleep 0.05 + page.within('.content') do + first('.btn-remove').click + end end step "I should not see tag 'v1.1.0'" do page.within '.tags' do - expect(page.all(visible: true)).not_to have_content 'v1.1.0' + expect(page).not_to have_link 'v1.1.0' end end end -- cgit v1.2.1 From 962b57df5a3f476407858b12455030d8cda66e4b Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Fri, 6 Nov 2015 15:05:19 +0100 Subject: Small UI improvements to new git tag page Signed-off-by: Dmitriy Zaporozhets --- app/views/projects/releases/edit.html.haml | 4 +++- app/views/projects/tags/new.html.haml | 14 ++++++++------ 2 files changed, 11 insertions(+), 7 deletions(-) diff --git a/app/views/projects/releases/edit.html.haml b/app/views/projects/releases/edit.html.haml index fb841b77a25..78741416347 100644 --- a/app/views/projects/releases/edit.html.haml +++ b/app/views/projects/releases/edit.html.haml @@ -3,7 +3,9 @@ .gray-content-block .oneline - Release notes for #{@tag.name} + .title + Release notes for tag + %strong #{@tag.name} .prepend-top-default = form_for(@release, method: :put, url: namespace_project_tag_release_path(@project.namespace, @project, @tag.name), html: { class: 'form-horizontal gfm-form release-form' }) do |f| diff --git a/app/views/projects/tags/new.html.haml b/app/views/projects/tags/new.html.haml index 9b224ff89b0..be8f2e6f70e 100644 --- a/app/views/projects/tags/new.html.haml +++ b/app/views/projects/tags/new.html.haml @@ -5,9 +5,11 @@ .alert.alert-danger %button{ type: "button", class: "close", "data-dismiss" => "alert"} × = @error + %h3.page-title - %i.fa.fa-code-fork - New tag + New git tag +%hr + = form_tag namespace_project_tags_path, method: :post, id: "new-tag-form", class: "form-horizontal tag-form" do .form-group = label_tag :tag_name, 'Name for new tag', class: 'control-label' @@ -17,15 +19,15 @@ = label_tag :ref, 'Create from', class: 'control-label' .col-sm-10 = text_field_tag :ref, params[:ref], placeholder: 'master', required: true, tabindex: 2, class: 'form-control' - .light Branch name or commit SHA + .help-block Branch name or commit SHA .form-group = label_tag :message, 'Message', class: 'control-label' .col-sm-10 = text_field_tag :message, nil, placeholder: 'Enter message.', required: false, tabindex: 3, class: 'form-control' - .light (Optional) Entering a message will create an annotated tag. + .help-block (Optional) Entering a message will create an annotated tag. %hr .form-group - = label_tag :release_description, 'Release description', class: 'control-label' + = label_tag :release_description, 'Release notes', class: 'control-label' .col-sm-10 = render layout: 'projects/md_preview', locals: { preview_class: "md-preview", referenced_users: true } do .zennable @@ -39,7 +41,7 @@ = icon('compress') = render 'projects/notes/hints' - .help-block You can add release description to your tag. It will be stored in GitLab database and displayed on tags page + .help-block (Optional) You can add release notes to your tag. It will be stored in GitLab database and displayed on tags page .form-actions = button_tag 'Create tag', class: 'btn btn-create', tabindex: 3 = link_to 'Cancel', namespace_project_tags_path(@project.namespace, @project), class: 'btn btn-cancel' -- cgit v1.2.1 From cb8b9c3fe2caba14752978f4283affc07581087c Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Fri, 6 Nov 2015 15:29:04 +0100 Subject: Add association and validation for Release model Signed-off-by: Dmitriy Zaporozhets --- app/models/release.rb | 3 +++ 1 file changed, 3 insertions(+) diff --git a/app/models/release.rb b/app/models/release.rb index 1dc9ce6dd4f..05647839e84 100644 --- a/app/models/release.rb +++ b/app/models/release.rb @@ -1,2 +1,5 @@ class Release < ActiveRecord::Base + belongs_to :project + + validates :description, :project, presence: true end -- cgit v1.2.1 From 6f15356aea488ce0085c982aac2c97cdd46db96b Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Fri, 6 Nov 2015 15:43:59 +0100 Subject: Add tests to release notes feature Signed-off-by: Dmitriy Zaporozhets --- app/views/projects/tags/show.html.haml | 6 +++--- features/project/commits/tags.feature | 12 ++++++++++++ features/steps/project/commits/tags.rb | 20 ++++++++++++++++++++ spec/factories/releases.rb | 6 +++--- spec/models/release_spec.rb | 13 ++++++++++++- 5 files changed, 50 insertions(+), 7 deletions(-) diff --git a/app/views/projects/tags/show.html.haml b/app/views/projects/tags/show.html.haml index f80ba5516a0..f95ae9edc4b 100644 --- a/app/views/projects/tags/show.html.haml +++ b/app/views/projects/tags/show.html.haml @@ -4,11 +4,11 @@ .gray-content-block .pull-right - = link_to edit_namespace_project_tag_release_path(@project.namespace, @project, @tag.name), class: 'btn-grouped btn' do + = link_to edit_namespace_project_tag_release_path(@project.namespace, @project, @tag.name), class: 'btn-grouped btn', title: 'Edit release notes' do = icon("pencil") - = link_to namespace_project_tree_path(@project.namespace, @project, @tag.name), class: 'btn btn-grouped' do + = link_to namespace_project_tree_path(@project.namespace, @project, @tag.name), class: 'btn btn-grouped', title: 'Browse source code' do = icon('files-o') - = link_to namespace_project_commits_path(@project.namespace, @project, @tag.name), class: 'btn btn-grouped' do + = link_to namespace_project_commits_path(@project.namespace, @project, @tag.name), class: 'btn btn-grouped', title: 'Browse commits' do = icon('history') - if can? current_user, :download_code, @project = render 'projects/tags/download', ref: @tag.name, project: @project diff --git a/features/project/commits/tags.feature b/features/project/commits/tags.feature index 660238c2319..56ee091acc0 100644 --- a/features/project/commits/tags.feature +++ b/features/project/commits/tags.feature @@ -12,6 +12,12 @@ Feature: Project Commits Tags And I submit new tag form Then I should see new tag created + Scenario: I create a tag with release notes + Given I click new tag link + And I submit new tag form with release notes + Then I should see new tag created + And I should see tag release notes + Scenario: I create a tag with invalid name And I click new tag link And I submit new tag form with invalid name @@ -31,3 +37,9 @@ Feature: Project Commits Tags Given I visit tag 'v1.1.0' page Given I delete tag 'v1.1.0' Then I should not see tag 'v1.1.0' + + Scenario: I add release notes to the tag + Given I visit tag 'v1.1.0' page + When I click edit tag link + And I fill release notes and submit form + Then I should see tag release notes diff --git a/features/steps/project/commits/tags.rb b/features/steps/project/commits/tags.rb index cb5fe20834d..eff4234a44a 100644 --- a/features/steps/project/commits/tags.rb +++ b/features/steps/project/commits/tags.rb @@ -18,6 +18,18 @@ class Spinach::Features::ProjectCommitsTags < Spinach::FeatureSteps click_button 'Create tag' end + step 'I submit new tag form with release notes' do + fill_in 'tag_name', with: 'v7.0' + fill_in 'ref', with: 'master' + fill_in 'release_description', with: 'Awesome release notes' + click_button 'Create tag' + end + + step 'I fill release notes and submit form' do + fill_in 'release_description', with: 'Awesome release notes' + click_button 'Save changes' + end + step 'I submit new tag form with invalid name' do fill_in 'tag_name', with: 'v 1.0' fill_in 'ref', with: 'master' @@ -67,4 +79,12 @@ class Spinach::Features::ProjectCommitsTags < Spinach::FeatureSteps expect(page).not_to have_link 'v1.1.0' end end + + step 'I click edit tag link' do + click_link 'Edit release notes' + end + + step 'I should see tag release notes' do + expect(page).to have_content 'Awesome release notes' + end end diff --git a/spec/factories/releases.rb b/spec/factories/releases.rb index 067d8138e41..80d6bbee6c7 100644 --- a/spec/factories/releases.rb +++ b/spec/factories/releases.rb @@ -2,8 +2,8 @@ FactoryGirl.define do factory :release do - tag "MyString" - description "MyText" - project_id 1 + tag "v1.1.0" + description "Awesome release" + project end end diff --git a/spec/models/release_spec.rb b/spec/models/release_spec.rb index e533734ba0d..527005b2b69 100644 --- a/spec/models/release_spec.rb +++ b/spec/models/release_spec.rb @@ -1,5 +1,16 @@ require 'rails_helper' RSpec.describe Release, type: :model do - pending "add some examples to (or delete) #{__FILE__}" + let(:release) { create(:release) } + + it { expect(release).to be_valid } + + describe 'associations' do + it { is_expected.to belong_to(:project) } + end + + describe 'validation' do + it { is_expected.to validate_presence_of(:project) } + it { is_expected.to validate_presence_of(:description) } + end end -- cgit v1.2.1 From 14518ba65a7727583445314917d466dabe4a6811 Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Fri, 6 Nov 2015 15:48:18 +0100 Subject: Better english Signed-off-by: Dmitriy Zaporozhets --- app/views/projects/tags/new.html.haml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/views/projects/tags/new.html.haml b/app/views/projects/tags/new.html.haml index be8f2e6f70e..e106be794f1 100644 --- a/app/views/projects/tags/new.html.haml +++ b/app/views/projects/tags/new.html.haml @@ -41,7 +41,7 @@ = icon('compress') = render 'projects/notes/hints' - .help-block (Optional) You can add release notes to your tag. It will be stored in GitLab database and displayed on tags page + .help-block (Optional) You can add release notes to your tag. It will be stored in the GitLab database and shown on the tags page .form-actions = button_tag 'Create tag', class: 'btn btn-create', tabindex: 3 = link_to 'Cancel', namespace_project_tags_path(@project.namespace, @project), class: 'btn btn-cancel' -- cgit v1.2.1 From c5ec2a23a466f45127b6056693e1a473ae7e503e Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Fri, 6 Nov 2015 16:27:18 +0100 Subject: Small UI improvements to merge request page Signed-off-by: Dmitriy Zaporozhets --- app/assets/stylesheets/framework/blocks.scss | 4 ++++ app/assets/stylesheets/pages/diff.scss | 1 - app/helpers/diff_helper.rb | 4 ++-- app/views/projects/diffs/_diffs.html.haml | 2 +- app/views/projects/merge_requests/_discussion.html.haml | 2 +- app/views/projects/merge_requests/show/_commits.html.haml | 4 ++++ 6 files changed, 12 insertions(+), 5 deletions(-) diff --git a/app/assets/stylesheets/framework/blocks.scss b/app/assets/stylesheets/framework/blocks.scss index 8917c53b1f5..1635df9c97b 100644 --- a/app/assets/stylesheets/framework/blocks.scss +++ b/app/assets/stylesheets/framework/blocks.scss @@ -28,6 +28,10 @@ border-bottom: 1px solid $border-color; color: $gl-gray; + &.oneline-block { + line-height: 42px; + } + &.white { background-color: white; } diff --git a/app/assets/stylesheets/pages/diff.scss b/app/assets/stylesheets/pages/diff.scss index d9ef06dc6b6..afd6fb73675 100644 --- a/app/assets/stylesheets/pages/diff.scss +++ b/app/assets/stylesheets/pages/diff.scss @@ -367,7 +367,6 @@ .inline-parallel-buttons { float: right; - margin-top: -5px; } // Mobile diff --git a/app/helpers/diff_helper.rb b/app/helpers/diff_helper.rb index e65e37211c4..b889fb28973 100644 --- a/app/helpers/diff_helper.rb +++ b/app/helpers/diff_helper.rb @@ -137,7 +137,7 @@ module DiffHelper # Always use HTML to handle case where JSON diff rendered this button params_copy.delete(:format) - link_to url_for(params_copy), id: "inline-diff-btn", class: (params[:view] != 'parallel' ? 'btn btn-sm active' : 'btn btn-sm') do + link_to url_for(params_copy), id: "inline-diff-btn", class: (params[:view] != 'parallel' ? 'btn active' : 'btn') do 'Inline' end end @@ -148,7 +148,7 @@ module DiffHelper # Always use HTML to handle case where JSON diff rendered this button params_copy.delete(:format) - link_to url_for(params_copy), id: "parallel-diff-btn", class: (params[:view] == 'parallel' ? 'btn active btn-sm' : 'btn btn-sm') do + link_to url_for(params_copy), id: "parallel-diff-btn", class: (params[:view] == 'parallel' ? 'btn active' : 'btn') do 'Side-by-side' end end diff --git a/app/views/projects/diffs/_diffs.html.haml b/app/views/projects/diffs/_diffs.html.haml index 56b51f038ba..e46bf1ab1e7 100644 --- a/app/views/projects/diffs/_diffs.html.haml +++ b/app/views/projects/diffs/_diffs.html.haml @@ -3,7 +3,7 @@ - diff_files = safe_diff_files(diffs) -.gray-content-block.second-block +.gray-content-block.second-block.oneline-block .inline-parallel-buttons .btn-group = inline_diff_btn diff --git a/app/views/projects/merge_requests/_discussion.html.haml b/app/views/projects/merge_requests/_discussion.html.haml index 38e66c3828b..7e60782ff5b 100644 --- a/app/views/projects/merge_requests/_discussion.html.haml +++ b/app/views/projects/merge_requests/_discussion.html.haml @@ -7,7 +7,7 @@ = render 'shared/show_aside' -.gray-content-block.second-block +.gray-content-block.second-block.oneline-block .row .col-md-9 .votes-holder.pull-right diff --git a/app/views/projects/merge_requests/show/_commits.html.haml b/app/views/projects/merge_requests/show/_commits.html.haml index a71b181a6a5..478054db517 100644 --- a/app/views/projects/merge_requests/show/_commits.html.haml +++ b/app/views/projects/merge_requests/show/_commits.html.haml @@ -1 +1,5 @@ +.gray-content-block.second-block.oneline-block + = icon("sort-amount-desc") + Most recent commits displayed first + = render "projects/commits/commits", project: @merge_request.project -- cgit v1.2.1 From 8f2561b193ad39f116655af0789798b45ad906c8 Mon Sep 17 00:00:00 2001 From: Stan Hu Date: Fri, 6 Nov 2015 08:04:02 -0800 Subject: Add spec for manual merge of merge request --- spec/services/merge_requests/refresh_service_spec.rb | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/spec/services/merge_requests/refresh_service_spec.rb b/spec/services/merge_requests/refresh_service_spec.rb index 227ac995ec2..7ee4488521d 100644 --- a/spec/services/merge_requests/refresh_service_spec.rb +++ b/spec/services/merge_requests/refresh_service_spec.rb @@ -62,6 +62,25 @@ describe MergeRequests::RefreshService do it { expect(@fork_merge_request.notes.last.note).to include('changed to merged') } end + context 'manual merge of source branch' do + before do + # Merge master -> feature branch + author = { email: 'test@gitlab.com', time: Time.now, name: "Me" } + commit_options = { message: 'Test message', committer: author, author: author } + master_commit = @project.repository.commit('master') + @project.repository.merge(@user, master_commit.id, 'feature', commit_options) + commit = @project.repository.commit('feature') + service.new(@project, @user).execute(@oldrev, commit.id, 'refs/heads/feature') + reload_mrs + end + + it { expect(@merge_request.notes.last.note).to include('changed to merged') } + it { expect(@merge_request).to be_merged } + it { expect(@merge_request.diffs.length).to be > 0 } + it { expect(@fork_merge_request).to be_merged } + it { expect(@fork_merge_request.notes.last.note).to include('changed to merged') } + end + context 'push to fork repo source branch' do let(:refresh_service) { service.new(@fork_project, @user) } before do -- cgit v1.2.1 From e34904370f7383853ed9e1f5392ff76defda9530 Mon Sep 17 00:00:00 2001 From: Baldinof Date: Fri, 6 Nov 2015 23:45:33 +0100 Subject: Merge button has color from CI status --- app/assets/stylesheets/pages/merge_requests.scss | 14 ++++++++++++++ .../projects/merge_requests/widget/open/_accept.html.haml | 4 +++- 2 files changed, 17 insertions(+), 1 deletion(-) diff --git a/app/assets/stylesheets/pages/merge_requests.scss b/app/assets/stylesheets/pages/merge_requests.scss index f0b3667acca..08e4bcdf529 100644 --- a/app/assets/stylesheets/pages/merge_requests.scss +++ b/app/assets/stylesheets/pages/merge_requests.scss @@ -19,6 +19,20 @@ .accept-merge-holder { .accept-action { display: inline-block; + + .accept_merge_request { + &.ci-pending, + &.ci-running { + @include btn-orange; + } + + &.ci-skipped, + &.ci-failed, + &.ci-canceled, + &.ci-error { + @include btn-red; + } + } } .accept-control { diff --git a/app/views/projects/merge_requests/widget/open/_accept.html.haml b/app/views/projects/merge_requests/widget/open/_accept.html.haml index 613525437ab..689247f3186 100644 --- a/app/views/projects/merge_requests/widget/open/_accept.html.haml +++ b/app/views/projects/merge_requests/widget/open/_accept.html.haml @@ -1,8 +1,10 @@ +- status_class = @merge_request.ci_commit ? " ci-#{@merge_request.ci_commit.status}" : nil + = form_for [:merge, @project.namespace.becomes(Namespace), @project, @merge_request], remote: true, method: :post, html: { class: 'accept-mr-form js-requires-input' } do |f| = hidden_field_tag :authenticity_token, form_authenticity_token .accept-merge-holder.clearfix.js-toggle-container .accept-action - = f.button class: "btn btn-create accept_merge_request" do + = f.button class: "btn btn-create accept_merge_request#{status_class}" do Accept Merge Request - if can_remove_branch?(@merge_request.source_project, @merge_request.source_branch) && !@merge_request.for_fork? .accept-control.checkbox -- cgit v1.2.1 From 78171d548158584fe19496fa5113052a9c3cc235 Mon Sep 17 00:00:00 2001 From: Sytse Sijbrandij Date: Fri, 6 Nov 2015 18:25:41 -0800 Subject: Prevent people from adding the link back. --- app/views/layouts/notify.html.haml | 1 + 1 file changed, 1 insertion(+) diff --git a/app/views/layouts/notify.html.haml b/app/views/layouts/notify.html.haml index f58b9bd6ba6..a02dd955186 100644 --- a/app/views/layouts/notify.html.haml +++ b/app/views/layouts/notify.html.haml @@ -42,6 +42,7 @@ - else #{link_to "View it on GitLab", @target_url}. %br + -# Don't link the host is the line below, hone link in the email is easier to quickly click than two. You're receiving this email because of your account on #{Gitlab.config.gitlab.host}. If you'd like to receive fewer emails, you can adjust your notification settings. -- cgit v1.2.1 From b14198a5e7520ce7cf356006507db9b190e3afe3 Mon Sep 17 00:00:00 2001 From: Christian Speich Date: Sat, 7 Nov 2015 12:40:14 +0100 Subject: Hide tab-bar in login-box when only one tabs is shown. --- app/views/devise/shared/_signin_box.html.haml | 46 ++++++++++++++++----------- 1 file changed, 27 insertions(+), 19 deletions(-) diff --git a/app/views/devise/shared/_signin_box.html.haml b/app/views/devise/shared/_signin_box.html.haml index 41ad2c231d4..9a1331b2549 100644 --- a/app/views/devise/shared/_signin_box.html.haml +++ b/app/views/devise/shared/_signin_box.html.haml @@ -7,26 +7,34 @@ %h3 Sign in .login-body - if form_based_providers.any? - %ul.nav.nav-tabs + - if form_based_providers.count >= 2 || signin_enabled? + %ul.nav.nav-tabs + - if crowd_enabled? + %li.active + = link_to "Crowd", "#tab-crowd", 'data-toggle' => 'tab' + - @ldap_servers.each_with_index do |server, i| + %li{class: (:active if i.zero? && !crowd_enabled?)} + = link_to server['label'], "#tab-#{server['provider_name']}", 'data-toggle' => 'tab' + - if signin_enabled? + %li + = link_to 'Standard', '#tab-signin', 'data-toggle' => 'tab' + .tab-content + - if crowd_enabled? + %div.tab-pane.active{id: "tab-crowd"} + = render 'devise/sessions/new_crowd' + - @ldap_servers.each_with_index do |server, i| + %div.tab-pane{id: "tab-#{server['provider_name']}", class: (:active if i.zero? && !crowd_enabled?)} + = render 'devise/sessions/new_ldap', server: server + - if signin_enabled? + %div#tab-signin.tab-pane + = render 'devise/sessions/new_base' + - else - if crowd_enabled? - %li.active - = link_to "Crowd", "#tab-crowd", 'data-toggle' => 'tab' - - @ldap_servers.each_with_index do |server, i| - %li{class: (:active if i.zero? && !crowd_enabled?)} - = link_to server['label'], "#tab-#{server['provider_name']}", 'data-toggle' => 'tab' - - if signin_enabled? - %li - = link_to 'Standard', '#tab-signin', 'data-toggle' => 'tab' - .tab-content - - if crowd_enabled? - %div.tab-pane.active{id: "tab-crowd"} - = render 'devise/sessions/new_crowd' - - @ldap_servers.each_with_index do |server, i| - %div.tab-pane{id: "tab-#{server['provider_name']}", class: (:active if i.zero? && !crowd_enabled?)} - = render 'devise/sessions/new_ldap', server: server - - if signin_enabled? - %div#tab-signin.tab-pane - = render 'devise/sessions/new_base' + = render 'devise/sessions/new_crowd' + - elsif @ldap_servers.any? + = render 'devise/sessions/new_ldap', server: @ldap_servers.first + - elsif signin_enabled? + = render 'devise/sessions/new_base' - elsif signin_enabled? = render 'devise/sessions/new_base' -- cgit v1.2.1 From 920a2d974c15662ffac49146348c8d638a9db92b Mon Sep 17 00:00:00 2001 From: Jeroen van Baarsen Date: Wed, 28 Oct 2015 15:58:40 +0100 Subject: Fixed markdown issue in PROCESS.md --- PROCESS.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/PROCESS.md b/PROCESS.md index d42168a7231..a4b0c83644b 100644 --- a/PROCESS.md +++ b/PROCESS.md @@ -119,6 +119,6 @@ rebase with master to see if that solves the issue. ### Closing down the issue tracker on GitHub We are currently in the process of closing down the issue tracker on GitHub, to -prevent duplication with the [GitLab.com issue tracker][https://gitlab.com/gitlab-org/gitlab-ce/issues]. +prevent duplication with the GitLab.com issue tracker. Since this is an older issue I'll be closing this for now. If you think this is -still an issue I encourage you to open it on the [GitLab.com issue tracker][https://gitlab.com/gitlab-org/gitlab-ce/issues]. +still an issue I encourage you to open it on the \[GitLab.com issue tracker\](https://gitlab.com/gitlab-org/gitlab-ce/issues). -- cgit v1.2.1 From 4099751ce9b33fbafbfcfbf1506e091a20f7c034 Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Sat, 7 Nov 2015 20:22:16 +0100 Subject: Render same markdown hint for issue, merge request, wiki and comment forms Signed-off-by: Dmitriy Zaporozhets --- app/assets/stylesheets/framework/markdown_area.scss | 1 + app/assets/stylesheets/pages/note_form.scss | 6 +++++- app/views/projects/wikis/_form.html.haml | 4 +--- app/views/shared/issuable/_form.html.haml | 9 +-------- 4 files changed, 8 insertions(+), 12 deletions(-) diff --git a/app/assets/stylesheets/framework/markdown_area.scss b/app/assets/stylesheets/framework/markdown_area.scss index ed0333d2336..cc660529cb4 100644 --- a/app/assets/stylesheets/framework/markdown_area.scss +++ b/app/assets/stylesheets/framework/markdown_area.scss @@ -106,6 +106,7 @@ } .markdown-area { + @include border-radius(0); background: #FFF; border: 1px solid #ddd; min-height: 140px; diff --git a/app/assets/stylesheets/pages/note_form.scss b/app/assets/stylesheets/pages/note_form.scss index 4392f08942b..268fc995aa7 100644 --- a/app/assets/stylesheets/pages/note_form.scss +++ b/app/assets/stylesheets/pages/note_form.scss @@ -56,6 +56,10 @@ .note_text { width: 100%; } + + .comment-hints { + margin-top: -12px; + } } /* loading indicator */ @@ -168,7 +172,7 @@ color: #999; background: #FFF; padding: 7px; - margin-top: -11px; + margin-top: -7px; border: 1px solid $border-color; font-size: 13px; } diff --git a/app/views/projects/wikis/_form.html.haml b/app/views/projects/wikis/_form.html.haml index 261d4a92d7d..9c94c43e747 100644 --- a/app/views/projects/wikis/_form.html.haml +++ b/app/views/projects/wikis/_form.html.haml @@ -23,9 +23,7 @@ .col-sm-10 = render layout: 'projects/md_preview', locals: { preview_class: "md-preview" } do = render 'projects/zen', f: f, attr: :content, classes: 'description form-control js-quick-submit' - .col-sm-12.hint - .pull-left Wiki content is parsed with #{link_to "GitLab Flavored Markdown", help_page_path("markdown", "markdown"), target: '_blank'} - .pull-right Attach files by dragging & dropping or #{link_to "selecting them", '#', class: 'markdown-selector' }. + = render 'projects/notes/hints' .clearfix .error-alert diff --git a/app/views/shared/issuable/_form.html.haml b/app/views/shared/issuable/_form.html.haml index 594e54f404c..0fc74d7d2b1 100644 --- a/app/views/shared/issuable/_form.html.haml +++ b/app/views/shared/issuable/_form.html.haml @@ -27,14 +27,7 @@ = render layout: 'projects/md_preview', locals: { preview_class: "md-preview", referenced_users: true } do = render 'projects/zen', f: f, attr: :description, classes: 'description form-control js-quick-submit' - .col-sm-12.hint - .pull-left - Parsed with - #{link_to 'GitLab Flavored Markdown', help_page_path('markdown', 'markdown'), target: '_blank'}. - .pull-right - Attach files by dragging & dropping - or #{link_to 'selecting them', '#', class: 'markdown-selector' }. - + = render 'projects/notes/hints' .clearfix .error-alert %hr -- cgit v1.2.1 From b8cd6f9aae2eb0753c8f36284331aef6b4557bab Mon Sep 17 00:00:00 2001 From: Achilleas Pipinellis Date: Sun, 8 Nov 2015 18:00:31 +0200 Subject: Update piwik template --- app/views/layouts/_piwik.html.haml | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/app/views/layouts/_piwik.html.haml b/app/views/layouts/_piwik.html.haml index 135e8daca26..259b4f7cdfc 100644 --- a/app/views/layouts/_piwik.html.haml +++ b/app/views/layouts/_piwik.html.haml @@ -1,12 +1,14 @@ + :javascript var _paq = _paq || []; - _paq.push(["trackPageView"]); - _paq.push(["enableLinkTracking"]); - + _paq.push(['trackPageView']); + _paq.push(['enableLinkTracking']); (function() { - var u=(("https:" == document.location.protocol) ? "https" : "http") + "://#{extra_config.piwik_url}/"; - _paq.push(["setTrackerUrl", u+"piwik.php"]); - _paq.push(["setSiteId", "#{extra_config.piwik_site_id}"]); - var d=document, g=d.createElement("script"), s=d.getElementsByTagName("script")[0]; g.type="text/javascript"; - g.defer=true; g.async=true; g.src=u+"piwik.js"; s.parentNode.insertBefore(g,s); + var u="//#{extra_config.piwik_url}/"; + _paq.push(['setTrackerUrl', u+'piwik.php']); + _paq.push(['setSiteId', #{extra_config.piwik_site_id}]); + var d=document, g=d.createElement('script'), s=d.getElementsByTagName('script')[0]; + g.type='text/javascript'; g.async=true; g.defer=true; g.src=u+'piwik.js'; s.parentNode.insertBefore(g,s); })(); + + -- cgit v1.2.1 From 2e5d32e07a75b98e57a0476a4cdb7a1ec41cadda Mon Sep 17 00:00:00 2001 From: Pirate Praveen Date: Sun, 8 Nov 2015 12:15:58 -0500 Subject: Switch to state_machines-activerecord (Fixes: #3374) --- Gemfile | 2 +- config/initializers/state_machine_patch.rb | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Gemfile b/Gemfile index 0bac8978160..ee8b2a7a51a 100644 --- a/Gemfile +++ b/Gemfile @@ -113,7 +113,7 @@ group :unicorn do end # State machine -gem "state_machine", '~> 1.2.0' +gem "state_machines-activerecord", '~> 0.3.0' # Run events after state machine commits gem 'after_commit_queue' diff --git a/config/initializers/state_machine_patch.rb b/config/initializers/state_machine_patch.rb index 72d010fa5de..51f05794361 100644 --- a/config/initializers/state_machine_patch.rb +++ b/config/initializers/state_machine_patch.rb @@ -1,6 +1,6 @@ # This is a patch to address the issue in https://github.com/pluginaweek/state_machine/issues/251 # where gem 'state_machine' was not working for Rails 4.1 -module StateMachine +module StateMachines module Integrations module ActiveModel public :around_validation -- cgit v1.2.1 From ac5b6c3b50b5220d3fc800508267b320fa7cf78b Mon Sep 17 00:00:00 2001 From: Christophe Poulette Date: Sun, 8 Nov 2015 19:29:22 +0100 Subject: Apply new design for project graphs page --- CHANGELOG | 1 + app/views/projects/graphs/_head.html.haml | 2 +- app/views/projects/graphs/ci.html.haml | 3 +++ app/views/projects/graphs/commits.html.haml | 10 +++++++--- app/views/projects/graphs/show.html.haml | 8 ++++++-- 5 files changed, 18 insertions(+), 6 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index 3a75f50e9a2..6f6bc8a7452 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -23,6 +23,7 @@ v 8.2.0 (unreleased) - Add "added", "modified" and "removed" properties to commit object in webhook - Rename "Back to" links to "Go to" because its not always a case it point to place user come from - Allow groups to appear in the search results if the group owner allows it + - New design for project graphs page v 8.1.3 - Spread out runner contacted_at updates diff --git a/app/views/projects/graphs/_head.html.haml b/app/views/projects/graphs/_head.html.haml index bbfaf422a82..e0d06a14bf4 100644 --- a/app/views/projects/graphs/_head.html.haml +++ b/app/views/projects/graphs/_head.html.haml @@ -1,4 +1,4 @@ -%ul.nav.nav-tabs +%ul.center-top-menu = nav_link(action: :show) do = link_to 'Contributors', namespace_project_graph_path = nav_link(action: :commits) do diff --git a/app/views/projects/graphs/ci.html.haml b/app/views/projects/graphs/ci.html.haml index 4f69cc64f7c..b2dfe97938a 100644 --- a/app/views/projects/graphs/ci.html.haml +++ b/app/views/projects/graphs/ci.html.haml @@ -1,6 +1,9 @@ - page_title "Continuous Integration", "Graphs" = render "header_title" = render 'head' +.gray-content-block + %ul.breadcrumb.repo-breadcrumb + = commits_breadcrumbs #charts.ci-charts = render 'projects/graphs/ci/builds' = render 'projects/graphs/ci/build_times' diff --git a/app/views/projects/graphs/commits.html.haml b/app/views/projects/graphs/commits.html.haml index 112be875b6b..a21d7448654 100644 --- a/app/views/projects/graphs/commits.html.haml +++ b/app/views/projects/graphs/commits.html.haml @@ -1,8 +1,12 @@ - page_title "Commits", "Graphs" = render "header_title" -.tree-ref-holder - = render 'shared/ref_switcher', destination: 'graphs_commits' -= render 'head' += reder 'head' + +.gray-content-block + .tree-ref-holder + = render 'shared/ref_switcher', destination: 'graphs_commits' + %ul.breadcrumb.repo-breadcrumb + = commits_breadcrumbs %p.lead Commit statistics for diff --git a/app/views/projects/graphs/show.html.haml b/app/views/projects/graphs/show.html.haml index bd342911e49..6bbf15d05a2 100644 --- a/app/views/projects/graphs/show.html.haml +++ b/app/views/projects/graphs/show.html.haml @@ -1,9 +1,13 @@ - page_title "Contributors", "Graphs" = render "header_title" -.tree-ref-holder - = render 'shared/ref_switcher', destination: 'graphs' = render 'head' +.gray-content-block + .tree-ref-holder + = render 'shared/ref_switcher', destination: 'graphs' + %ul.breadcrumb.repo-breadcrumb + = commits_breadcrumbs + .loading-graph .center %h3.page-title -- cgit v1.2.1 From b68a2e6f251cd0af7179eba5ed058fcaab009377 Mon Sep 17 00:00:00 2001 From: Christophe Poulette Date: Sun, 8 Nov 2015 20:15:03 +0100 Subject: Fix typo --- app/views/projects/graphs/commits.html.haml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/views/projects/graphs/commits.html.haml b/app/views/projects/graphs/commits.html.haml index a21d7448654..838d3e40614 100644 --- a/app/views/projects/graphs/commits.html.haml +++ b/app/views/projects/graphs/commits.html.haml @@ -1,6 +1,6 @@ - page_title "Commits", "Graphs" = render "header_title" -= reder 'head' += redner 'head' .gray-content-block .tree-ref-holder -- cgit v1.2.1 From 4ac26c6463b53e2a02a43835e6a919e2bc023fb7 Mon Sep 17 00:00:00 2001 From: Christophe Poulette Date: Sun, 8 Nov 2015 20:31:55 +0100 Subject: Fix typo. --- app/views/projects/graphs/commits.html.haml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/views/projects/graphs/commits.html.haml b/app/views/projects/graphs/commits.html.haml index 838d3e40614..4e0c3e5b3de 100644 --- a/app/views/projects/graphs/commits.html.haml +++ b/app/views/projects/graphs/commits.html.haml @@ -1,6 +1,6 @@ - page_title "Commits", "Graphs" = render "header_title" -= redner 'head' += render 'head' .gray-content-block .tree-ref-holder -- cgit v1.2.1 From 4fda9ef8a522352886fad08524b4ad4054a7eb60 Mon Sep 17 00:00:00 2001 From: Kamil Trzcinski Date: Thu, 5 Nov 2015 16:22:37 +0100 Subject: Fix tests --- spec/factories/ci/projects.rb | 2 ++ spec/models/application_setting_spec.rb | 28 ++++++++++++++++++++++--- spec/services/ci/register_build_service_spec.rb | 4 ++++ 3 files changed, 31 insertions(+), 3 deletions(-) diff --git a/spec/factories/ci/projects.rb b/spec/factories/ci/projects.rb index 111e1a82816..1183a190353 100644 --- a/spec/factories/ci/projects.rb +++ b/spec/factories/ci/projects.rb @@ -33,6 +33,8 @@ FactoryGirl.define do gl_project factory: :empty_project + shared_runners_enabled false + factory :ci_project do token 'iPWx6WM4lhHNedGfBpPJNP' end diff --git a/spec/models/application_setting_spec.rb b/spec/models/application_setting_spec.rb index de0b2ef4cda..f01fe8bd398 100644 --- a/spec/models/application_setting_spec.rb +++ b/spec/models/application_setting_spec.rb @@ -28,11 +28,11 @@ require 'spec_helper' describe ApplicationSetting, models: true do - it { expect(ApplicationSetting.create_from_defaults).to be_valid } + let(:setting) { ApplicationSetting.create_from_defaults } - context 'restricted signup domains' do - let(:setting) { ApplicationSetting.create_from_defaults } + it { expect(setting).to be_valid } + context 'restricted signup domains' do it 'set single domain' do setting.restricted_signup_domains_raw = 'example.com' expect(setting.restricted_signup_domains).to eq(['example.com']) @@ -53,4 +53,26 @@ describe ApplicationSetting, models: true do expect(setting.restricted_signup_domains).to eq(['example.com', '*.example.com']) end end + + context 'shared runners' do + let(:gl_project) { create(:empty_project) } + + before do + allow_any_instance_of(Project).to receive(:current_application_settings).and_return(setting) + end + + subject { gl_project.ensure_gitlab_ci_project.shared_runners_enabled } + + context 'enabled' do + before { setting.update_attributes(shared_runners_enabled: true) } + + it { is_expected.to be_truthy } + end + + context 'disabled' do + before { setting.update_attributes(shared_runners_enabled: false) } + + it { is_expected.to be_falsey } + end + end end diff --git a/spec/services/ci/register_build_service_spec.rb b/spec/services/ci/register_build_service_spec.rb index 781764627ac..b370dfbe113 100644 --- a/spec/services/ci/register_build_service_spec.rb +++ b/spec/services/ci/register_build_service_spec.rb @@ -70,6 +70,10 @@ module Ci end context 'disallow shared runners' do + before do + gl_project.gitlab_ci_project.update(shared_runners_enabled: false) + end + context 'shared runner' do let(:build) { service.execute(shared_runner) } -- cgit v1.2.1 From 3727c9cab2ab48ca6aa2f5cfa3cd3126a02002b1 Mon Sep 17 00:00:00 2001 From: Sullivan SENECHAL Date: Wed, 21 Oct 2015 10:40:05 +0200 Subject: Add GitLabCI code coverage regex sample for PHPUnit --- app/views/projects/ci_settings/_form.html.haml | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/app/views/projects/ci_settings/_form.html.haml b/app/views/projects/ci_settings/_form.html.haml index 20bdccc9027..ee6b8885e2d 100644 --- a/app/views/projects/ci_settings/_form.html.haml +++ b/app/views/projects/ci_settings/_form.html.haml @@ -103,8 +103,9 @@ %li pytest-cov (Python) - %code \d+\%\s*$ - - + %li + phpunit --coverage-text --colors=never (PHP) - + %code ^\s*Lines:\s*\d+.\d+\% %fieldset %legend Advanced settings -- cgit v1.2.1 From 0fb85939da482e50a7337d8762fb26e75bb16ce5 Mon Sep 17 00:00:00 2001 From: Douwe Maan Date: Mon, 9 Nov 2015 14:12:05 +0100 Subject: Fix incoming email config defaults --- CHANGELOG | 1 + config/initializers/1_settings.rb | 4 ++-- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index 22012211164..4951ae172c2 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -24,6 +24,7 @@ v 8.2.0 (unreleased) - Add "added", "modified" and "removed" properties to commit object in webhook - Rename "Back to" links to "Go to" because its not always a case it point to place user come from - Allow groups to appear in the search results if the group owner allows it + - Fix incoming email config defaults v 8.1.3 - Spread out runner contacted_at updates diff --git a/config/initializers/1_settings.rb b/config/initializers/1_settings.rb index 64d73d7232d..8192d727f2a 100644 --- a/config/initializers/1_settings.rb +++ b/config/initializers/1_settings.rb @@ -193,8 +193,8 @@ Settings.gitlab_ci['builds_path'] = File.expand_path(Settings.gitlab_c Settings['incoming_email'] ||= Settingslogic.new({}) Settings.incoming_email['enabled'] = false if Settings.incoming_email['enabled'].nil? Settings.incoming_email['port'] = 143 if Settings.incoming_email['port'].nil? -Settings.incoming_email['ssl'] = 143 if Settings.incoming_email['ssl'].nil? -Settings.incoming_email['start_tls'] = 143 if Settings.incoming_email['start_tls'].nil? +Settings.incoming_email['ssl'] = false if Settings.incoming_email['ssl'].nil? +Settings.incoming_email['start_tls'] = false if Settings.incoming_email['start_tls'].nil? Settings.incoming_email['mailbox'] = "inbox" if Settings.incoming_email['mailbox'].nil? # -- cgit v1.2.1 From dec3e4ce64df5f71a7cba7734cada1baa79242cd Mon Sep 17 00:00:00 2001 From: Yorick Peterse Date: Wed, 4 Nov 2015 19:13:19 +0100 Subject: Added Sherlock, a custom profiling tool for GitLab Sherlock will be a new GitLab specific tool for measuring the performance of Rails requests (and SideKiq jobs at some point). Some of the things that are currently tracked: * SQL queries along with their timings, backtraces and query plans (using "EXPLAIN ANALYZE" for PostgreSQL and regular "EXPLAIN" for MySQL) * Timings of application files (including views) on a per line basis * Some meta data such as the request method, path, total duration, etc More tracking (e.g. Rugged or gitlab-shell timings) might be added in the future. Sherlock will replace any existing tools we have used so far (e.g. active_record_query_trace and rack-mini-profiler), hence the corresponding Gems have been removed from the Gemfile. Sherlock can be enabled by starting Rails as following: ENABLE_SHERLOCK=1 bundle exec rails s Recorded transactions can be found at `/sherlock/transactions`. --- Gemfile | 4 +- Gemfile.lock | 11 +-- app/assets/stylesheets/pages/sherlock.scss | 33 ++++++++ app/controllers/sherlock/application_controller.rb | 12 +++ .../sherlock/file_samples_controller.rb | 7 ++ app/controllers/sherlock/queries_controller.rb | 7 ++ .../sherlock/transactions_controller.rb | 19 +++++ app/views/sherlock/file_samples/show.html.haml | 55 +++++++++++++ app/views/sherlock/queries/_backtrace.html.haml | 27 ++++++ app/views/sherlock/queries/_general.html.haml | 50 +++++++++++ app/views/sherlock/queries/show.html.haml | 26 ++++++ .../sherlock/transactions/_file_samples.html.haml | 22 +++++ app/views/sherlock/transactions/_general.html.haml | 33 ++++++++ app/views/sherlock/transactions/_queries.html.haml | 24 ++++++ app/views/sherlock/transactions/index.html.haml | 40 +++++++++ app/views/sherlock/transactions/show.html.haml | 36 ++++++++ config/initializers/rack_profiler.rb | 10 --- config/initializers/sherlock.rb | 5 ++ config/locales/sherlock.en.yml | 36 ++++++++ config/routes.rb | 13 +++ lib/gitlab/sherlock.rb | 20 +++++ lib/gitlab/sherlock/collection.rb | 42 ++++++++++ lib/gitlab/sherlock/file_sample.rb | 27 ++++++ lib/gitlab/sherlock/line_profiler.rb | 60 ++++++++++++++ lib/gitlab/sherlock/line_sample.rb | 20 +++++ lib/gitlab/sherlock/location.rb | 22 +++++ lib/gitlab/sherlock/middleware.rb | 36 ++++++++ lib/gitlab/sherlock/query.rb | 96 ++++++++++++++++++++++ lib/gitlab/sherlock/transaction.rb | 85 +++++++++++++++++++ 29 files changed, 855 insertions(+), 23 deletions(-) create mode 100644 app/assets/stylesheets/pages/sherlock.scss create mode 100644 app/controllers/sherlock/application_controller.rb create mode 100644 app/controllers/sherlock/file_samples_controller.rb create mode 100644 app/controllers/sherlock/queries_controller.rb create mode 100644 app/controllers/sherlock/transactions_controller.rb create mode 100644 app/views/sherlock/file_samples/show.html.haml create mode 100644 app/views/sherlock/queries/_backtrace.html.haml create mode 100644 app/views/sherlock/queries/_general.html.haml create mode 100644 app/views/sherlock/queries/show.html.haml create mode 100644 app/views/sherlock/transactions/_file_samples.html.haml create mode 100644 app/views/sherlock/transactions/_general.html.haml create mode 100644 app/views/sherlock/transactions/_queries.html.haml create mode 100644 app/views/sherlock/transactions/index.html.haml create mode 100644 app/views/sherlock/transactions/show.html.haml delete mode 100644 config/initializers/rack_profiler.rb create mode 100644 config/initializers/sherlock.rb create mode 100644 config/locales/sherlock.en.yml create mode 100644 lib/gitlab/sherlock.rb create mode 100644 lib/gitlab/sherlock/collection.rb create mode 100644 lib/gitlab/sherlock/file_sample.rb create mode 100644 lib/gitlab/sherlock/line_profiler.rb create mode 100644 lib/gitlab/sherlock/line_sample.rb create mode 100644 lib/gitlab/sherlock/location.rb create mode 100644 lib/gitlab/sherlock/middleware.rb create mode 100644 lib/gitlab/sherlock/query.rb create mode 100644 lib/gitlab/sherlock/transaction.rb diff --git a/Gemfile b/Gemfile index 0bac8978160..b0a7c9b9458 100644 --- a/Gemfile +++ b/Gemfile @@ -215,11 +215,9 @@ group :development do gem "annotate", "~> 2.6.0" gem "letter_opener", '~> 1.1.2' gem 'quiet_assets', '~> 1.0.2' - gem 'rack-mini-profiler', '~> 0.9.0', require: false gem 'rerun', '~> 0.10.0' gem 'bullet', require: false - gem 'active_record_query_trace', require: false - gem 'rack-lineprof', platform: :mri + gem 'rblineprof', platform: :mri, require: false # Better errors handler gem 'better_errors', '~> 1.0.1' diff --git a/Gemfile.lock b/Gemfile.lock index dce728baf18..c602d406711 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -17,7 +17,6 @@ GEM activesupport (= 4.1.12) builder (~> 3.1) erubis (~> 2.7.0) - active_record_query_trace (1.5) activemodel (4.1.12) activesupport (= 4.1.12) builder (~> 3.1) @@ -491,12 +490,6 @@ GEM rack-attack (4.3.0) rack rack-cors (0.4.0) - rack-lineprof (0.0.3) - rack (~> 1.5) - rblineprof (~> 0.3.6) - term-ansicolor (~> 1.3) - rack-mini-profiler (0.9.7) - rack (>= 1.1.3) rack-mount (0.8.3) rack (>= 1.0.0) rack-oauth2 (1.0.10) @@ -779,7 +772,6 @@ PLATFORMS DEPENDENCIES RedCloth (~> 4.2.9) ace-rails-ap (~> 2.0.1) - active_record_query_trace activerecord-deprecated_finders (~> 1.0.3) activerecord-session_store (~> 0.1.0) acts-as-taggable-on (~> 3.4) @@ -878,11 +870,10 @@ DEPENDENCIES quiet_assets (~> 1.0.2) rack-attack (~> 4.3.0) rack-cors (~> 0.4.0) - rack-lineprof - rack-mini-profiler (~> 0.9.0) rack-oauth2 (~> 1.0.5) rails (= 4.1.12) raphael-rails (~> 2.1.2) + rblineprof rdoc (~> 3.6) redcarpet (~> 3.3.3) redis-rails (~> 4.0.0) diff --git a/app/assets/stylesheets/pages/sherlock.scss b/app/assets/stylesheets/pages/sherlock.scss new file mode 100644 index 00000000000..92d84d9640f --- /dev/null +++ b/app/assets/stylesheets/pages/sherlock.scss @@ -0,0 +1,33 @@ +table .sherlock-code { + max-width: 700px; +} + +.sherlock-code { + pre { + word-wrap: normal; + } + + pre code { + white-space: pre; + } +} + +.sherlock-line-samples-table { + margin-bottom: 0px !important; + + thead tr th, + tbody tr td { + font-size: 13px !important; + text-align: right; + padding: 0px 10px !important; + } +} + +.sherlock-file-sample pre { + padding-top: 28px !important; +} + +.sherlock-line-samples-table .slow { + color: $red-light; + font-weight: bold; +} diff --git a/app/controllers/sherlock/application_controller.rb b/app/controllers/sherlock/application_controller.rb new file mode 100644 index 00000000000..682ca5e3821 --- /dev/null +++ b/app/controllers/sherlock/application_controller.rb @@ -0,0 +1,12 @@ +module Sherlock + class ApplicationController < ::ApplicationController + before_action :find_transaction + + def find_transaction + if params[:transaction_id] + @transaction = Gitlab::Sherlock.collection. + find_transaction(params[:transaction_id]) + end + end + end +end diff --git a/app/controllers/sherlock/file_samples_controller.rb b/app/controllers/sherlock/file_samples_controller.rb new file mode 100644 index 00000000000..0c3bc100106 --- /dev/null +++ b/app/controllers/sherlock/file_samples_controller.rb @@ -0,0 +1,7 @@ +module Sherlock + class FileSamplesController < Sherlock::ApplicationController + def show + @file_sample = @transaction.find_file_sample(params[:id]) + end + end +end diff --git a/app/controllers/sherlock/queries_controller.rb b/app/controllers/sherlock/queries_controller.rb new file mode 100644 index 00000000000..63b26aab1a4 --- /dev/null +++ b/app/controllers/sherlock/queries_controller.rb @@ -0,0 +1,7 @@ +module Sherlock + class QueriesController < Sherlock::ApplicationController + def show + @query = @transaction.find_query(params[:id]) + end + end +end diff --git a/app/controllers/sherlock/transactions_controller.rb b/app/controllers/sherlock/transactions_controller.rb new file mode 100644 index 00000000000..ccc739da879 --- /dev/null +++ b/app/controllers/sherlock/transactions_controller.rb @@ -0,0 +1,19 @@ +module Sherlock + class TransactionsController < Sherlock::ApplicationController + def index + @transactions = Gitlab::Sherlock.collection.newest_first + end + + def show + @transaction = Gitlab::Sherlock.collection.find_transaction(params[:id]) + + render_404 unless @transaction + end + + def destroy_all + Gitlab::Sherlock.collection.clear + + redirect_to(:back) + end + end +end diff --git a/app/views/sherlock/file_samples/show.html.haml b/app/views/sherlock/file_samples/show.html.haml new file mode 100644 index 00000000000..cfd11e45b6a --- /dev/null +++ b/app/views/sherlock/file_samples/show.html.haml @@ -0,0 +1,55 @@ +- page_title t('sherlock.title'), t('sherlock.transaction'), + t('sherlock.file_sample') + +- header_title t('sherlock.title'), sherlock_transactions_path + +.gray-content-block + .pull-right + = link_to(sherlock_transaction_path(@transaction), class: 'btn') do + %i.fa.fa-arrow-left + = t('sherlock.transaction') + .oneline + = t('sherlock.file_sample') + = @file_sample.id + +.prepend-top-default + %p + %span.light + #{t('sherlock.time')}: + %strong + = @file_sample.duration.round(2) + = t('sherlock.milliseconds') + %p + %span.light + #{t('sherlock.events')}: + %strong + = @file_sample.events + +%article.file-holder + .file-title + %i.fa.fa-file-text-o.fa-fw + %strong + = @file_sample.file + .code.file-content.js-syntax-highlight + .line-numbers + %table.sherlock-line-samples-table + %thead + %tr + %th= t('sherlock.line_capitalized') + %th= t('sherlock.events') + %th= t('sherlock.time') + %th= t('sherlock.percent') + %tbody + - @file_sample.line_samples.each_with_index do |sample, index| + %tr{class: sample.majority_of?(@file_sample.duration) ? 'slow' : ''} + %td= index + 1 + %td= sample.events + %td + = sample.duration.round(2) + = t('sherlock.milliseconds') + %td + = sample.percentage_of(@file_sample.duration).round + = t('sherlock.percent') + + .sherlock-file-sample + = highlight(@file_sample.file, @file_sample.source) diff --git a/app/views/sherlock/queries/_backtrace.html.haml b/app/views/sherlock/queries/_backtrace.html.haml new file mode 100644 index 00000000000..5c9294c0ab5 --- /dev/null +++ b/app/views/sherlock/queries/_backtrace.html.haml @@ -0,0 +1,27 @@ +.prepend-top-default + .panel.panel-default + .panel-heading + %strong + = t('sherlock.application_backtrace') + %ul.well-list + - @query.application_backtrace.each do |location| + %li + = location.path + %small.light + = t('sherlock.line') + = location.line + + .panel.panel-default + .panel-heading + %strong + = t('sherlock.full_backtrace') + %ul.well-list + - @query.backtrace.each do |location| + %li + - if location.application? + %strong= location.path + - else + = location.path + %small.light + = t('sherlock.line') + = location.line diff --git a/app/views/sherlock/queries/_general.html.haml b/app/views/sherlock/queries/_general.html.haml new file mode 100644 index 00000000000..549b47430e6 --- /dev/null +++ b/app/views/sherlock/queries/_general.html.haml @@ -0,0 +1,50 @@ +.prepend-top-default + .panel.panel-default + .panel-heading + %strong + = t('sherlock.general') + %ul.well-list + %li + %span.light + #{t('sherlock.time')}: + %strong + = @query.duration.round(4) + = t('sherlock.milliseconds') + %li + %span.light + #{t('sherlock.origin')}: + %strong + = @query.last_application_frame.path + %small.light + = t('sherlock.line') + = @query.last_application_frame.line + + .panel.panel-default + .panel-heading + .pull-right + %button.js-clipboard-trigger.btn.btn-xs{title: t('sherlock.copy_to_clipboard'), type: :button} + %i.fa.fa-clipboard + %pre.hidden + = @query.formatted_query + %strong + = t('sherlock.query') + %ul.well-list + %li + .code.js-syntax-highlight.sherlock-code + :preserve + #{highlight("#{@query.id}.sql", @query.formatted_query)} + + .panel.panel-default + .panel-heading + .pull-right + %button.js-clipboard-trigger.btn.btn-xs{title: t('sherlock.copy_to_clipboard'), type: :button} + %i.fa.fa-clipboard + %pre.hidden + = @query.explain + %strong + = t('sherlock.query_plan') + %ul.well-list + %li + .code.js-syntax-highlight.sherlock-code + %pre + %code= @query.explain diff --git a/app/views/sherlock/queries/show.html.haml b/app/views/sherlock/queries/show.html.haml new file mode 100644 index 00000000000..4a84348ac82 --- /dev/null +++ b/app/views/sherlock/queries/show.html.haml @@ -0,0 +1,26 @@ +- page_title t('sherlock.title'), t('sherlock.transaction'), t('sherlock.query') +- header_title t('sherlock.title'), sherlock_transactions_path + +%ul.center-top-menu + %li.active + %a(href="#tab-general" data-toggle="tab") + = t('sherlock.general') + %li + %a(href="#tab-backtrace" data-toggle="tab") + = t('sherlock.backtrace') + +.gray-content-block + .pull-right + = link_to(sherlock_transaction_path(@transaction), class: 'btn') do + %i.fa.fa-arrow-left + = t('sherlock.transaction') + .oneline + = t('sherlock.query') + = @query.id + +.tab-content + .tab-pane.active#tab-general + = render(partial: 'general') + + .tab-pane#tab-backtrace + = render(partial: 'backtrace') diff --git a/app/views/sherlock/transactions/_file_samples.html.haml b/app/views/sherlock/transactions/_file_samples.html.haml new file mode 100644 index 00000000000..0afdbc8dffa --- /dev/null +++ b/app/views/sherlock/transactions/_file_samples.html.haml @@ -0,0 +1,22 @@ +- if @transaction.file_samples.empty? + .nothing-here-block + = t('sherlock.no_file_samples') +- else + .table-holder + %table.table + %thead + %tr + %th= t('sherlock.time_inclusive') + %th= t('sherlock.path') + %th + %tbody + - @transaction.sorted_file_samples.each do |sample| + %tr + %td + = sample.duration.round(2) + = t('sherlock.milliseconds') + %td= sample.relative_path + %td + = link_to(t('sherlock.view'), + sherlock_transaction_file_sample_path(@transaction, sample), + class: 'btn btn-xs') diff --git a/app/views/sherlock/transactions/_general.html.haml b/app/views/sherlock/transactions/_general.html.haml new file mode 100644 index 00000000000..4287a0c3203 --- /dev/null +++ b/app/views/sherlock/transactions/_general.html.haml @@ -0,0 +1,33 @@ +.prepend-top-default + .panel.panel-default + .panel-heading + %strong + = t('sherlock.general') + %ul.well-list + %li + %span.light + #{t('sherlock.id')}: + %strong + = @transaction.id + %li + %span.light + #{t('sherlock.type')}: + %strong + = @transaction.type + %li + %span.light + #{t('sherlock.path')}: + %strong + = @transaction.path + %li + %span.light + #{t('sherlock.time')}: + %strong + = @transaction.duration.round(2) + = t('sherlock.seconds') + %li + %span.light + #{t('sherlock.finished_at')}: + %strong + = time_ago_in_words(@transaction.finished_at) + = t('sherlock.ago') diff --git a/app/views/sherlock/transactions/_queries.html.haml b/app/views/sherlock/transactions/_queries.html.haml new file mode 100644 index 00000000000..b7e0162e80d --- /dev/null +++ b/app/views/sherlock/transactions/_queries.html.haml @@ -0,0 +1,24 @@ +- if @transaction.queries.empty? + .nothing-here-block + = t('sherlock.no_queries') +- else + .table-holder + %table.table#sherlock-queries + %thead + %tr + %th= t('sherlock.time') + %th= t('sherlock.query') + %td + %tbody + - @transaction.sorted_queries.each do |query| + %tr + %td + = query.duration.round(2) + = t('sherlock.milliseconds') + %td + .code.js-syntax-highlight.sherlock-code + = highlight("#{query.id}.sql", query.formatted_query) + %td + = link_to(t('sherlock.view'), + sherlock_transaction_query_path(@transaction, query), + class: 'btn btn-xs') diff --git a/app/views/sherlock/transactions/index.html.haml b/app/views/sherlock/transactions/index.html.haml new file mode 100644 index 00000000000..fb31131ba88 --- /dev/null +++ b/app/views/sherlock/transactions/index.html.haml @@ -0,0 +1,40 @@ +- page_title t('sherlock.title') +- header_title t('sherlock.title'), sherlock_transactions_path + +.gray-content-block + .pull-right + = link_to(destroy_all_sherlock_transactions_path, + class: 'btn btn-danger', + method: :delete) do + %i.fa.fa-trash + = t('sherlock.delete_all_transactions') + .oneline= t('sherlock.introduction') + +- if @transactions.empty? + .nothing-here-block= t('sherlock.no_transactions') +- else + .table-holder + %table.table + %thead + %tr + %th= t('sherlock.type') + %th= t('sherlock.path') + %th= t('sherlock.time') + %th= t('sherlock.queries') + %th= t('sherlock.finished_at') + %th + %tbody + - @transactions.each do |trans| + %tr + %td= trans.type + %td= trans.path + %td + = trans.duration.round(2) + = t('sherlock.seconds') + %td= trans.queries.length + %td + = time_ago_in_words(trans.finished_at) + = t('sherlock.ago') + %td + = link_to(sherlock_transaction_path(trans), class: 'btn btn-xs') do + = t('sherlock.view') diff --git a/app/views/sherlock/transactions/show.html.haml b/app/views/sherlock/transactions/show.html.haml new file mode 100644 index 00000000000..3c8ffb06648 --- /dev/null +++ b/app/views/sherlock/transactions/show.html.haml @@ -0,0 +1,36 @@ +- page_title t('sherlock.title'), t('sherlock.transaction') +- header_title t('sherlock.title'), sherlock_transactions_path + +%ul.center-top-menu + %li.active + %a(href="#tab-general" data-toggle="tab") + = t('sherlock.general') + %li + %a(href="#tab-queries" data-toggle="tab") + = t('sherlock.queries') + %span.badge + #{@transaction.queries.length} + %li + %a(href="#tab-file-samples" data-toggle="tab") + = t('sherlock.file_samples') + %span.badge + #{@transaction.file_samples.length} + +.gray-content-block + .pull-right + = link_to(sherlock_transactions_path, class: 'btn') do + %i.fa.fa-arrow-left + = t('sherlock.all_transactions') + .oneline + = t('sherlock.transaction') + = @transaction.id + +.tab-content + .tab-pane.active#tab-general + = render(partial: 'general') + + .tab-pane#tab-queries + = render(partial: 'queries') + + .tab-pane#tab-file-samples + = render(partial: 'file_samples') diff --git a/config/initializers/rack_profiler.rb b/config/initializers/rack_profiler.rb deleted file mode 100644 index 7710eeac453..00000000000 --- a/config/initializers/rack_profiler.rb +++ /dev/null @@ -1,10 +0,0 @@ -if Rails.env.development? - require 'rack-mini-profiler' - - # initialization is skipped so trigger it - Rack::MiniProfilerRails.initialize!(Gitlab::Application) - - Rack::MiniProfiler.config.position = 'right' - Rack::MiniProfiler.config.start_hidden = false - Rack::MiniProfiler.config.skip_paths << '/teaspoon' -end diff --git a/config/initializers/sherlock.rb b/config/initializers/sherlock.rb new file mode 100644 index 00000000000..42b0d78c85f --- /dev/null +++ b/config/initializers/sherlock.rb @@ -0,0 +1,5 @@ +if Gitlab::Sherlock.enabled? + Gitlab::Application.configure do |config| + config.middleware.use(Gitlab::Sherlock::Middleware) + end +end diff --git a/config/locales/sherlock.en.yml b/config/locales/sherlock.en.yml new file mode 100644 index 00000000000..5c146b172b1 --- /dev/null +++ b/config/locales/sherlock.en.yml @@ -0,0 +1,36 @@ +en: + sherlock: + title: Sherlock + delete_all_transactions: Delete All Transactions + introduction: > + Below is a list of all transactions recorded by Sherlock. Requests to + Sherlock's own routes are ignored. + no_transactions: No transactions to show + no_queries: No queries to show + no_file_samples: No file samples to show + all_transactions: All Transactions + transaction: Transaction + query: Query + file_sample: File Sample + type: Type + path: Path + time: Time + queries: Queries + finished_at: Finished at + ago: ago + view: View + seconds: seconds + milliseconds: ms + general: General + id: ID + time_inclusive: Time (inclusive) + backtrace: Backtrace + application_backtrace: Application Backtrace + full_backtrace: Full Backtrace + origin: Origin + line: line + line_capitalized: Line + copy_to_clipboard: Copy to clipboard + query_plan: Query Plan + events: Events + percent: '%' diff --git a/config/routes.rb b/config/routes.rb index 990a00e3d0b..7d8a546a64c 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -2,6 +2,19 @@ require 'sidekiq/web' require 'api/api' Gitlab::Application.routes.draw do + if Gitlab::Sherlock.enabled? + namespace :sherlock do + resources :transactions, only: [:index, :show] do + resources :queries, only: [:show] + resources :file_samples, only: [:show] + + collection do + delete :destroy_all + end + end + end + end + namespace :ci do # CI API Ci::API::API.logger Rails.logger diff --git a/lib/gitlab/sherlock.rb b/lib/gitlab/sherlock.rb new file mode 100644 index 00000000000..c4b35b24ceb --- /dev/null +++ b/lib/gitlab/sherlock.rb @@ -0,0 +1,20 @@ +require 'securerandom' +require 'rblineprof' if RUBY_ENGINE == 'ruby' + +module Gitlab + module Sherlock + @collection = Collection.new + + class << self + attr_reader :collection + end + + def self.enabled? + Rails.env.development? && !!ENV['ENABLE_SHERLOCK'] + end + + def self.enable_line_profiler? + RUBY_ENGINE == 'ruby' + end + end +end diff --git a/lib/gitlab/sherlock/collection.rb b/lib/gitlab/sherlock/collection.rb new file mode 100644 index 00000000000..accdc6469bc --- /dev/null +++ b/lib/gitlab/sherlock/collection.rb @@ -0,0 +1,42 @@ +module Gitlab + module Sherlock + class Collection + include Enumerable + + def initialize + @transactions = [] + @mutex = Mutex.new + end + + def add(transaction) + synchronize { @transactions << transaction } + end + + alias_method :<<, :add + + def each(&block) + synchronize { @transactions.each(&block) } + end + + def clear + synchronize { @transactions.clear } + end + + def empty? + synchronize { @transactions.empty? } + end + + def find_transaction(id) + find { |trans| trans.id == id } + end + + def newest_first + sort { |a, b| b.finished_at <=> a.finished_at } + end + + def synchronize(&block) + @mutex.synchronize(&block) + end + end + end +end diff --git a/lib/gitlab/sherlock/file_sample.rb b/lib/gitlab/sherlock/file_sample.rb new file mode 100644 index 00000000000..7a220de9abc --- /dev/null +++ b/lib/gitlab/sherlock/file_sample.rb @@ -0,0 +1,27 @@ +module Gitlab + module Sherlock + class FileSample + attr_reader :id, :file, :line_samples, :events, :duration + + def initialize(file, line_samples, duration, events) + @id = SecureRandom.uuid + @file = file + @line_samples = line_samples + @duration = duration + @events = events + end + + def relative_path + @relative_path ||= @file.gsub(/^#{Rails.root.to_s}\/?/, '') + end + + def to_param + @id + end + + def source + @source ||= File.read(@file) + end + end + end +end diff --git a/lib/gitlab/sherlock/line_profiler.rb b/lib/gitlab/sherlock/line_profiler.rb new file mode 100644 index 00000000000..a191b1e646d --- /dev/null +++ b/lib/gitlab/sherlock/line_profiler.rb @@ -0,0 +1,60 @@ +module Gitlab + module Sherlock + class LineProfiler + # The minimum amount of time that has to be spent in a file for it to be + # included in a list of samples. + MINIMUM_DURATION = 10.0 + + def profile(&block) + if RUBY_ENGINE == 'ruby' + profile_mri(&block) + else + raise NotImplementedError, + 'Line profiling is not supported on this platform' + end + end + + def profile_mri + retval = nil + samples = lineprof(/^#{Rails.root.to_s}/) { retval = yield } + + file_samples = aggregate_rblineprof(samples) + + [retval, file_samples] + end + + # Returns an Array of file samples based on the output of rblineprof. + def aggregate_rblineprof(lineprof_stats) + samples = [] + + lineprof_stats.each do |(file, stats)| + source_lines = File.read(file).each_line.to_a + line_samples = [] + + total_duration = microsec_to_millisec(stats[0][0]) + total_events = stats[0][2] + + next if total_duration <= MINIMUM_DURATION + + stats[1..-1].each_with_index do |data, index| + next unless source_lines[index] + + duration = microsec_to_millisec(data[0]) + events = data[2] + + line_samples << LineSample.new(duration, events) + end + + samples << FileSample. + new(file, line_samples, total_duration, total_events) + end + + samples + end + + def microsec_to_millisec(microsec) + microsec / 1000.0 + end + end + end +end diff --git a/lib/gitlab/sherlock/line_sample.rb b/lib/gitlab/sherlock/line_sample.rb new file mode 100644 index 00000000000..38df7a88e4e --- /dev/null +++ b/lib/gitlab/sherlock/line_sample.rb @@ -0,0 +1,20 @@ +module Gitlab + module Sherlock + class LineSample + attr_reader :duration, :events + + def initialize(duration, events) + @duration = duration + @events = events + end + + def percentage_of(total_duration) + (duration.to_f / total_duration) * 100.0 + end + + def majority_of?(total_duration) + percentage_of(total_duration) >= 30 + end + end + end +end diff --git a/lib/gitlab/sherlock/location.rb b/lib/gitlab/sherlock/location.rb new file mode 100644 index 00000000000..8c0b77dce1a --- /dev/null +++ b/lib/gitlab/sherlock/location.rb @@ -0,0 +1,22 @@ +module Gitlab + module Sherlock + class Location + attr_reader :path, :line + + SHERLOCK_DIR = File.dirname(__FILE__) + + def self.from_ruby_location(location) + new(location.path, location.lineno) + end + + def initialize(path, line) + @path = path + @line = line + end + + def application? + @path.start_with?(Rails.root.to_s) && !path.start_with?(SHERLOCK_DIR) + end + end + end +end diff --git a/lib/gitlab/sherlock/middleware.rb b/lib/gitlab/sherlock/middleware.rb new file mode 100644 index 00000000000..fca7be858eb --- /dev/null +++ b/lib/gitlab/sherlock/middleware.rb @@ -0,0 +1,36 @@ +module Gitlab + module Sherlock + # Rack middleware used for tracking request metrics. + class Middleware + CONTENT_TYPES = /text\/html|application\/json/i + + IGNORE_PATHS = %r{^/sherlock} + + def initialize(app) + @app = app + end + + def call(env) + if instrument?(env) + call_with_instrumentation(env) + else + @app.call(env) + end + end + + def call_with_instrumentation(env) + trans = Transaction.new(env['REQUEST_METHOD'], env['REQUEST_URI']) + retval = trans.run { @app.call(env) } + + Sherlock.collection.add(trans) + + retval + end + + def instrument?(env) + !!(env['HTTP_ACCEPT'] =~ CONTENT_TYPES && + env['REQUEST_URI'] !~ IGNORE_PATHS) + end + end + end +end diff --git a/lib/gitlab/sherlock/query.rb b/lib/gitlab/sherlock/query.rb new file mode 100644 index 00000000000..af76e6fd2bf --- /dev/null +++ b/lib/gitlab/sherlock/query.rb @@ -0,0 +1,96 @@ +module Gitlab + module Sherlock + class Query + attr_reader :id, :query, :started_at, :finished_at, :backtrace + + PREFIX_NEWLINE = / + \s+(FROM + |(LEFT|RIGHT)?INNER\s+JOIN + |(LEFT|RIGHT)?OUTER\s+JOIN + |WHERE + |AND + |GROUP\s+BY + |ORDER\s+BY + |LIMIT + |OFFSET)\s+ + /ix + + def self.new_with_bindings(query, bindings, started_at, finished_at) + bindings.each_with_index do |(column, value), index| + quoted_value = ActiveRecord::Base.connection.quote(value) + + query = query.gsub("$#{index + 1}", quoted_value) + end + + new(query, started_at, finished_at) + end + + def initialize(query, started_at, finished_at) + @id = SecureRandom.uuid + @query = query + @started_at = started_at + @finished_at = finished_at + @backtrace = caller_locations.map do |loc| + Location.from_ruby_location(loc) + end + + unless @query.end_with?(';') + @query += ';' + end + end + + def duration + @duration ||= (@finished_at - @started_at) * 1000.0 + end + + def to_param + @id + end + + def formatted_query + @formatted_query ||= format_sql(@query) + end + + def last_application_frame + @last_application_frame ||= @backtrace.find(&:application?) + end + + def application_backtrace + @application_backtrace ||= @backtrace.select(&:application?) + end + + def explain + unless @explain + ActiveRecord::Base.connection.transaction do + @explain = raw_explain(@query).values.flatten.join("\n") + + # Roll back any queries that mutate data so we don't mess up + # anything when running explain on an INSERT, UPDATE, DELETE, etc. + raise ActiveRecord::Rollback + end + end + + @explain + end + + private + + def raw_explain(query) + if Gitlab::Database.postgresql? + explain = "EXPLAIN ANALYZE #{query};" + else + explain = "EXPLAIN #{query};" + end + + ActiveRecord::Base.connection.execute(explain) + end + + def format_sql(query) + query.each_line. + map { |line| line.strip }. + join("\n"). + gsub(PREFIX_NEWLINE) { "\n#{$1} " } + end + end + end +end diff --git a/lib/gitlab/sherlock/transaction.rb b/lib/gitlab/sherlock/transaction.rb new file mode 100644 index 00000000000..5cb3e86aa4e --- /dev/null +++ b/lib/gitlab/sherlock/transaction.rb @@ -0,0 +1,85 @@ +module Gitlab + module Sherlock + class Transaction + attr_reader :id, :type, :path, :queries, :file_samples, :started_at, + :finished_at + + def initialize(type, path) + @id = SecureRandom.uuid + @type = type + @path = path + @duration = 0 + @queries = [] + @file_samples = [] + @started_at = nil + @finished_at = nil + @thread = Thread.current + end + + def run + @started_at = Time.now + + subscriber = subscribe_to_active_record + + retval = profile_lines { yield } + + @finished_at = Time.now + + ActiveSupport::Notifications.unsubscribe(subscriber) + + retval + end + + def duration + @started_at && @finished_at ? @finished_at - @started_at : 0 + end + + def to_param + @id + end + + def sorted_queries + @queries.sort { |a, b| b.duration <=> a.duration } + end + + def sorted_file_samples + @file_samples.sort { |a, b| b.duration <=> a.duration } + end + + def find_query(id) + @queries.find { |query| query.id == id } + end + + def find_file_sample(id) + @file_samples.find { |sample| sample.id == id } + end + + def track_query(query, bindings, start, finish) + @queries << Query.new_with_bindings(query, bindings, start, finish) + end + + def profile_lines + retval = nil + + if Sherlock.enable_line_profiler? + retval, @file_samples = LineProfiler.new.profile { yield } + else + retval = yield + end + + retval + end + + def subscribe_to_active_record + ActiveSupport::Notifications.subscribe('sql.active_record') do |_, start, finish, _, data| + # In case somebody uses a multi-threaded server locally (e.g. Puma) we + # _only_ want to track queries that originate from the transaction + # thread. + next unless Thread.current == @thread + + track_query(data[:sql].strip, data[:binds], start, finish) + end + end + end + end +end -- cgit v1.2.1 From 265ef867fff165643784640d837579ce4fcc2207 Mon Sep 17 00:00:00 2001 From: Yorick Peterse Date: Thu, 5 Nov 2015 18:01:05 +0100 Subject: Added specs and source documentation for Sherlock --- lib/gitlab/sherlock/collection.rb | 7 ++ lib/gitlab/sherlock/file_sample.rb | 4 + lib/gitlab/sherlock/line_profiler.rb | 38 +++++- lib/gitlab/sherlock/line_sample.rb | 16 +++ lib/gitlab/sherlock/location.rb | 4 + lib/gitlab/sherlock/middleware.rb | 7 +- lib/gitlab/sherlock/query.rb | 26 +++- lib/gitlab/sherlock/transaction.rb | 29 ++++- spec/lib/gitlab/sherlock/collection_spec.rb | 82 ++++++++++++ spec/lib/gitlab/sherlock/file_sample_spec.rb | 54 ++++++++ spec/lib/gitlab/sherlock/line_profiler_spec.rb | 73 +++++++++++ spec/lib/gitlab/sherlock/line_sample_spec.rb | 33 +++++ spec/lib/gitlab/sherlock/location_spec.rb | 40 ++++++ spec/lib/gitlab/sherlock/middleware_spec.rb | 79 ++++++++++++ spec/lib/gitlab/sherlock/query_spec.rb | 113 +++++++++++++++++ spec/lib/gitlab/sherlock/transaction_spec.rb | 165 +++++++++++++++++++++++++ 16 files changed, 758 insertions(+), 12 deletions(-) create mode 100644 spec/lib/gitlab/sherlock/collection_spec.rb create mode 100644 spec/lib/gitlab/sherlock/file_sample_spec.rb create mode 100644 spec/lib/gitlab/sherlock/line_profiler_spec.rb create mode 100644 spec/lib/gitlab/sherlock/line_sample_spec.rb create mode 100644 spec/lib/gitlab/sherlock/location_spec.rb create mode 100644 spec/lib/gitlab/sherlock/middleware_spec.rb create mode 100644 spec/lib/gitlab/sherlock/query_spec.rb create mode 100644 spec/lib/gitlab/sherlock/transaction_spec.rb diff --git a/lib/gitlab/sherlock/collection.rb b/lib/gitlab/sherlock/collection.rb index accdc6469bc..66bd6258521 100644 --- a/lib/gitlab/sherlock/collection.rb +++ b/lib/gitlab/sherlock/collection.rb @@ -1,5 +1,10 @@ module Gitlab module Sherlock + # A collection of transactions recorded by Sherlock. + # + # Method calls for this class are synchronized using a mutex to allow + # sharing of a single Collection instance between threads (e.g. when using + # Puma as a webserver). class Collection include Enumerable @@ -34,6 +39,8 @@ module Gitlab sort { |a, b| b.finished_at <=> a.finished_at } end + private + def synchronize(&block) @mutex.synchronize(&block) end diff --git a/lib/gitlab/sherlock/file_sample.rb b/lib/gitlab/sherlock/file_sample.rb index 7a220de9abc..8a3e1a5e5bf 100644 --- a/lib/gitlab/sherlock/file_sample.rb +++ b/lib/gitlab/sherlock/file_sample.rb @@ -3,6 +3,10 @@ module Gitlab class FileSample attr_reader :id, :file, :line_samples, :events, :duration + # file - The full path to the file this sample belongs to. + # line_samples - An array of LineSample objects. + # duration - The total execution time in milliseconds. + # events - The total amount of events. def initialize(file, line_samples, duration, events) @id = SecureRandom.uuid @file = file diff --git a/lib/gitlab/sherlock/line_profiler.rb b/lib/gitlab/sherlock/line_profiler.rb index a191b1e646d..152749dcc39 100644 --- a/lib/gitlab/sherlock/line_profiler.rb +++ b/lib/gitlab/sherlock/line_profiler.rb @@ -1,12 +1,36 @@ module Gitlab module Sherlock + # Class for profiling code on a per line basis. + # + # The LineProfiler class can be used to profile code on per line basis + # without littering your code with Ruby implementation specific profiling + # methods. + # + # This profiler only includes samples taking longer than a given threshold + # and those that occur in the actual application (e.g. files from Gems are + # ignored). class LineProfiler # The minimum amount of time that has to be spent in a file for it to be # included in a list of samples. MINIMUM_DURATION = 10.0 + # Profiles the given block. + # + # Example: + # + # profiler = LineProfiler.new + # + # retval, samples = profiler.profile do + # "cats are amazing" + # end + # + # retval # => "cats are amazing" + # samples # => [#, ...] + # + # Returns an Array containing the block's return value and an Array of + # FileSample objects. def profile(&block) - if RUBY_ENGINE == 'ruby' + if mri? profile_mri(&block) else raise NotImplementedError, @@ -14,6 +38,7 @@ module Gitlab end end + # Profiles the given block using rblineprof (MRI only). def profile_mri retval = nil samples = lineprof(/^#{Rails.root.to_s}/) { retval = yield } @@ -24,6 +49,11 @@ module Gitlab end # Returns an Array of file samples based on the output of rblineprof. + # + # lineprof_stats - A Hash containing rblineprof statistics on a per file + # basis. + # + # Returns an Array of FileSample objects. def aggregate_rblineprof(lineprof_stats) samples = [] @@ -52,9 +82,15 @@ module Gitlab samples end + private + def microsec_to_millisec(microsec) microsec / 1000.0 end + + def mri? + RUBY_ENGINE == 'ruby' + end end end end diff --git a/lib/gitlab/sherlock/line_sample.rb b/lib/gitlab/sherlock/line_sample.rb index 38df7a88e4e..eb1948eb6d6 100644 --- a/lib/gitlab/sherlock/line_sample.rb +++ b/lib/gitlab/sherlock/line_sample.rb @@ -3,15 +3,31 @@ module Gitlab class LineSample attr_reader :duration, :events + # duration - The execution time in milliseconds. + # events - The amount of events. def initialize(duration, events) @duration = duration @events = events end + # Returns the sample duration percentage relative to the given duration. + # + # Example: + # + # sample.duration # => 150 + # sample.percentage_of(1500) # => 10.0 + # + # total_duration - The total duration to compare with. + # + # Returns a float def percentage_of(total_duration) (duration.to_f / total_duration) * 100.0 end + # Returns true if the current sample takes up the majority of the given + # duration. + # + # total_duration - The total duration to compare with. def majority_of?(total_duration) percentage_of(total_duration) >= 30 end diff --git a/lib/gitlab/sherlock/location.rb b/lib/gitlab/sherlock/location.rb index 8c0b77dce1a..5ac265618ad 100644 --- a/lib/gitlab/sherlock/location.rb +++ b/lib/gitlab/sherlock/location.rb @@ -5,15 +5,19 @@ module Gitlab SHERLOCK_DIR = File.dirname(__FILE__) + # Creates a new Location from a `Thread::Backtrace::Location`. def self.from_ruby_location(location) new(location.path, location.lineno) end + # path - The full path of the frame as a String. + # line - The line number of the frame as a Fixnum. def initialize(path, line) @path = path @line = line end + # Returns true if the current frame originated from the application. def application? @path.start_with?(Rails.root.to_s) && !path.start_with?(SHERLOCK_DIR) end diff --git a/lib/gitlab/sherlock/middleware.rb b/lib/gitlab/sherlock/middleware.rb index fca7be858eb..687332fc5fc 100644 --- a/lib/gitlab/sherlock/middleware.rb +++ b/lib/gitlab/sherlock/middleware.rb @@ -10,6 +10,7 @@ module Gitlab @app = app end + # env - A Hash containing Rack environment details. def call(env) if instrument?(env) call_with_instrumentation(env) @@ -19,7 +20,7 @@ module Gitlab end def call_with_instrumentation(env) - trans = Transaction.new(env['REQUEST_METHOD'], env['REQUEST_URI']) + trans = transaction_from_env(env) retval = trans.run { @app.call(env) } Sherlock.collection.add(trans) @@ -31,6 +32,10 @@ module Gitlab !!(env['HTTP_ACCEPT'] =~ CONTENT_TYPES && env['REQUEST_URI'] !~ IGNORE_PATHS) end + + def transaction_from_env(env) + Transaction.new(env['REQUEST_METHOD'], env['REQUEST_URI']) + end end end end diff --git a/lib/gitlab/sherlock/query.rb b/lib/gitlab/sherlock/query.rb index af76e6fd2bf..4917c4ae2ac 100644 --- a/lib/gitlab/sherlock/query.rb +++ b/lib/gitlab/sherlock/query.rb @@ -3,6 +3,7 @@ module Gitlab class Query attr_reader :id, :query, :started_at, :finished_at, :backtrace + # SQL identifiers that should be prefixed with newlines. PREFIX_NEWLINE = / \s+(FROM |(LEFT|RIGHT)?INNER\s+JOIN @@ -12,11 +13,20 @@ module Gitlab |GROUP\s+BY |ORDER\s+BY |LIMIT - |OFFSET)\s+ - /ix - + |OFFSET)\s+/ix # Vim indent breaks when this is on a newline :< + + # Creates a new Query using a String and a separate Array of bindings. + # + # query - A String containing a SQL query, optionally with numeric + # placeholders (`$1`, `$2`, etc). + # + # bindings - An Array of ActiveRecord columns and their values. + # started_at - The start time of the query as a Time-like object. + # finished_at - The completion time of the query as a Time-like object. + # + # Returns a new Query object. def self.new_with_bindings(query, bindings, started_at, finished_at) - bindings.each_with_index do |(column, value), index| + bindings.each_with_index do |(_, value), index| quoted_value = ActiveRecord::Base.connection.quote(value) query = query.gsub("$#{index + 1}", quoted_value) @@ -25,6 +35,9 @@ module Gitlab new(query, started_at, finished_at) end + # query - The SQL query as a String (without placeholders). + # started_at - The start time of the query as a Time-like object. + # finished_at - The completion time of the query as a Time-like object. def initialize(query, started_at, finished_at) @id = SecureRandom.uuid @query = query @@ -39,6 +52,7 @@ module Gitlab end end + # Returns the query duration in milliseconds. def duration @duration ||= (@finished_at - @started_at) * 1000.0 end @@ -47,18 +61,22 @@ module Gitlab @id end + # Returns a human readable version of the query. def formatted_query @formatted_query ||= format_sql(@query) end + # Returns the last application frame of the backtrace. def last_application_frame @last_application_frame ||= @backtrace.find(&:application?) end + # Returns an Array of application frames (excluding Gems and the likes). def application_backtrace @application_backtrace ||= @backtrace.select(&:application?) end + # Returns the query plan as a String. def explain unless @explain ActiveRecord::Base.connection.transaction do diff --git a/lib/gitlab/sherlock/transaction.rb b/lib/gitlab/sherlock/transaction.rb index 5cb3e86aa4e..4641f15ee33 100644 --- a/lib/gitlab/sherlock/transaction.rb +++ b/lib/gitlab/sherlock/transaction.rb @@ -4,11 +4,12 @@ module Gitlab attr_reader :id, :type, :path, :queries, :file_samples, :started_at, :finished_at + # type - The type of transaction (e.g. "GET", "POST", etc) + # path - The path of the transaction (e.g. the HTTP request path) def initialize(type, path) @id = SecureRandom.uuid @type = type @path = path - @duration = 0 @queries = [] @file_samples = [] @started_at = nil @@ -16,6 +17,7 @@ module Gitlab @thread = Thread.current end + # Runs the transaction and returns the block's return value. def run @started_at = Time.now @@ -30,34 +32,43 @@ module Gitlab retval end + # Returns the duration in seconds. def duration - @started_at && @finished_at ? @finished_at - @started_at : 0 + @duration ||= started_at && finished_at ? finished_at - started_at : 0 end def to_param @id end + # Returns the queries sorted in descending order by their durations. def sorted_queries @queries.sort { |a, b| b.duration <=> a.duration } end + # Returns the file samples sorted in descending order by their durations. def sorted_file_samples @file_samples.sort { |a, b| b.duration <=> a.duration } end + # Finds a query by the given ID. + # + # id - The query ID as a String. + # + # Returns a Query object if one could be found, nil otherwise. def find_query(id) @queries.find { |query| query.id == id } end + # Finds a file sample by the given ID. + # + # id - The query ID as a String. + # + # Returns a FileSample object if one could be found, nil otherwise. def find_file_sample(id) @file_samples.find { |sample| sample.id == id } end - def track_query(query, bindings, start, finish) - @queries << Query.new_with_bindings(query, bindings, start, finish) - end - def profile_lines retval = nil @@ -70,6 +81,12 @@ module Gitlab retval end + private + + def track_query(query, bindings, start, finish) + @queries << Query.new_with_bindings(query, bindings, start, finish) + end + def subscribe_to_active_record ActiveSupport::Notifications.subscribe('sql.active_record') do |_, start, finish, _, data| # In case somebody uses a multi-threaded server locally (e.g. Puma) we diff --git a/spec/lib/gitlab/sherlock/collection_spec.rb b/spec/lib/gitlab/sherlock/collection_spec.rb new file mode 100644 index 00000000000..a8a9d6fc7bc --- /dev/null +++ b/spec/lib/gitlab/sherlock/collection_spec.rb @@ -0,0 +1,82 @@ +require 'spec_helper' + +describe Gitlab::Sherlock::Collection do + let(:collection) { described_class.new } + + let(:transaction) do + Gitlab::Sherlock::Transaction.new('POST', '/cat_pictures') + end + + describe '#add' do + it 'adds a new transaction' do + collection.add(transaction) + + expect(collection).to_not be_empty + end + + it 'is aliased as <<' do + collection << transaction + + expect(collection).to_not be_empty + end + end + + describe '#each' do + it 'iterates over every transaction' do + collection.add(transaction) + + expect { |b| collection.each(&b) }.to yield_with_args(transaction) + end + end + + describe '#clear' do + it 'removes all transactions' do + collection.add(transaction) + + collection.clear + + expect(collection).to be_empty + end + end + + describe '#empty?' do + it 'returns true for an empty collection' do + expect(collection).to be_empty + end + + it 'returns false for a collection with a transaction' do + collection.add(transaction) + + expect(collection).to_not be_empty + end + end + + describe '#find_transaction' do + it 'returns the transaction for the given ID' do + collection.add(transaction) + + expect(collection.find_transaction(transaction.id)).to eq(transaction) + end + + it 'returns nil when no transaction could be found' do + collection.add(transaction) + + expect(collection.find_transaction('cats')).to be_nil + end + end + + describe '#newest_first' do + it 'returns transactions sorted from new to old' do + trans1 = Gitlab::Sherlock::Transaction.new('POST', '/cat_pictures') + trans2 = Gitlab::Sherlock::Transaction.new('POST', '/more_cat_pictures') + + allow(trans1).to receive(:finished_at).and_return(Time.utc(2015, 1, 1)) + allow(trans2).to receive(:finished_at).and_return(Time.utc(2015, 1, 2)) + + collection.add(trans1) + collection.add(trans2) + + expect(collection.newest_first).to eq([trans2, trans1]) + end + end +end diff --git a/spec/lib/gitlab/sherlock/file_sample_spec.rb b/spec/lib/gitlab/sherlock/file_sample_spec.rb new file mode 100644 index 00000000000..f05a59f56f6 --- /dev/null +++ b/spec/lib/gitlab/sherlock/file_sample_spec.rb @@ -0,0 +1,54 @@ +require 'spec_helper' + +describe Gitlab::Sherlock::FileSample do + let(:sample) { described_class.new(__FILE__, [], 150.4, 2) } + + describe '#id' do + it 'returns the ID' do + expect(sample.id).to be_an_instance_of(String) + end + end + + describe '#file' do + it 'returns the file path' do + expect(sample.file).to eq(__FILE__) + end + end + + describe '#line_samples' do + it 'returns the line samples' do + expect(sample.line_samples).to eq([]) + end + end + + describe '#events' do + it 'returns the total number of events' do + expect(sample.events).to eq(2) + end + end + + describe '#duration' do + it 'returns the total execution time' do + expect(sample.duration).to eq(150.4) + end + end + + describe '#relative_path' do + it 'returns the relative path' do + expect(sample.relative_path). + to eq('spec/lib/gitlab/sherlock/file_sample_spec.rb') + end + end + + describe '#to_param' do + it 'returns the sample ID' do + expect(sample.to_param).to eq(sample.id) + end + end + + describe '#source' do + it 'returns the contents of the file' do + expect(sample.source).to eq(File.read(__FILE__)) + end + end +end diff --git a/spec/lib/gitlab/sherlock/line_profiler_spec.rb b/spec/lib/gitlab/sherlock/line_profiler_spec.rb new file mode 100644 index 00000000000..8f2e1299714 --- /dev/null +++ b/spec/lib/gitlab/sherlock/line_profiler_spec.rb @@ -0,0 +1,73 @@ +require 'spec_helper' + +describe Gitlab::Sherlock::LineProfiler do + let(:profiler) { described_class.new } + + describe '#profile' do + it 'runs the profiler when using MRI' do + allow(profiler).to receive(:mri?).and_return(true) + allow(profiler).to receive(:profile_mri) + + profiler.profile { 'cats' } + end + + it 'raises NotImplementedError when profiling an unsupported platform' do + allow(profiler).to receive(:mri?).and_return(false) + + expect { profiler.profile { 'cats' } }.to raise_error(NotImplementedError) + end + end + + describe '#profile_mri' do + it 'returns an Array containing the return value and profiling samples' do + allow(profiler).to receive(:lineprof). + and_yield. + and_return({ __FILE__ => [[0, 0, 0, 0]] }) + + retval, samples = profiler.profile_mri { 42 } + + expect(retval).to eq(42) + expect(samples).to eq([]) + end + end + + describe '#aggregate_rblineprof' do + let(:raw_samples) do + { __FILE__ => [[30000, 30000, 5, 0], [15000, 15000, 4, 0]] } + end + + it 'returns an Array of FileSample objects' do + samples = profiler.aggregate_rblineprof(raw_samples) + + expect(samples).to be_an_instance_of(Array) + expect(samples[0]).to be_an_instance_of(Gitlab::Sherlock::FileSample) + end + + describe 'the first FileSample object' do + let(:file_sample) do + profiler.aggregate_rblineprof(raw_samples)[0] + end + + it 'uses the correct file path' do + expect(file_sample.file).to eq(__FILE__) + end + + it 'contains a list of line samples' do + line_sample = file_sample.line_samples[0] + + expect(line_sample).to be_an_instance_of(Gitlab::Sherlock::LineSample) + + expect(line_sample.duration).to eq(15.0) + expect(line_sample.events).to eq(4) + end + + it 'contains the total file execution time' do + expect(file_sample.duration).to eq(30.0) + end + + it 'contains the total amount of file events' do + expect(file_sample.events).to eq(5) + end + end + end +end diff --git a/spec/lib/gitlab/sherlock/line_sample_spec.rb b/spec/lib/gitlab/sherlock/line_sample_spec.rb new file mode 100644 index 00000000000..5f02f6a3213 --- /dev/null +++ b/spec/lib/gitlab/sherlock/line_sample_spec.rb @@ -0,0 +1,33 @@ +require 'spec_helper' + +describe Gitlab::Sherlock::LineSample do + let(:sample) { described_class.new(150.0, 4) } + + describe '#duration' do + it 'returns the duration' do + expect(sample.duration).to eq(150.0) + end + end + + describe '#events' do + it 'returns the amount of events' do + expect(sample.events).to eq(4) + end + end + + describe '#percentage_of' do + it 'returns the percentage of 1500.0' do + expect(sample.percentage_of(1500.0)).to be_within(0.1).of(10.0) + end + end + + describe '#majority_of' do + it 'returns true if the sample takes up the majority of the given duration' do + expect(sample.majority_of?(500.0)).to eq(true) + end + + it "returns false if the sample doesn't take up the majority of the given duration" do + expect(sample.majority_of?(1500.0)).to eq(false) + end + end +end diff --git a/spec/lib/gitlab/sherlock/location_spec.rb b/spec/lib/gitlab/sherlock/location_spec.rb new file mode 100644 index 00000000000..b295a624b35 --- /dev/null +++ b/spec/lib/gitlab/sherlock/location_spec.rb @@ -0,0 +1,40 @@ +require 'spec_helper' + +describe Gitlab::Sherlock::Location do + let(:location) { described_class.new(__FILE__, 1) } + + describe 'from_ruby_location' do + it 'creates a Location from a Thread::Backtrace::Location' do + input = caller_locations[0] + output = described_class.from_ruby_location(input) + + expect(output).to be_an_instance_of(described_class) + expect(output.path).to eq(input.path) + expect(output.line).to eq(input.lineno) + end + end + + describe '#path' do + it 'returns the file path' do + expect(location.path).to eq(__FILE__) + end + end + + describe '#line' do + it 'returns the line number' do + expect(location.line).to eq(1) + end + end + + describe '#application?' do + it 'returns true for an application frame' do + expect(location.application?).to eq(true) + end + + it 'returns false for a non application frame' do + loc = described_class.new('/tmp/cats.rb', 1) + + expect(loc.application?).to eq(false) + end + end +end diff --git a/spec/lib/gitlab/sherlock/middleware_spec.rb b/spec/lib/gitlab/sherlock/middleware_spec.rb new file mode 100644 index 00000000000..aa74fc53a79 --- /dev/null +++ b/spec/lib/gitlab/sherlock/middleware_spec.rb @@ -0,0 +1,79 @@ +require 'spec_helper' + +describe Gitlab::Sherlock::Middleware do + let(:app) { double(:app) } + let(:middleware) { described_class.new(app) } + + describe '#call' do + describe 'when instrumentation is enabled' do + it 'instruments a request' do + allow(middleware).to receive(:instrument?).and_return(true) + allow(middleware).to receive(:call_with_instrumentation) + + middleware.call({}) + end + end + + describe 'when instrumentation is disabled' do + it "doesn't instrument a request" do + allow(middleware).to receive(:instrument).and_return(false) + allow(app).to receive(:call) + + middleware.call({}) + end + end + end + + describe '#call_with_instrumentation' do + it 'instruments a request' do + trans = double(:transaction) + retval = 'cats are amazing' + env = {} + + allow(app).to receive(:call).with(env).and_return(retval) + allow(middleware).to receive(:transaction_from_env).and_return(trans) + allow(trans).to receive(:run).and_yield.and_return(retval) + allow(Gitlab::Sherlock.collection).to receive(:add).with(trans) + + middleware.call_with_instrumentation(env) + end + end + + describe '#instrument?' do + it 'returns false for a text/css request' do + env = { 'HTTP_ACCEPT' => 'text/css', 'REQUEST_URI' => '/' } + + expect(middleware.instrument?(env)).to eq(false) + end + + it 'returns false for a request to a Sherlock route' do + env = { + 'HTTP_ACCEPT' => 'text/html', + 'REQUEST_URI' => '/sherlock/transactions' + } + + expect(middleware.instrument?(env)).to eq(false) + end + + it 'returns true for a request that should be instrumented' do + env = { + 'HTTP_ACCEPT' => 'text/html', + 'REQUEST_URI' => '/cats' + } + + expect(middleware.instrument?(env)).to eq(true) + end + end + + describe '#transaction_from_env' do + it 'returns a Transaction' do + env = { + 'HTTP_ACCEPT' => 'text/html', + 'REQUEST_URI' => '/cats' + } + + expect(middleware.transaction_from_env(env)). + to be_an_instance_of(Gitlab::Sherlock::Transaction) + end + end +end diff --git a/spec/lib/gitlab/sherlock/query_spec.rb b/spec/lib/gitlab/sherlock/query_spec.rb new file mode 100644 index 00000000000..b15a125a40c --- /dev/null +++ b/spec/lib/gitlab/sherlock/query_spec.rb @@ -0,0 +1,113 @@ +require 'spec_helper' + +describe Gitlab::Sherlock::Query do + let(:started_at) { Time.utc(2015, 1, 1) } + let(:finished_at) { started_at + 5 } + + let(:query) do + described_class.new('SELECT COUNT(*) FROM users', started_at, finished_at) + end + + describe 'new_with_bindings' do + it 'returns a Query' do + sql = 'SELECT COUNT(*) FROM users WHERE id = $1' + bindings = [[double(:column), 10]] + + query = described_class. + new_with_bindings(sql, bindings, started_at, finished_at) + + expect(query.query).to eq('SELECT COUNT(*) FROM users WHERE id = 10;') + end + end + + describe '#id' do + it 'returns a String' do + expect(query.id).to be_an_instance_of(String) + end + end + + describe '#query' do + it 'returns the query with a trailing semi-colon' do + expect(query.query).to eq('SELECT COUNT(*) FROM users;') + end + end + + describe '#started_at' do + it 'returns the start time' do + expect(query.started_at).to eq(started_at) + end + end + + describe '#finished_at' do + it 'returns the completion time' do + expect(query.finished_at).to eq(finished_at) + end + end + + describe '#backtrace' do + it 'returns the backtrace' do + expect(query.backtrace).to be_an_instance_of(Array) + end + end + + describe '#duration' do + it 'returns the duration in milliseconds' do + expect(query.duration).to be_within(0.1).of(5000.0) + end + end + + describe '#to_param' do + it 'returns the query ID' do + expect(query.to_param).to eq(query.id) + end + end + + describe '#formatted_query' do + it 'returns a formatted version of the query' do + expect(query.formatted_query).to eq(<<-EOF.strip) +SELECT COUNT(*) +FROM users; + EOF + end + end + + describe '#last_application_frame' do + it 'returns the last application frame' do + frame = query.last_application_frame + + expect(frame).to be_an_instance_of(Gitlab::Sherlock::Location) + expect(frame.path).to eq(__FILE__) + end + end + + describe '#application_backtrace' do + it 'returns an Array of application frames' do + frames = query.application_backtrace + + expect(frames).to be_an_instance_of(Array) + expect(frames).to_not be_empty + + frames.each do |frame| + expect(frame.path).to start_with(Rails.root.to_s) + end + end + end + + describe '#explain' do + it 'returns the query plan as a String' do + lines = [ + ['Aggregate (cost=123 rows=1)'], + [' -> Index Only Scan using index_cats_are_amazing'] + ] + + result = double(:result, :values => lines) + + allow(query).to receive(:raw_explain).and_return(result) + + expect(query.explain).to eq(<<-EOF.strip) +Aggregate (cost=123 rows=1) + -> Index Only Scan using index_cats_are_amazing + EOF + end + end +end diff --git a/spec/lib/gitlab/sherlock/transaction_spec.rb b/spec/lib/gitlab/sherlock/transaction_spec.rb new file mode 100644 index 00000000000..bb4ff42e6e1 --- /dev/null +++ b/spec/lib/gitlab/sherlock/transaction_spec.rb @@ -0,0 +1,165 @@ +require 'spec_helper' + +describe Gitlab::Sherlock::Transaction do + let(:transaction) { described_class.new('POST', '/cat_pictures') } + + describe '#id' do + it 'returns the transaction ID' do + expect(transaction.id).to be_an_instance_of(String) + end + end + + describe '#type' do + it 'returns the type' do + expect(transaction.type).to eq('POST') + end + end + + describe '#path' do + it 'returns the path' do + expect(transaction.path).to eq('/cat_pictures') + end + end + + describe '#queries' do + it 'returns an Array of queries' do + expect(transaction.queries).to be_an_instance_of(Array) + end + end + + describe '#file_samples' do + it 'returns an Array of file samples' do + expect(transaction.file_samples).to be_an_instance_of(Array) + end + end + + describe '#started_at' do + it 'returns the start time' do + allow(transaction).to receive(:profile_lines).and_yield + + transaction.run { 'cats are amazing' } + + expect(transaction.started_at).to be_an_instance_of(Time) + end + end + + describe '#finished_at' do + it 'returns the completion time' do + allow(transaction).to receive(:profile_lines).and_yield + + transaction.run { 'cats are amazing' } + + expect(transaction.finished_at).to be_an_instance_of(Time) + end + end + + describe '#run' do + it 'runs the transaction' do + allow(transaction).to receive(:profile_lines).and_yield + + retval = transaction.run { 'cats are amazing' } + + expect(retval).to eq('cats are amazing') + end + end + + describe '#duration' do + it 'returns the duration in seconds' do + start_time = Time.now + + allow(transaction).to receive(:started_at).and_return(start_time) + allow(transaction).to receive(:finished_at).and_return(start_time + 5) + + expect(transaction.duration).to be_within(0.1).of(5.0) + end + end + + describe '#to_param' do + it 'returns the transaction ID' do + expect(transaction.to_param).to eq(transaction.id) + end + end + + describe '#sorted_queries' do + it 'returns the queries in descending order' do + start_time = Time.now + + query1 = Gitlab::Sherlock::Query.new('SELECT 1', start_time, start_time) + + query2 = Gitlab::Sherlock::Query. + new('SELECT 2', start_time, start_time + 5) + + transaction.queries << query1 + transaction.queries << query2 + + expect(transaction.sorted_queries).to eq([query2, query1]) + end + end + + describe '#sorted_file_samples' do + it 'returns the file samples in descending order' do + sample1 = Gitlab::Sherlock::FileSample.new(__FILE__, [], 10.0, 1) + sample2 = Gitlab::Sherlock::FileSample.new(__FILE__, [], 15.0, 1) + + transaction.file_samples << sample1 + transaction.file_samples << sample2 + + expect(transaction.sorted_file_samples).to eq([sample2, sample1]) + end + end + + describe '#find_query' do + it 'returns a Query when found' do + query = Gitlab::Sherlock::Query.new('SELECT 1', Time.now, Time.now) + + transaction.queries << query + + expect(transaction.find_query(query.id)).to eq(query) + end + + it 'returns nil when no query could be found' do + expect(transaction.find_query('cats')).to be_nil + end + end + + describe '#find_file_sample' do + it 'returns a FileSample when found' do + sample = Gitlab::Sherlock::FileSample.new(__FILE__, [], 10.0, 1) + + transaction.file_samples << sample + + expect(transaction.find_file_sample(sample.id)).to eq(sample) + end + + it 'returns nil when no file sample could be found' do + expect(transaction.find_file_sample('cats')).to be_nil + end + end + + describe '#profile_lines' do + describe 'when line profiling is enabled' do + it 'yields the block using the line profiler' do + allow(Gitlab::Sherlock).to receive(:enable_line_profiler?). + and_return(true) + + allow_any_instance_of(Gitlab::Sherlock::LineProfiler). + to receive(:profile).and_return('cats are amazing', []) + + retval = transaction.profile_lines { 'cats are amazing' } + + expect(retval).to eq('cats are amazing') + end + end + + describe 'when line profiling is disabled' do + it 'yields the block' do + allow(Gitlab::Sherlock).to receive(:enable_line_profiler?). + and_return(false) + + retval = transaction.profile_lines { 'cats are amazing' } + + expect(retval).to eq('cats are amazing') + end + end + end +end -- cgit v1.2.1 From 126a2428cd7fb5b2766da10373f72a370aa68ba5 Mon Sep 17 00:00:00 2001 From: Yorick Peterse Date: Thu, 5 Nov 2015 18:06:05 +0100 Subject: Updated profiling guides for Sherlock --- doc/development/profiling.md | 45 ++++++++------------------------------------ 1 file changed, 8 insertions(+), 37 deletions(-) diff --git a/doc/development/profiling.md b/doc/development/profiling.md index 80c86ef921e..e244ad4e881 100644 --- a/doc/development/profiling.md +++ b/doc/development/profiling.md @@ -4,11 +4,15 @@ To make it easier to track down performance problems GitLab comes with a set of profiling tools, some of these are available by default while others need to be explicitly enabled. -## rack-mini-profiler +## Sherlock -This Gem is enabled by default in development only. It allows you to see the -timings of the various components that made up a web request (e.g. the SQL -queries executed and their execution timings). +Sherlock is a custom profiling tool built into GitLab. Sherlock is _only_ +available when running GitLab in development mode _and_ when setting the +environment variable `ENABLE_SHERLOCK` to a non empty value. For example: + + ENABLE_SHERLOCK=1 bundle exec rails s + +Recorded transactions can be found by navigating to `/sherlock/transactions`. ## Bullet @@ -21,36 +25,3 @@ starting GitLab. For example: Bullet will log query problems to both the Rails log as well as the Chrome console. - -## ActiveRecord Query Trace - -This Gem adds backtraces for every ActiveRecord query in the Rails console. This -can be useful to track down where a query was executed. Because this Gem adds -quite a bit of noise (5-10 extra lines per ActiveRecord query) it's disabled by -default. To use this Gem you'll need to set `ENABLE_QUERY_TRACE` to a non empty -file before starting GitLab. For example: - - ENABLE_QUERY_TRACE=true bundle exec rails s - -## rack-lineprof - -This is a Gem that can trace the execution time of code on a per line basis. -Because this Gem can add quite a bit of overhead it's disabled by default. To -enable it, set the environment variable `ENABLE_LINEPROF` to a non-empty value. -For example: - - ENABLE_LINEPROF=true bundle exec rails s - -Once enabled you'll need to add a query string parameter to a request to -actually profile code execution. The name of the parameter is `lineprof` and -should be set to a regular expression (minus the starting/ending slash) used to -select what files to profile. To profile all files containing "foo" somewhere in -the path you'd use the following parameter: - - ?lineprof=foo - -Or when filtering for files containing "foo" and "bar" in their path: - - ?lineprof=foo|bar - -Once set the profiling output will be displayed in your terminal. -- cgit v1.2.1 From db46d49c0ed7e34a9679b0475480306d92b0de31 Mon Sep 17 00:00:00 2001 From: Yorick Peterse Date: Mon, 9 Nov 2015 11:21:50 +0100 Subject: Fixed Hash key style in Sherlock::Query spec --- spec/lib/gitlab/sherlock/query_spec.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spec/lib/gitlab/sherlock/query_spec.rb b/spec/lib/gitlab/sherlock/query_spec.rb index b15a125a40c..a9afef5dc1d 100644 --- a/spec/lib/gitlab/sherlock/query_spec.rb +++ b/spec/lib/gitlab/sherlock/query_spec.rb @@ -100,7 +100,7 @@ FROM users; [' -> Index Only Scan using index_cats_are_amazing'] ] - result = double(:result, :values => lines) + result = double(:result, values: lines) allow(query).to receive(:raw_explain).and_return(result) -- cgit v1.2.1 From cdaa97443e89a08d857a244e6e8ab0235db9746d Mon Sep 17 00:00:00 2001 From: Yorick Peterse Date: Mon, 9 Nov 2015 11:30:57 +0100 Subject: Added navigation link to Sherlock --- app/views/layouts/header/_default.html.haml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/app/views/layouts/header/_default.html.haml b/app/views/layouts/header/_default.html.haml index c31b1cbe9a8..c08a7b80744 100644 --- a/app/views/layouts/header/_default.html.haml +++ b/app/views/layouts/header/_default.html.haml @@ -21,6 +21,11 @@ %li = link_to new_project_path, title: 'New project', data: {toggle: 'tooltip', placement: 'bottom'} do = icon('plus fw') + - if Gitlab::Sherlock.enabled? + %li + = link_to sherlock_transactions_path, title: 'Sherlock Transactions', + data: {toggle: 'tooltip', placement: 'bottom'} do + = icon('tachometer fw') %li = link_to destroy_user_session_path, class: 'logout', method: :delete, title: 'Sign out', data: {toggle: 'tooltip', placement: 'bottom'} do = icon('sign-out') -- cgit v1.2.1 From 7b5fd8742e6112491f61f27dcca2d8e441cc33a1 Mon Sep 17 00:00:00 2001 From: Yorick Peterse Date: Mon, 9 Nov 2015 12:36:01 +0100 Subject: Track the amount of times views are rendered --- .../sherlock/transactions/_file_samples.html.haml | 2 + config/locales/sherlock.en.yml | 1 + lib/gitlab/sherlock/transaction.rb | 57 ++++++++++++++++------ spec/lib/gitlab/sherlock/transaction_spec.rb | 57 ++++++++++++++++++++++ 4 files changed, 103 insertions(+), 14 deletions(-) diff --git a/app/views/sherlock/transactions/_file_samples.html.haml b/app/views/sherlock/transactions/_file_samples.html.haml index 0afdbc8dffa..4349c9b7ace 100644 --- a/app/views/sherlock/transactions/_file_samples.html.haml +++ b/app/views/sherlock/transactions/_file_samples.html.haml @@ -7,6 +7,7 @@ %thead %tr %th= t('sherlock.time_inclusive') + %th= t('sherlock.count') %th= t('sherlock.path') %th %tbody @@ -15,6 +16,7 @@ %td = sample.duration.round(2) = t('sherlock.milliseconds') + %td= @transaction.view_counts.fetch(sample.file, 1) %td= sample.relative_path %td = link_to(t('sherlock.view'), diff --git a/config/locales/sherlock.en.yml b/config/locales/sherlock.en.yml index 5c146b172b1..683b09dc329 100644 --- a/config/locales/sherlock.en.yml +++ b/config/locales/sherlock.en.yml @@ -34,3 +34,4 @@ en: query_plan: Query Plan events: Events percent: '%' + count: Count diff --git a/lib/gitlab/sherlock/transaction.rb b/lib/gitlab/sherlock/transaction.rb index 4641f15ee33..d87a4c9bb4a 100644 --- a/lib/gitlab/sherlock/transaction.rb +++ b/lib/gitlab/sherlock/transaction.rb @@ -2,7 +2,7 @@ module Gitlab module Sherlock class Transaction attr_reader :id, :type, :path, :queries, :file_samples, :started_at, - :finished_at + :finished_at, :view_counts # type - The type of transaction (e.g. "GET", "POST", etc) # path - The path of the transaction (e.g. the HTTP request path) @@ -15,20 +15,19 @@ module Gitlab @started_at = nil @finished_at = nil @thread = Thread.current + @view_counts = Hash.new(0) end # Runs the transaction and returns the block's return value. def run @started_at = Time.now - subscriber = subscribe_to_active_record - - retval = profile_lines { yield } + retval = with_subscriptions do + profile_lines { yield } + end @finished_at = Time.now - ActiveSupport::Notifications.unsubscribe(subscriber) - retval end @@ -81,21 +80,51 @@ module Gitlab retval end + def subscribe_to_active_record + ActiveSupport::Notifications.subscribe('sql.active_record') do |_, start, finish, _, data| + next unless same_thread? + + track_query(data[:sql].strip, data[:binds], start, finish) + end + end + + def subscribe_to_action_view + regex = /render_(template|partial)\.action_view/ + + ActiveSupport::Notifications.subscribe(regex) do |_, start, finish, _, data| + next unless same_thread? + + track_view(data[:identifier]) + end + end + private def track_query(query, bindings, start, finish) @queries << Query.new_with_bindings(query, bindings, start, finish) end - def subscribe_to_active_record - ActiveSupport::Notifications.subscribe('sql.active_record') do |_, start, finish, _, data| - # In case somebody uses a multi-threaded server locally (e.g. Puma) we - # _only_ want to track queries that originate from the transaction - # thread. - next unless Thread.current == @thread + def track_view(path) + @view_counts[path] += 1 + end - track_query(data[:sql].strip, data[:binds], start, finish) - end + def with_subscriptions + ar_subscriber = subscribe_to_active_record + av_subscriber = subscribe_to_action_view + + retval = yield + + ActiveSupport::Notifications.unsubscribe(ar_subscriber) + ActiveSupport::Notifications.unsubscribe(av_subscriber) + + retval + end + + # In case somebody uses a multi-threaded server locally (e.g. Puma) we + # _only_ want to track notifications that originate from the transaction + # thread. + def same_thread? + Thread.current == @thread end end end diff --git a/spec/lib/gitlab/sherlock/transaction_spec.rb b/spec/lib/gitlab/sherlock/transaction_spec.rb index bb4ff42e6e1..bb49fb65cf8 100644 --- a/spec/lib/gitlab/sherlock/transaction_spec.rb +++ b/spec/lib/gitlab/sherlock/transaction_spec.rb @@ -53,6 +53,16 @@ describe Gitlab::Sherlock::Transaction do end end + describe '#view_counts' do + it 'returns a Hash' do + expect(transaction.view_counts).to be_an_instance_of(Hash) + end + + it 'sets the default value of a key to 0' do + expect(transaction.view_counts['cats.rb']).to be_zero + end + end + describe '#run' do it 'runs the transaction' do allow(transaction).to receive(:profile_lines).and_yield @@ -162,4 +172,51 @@ describe Gitlab::Sherlock::Transaction do end end end + + describe '#subscribe_to_active_record' do + let(:subscription) { transaction.subscribe_to_active_record } + let(:time) { Time.now } + let(:query_data) { { sql: 'SELECT 1', binds: [] } } + + after do + ActiveSupport::Notifications.unsubscribe(subscription) + end + + it 'tracks executed queries' do + expect(transaction).to receive(:track_query). + with('SELECT 1', [], time, time) + + subscription.publish('test', time, time, nil, query_data) + end + + it 'only tracks queries triggered from the transaction thread' do + expect(transaction).to_not receive(:track_query) + + Thread.new { subscription.publish('test', time, time, nil, query_data) }. + join + end + end + + describe '#subscribe_to_action_view' do + let(:subscription) { transaction.subscribe_to_action_view } + let(:time) { Time.now } + let(:view_data) { { identifier: 'foo.rb' } } + + after do + ActiveSupport::Notifications.unsubscribe(subscription) + end + + it 'tracks rendered views' do + expect(transaction).to receive(:track_view).with('foo.rb') + + subscription.publish('test', time, time, nil, view_data) + end + + it 'only tracks views rendered from the transaction thread' do + expect(transaction).to_not receive(:track_view) + + Thread.new { subscription.publish('test', time, time, nil, view_data) }. + join + end + end end -- cgit v1.2.1 From 7f9f07023bbe4393620998d1be46cc65d836d5c8 Mon Sep 17 00:00:00 2001 From: Yorick Peterse Date: Mon, 9 Nov 2015 12:42:28 +0100 Subject: Truncate transaction paths to 70 characters This ensures that long URLs don't completely mess up the layout of the table. --- app/views/sherlock/transactions/index.html.haml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/app/views/sherlock/transactions/index.html.haml b/app/views/sherlock/transactions/index.html.haml index fb31131ba88..010e1a2a902 100644 --- a/app/views/sherlock/transactions/index.html.haml +++ b/app/views/sherlock/transactions/index.html.haml @@ -27,7 +27,9 @@ - @transactions.each do |trans| %tr %td= trans.type - %td= trans.path + %td + %span{title: trans.path} + = truncate(trans.path, length: 70) %td = trans.duration.round(2) = t('sherlock.seconds') -- cgit v1.2.1 From 68843a53e6cfe5493ad46dac58b469dd969a0edf Mon Sep 17 00:00:00 2001 From: Yorick Peterse Date: Mon, 9 Nov 2015 14:29:50 +0100 Subject: Added changelog entry for Sherlock --- CHANGELOG | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG b/CHANGELOG index 19f288d0c7e..217dc4e0043 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,6 +1,7 @@ Please view this file on the master branch, on stable branches it's out of date. v 8.2.0 (unreleased) + - Added a GitLab specific profiling tool called "Sherlock" (see GitLab CE merge request #1749) - Fix bug where manually merged branches in a MR would end up with an empty diff (Stan Hu) - Force update refs/merge-requests/X/head upon a push to the source branch of a merge request (Stan Hu) - Improved performance of finding users by one of their Email addresses -- cgit v1.2.1 From e357e4fbab79b0d834590b623644476a2ef980f5 Mon Sep 17 00:00:00 2001 From: Pirate Praveen Date: Mon, 9 Nov 2015 08:34:25 -0500 Subject: remove state_machine_patch.rb --- config/initializers/state_machine_patch.rb | 9 --------- 1 file changed, 9 deletions(-) delete mode 100644 config/initializers/state_machine_patch.rb diff --git a/config/initializers/state_machine_patch.rb b/config/initializers/state_machine_patch.rb deleted file mode 100644 index 51f05794361..00000000000 --- a/config/initializers/state_machine_patch.rb +++ /dev/null @@ -1,9 +0,0 @@ -# This is a patch to address the issue in https://github.com/pluginaweek/state_machine/issues/251 -# where gem 'state_machine' was not working for Rails 4.1 -module StateMachines - module Integrations - module ActiveModel - public :around_validation - end - end -end -- cgit v1.2.1 From ddd3dd72fec5d31fc76023e10f824cc079f65b63 Mon Sep 17 00:00:00 2001 From: Pirate Praveen Date: Mon, 9 Nov 2015 09:11:42 -0500 Subject: update Gemfile.lock --- Gemfile.lock | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/Gemfile.lock b/Gemfile.lock index dce728baf18..21cbf854c1d 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -692,7 +692,13 @@ GEM activesupport (>= 3.0) sprockets (>= 2.8, < 4.0) stamp (0.6.0) - state_machine (1.2.0) + state_machines (0.4.0) + state_machines-activemodel (0.3.0) + activemodel (~> 4.1) + state_machines (>= 0.4.0) + state_machines-activerecord (0.3.0) + activerecord (~> 4.1) + state_machines-activemodel (>= 0.3.0) stringex (2.5.2) systemu (2.6.5) task_list (1.0.2) @@ -913,7 +919,7 @@ DEPENDENCIES spring-commands-teaspoon (~> 0.0.2) sprockets (~> 2.12.3) stamp (~> 0.6.0) - state_machine (~> 1.2.0) + state_machines-activerecord (~> 0.3.0) task_list (~> 1.0.2) teaspoon (~> 1.0.0) teaspoon-jasmine (~> 2.2.0) -- cgit v1.2.1 From b67fdfff3c245538ee5a5e9360a2613b76ebada5 Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Mon, 9 Nov 2015 15:30:50 +0100 Subject: Refactor release code a bit Signed-off-by: Dmitriy Zaporozhets --- app/controllers/projects/releases_controller.rb | 8 +++++--- app/controllers/projects/tags_controller.rb | 8 -------- app/models/release.rb | 2 +- app/services/create_tag_service.rb | 8 ++++++-- app/services/delete_tag_service.rb | 4 +++- 5 files changed, 15 insertions(+), 15 deletions(-) diff --git a/app/controllers/projects/releases_controller.rb b/app/controllers/projects/releases_controller.rb index f69a4bc729e..0825a4311cb 100644 --- a/app/controllers/projects/releases_controller.rb +++ b/app/controllers/projects/releases_controller.rb @@ -10,9 +10,7 @@ class Projects::ReleasesController < Projects::ApplicationController end def update - description = params[:release][:description] - release.update_attributes(description: description) - release.save + release.update_attributes(release_params) redirect_to namespace_project_tag_path(@project.namespace, @project, @tag.name) end @@ -26,4 +24,8 @@ class Projects::ReleasesController < Projects::ApplicationController def release @release ||= @project.releases.find_or_initialize_by(tag: @tag.name) end + + def release_params + params.require(:release).permit(:description) + end end diff --git a/app/controllers/projects/tags_controller.rb b/app/controllers/projects/tags_controller.rb index 670f5d3067b..f512f01dc78 100644 --- a/app/controllers/projects/tags_controller.rb +++ b/app/controllers/projects/tags_controller.rb @@ -24,12 +24,6 @@ class Projects::TagsController < Projects::ApplicationController if result[:status] == :success @tag = result[:tag] - if params[:release_description] - release = @project.releases.find_or_initialize_by(tag: @tag.name) - release.update_attributes(description: params[:release_description]) - release.save - end - redirect_to namespace_project_tag_path(@project.namespace, @project, @tag.name) else @error = result[:message] @@ -39,8 +33,6 @@ class Projects::TagsController < Projects::ApplicationController def destroy DeleteTagService.new(project, current_user).execute(params[:id]) - release = project.releases.find_by(tag: params[:id]) - release.destroy if release redirect_to namespace_project_tags_path(@project.namespace, @project) end diff --git a/app/models/release.rb b/app/models/release.rb index 05647839e84..e196b84eb18 100644 --- a/app/models/release.rb +++ b/app/models/release.rb @@ -1,5 +1,5 @@ class Release < ActiveRecord::Base belongs_to :project - validates :description, :project, presence: true + validates :description, :project, :tag, presence: true end diff --git a/app/services/create_tag_service.rb b/app/services/create_tag_service.rb index 1a7318048b3..9917119fce2 100644 --- a/app/services/create_tag_service.rb +++ b/app/services/create_tag_service.rb @@ -1,7 +1,7 @@ require_relative 'base_service' class CreateTagService < BaseService - def execute(tag_name, ref, message) + def execute(tag_name, ref, message, release_description = nil) valid_tag = Gitlab::GitRefValidator.validate(tag_name) if valid_tag == false return error('Tag name invalid') @@ -19,8 +19,12 @@ class CreateTagService < BaseService new_tag = repository.find_tag(tag_name) if new_tag - push_data = create_push_data(project, current_user, new_tag) + if release_description + release = project.releases.find_or_initialize_by(tag: tag_name) + release.update_attributes(description: release_description) + end + push_data = create_push_data(project, current_user, new_tag) EventCreateService.new.push(project, current_user, push_data) project.execute_hooks(push_data.dup, :tag_push_hooks) project.execute_services(push_data.dup, :tag_push_hooks) diff --git a/app/services/delete_tag_service.rb b/app/services/delete_tag_service.rb index 0c836401136..de3352a6756 100644 --- a/app/services/delete_tag_service.rb +++ b/app/services/delete_tag_service.rb @@ -11,8 +11,10 @@ class DeleteTagService < BaseService end if repository.rm_tag(tag_name) + release = project.releases.find_by(tag: tag_name) + release.destroy if release + push_data = build_push_data(tag) - EventCreateService.new.push(project, current_user, push_data) project.execute_hooks(push_data.dup, :tag_push_hooks) project.execute_services(push_data.dup, :tag_push_hooks) -- cgit v1.2.1 From b7619dad52504f8fc61bfb3b42e7f8bcc42dc06d Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Mon, 9 Nov 2015 15:39:18 +0100 Subject: Add missing param and title for tag Signed-off-by: Dmitriy Zaporozhets --- app/controllers/projects/tags_controller.rb | 2 +- app/views/projects/releases/edit.html.haml | 1 + app/views/projects/tags/show.html.haml | 7 ++++--- 3 files changed, 6 insertions(+), 4 deletions(-) diff --git a/app/controllers/projects/tags_controller.rb b/app/controllers/projects/tags_controller.rb index f512f01dc78..cb39c2b8782 100644 --- a/app/controllers/projects/tags_controller.rb +++ b/app/controllers/projects/tags_controller.rb @@ -19,7 +19,7 @@ class Projects::TagsController < Projects::ApplicationController def create result = CreateTagService.new(@project, current_user). - execute(params[:tag_name], params[:ref], params[:message]) + execute(params[:tag_name], params[:ref], params[:message], params[:release_description]) if result[:status] == :success @tag = result[:tag] diff --git a/app/views/projects/releases/edit.html.haml b/app/views/projects/releases/edit.html.haml index 78741416347..e7db09cdaa9 100644 --- a/app/views/projects/releases/edit.html.haml +++ b/app/views/projects/releases/edit.html.haml @@ -1,3 +1,4 @@ +- page_title "Edit", @tag.name, "Tags" = render "projects/commits/header_title" = render "projects/commits/head" diff --git a/app/views/projects/tags/show.html.haml b/app/views/projects/tags/show.html.haml index f95ae9edc4b..ebe3718afcc 100644 --- a/app/views/projects/tags/show.html.haml +++ b/app/views/projects/tags/show.html.haml @@ -4,8 +4,9 @@ .gray-content-block .pull-right - = link_to edit_namespace_project_tag_release_path(@project.namespace, @project, @tag.name), class: 'btn-grouped btn', title: 'Edit release notes' do - = icon("pencil") + - if can?(current_user, :push_code, @project) + = link_to edit_namespace_project_tag_release_path(@project.namespace, @project, @tag.name), class: 'btn-grouped btn', title: 'Edit release notes' do + = icon("pencil") = link_to namespace_project_tree_path(@project.namespace, @project, @tag.name), class: 'btn btn-grouped', title: 'Browse source code' do = icon('files-o') = link_to namespace_project_commits_path(@project.namespace, @project, @tag.name), class: 'btn btn-grouped', title: 'Browse commits' do @@ -35,4 +36,4 @@ = preserve do = markdown @release.description - else - This tag has no release notes yet. Press edit button to add one + This tag has no release notes. -- cgit v1.2.1 From 73cf0f1647806a4ce064707c6f1f416181de48ef Mon Sep 17 00:00:00 2001 From: Yorick Peterse Date: Mon, 9 Nov 2015 15:54:13 +0100 Subject: Only load rblineprof when actually needed This ensures the application can still boot when the "development" group is not available. --- lib/gitlab/sherlock.rb | 1 - lib/gitlab/sherlock/line_profiler.rb | 2 ++ 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/gitlab/sherlock.rb b/lib/gitlab/sherlock.rb index c4b35b24ceb..6360527a7aa 100644 --- a/lib/gitlab/sherlock.rb +++ b/lib/gitlab/sherlock.rb @@ -1,5 +1,4 @@ require 'securerandom' -require 'rblineprof' if RUBY_ENGINE == 'ruby' module Gitlab module Sherlock diff --git a/lib/gitlab/sherlock/line_profiler.rb b/lib/gitlab/sherlock/line_profiler.rb index 152749dcc39..aa1468bff6b 100644 --- a/lib/gitlab/sherlock/line_profiler.rb +++ b/lib/gitlab/sherlock/line_profiler.rb @@ -40,6 +40,8 @@ module Gitlab # Profiles the given block using rblineprof (MRI only). def profile_mri + require 'rblineprof' + retval = nil samples = lineprof(/^#{Rails.root.to_s}/) { retval = yield } -- cgit v1.2.1 From 4017a4fcbcb0ed1beb56718cf586c38bbb951527 Mon Sep 17 00:00:00 2001 From: Stan Hu Date: Mon, 9 Nov 2015 04:40:29 -0800 Subject: Upgrade gitlab_git to 7.2.20 and rugged to 0.23.3. Switch back to github-linguist --- CHANGELOG | 1 + Gemfile | 10 +++------- Gemfile.lock | 25 +++++++++++++------------ 3 files changed, 17 insertions(+), 19 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index 217dc4e0043..afb3d1086b2 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -2,6 +2,7 @@ Please view this file on the master branch, on stable branches it's out of date. v 8.2.0 (unreleased) - Added a GitLab specific profiling tool called "Sherlock" (see GitLab CE merge request #1749) + - Upgrade gitlab_git to 7.2.20 and rugged to 0.23.3 (Stan Hu) - Fix bug where manually merged branches in a MR would end up with an empty diff (Stan Hu) - Force update refs/merge-requests/X/head upon a push to the source branch of a merge request (Stan Hu) - Improved performance of finding users by one of their Email addresses diff --git a/Gemfile b/Gemfile index b0a7c9b9458..51848621b64 100644 --- a/Gemfile +++ b/Gemfile @@ -40,7 +40,7 @@ gem "browser", '~> 1.0.0' # Extracting information from a git repository # Provide access to Gitlab::Git library -gem "gitlab_git", '~> 7.2.19' +gem "gitlab_git", '~> 7.2.20' # LDAP Auth # GitLab fork with several improvements to original library. For full list of changes @@ -51,11 +51,7 @@ gem 'gitlab_omniauth-ldap', '~> 1.2.1', require: "omniauth-ldap" gem 'gollum-lib', '~> 4.0.2' # Language detection -# GitLab fork of linguist does not require pygments/python dependency. -# New version of original gem also dropped pygments support but it has strict -# dependency to unstable rugged version. We have internal issue for replacing -# fork with original gem when we meet on same rugged version - https://dev.gitlab.org/gitlab/gitlabhq/issues/2052. -gem "gitlab-linguist", "~> 3.0.1", require: "linguist" +gem "github-linguist", "~> 4.7.0", require: "linguist" # API gem 'grape', '~> 0.6.1' @@ -185,7 +181,7 @@ gem 'ace-rails-ap', '~> 2.0.1' gem 'mousetrap-rails', '~> 1.4.6' # Detect and convert string character encoding -gem 'charlock_holmes', '~> 0.6.9.4' +gem 'charlock_holmes', '~> 0.7.3' gem "sass-rails", '~> 4.0.5' gem "coffee-rails", '~> 4.1.0' diff --git a/Gemfile.lock b/Gemfile.lock index c602d406711..d358e236302 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -175,7 +175,7 @@ GEM activesupport (>= 3.2) equalizer (0.0.11) erubis (2.7.0) - escape_utils (0.2.4) + escape_utils (1.1.0) eventmachine (1.0.8) excon (0.45.4) execjs (2.6.0) @@ -266,6 +266,11 @@ GEM json get_process_mem (0.2.0) gherkin-ruby (0.3.2) + github-linguist (4.7.0) + charlock_holmes (~> 0.7.3) + escape_utils (~> 1.1.0) + mime-types (>= 1.19) + rugged (>= 0.23.0b) github-markup (1.3.3) gitlab-flowdock-git-hook (1.0.1) flowdock (~> 0.7) @@ -276,17 +281,13 @@ GEM diff-lcs (~> 1.1) mime-types (~> 1.15) posix-spawn (~> 0.3) - gitlab-linguist (3.0.1) - charlock_holmes (~> 0.6.6) - escape_utils (~> 0.2.4) - mime-types (~> 1.19) gitlab_emoji (0.1.1) gemojione (~> 2.0) - gitlab_git (7.2.19) + gitlab_git (7.2.20) activesupport (~> 4.0) - charlock_holmes (~> 0.6) - gitlab-linguist (~> 3.0) - rugged (~> 0.22.2) + charlock_holmes (~> 0.7.3) + github-linguist (~> 4.7.0) + rugged (~> 0.23.3) gitlab_meta (7.0) gitlab_omniauth-ldap (1.2.1) net-ldap (~> 0.9) @@ -794,7 +795,7 @@ DEPENDENCIES capybara (~> 2.4.0) capybara-screenshot (~> 1.0.0) carrierwave (~> 0.9.0) - charlock_holmes (~> 0.6.9.4) + charlock_holmes (~> 0.7.3) coffee-rails (~> 4.1.0) colored (~> 1.2) colorize (~> 0.5.8) @@ -819,11 +820,11 @@ DEPENDENCIES foreman fuubar (~> 2.0.0) gemnasium-gitlab-service (~> 0.2) + github-linguist (~> 4.7.0) github-markup (~> 1.3.1) gitlab-flowdock-git-hook (~> 1.0.1) - gitlab-linguist (~> 3.0.1) gitlab_emoji (~> 0.1) - gitlab_git (~> 7.2.19) + gitlab_git (~> 7.2.20) gitlab_meta (= 7.0) gitlab_omniauth-ldap (~> 1.2.1) gollum-lib (~> 4.0.2) -- cgit v1.2.1 From f526d43432447fe8de84ffc247b65e987ddfde84 Mon Sep 17 00:00:00 2001 From: Robert Speicher Date: Mon, 9 Nov 2015 13:26:29 -0500 Subject: Update CHANGELOG [ci skip] --- CHANGELOG | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index 78ce4f3bfdd..4c0e9aa0fb9 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -2,8 +2,6 @@ Please view this file on the master branch, on stable branches it's out of date. v 8.2.0 (unreleased) - Added a GitLab specific profiling tool called "Sherlock" (see GitLab CE merge request #1749) - - Fix bug where manually merged branches in a MR would end up with an empty diff (Stan Hu) - - Force update refs/merge-requests/X/head upon a push to the source branch of a merge request (Stan Hu) - Improved performance of finding users by one of their Email addresses - Improved performance of replacing references in comments - Show last project commit to default branch on project home page @@ -19,7 +17,6 @@ v 8.2.0 (unreleased) - Enable shared runners to all new projects - Fix: 500 error returned if destroy request without HTTP referer (Kazuki Shimizu) - Remove deprecated CI events from project settings page - - Use issue editor as cross reference comment author when issue is edited with a new mention. - [API] Add ability to fetch the commit ID of the last commit that actually touched a file - Add "New file" link to dropdown on project page - Include commit logs in project search @@ -29,9 +26,14 @@ v 8.2.0 (unreleased) - New design for project graphs page - Fix incoming email config defaults +v 8.1.4 + - Fix bug where manually merged branches in a MR would end up with an empty diff (Stan Hu) + - Prevent redirect loop when home_page_url is set to the root URL + v 8.1.3 + - Force update refs/merge-requests/X/head upon a push to the source branch of a merge request (Stan Hu) - Spread out runner contacted_at updates - - New design for user profile page + - Use issue editor as cross reference comment author when issue is edited with a new mention - Add Facebook authentication v 8.1.1 -- cgit v1.2.1 From 9822bce467b19e7b04e3e3c97bb1bcd9e4074161 Mon Sep 17 00:00:00 2001 From: Robert Speicher Date: Mon, 9 Nov 2015 14:24:26 -0500 Subject: Update monthly release issue template [ci skip] --- doc/release/monthly.md | 86 ++++++++++++++++++++++++++++++-------------------- 1 file changed, 51 insertions(+), 35 deletions(-) diff --git a/doc/release/monthly.md b/doc/release/monthly.md index bd8a67d1d85..4925816daaa 100644 --- a/doc/release/monthly.md +++ b/doc/release/monthly.md @@ -25,68 +25,84 @@ If the release is falling behind immediately warn the team. ## Create an overall issue and follow it -Create issue for GitLab CE project(internal). Name it "Release x.x.x" for easier searching. -Replace the dates with actual dates based on the number of workdays before the release. -All steps from issue template are explained below +Create an issue in the GitLab CE project. Name it "Release x.x" and tag it with +the `release` label for easier searching. Replace the dates with actual dates +based on the number of workdays before the release. All steps from issue +template are explained below: ``` -Xth: (7 working days before the 22nd) +### Xth: (7 working days before the 22nd) -- [ ] Triage the omnibus-gitlab milestone +- [ ] Triage the [Omnibus milestone] -Xth: (6 working days before the 22nd) +### Xth: (6 working days before the 22nd) -- [ ] Merge CE master in to EE master via merge request (#LINK) +- [ ] Merge CE `master` into EE `master` via merge request (#LINK) - [ ] Determine QA person and notify this person - [ ] Check the tasks in [how to rc1 guide](https://dev.gitlab.org/gitlab/gitlabhq/blob/master/doc/release/howto_rc1.md) and delegate tasks if necessary -- [ ] Create CE, EE, CI RC1 versions (#LINK) -- [ ] Build RC1 packages (EE first) (#LINK) +- [ ] Create CE and EE RC1 versions (#LINK) +- [ ] Build RC1 packages -Xth: (5 working days before the 22nd) +### Xth: (5 working days before the 22nd) - [ ] Do QA and fix anything coming out of it (#LINK) -- [ ] Close the omnibus-gitlab milestone -- [ ] Prepare the blog post (#LINK) +- [ ] Close the [Omnibus milestone] +- [ ] Prepare the [blog post] -Xth: (4 working days before the 22nd) +### Xth: (4 working days before the 22nd) -- [ ] Update GitLab.com with rc1 (#LINK) (https://dev.gitlab.org/cookbooks/chef-repo/blob/master/doc/administration.md#deploy-the-package) -- [ ] Update ci.gitLab.com with rc1 (#LINK) (https://dev.gitlab.org/cookbooks/chef-repo/blob/master/doc/administration.md#deploy-the-package) -- [ ] Create regression issues (CE, CI) (#LINK) -- [ ] Tweet about rc1 (#LINK), proposed text: +- [ ] Update GitLab.com with RC1 +- [ ] Create the regression issue in the CE issue tracker: -> GitLab x.x.0.rc1 is available https://packages.gitlab.com/gitlab/unstable Use at your own risk. Please link regressions issues from LINK_TO_REGRESSION_ISSUE + > This is a meta issue to index possible regressions in this monthly release + > and any patch versions. + > + > Please do not raise or discuss issues directly in this issue but link to + > issues that might warrant a patch release. If there is a Merge Request + > that fixes the issue, please link to that as well. + > + > Please only post one regression issue and/or merge request per comment. + > Comments will be updated by the release manager as they are addressed. -Xth: (3 working days before the 22nd) +- [ ] Tweet about RC1 release: -- [ ] Merge CE stable branch into EE stable branch + > GitLab x.y.0.rc1 is available: https://packages.gitlab.com/gitlab/unstable + > Use at your own risk. Please link regressions issues from + > LINK_TO_REGRESSION_ISSUE -Xth: (2 working days before the 22nd) +### Xth: (3 working days before the 22nd) -- [ ] Check that everyone is mentioned on the blog post using `@all` (the reviewer should have done this one working day ago) -- [ ] Check that MVP is added to the mvp page (source/mvp/index.html in www-gitlab-com) +- [ ] Merge `x-y-stable` into `x-y-stable-ee` +- [ ] Check that everyone is mentioned on the [blog post] using `@all` -Xth: (1 working day before the 22nd) +### Xth: (2 working days before the 22nd) -- [ ] Merge CE stable into EE stable -- [ ] Create CE, EE, CI release candidates (#LINK) (hopefully final ones with the same commit as the release tomorrow) +- [ ] Check that MVP is added to the [MVP page] + +### Xth: (1 working day before the 22nd) + +- [ ] Merge `x-y-stable` into `x-y-stable-ee` +- [ ] Create CE and EE release candidates - [ ] Create Omnibus tags and build packages for the latest release candidates -- [ ] Update GitLab.com with the latest RC (#LINK) -- [ ] Update ci.gitLab.com with the latest RC (#LINK) +- [ ] Update GitLab.com with the latest RC -22nd before 1200 CET: +### 22nd before 1200 CET: Release before 1200 CET / 2AM PST, to make sure the majority of our users get the new version on the 22nd and there is sufficient time in the European workday to quickly fix any issues. -- [ ] Merge CE stable into EE stable (#LINK) -- [ ] Create the 'x.y.0' tag with the [release tools](https://dev.gitlab.org/gitlab/release-tools) (#LINK) +- [ ] Merge `x-y-stable` into `x-y-stable-ee` +- [ ] Create the 'x.y.0' tag with the [release tools](https://dev.gitlab.org/gitlab/release-tools) - [ ] Create the 'x.y.0' version on version.gitlab.com -- [ ] Try to do before 1100 CET: Create and push omnibus tags for x.y.0 (will auto-release the packages) (#LINK) -- [ ] Try to do before 1200 CET: Publish the release blog post (#LINK) -- [ ] Tweet about the release (blog post) (#LINK) -- [ ] Schedule a second tweet of the release announcement with the same text at 1800 CET / 8AM PST +- [ ] Try to do before 1100 CET: Create and push Omnibus tags for x.y.0 (will auto-release the packages) +- [ ] Try to do before 1200 CET: Publish the release [blog post] +- [ ] Tweet about the release +- [ ] Schedule a second Tweet of the release announcement with the same text at 1800 CET / 8AM PST + +[Omnibus milestone]: LINK_TO_OMNIBUS_MILESTONE +[blog post]: LINK_TO_WIP_BLOG_POST +[MVP page]: https://gitlab.com/gitlab-com/www-gitlab-com/blob/master/source/mvp/index.html ``` - - - -- cgit v1.2.1 From 746e49fee9a28f509f115074d9985830de45513d Mon Sep 17 00:00:00 2001 From: Anton Baklanov Date: Tue, 3 Nov 2015 16:44:14 +0200 Subject: Display target branch on MR list when it is different from project's default --- CHANGELOG | 1 + .../projects/merge_requests_controller.rb | 1 + .../projects/merge_requests/_merge_request.html.haml | 5 +++++ features/project/merge_requests.feature | 9 +++++++++ features/steps/project/merge_requests.rb | 20 ++++++++++++++++++++ 5 files changed, 36 insertions(+) diff --git a/CHANGELOG b/CHANGELOG index 44c78ed62c6..fa0b3614599 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -28,6 +28,7 @@ v 8.2.0 (unreleased) - Allow groups to appear in the search results if the group owner allows it - New design for project graphs page - Fix incoming email config defaults + - MR target branch is now visible on a list view when it is different from project's default one v 8.1.4 - Fix bug where manually merged branches in a MR would end up with an empty diff (Stan Hu) diff --git a/app/controllers/projects/merge_requests_controller.rb b/app/controllers/projects/merge_requests_controller.rb index 16c42386623..b0788a2d073 100644 --- a/app/controllers/projects/merge_requests_controller.rb +++ b/app/controllers/projects/merge_requests_controller.rb @@ -31,6 +31,7 @@ class Projects::MergeRequestsController < Projects::ApplicationController end @merge_requests = @merge_requests.page(params[:page]).per(PER_PAGE) + @merge_requests = @merge_requests.preload(:target_project) respond_to do |format| format.html diff --git a/app/views/projects/merge_requests/_merge_request.html.haml b/app/views/projects/merge_requests/_merge_request.html.haml index 300a3715292..c5234c0618c 100644 --- a/app/views/projects/merge_requests/_merge_request.html.haml +++ b/app/views/projects/merge_requests/_merge_request.html.haml @@ -41,6 +41,11 @@ %span %i.fa.fa-clock-o = merge_request.milestone.title + - if merge_request.target_project.default_branch != merge_request.target_branch +   + %span + %i.fa.fa-code-fork + = merge_request.target_branch - if merge_request.tasks? %span.task-status = merge_request.task_status diff --git a/features/project/merge_requests.feature b/features/project/merge_requests.feature index f423c3ba542..6cd081c868e 100644 --- a/features/project/merge_requests.feature +++ b/features/project/merge_requests.feature @@ -16,6 +16,15 @@ Feature: Project Merge Requests When I visit project "Shop" merge requests page Then I should see merge request "Bug NS-05" with CI status + Scenario: I should not see target branch name when it is project's default branch + Then I should see "Bug NS-04" in merge requests + And I should not see "master" branch + + Scenario: I should see target branch when it is different from default + Given project "Shop" have "Bug NS-06" open merge request + When I visit project "Shop" merge requests page + Then I should see "other_branch" branch + Scenario: I should see rejected merge requests Given I click link "Closed" Then I should see "Feature NS-03" in merge requests diff --git a/features/steps/project/merge_requests.rb b/features/steps/project/merge_requests.rb index 92ec14d0d76..d5f2c4209a1 100644 --- a/features/steps/project/merge_requests.rb +++ b/features/steps/project/merge_requests.rb @@ -40,6 +40,14 @@ class Spinach::Features::ProjectMergeRequests < Spinach::FeatureSteps expect(page).to have_content "Bug NS-04" end + step 'I should not see "master" branch' do + expect(page).not_to have_content "master" + end + + step 'I should see "other_branch" branch' do + expect(page).to have_content "other_branch" + end + step 'I should see "Bug NS-04" in merge requests' do expect(page).to have_content "Bug NS-04" end @@ -93,6 +101,18 @@ class Spinach::Features::ProjectMergeRequests < Spinach::FeatureSteps ) end + step 'project "Shop" have "Bug NS-06" open merge request' do + create(:merge_request, + title: "Bug NS-06", + source_project: project, + target_project: project, + source_branch: 'fix', + target_branch: 'other_branch', + author: project.users.first, + description: "# Description header" + ) + end + step 'project "Shop" have "Bug NS-05" open merge request with diffs inside' do create(:merge_request_with_diffs, title: "Bug NS-05", -- cgit v1.2.1 From f3bf0fe7aca0672c406141ff88fffe623e507bdc Mon Sep 17 00:00:00 2001 From: Marco Vito Moscaritolo Date: Tue, 10 Nov 2015 11:25:28 +0100 Subject: Fix duplicate entry for 8.1.0 release Fix duplicate entry for 8.1.0 release and remove unreleased tag. --- CHANGELOG | 2 -- 1 file changed, 2 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index d11076f4848..843589eacfb 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -56,8 +56,6 @@ v 8.1.0 - Redirect to a default path if HTTP_REFERER is not set (Stan Hu) - Adds ability to create directories using the web editor (Ben Ford) - Cleanup stuck CI builds - -v 8.1.0 (unreleased) - Send an email to admin email when a user is reported for spam (Jonathan Rochkind) - Show notifications button when user is member of group rather than project (Grzegorz Bizon) - Fix bug preventing mentioned issued from being closed when MR is merged using fast-forward merge. -- cgit v1.2.1 From 1b7a2fc5363d7e2334f5c48940e8eca9d88354a6 Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Tue, 10 Nov 2015 11:49:38 +0100 Subject: Improve Continuous Integration graphs page * fix commit duration graph * make graphs responsive * fix wrong padding * add a bit of explanation to colors Signed-off-by: Dmitriy Zaporozhets --- app/views/projects/graphs/ci.html.haml | 16 ++++++--- app/views/projects/graphs/ci/_build_times.haml | 17 ++++----- app/views/projects/graphs/ci/_builds.haml | 48 ++++++++++++++++---------- app/views/projects/graphs/ci/_overall.haml | 16 ++++----- app/views/projects/graphs/commits.html.haml | 2 +- app/views/projects/graphs/show.html.haml | 2 +- lib/ci/charts.rb | 3 +- 7 files changed, 60 insertions(+), 44 deletions(-) diff --git a/app/views/projects/graphs/ci.html.haml b/app/views/projects/graphs/ci.html.haml index b2dfe97938a..6fa77cc10c6 100644 --- a/app/views/projects/graphs/ci.html.haml +++ b/app/views/projects/graphs/ci.html.haml @@ -1,10 +1,16 @@ - page_title "Continuous Integration", "Graphs" = render "header_title" = render 'head' -.gray-content-block - %ul.breadcrumb.repo-breadcrumb - = commits_breadcrumbs +.gray-content-block.append-bottom-default + .oneline + A collection of graphs for Continuous Integration + #charts.ci-charts + .row + .col-md-6 + = render 'projects/graphs/ci/overall' + .col-md-6 + = render 'projects/graphs/ci/build_times' + + %hr = render 'projects/graphs/ci/builds' - = render 'projects/graphs/ci/build_times' -= render 'projects/graphs/ci/overall' diff --git a/app/views/projects/graphs/ci/_build_times.haml b/app/views/projects/graphs/ci/_build_times.haml index c3c2f572414..c58223fd39e 100644 --- a/app/views/projects/graphs/ci/_build_times.haml +++ b/app/views/projects/graphs/ci/_build_times.haml @@ -1,21 +1,22 @@ -%fieldset - %legend +%div + %p.light Commit duration in minutes for last 30 commits - %canvas#build_timesChart.padded{width: 800, height: 300} + %canvas#build_timesChart{height: 200} :javascript var data = { labels : #{@charts[:build_times].labels.to_json}, datasets : [ { - fillColor : "#4A3", - strokeColor : "rgba(151,187,205,1)", - pointColor : "rgba(151,187,205,1)", - pointStrokeColor : "#fff", + fillColor : "rgba(220,220,220,0.5)", + strokeColor : "rgba(220,220,220,1)", + barStrokeWidth: 1, + barValueSpacing: 1, + barDatasetSpacing: 1, data : #{@charts[:build_times].build_times.to_json} } ] } var ctx = $("#build_timesChart").get(0).getContext("2d"); - new Chart(ctx).Line(data,{"scaleOverlay": true}); + new Chart(ctx).Bar(data,{"scaleOverlay": true, responsive: true, maintainAspectRatio: false}); diff --git a/app/views/projects/graphs/ci/_builds.haml b/app/views/projects/graphs/ci/_builds.haml index 1b0039fb834..84247455403 100644 --- a/app/views/projects/graphs/ci/_builds.haml +++ b/app/views/projects/graphs/ci/_builds.haml @@ -1,20 +1,30 @@ -%fieldset - %legend - Builds chart for last week - (#{date_from_to(Date.today - 7.days, Date.today)}) +%h4 Build charts +%p +   + %span.cgreen + = icon("circle") + success +   + %span.cgray + = icon("circle") + all - %canvas#weekChart.padded{width: 800, height: 200} +.prepend-top-default + %p.light + Builds for last week + (#{date_from_to(Date.today - 7.days, Date.today)}) + %canvas#weekChart{height: 200} -%fieldset - %legend +.prepend-top-default + %p.light Builds chart for last month (#{date_from_to(Date.today - 30.days, Date.today)}) + %canvas#monthChart{height: 200} - %canvas#monthChart.padded{width: 800, height: 300} - -%fieldset - %legend Builds chart for last year - %canvas#yearChart.padded{width: 800, height: 400} +.prepend-top-default + %p.light + Builds chart for last year + %canvas#yearChart.padded{height: 250} - [:week, :month, :year].each do |scope| :javascript @@ -22,20 +32,20 @@ labels : #{@charts[scope].labels.to_json}, datasets : [ { - fillColor : "rgba(220,220,220,0.5)", - strokeColor : "rgba(220,220,220,1)", - pointColor : "rgba(220,220,220,1)", + fillColor : "#7f8fa4", + strokeColor : "#7f8fa4", + pointColor : "#7f8fa4", pointStrokeColor : "#EEE", data : #{@charts[scope].total.to_json} }, { - fillColor : "#4A3", - strokeColor : "rgba(151,187,205,1)", - pointColor : "rgba(151,187,205,1)", + fillColor : "#44aa22", + strokeColor : "#44aa22", + pointColor : "#44aa22", pointStrokeColor : "#fff", data : #{@charts[scope].success.to_json} } ] } var ctx = $("##{scope}Chart").get(0).getContext("2d"); - new Chart(ctx).Line(data,{"scaleOverlay": true}); + new Chart(ctx).Line(data,{"scaleOverlay": true, responsive: true, maintainAspectRatio: false}); diff --git a/app/views/projects/graphs/ci/_overall.haml b/app/views/projects/graphs/ci/_overall.haml index 9550d719471..cf4285a2671 100644 --- a/app/views/projects/graphs/ci/_overall.haml +++ b/app/views/projects/graphs/ci/_overall.haml @@ -1,22 +1,20 @@ - ci_project = @project.gitlab_ci_project -%fieldset - %legend Overall - %p +%h4 Overall stats +%ul + %li Total: %strong= pluralize ci_project.builds.count(:all), 'build' - %p + %li Successful: %strong= pluralize ci_project.builds.success.count(:all), 'build' - %p + %li Failed: %strong= pluralize ci_project.builds.failed.count(:all), 'build' - - %p + %li Success ratio: %strong #{success_ratio(ci_project.builds.success, ci_project.builds.failed)}% - - %p + %li Commits covered: %strong = ci_project.commits.count(:all) diff --git a/app/views/projects/graphs/commits.html.haml b/app/views/projects/graphs/commits.html.haml index 4e0c3e5b3de..c03790aea06 100644 --- a/app/views/projects/graphs/commits.html.haml +++ b/app/views/projects/graphs/commits.html.haml @@ -2,7 +2,7 @@ = render "header_title" = render 'head' -.gray-content-block +.gray-content-block.append-bottom-default .tree-ref-holder = render 'shared/ref_switcher', destination: 'graphs_commits' %ul.breadcrumb.repo-breadcrumb diff --git a/app/views/projects/graphs/show.html.haml b/app/views/projects/graphs/show.html.haml index 6bbf15d05a2..84ee843d9b7 100644 --- a/app/views/projects/graphs/show.html.haml +++ b/app/views/projects/graphs/show.html.haml @@ -2,7 +2,7 @@ = render "header_title" = render 'head' -.gray-content-block +.gray-content-block.append-bottom-default .tree-ref-holder = render 'shared/ref_switcher', destination: 'graphs' %ul.breadcrumb.repo-breadcrumb diff --git a/lib/ci/charts.rb b/lib/ci/charts.rb index 915a4f526a6..5ff7407c6fe 100644 --- a/lib/ci/charts.rb +++ b/lib/ci/charts.rb @@ -60,7 +60,8 @@ module Ci class BuildTime < Chart def collect - commits = project.commits.joins(:builds).where("#{Ci::Build.table_name}.finished_at is NOT NULL AND #{Ci::Build.table_name}.started_at is NOT NULL").last(30) + commits = project.commits.last(30) + commits.each do |commit| @labels << commit.short_sha @build_times << (commit.duration / 60) -- cgit v1.2.1 From b1a1cadcc2056540e4eb5a6b48c87b83656633be Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Tue, 10 Nov 2015 11:51:58 +0100 Subject: Add changelog item Signed-off-by: Dmitriy Zaporozhets --- CHANGELOG | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG b/CHANGELOG index d11076f4848..fe521e0f140 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -28,6 +28,7 @@ v 8.2.0 (unreleased) - Allow groups to appear in the search results if the group owner allows it - New design for project graphs page - Fix incoming email config defaults + - Improve Continuous Integration graphs page v 8.1.4 - Fix bug where manually merged branches in a MR would end up with an empty diff (Stan Hu) -- cgit v1.2.1 From e8d97eb118ecbfe2a77abf2dcd56d7ab1cfac62a Mon Sep 17 00:00:00 2001 From: Kamil Trzcinski Date: Tue, 10 Nov 2015 12:01:29 +0100 Subject: Send build name and stage in CI notification e-mail --- CHANGELOG | 1 + app/views/ci/notify/build_fail_email.html.haml | 4 ++++ app/views/ci/notify/build_fail_email.text.erb | 2 ++ app/views/ci/notify/build_success_email.html.haml | 4 ++++ app/views/ci/notify/build_success_email.text.erb | 2 ++ 5 files changed, 13 insertions(+) diff --git a/CHANGELOG b/CHANGELOG index d11076f4848..19850b58f79 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -16,6 +16,7 @@ v 8.2.0 (unreleased) - Fix: Inability to reply to code comments in the MR view, if the MR comes from a fork - Use git follow flag for commits page when retrieve history for file or directory - Show merge request CI status on merge requests index page + - Send build name and stage in CI notification e-mail - Extend yml syntax for only and except to support specifying repository path - Enable shared runners to all new projects - Fix: 500 error returned if destroy request without HTTP referer (Kazuki Shimizu) diff --git a/app/views/ci/notify/build_fail_email.html.haml b/app/views/ci/notify/build_fail_email.html.haml index cefb75040e9..b0aaea89075 100644 --- a/app/views/ci/notify/build_fail_email.html.haml +++ b/app/views/ci/notify/build_fail_email.html.haml @@ -12,6 +12,10 @@ Author: #{@build.commit.git_author_name} %p Branch: #{@build.ref} +%p + Stage: #{@build.stage} +%p + Job: #{@build.name} %p Message: #{@build.commit.git_commit_message} diff --git a/app/views/ci/notify/build_fail_email.text.erb b/app/views/ci/notify/build_fail_email.text.erb index 6de5dc10f17..17a3b9b1d33 100644 --- a/app/views/ci/notify/build_fail_email.text.erb +++ b/app/views/ci/notify/build_fail_email.text.erb @@ -4,6 +4,8 @@ Status: <%= @build.status %> Commit: <%= @build.commit.short_sha %> Author: <%= @build.commit.git_author_name %> Branch: <%= @build.ref %> +Stage: <%= @build.stage %> +Job: <%= @build.name %> Message: <%= @build.commit.git_commit_message %> Url: <%= namespace_project_build_url(@build.gl_project.namespace, @build.gl_project, @build) %> diff --git a/app/views/ci/notify/build_success_email.html.haml b/app/views/ci/notify/build_success_email.html.haml index 617b88f7345..24c439e50eb 100644 --- a/app/views/ci/notify/build_success_email.html.haml +++ b/app/views/ci/notify/build_success_email.html.haml @@ -13,6 +13,10 @@ Author: #{@build.commit.git_author_name} %p Branch: #{@build.ref} +%p + Stage: #{@build.stage} +%p + Job: #{@build.name} %p Message: #{@build.commit.git_commit_message} diff --git a/app/views/ci/notify/build_success_email.text.erb b/app/views/ci/notify/build_success_email.text.erb index d0a43ae1c12..bc8b978c3d7 100644 --- a/app/views/ci/notify/build_success_email.text.erb +++ b/app/views/ci/notify/build_success_email.text.erb @@ -4,6 +4,8 @@ Status: <%= @build.status %> Commit: <%= @build.commit.short_sha %> Author: <%= @build.commit.git_author_name %> Branch: <%= @build.ref %> +Stage: <%= @build.stage %> +Job: <%= @build.name %> Message: <%= @build.commit.git_commit_message %> Url: <%= namespace_project_build_url(@build.gl_project.namespace, @build.gl_project, @build) %> -- cgit v1.2.1 From 18cb430f7983ea557cf2308f5ea7c0af8b79a7b5 Mon Sep 17 00:00:00 2001 From: Jason Lee Date: Tue, 10 Nov 2015 19:17:37 +0800 Subject: Replace CoffeeScript block into JavaScript in Views. For example view: shared/issuable/_context CoffeeScript: 190ms JavaScript: 19.7ms --- app/views/admin/labels/_form.html.haml | 4 +- app/views/ci/lints/show.html.haml | 16 ++++--- app/views/groups/group_members/index.html.haml | 9 ++-- app/views/help/_shortcuts.html.haml | 8 ++-- app/views/import/bitbucket/status.html.haml | 4 +- app/views/import/fogbugz/new_user_map.html.haml | 6 +-- app/views/import/fogbugz/status.html.haml | 4 +- app/views/import/github/status.html.haml | 4 +- app/views/import/gitlab/status.html.haml | 4 +- app/views/import/gitorious/status.html.haml | 4 +- app/views/import/google_code/status.html.haml | 4 +- app/views/layouts/_search.html.haml | 4 +- app/views/projects/_activity.html.haml | 4 +- app/views/projects/blob/_new_dir.html.haml | 2 +- app/views/projects/blob/_upload.html.haml | 6 +-- app/views/projects/buttons/_star.html.haml | 12 ++--- app/views/projects/commit/_commit_box.html.haml | 4 +- app/views/projects/graphs/commits.html.haml | 52 +++++++++++----------- app/views/projects/graphs/show.html.haml | 21 +++++---- .../projects/merge_requests/_new_compare.html.haml | 17 +++---- .../merge_requests/widget/_heading.html.haml | 7 +-- .../merge_requests/widget/_merged.html.haml | 31 +++++++------ .../merge_requests/widget/open/_accept.html.haml | 11 ++--- .../merge_requests/widget/open/_check.html.haml | 8 ++-- app/views/projects/new.html.haml | 14 +++--- app/views/projects/project_members/index.html.haml | 9 ++-- app/views/shared/issuable/_context.html.haml | 6 +-- app/views/shared/issuable/_filter.html.haml | 12 ++--- app/views/shared/projects/_list.html.haml | 4 +- app/views/users/show.html.haml | 4 +- 30 files changed, 157 insertions(+), 138 deletions(-) diff --git a/app/views/admin/labels/_form.html.haml b/app/views/admin/labels/_form.html.haml index ad58a3837f6..a5ace4e7a3b 100644 --- a/app/views/admin/labels/_form.html.haml +++ b/app/views/admin/labels/_form.html.haml @@ -31,5 +31,5 @@ = f.submit 'Save', class: 'btn btn-save js-save-button' = link_to "Cancel", admin_labels_path, class: 'btn btn-cancel' -:coffeescript - new Labels +:javascript + new Labels(); diff --git a/app/views/ci/lints/show.html.haml b/app/views/ci/lints/show.html.haml index a9b954771c5..fb9057e4882 100644 --- a/app/views/ci/lints/show.html.haml +++ b/app/views/ci/lints/show.html.haml @@ -11,15 +11,17 @@ .controls.pull-left.prepend-top-10 = submit_tag "Validate", class: 'btn btn-success submit-yml' - + %p.text-center.loading %i.fa.fa-refresh.fa-spin .results.prepend-top-20 -:coffeescript - $(".loading").hide() - $('form').bind 'ajax:beforeSend', -> - $(".loading").show() - $('form').bind 'ajax:complete', -> - $(".loading").hide() +:javascript + $(".loading").hide(); + $('form').bind('ajax:beforeSend', function() { + $(".loading").show(); + }); + $('form').bind('ajax:complete', function() { + $(".loading").hide(); + }); diff --git a/app/views/groups/group_members/index.html.haml b/app/views/groups/group_members/index.html.haml index fee4b0052b5..15d289471c9 100644 --- a/app/views/groups/group_members/index.html.haml +++ b/app/views/groups/group_members/index.html.haml @@ -36,7 +36,8 @@ = paginate @members, theme: 'gitlab' -:coffeescript - $('form.member-search-form').on 'submit', (event) -> - event.preventDefault() - Turbolinks.visit @.action + '?' + $(@).serialize() +:javascript + $('form.member-search-form').on('submit', function(event) { + event.preventDefault(); + Turbolinks.visit(this.action + '?' + $(this).serialize()); + }); diff --git a/app/views/help/_shortcuts.html.haml b/app/views/help/_shortcuts.html.haml index 67349fcbd78..7e801b5332d 100644 --- a/app/views/help/_shortcuts.html.haml +++ b/app/views/help/_shortcuts.html.haml @@ -222,8 +222,8 @@ :javascript - $('.js-more-help-button').click(function(e){ - $(this).remove() - $('.hidden-shortcut').show() - e.preventDefault() + $('.js-more-help-button').click(function (e) { + $(this).remove()l + $('.hidden-shortcut').show(); + e.preventDefault(); }); diff --git a/app/views/import/bitbucket/status.html.haml b/app/views/import/bitbucket/status.html.haml index 30bcdb86827..1f09a27e2d6 100644 --- a/app/views/import/bitbucket/status.html.haml +++ b/app/views/import/bitbucket/status.html.haml @@ -66,5 +66,5 @@ again. -:coffeescript - new ImporterStatus("#{jobs_import_bitbucket_path}", "#{import_bitbucket_path}") +:javascript + new ImporterStatus("#{jobs_import_bitbucket_path}", "#{import_bitbucket_path}"); diff --git a/app/views/import/fogbugz/new_user_map.html.haml b/app/views/import/fogbugz/new_user_map.html.haml index a701e49ac56..bc3c90294e3 100644 --- a/app/views/import/fogbugz/new_user_map.html.haml +++ b/app/views/import/fogbugz/new_user_map.html.haml @@ -22,7 +22,7 @@ %strong Map a FogBugz account ID to a GitLab user %p Selecting a GitLab user will add a link to the GitLab user in the descriptions - of issues and comments (e.g. "By @johnsmith"). It will also + of issues and comments (e.g. "By @johnsmith"). It will also associate and/or assign these issues and comments with the selected user. .table-holder @@ -46,5 +46,5 @@ .form-actions = submit_tag 'Continue to the next step', class: 'btn btn-create' -:coffeescript - new UsersSelect() +:javascript + new UsersSelect(); diff --git a/app/views/import/fogbugz/status.html.haml b/app/views/import/fogbugz/status.html.haml index beca6ab1423..b902006597b 100644 --- a/app/views/import/fogbugz/status.html.haml +++ b/app/views/import/fogbugz/status.html.haml @@ -48,5 +48,5 @@ %td.import-actions.job-status = button_tag "Import", class: "btn js-add-to-import" -:coffeescript - new ImporterStatus("#{jobs_import_fogbugz_path}", "#{import_fogbugz_path}") +:javascript + new ImporterStatus("#{jobs_import_fogbugz_path}", "#{import_fogbugz_path}"); diff --git a/app/views/import/github/status.html.haml b/app/views/import/github/status.html.haml index 0669b05adca..0699321c8c0 100644 --- a/app/views/import/github/status.html.haml +++ b/app/views/import/github/status.html.haml @@ -43,5 +43,5 @@ %td.import-actions.job-status = button_tag "Import", class: "btn js-add-to-import" -:coffeescript - new ImporterStatus("#{jobs_import_github_path}", "#{import_github_path}") +:javascript + new ImporterStatus("#{jobs_import_github_path}", "#{import_github_path}"); diff --git a/app/views/import/gitlab/status.html.haml b/app/views/import/gitlab/status.html.haml index 3bc85059e7d..f4a2b33af21 100644 --- a/app/views/import/gitlab/status.html.haml +++ b/app/views/import/gitlab/status.html.haml @@ -43,5 +43,5 @@ %td.import-actions.job-status = button_tag "Import", class: "btn js-add-to-import" -:coffeescript - new ImporterStatus("#{jobs_import_gitlab_path}", "#{import_gitlab_path}") +:javascript + new ImporterStatus("#{jobs_import_gitlab_path}", "#{import_gitlab_path}"); diff --git a/app/views/import/gitorious/status.html.haml b/app/views/import/gitorious/status.html.haml index 2e3a535737f..71752d21efa 100644 --- a/app/views/import/gitorious/status.html.haml +++ b/app/views/import/gitorious/status.html.haml @@ -43,5 +43,5 @@ %td.import-actions.job-status = button_tag "Import", class: "btn js-add-to-import" -:coffeescript - new ImporterStatus("#{jobs_import_gitorious_path}", "#{import_gitorious_path}") +:javascript + new ImporterStatus("#{jobs_import_gitorious_path}", "#{import_gitorious_path}"); diff --git a/app/views/import/google_code/status.html.haml b/app/views/import/google_code/status.html.haml index c5af06edf87..8c64fd27e60 100644 --- a/app/views/import/google_code/status.html.haml +++ b/app/views/import/google_code/status.html.haml @@ -67,5 +67,5 @@ = link_to "import flow", new_import_google_code_path again. -:coffeescript - new ImporterStatus("#{jobs_import_google_code_path}", "#{import_google_code_path}") +:javascript + new ImporterStatus("#{jobs_import_google_code_path}", "#{import_google_code_path}"); diff --git a/app/views/layouts/_search.html.haml b/app/views/layouts/_search.html.haml index d1aa8f62463..a44f5762a6b 100644 --- a/app/views/layouts/_search.html.haml +++ b/app/views/layouts/_search.html.haml @@ -25,6 +25,6 @@ :javascript $('.search-input').on('keyup', function(e) { if (e.keyCode == 27) { - $('.search-input').blur() + $('.search-input').blur(); } - }) + }); diff --git a/app/views/projects/_activity.html.haml b/app/views/projects/_activity.html.haml index 012858f70b4..101880bd105 100644 --- a/app/views/projects/_activity.html.haml +++ b/app/views/projects/_activity.html.haml @@ -8,5 +8,5 @@ .content_list{:"data-href" => activity_project_path(@project)} = spinner -:coffeescript - new Activities() +:javascript + new Activities(); diff --git a/app/views/projects/blob/_new_dir.html.haml b/app/views/projects/blob/_new_dir.html.haml index cb1567a2e68..a0fc8bbd752 100644 --- a/app/views/projects/blob/_new_dir.html.haml +++ b/app/views/projects/blob/_new_dir.html.haml @@ -21,5 +21,5 @@ = submit_tag "Create directory", class: 'btn btn-primary btn-create' = link_to "Cancel", '#', class: "btn btn-cancel", "data-dismiss" => "modal" -:coffeescript +:javascript disableButtonIfAnyEmptyField($("#dir-create-form"), ".form-control", ".btn-create"); diff --git a/app/views/projects/blob/_upload.html.haml b/app/views/projects/blob/_upload.html.haml index e27f1707527..a1c54e731f0 100644 --- a/app/views/projects/blob/_upload.html.haml +++ b/app/views/projects/blob/_upload.html.haml @@ -26,6 +26,6 @@ = button_tag button_title, class: 'btn btn-small btn-primary btn-upload-file', id: 'submit-all' = link_to "Cancel", '#', class: "btn btn-cancel", "data-dismiss" => "modal" -:coffeescript - disableButtonIfEmptyField $('.blob-file-upload-form-js').find('#commit_message'), '.btn-upload-file' - new BlobFileDropzone($('.blob-file-upload-form-js'), '#{method}') +:javascript + disableButtonIfEmptyField($('.blob-file-upload-form-js').find('#commit_message'), '.btn-upload-file'); + new BlobFileDropzone($('.blob-file-upload-form-js'), '#{method}'); diff --git a/app/views/projects/buttons/_star.html.haml b/app/views/projects/buttons/_star.html.haml index 3501dddefbe..06583902035 100644 --- a/app/views/projects/buttons/_star.html.haml +++ b/app/views/projects/buttons/_star.html.haml @@ -4,11 +4,13 @@ %span.count = @project.star_count - :coffeescript - $('.project-home-panel .toggle-star').on 'ajax:success', (e, data, status, xhr) -> - $(@).replaceWith(data.html) - .on 'ajax:error', (e, xhr, status, error) -> - new Flash('Star toggle failed. Try again later.', 'alert') + :javascript + $('.project-home-panel .toggle-star').on('ajax:success', function (e, data, status, xhr) { + $(this).replaceWith(data.html); + }) + .on('ajax:error', function (e, xhr, status, error) { + new Flash('Star toggle failed. Try again later.', 'alert'); + }); - else = link_to new_user_session_path, class: 'btn has_tooltip star-btn', title: 'You must sign in to star a project' do diff --git a/app/views/projects/commit/_commit_box.html.haml b/app/views/projects/commit/_commit_box.html.haml index a6458b84860..776768537d0 100644 --- a/app/views/projects/commit/_commit_box.html.haml +++ b/app/views/projects/commit/_commit_box.html.haml @@ -55,5 +55,5 @@ %pre.commit-description = preserve(gfm(escape_once(@commit.description))) -:coffeescript - $(".commit-info-row.branches").load("#{branches_namespace_project_commit_path(@project.namespace, @project, @commit.id)}") +:javascript + $(".commit-info-row.branches").load("#{branches_namespace_project_commit_path(@project.namespace, @project, @commit.id)}"); diff --git a/app/views/projects/graphs/commits.html.haml b/app/views/projects/graphs/commits.html.haml index 4e0c3e5b3de..eb33da7a5bb 100644 --- a/app/views/projects/graphs/commits.html.haml +++ b/app/views/projects/graphs/commits.html.haml @@ -49,26 +49,24 @@ Commits per weekday %canvas#weekday-chart -:coffeescript - responsiveChart = (selector, data) -> - options = { "scaleOverlay": true, responsive: true, pointHitDetectionRadius: 2, maintainAspectRatio: false } +:javascript + var responsiveChart = function (selector, data) { + var options = { "scaleOverlay": true, responsive: true, pointHitDetectionRadius: 2, maintainAspectRatio: false }; + // get selector by context + var ctx = selector.get(0).getContext("2d"); + // pointing parent container to make chart.js inherit its width + var container = $(selector).parent(); + var generateChart = function() { + selector.attr('width', $(container).width()); + return new Chart(ctx).Bar(data, options); + }; + // enabling auto-resizing + $(window).resize(generateChart); + return generateChart(); + }; - # get selector by context - ctx = selector.get(0).getContext("2d") - # pointing parent container to make chart.js inherit its width - container = $(selector).parent() - - generateChart = -> - selector.attr('width', $(container).width()) - new Chart(ctx).Bar(data, options) - - # enabling auto-resizing - $(window).resize( generateChart ) - - generateChart() - - chartData = (keys, values) -> - data = { + var chartData = function (keys, values) { + var data = { labels : keys, datasets : [{ fillColor : "rgba(220,220,220,0.5)", @@ -78,13 +76,15 @@ barDatasetSpacing: 1, data : values }] - } + }; + return data; + }; - hourData = chartData(#{@commits_per_time.keys.to_json}, #{@commits_per_time.values.to_json}) - responsiveChart($('#hour-chart'), hourData) + var hourData = chartData(#{@commits_per_time.keys.to_json}, #{@commits_per_time.values.to_json}); + responsiveChart($('#hour-chart'), hourData); - dayData = chartData(#{@commits_per_week_days.keys.to_json}, #{@commits_per_week_days.values.to_json}) - responsiveChart($('#weekday-chart'), dayData) + var dayData = chartData(#{@commits_per_week_days.keys.to_json}, #{@commits_per_week_days.values.to_json}); + responsiveChart($('#weekday-chart'), dayData); - monthData = chartData(#{@commits_per_month.keys.to_json}, #{@commits_per_month.values.to_json}) - responsiveChart($('#month-chart'), monthData) + var monthData = chartData(#{@commits_per_month.keys.to_json}, #{@commits_per_month.values.to_json}); + responsiveChart($('#month-chart'), monthData); diff --git a/app/views/projects/graphs/show.html.haml b/app/views/projects/graphs/show.html.haml index 6bbf15d05a2..9e1feadeb26 100644 --- a/app/views/projects/graphs/show.html.haml +++ b/app/views/projects/graphs/show.html.haml @@ -28,18 +28,21 @@ -:coffeescript - $.ajax +:javascript + $.ajax({ type: "GET", url: location.href, - success: (data) -> - graph = new ContributorsStatGraph() - graph.init(data) + dataType: "json", + success: function (data) { + var graph = new ContributorsStatGraph(); + graph.init(data); - $("#brush_change").change -> - graph.change_date_header() - graph.redraw_authors() + $("#brush_change").change(function(){ + graph.change_date_header(); + graph.redraw_authors(); + }); $(".stat-graph").fadeIn(); $(".loading-graph").hide(); - dataType: "json" + } + }); diff --git a/app/views/projects/merge_requests/_new_compare.html.haml b/app/views/projects/merge_requests/_new_compare.html.haml index 452006162db..d9eff1f9320 100644 --- a/app/views/projects/merge_requests/_new_compare.html.haml +++ b/app/views/projects/merge_requests/_new_compare.html.haml @@ -77,12 +77,13 @@ }); -:coffeescript - - $(".merge-request-form").on 'submit', -> - if $("#merge_request_source_branch").val() is "" or $('#merge_request_target_branch').val() is "" - $(".mr-compare-errors").html("You must select source and target branch to proceed") - $(".mr-compare-errors").fadeIn() - event.preventDefault() - return +:javascript + $(".merge-request-form").on('submit', function () { + if ($("#merge_request_source_branch").val() === "" || $('#merge_request_target_branch').val() === "") { + $(".mr-compare-errors").html("You must select source and target branch to proceed"); + $(".mr-compare-errors").fadeIn(); + event.preventDefault(); + return; + } + }); diff --git a/app/views/projects/merge_requests/widget/_heading.html.haml b/app/views/projects/merge_requests/widget/_heading.html.haml index a3551516bfe..ba5ad22bca7 100644 --- a/app/views/projects/merge_requests/widget/_heading.html.haml +++ b/app/views/projects/merge_requests/widget/_heading.html.haml @@ -38,6 +38,7 @@ = icon("times-circle") Could not connect to the CI server. Please check your settings and try again. - :coffeescript - $ -> - merge_request_widget.getCiStatus() + :javascript + $(function() { + merge_request_widget.getCiStatus(); + }); diff --git a/app/views/projects/merge_requests/widget/_merged.html.haml b/app/views/projects/merge_requests/widget/_merged.html.haml index f223f687def..a788fcea23f 100644 --- a/app/views/projects/merge_requests/widget/_merged.html.haml +++ b/app/views/projects/merge_requests/widget/_merged.html.haml @@ -15,7 +15,7 @@ - elsif can_remove_branch?(@merge_request.source_project, @merge_request.source_branch) .remove_source_branch_widget - %p + %p = succeed '.' do The changes were merged into %span.label-branch= @merge_request.target_branch @@ -25,7 +25,7 @@ Remove Source Branch .remove_source_branch_widget.failed.hide - %p + %p Failed to remove source branch '#{@merge_request.source_branch}'. .remove_source_branch_in_progress.hide @@ -33,17 +33,20 @@ = icon('spinner spin') Removing source branch '#{@merge_request.source_branch}'. Please wait. This page will be automatically reload. - :coffeescript - $('.remove_source_branch').on 'click', -> - $('.remove_source_branch_widget').hide() - $('.remove_source_branch_in_progress').show() - - $(".remove_source_branch").on "ajax:success", (e, data, status, xhr) -> - location.reload() - - $(".remove_source_branch").on "ajax:error", (e, data, status, xhr) -> - $('.remove_source_branch_widget').hide() - $('.remove_source_branch_in_progress').hide() - $('.remove_source_branch_widget.failed').show() + :javascript + $('.remove_source_branch').on('click', function() { + $('.remove_source_branch_widget').hide(); + $('.remove_source_branch_in_progress').show(); + }); + + $(".remove_source_branch").on("ajax:success", function (e, data, status, xhr) { + location.reload(); + }); + + $(".remove_source_branch").on("ajax:error", function (e, data, status, xhr) { + $('.remove_source_branch_widget').hide(); + $('.remove_source_branch_in_progress').hide(); + $('.remove_source_branch_widget.failed').show(); + }); diff --git a/app/views/projects/merge_requests/widget/open/_accept.html.haml b/app/views/projects/merge_requests/widget/open/_accept.html.haml index 689247f3186..9b31014b581 100644 --- a/app/views/projects/merge_requests/widget/open/_accept.html.haml +++ b/app/views/projects/merge_requests/widget/open/_accept.html.haml @@ -20,8 +20,9 @@ text: @merge_request.merge_commit_message, rows: 14, hint: true - :coffeescript - $('.accept-mr-form').on 'ajax:before', -> - btn = $('.accept_merge_request') - btn.disable() - btn.html(" Merge in progress") + :javascript + $('.accept-mr-form').on('ajax:before', function() { + var btn = $('.accept_merge_request'); + btn.disable(); + btn.html(" Merge in progress"); + }); diff --git a/app/views/projects/merge_requests/widget/open/_check.html.haml b/app/views/projects/merge_requests/widget/open/_check.html.haml index b6b8974297e..e16878ba513 100644 --- a/app/views/projects/merge_requests/widget/open/_check.html.haml +++ b/app/views/projects/merge_requests/widget/open/_check.html.haml @@ -2,6 +2,8 @@ = icon("spinner spin") Checking ability to merge automatically… -:coffeescript - $ -> - merge_request_widget.getMergeStatus() +:javascript + $(function() { + merge_request_widget.getMergeStatus(); + }); + diff --git a/app/views/projects/new.html.haml b/app/views/projects/new.html.haml index daab2326bc7..a02c12f06a8 100644 --- a/app/views/projects/new.html.haml +++ b/app/views/projects/new.html.haml @@ -124,9 +124,11 @@ Creating project & repository. %p Please wait a moment, this page will automatically refresh when ready. -:coffeescript - $('.how_to_import_link').bind 'click', (e) -> - e.preventDefault() - import_modal = $(this).next(".modal").show() - $('.modal-header .close').bind 'click', -> - $(".modal").hide() +:javascript + $('.how_to_import_link').bind('click', function (e) { + e.preventDefault(); + var import_modal = $(this).next(".modal").show(); + }); + $('.modal-header .close').bind('click', function() { + $(".modal").hide(); + }); diff --git a/app/views/projects/project_members/index.html.haml b/app/views/projects/project_members/index.html.haml index 82809bec5b8..9fc4be583cc 100644 --- a/app/views/projects/project_members/index.html.haml +++ b/app/views/projects/project_members/index.html.haml @@ -29,7 +29,8 @@ - if @group = render "group_members", members: @group_members -:coffeescript - $('form.member-search-form').on 'submit', (event) -> - event.preventDefault() - Turbolinks.visit @.action + '?' + $(@).serialize() +:javascript + $('form.member-search-form').on('submit', function (event) { + event.preventDefault(); + Turbolinks.visit(this.action + '?' + $(this).serialize()); + }); diff --git a/app/views/shared/issuable/_context.html.haml b/app/views/shared/issuable/_context.html.haml index cba18c14568..be66256c7b0 100644 --- a/app/views/shared/issuable/_context.html.haml +++ b/app/views/shared/issuable/_context.html.haml @@ -45,6 +45,6 @@ .description-block.subscribed{class: ( 'hidden' unless subscribed )} You're receiving notifications because you're subscribed to this thread. -:coffeescript - new Subscription("#{toggle_subscription_path(issuable)}") - new IssuableContext() +:javascript + new Subscription("#{toggle_subscription_path(issuable)}"); + new IssuableContext(); diff --git a/app/views/shared/issuable/_filter.html.haml b/app/views/shared/issuable/_filter.html.haml index 0e4e9c0987a..d1231438ee4 100644 --- a/app/views/shared/issuable/_filter.html.haml +++ b/app/views/shared/issuable/_filter.html.haml @@ -60,9 +60,9 @@ = hidden_field_tag :state_event, params[:state_event] = button_tag "Update issues", class: "btn update_selected_issues btn-save" -:coffeescript - new UsersSelect() - - $('form.filter-form').on 'submit', (event) -> - event.preventDefault() - Turbolinks.visit @.action + '&' + $(@).serialize() +:javascript + new UsersSelect(); + $('form.filter-form').on('submit', function (event) { + event.preventDefault(); + Turbolinks.visit(this.action + '&' + $(this).serialize()); + }); diff --git a/app/views/shared/projects/_list.html.haml b/app/views/shared/projects/_list.html.haml index 357cfd6a370..e5ffe1e29ae 100644 --- a/app/views/shared/projects/_list.html.haml +++ b/app/views/shared/projects/_list.html.haml @@ -17,5 +17,5 @@ = link_to '#', class: 'js-expand' do Show all -:coffeescript - new ProjectsList() +:javascript + new ProjectsList(); diff --git a/app/views/users/show.html.haml b/app/views/users/show.html.haml index 5a15c6c244a..30992412184 100644 --- a/app/views/users/show.html.haml +++ b/app/views/users/show.html.haml @@ -115,5 +115,5 @@ projects: @projects.sort_by(&:star_count).reverse, projects_limit: 10, stars: true, avatar: true -:coffeescript - $(".user-calendar").load("#{user_calendar_path}") +:javascript + $(".user-calendar").load("#{user_calendar_path}"); -- cgit v1.2.1 From d0e3e823a2dd56260550aec648b0cbfae64543ae Mon Sep 17 00:00:00 2001 From: Kamil Trzcinski Date: Mon, 12 Oct 2015 23:47:32 +0200 Subject: Implement Build Artifacts - Offloads uploading to GitLab Workhorse - Use /authorize request for fast uploading - Added backup recipes for artifacts - Support download acceleration using X-Sendfile --- .gitignore | 3 + CHANGELOG | 1 + Gemfile | 2 +- Gemfile.lock | 6 +- .../admin/application_settings_controller.rb | 1 + app/controllers/projects/builds_controller.rb | 27 +++ app/models/ability.rb | 1 + app/models/application_setting.rb | 1 + app/models/ci/build.rb | 17 ++ app/models/commit_status.rb | 4 + app/uploaders/artifact_uploader.rb | 50 ++++++ .../admin/application_settings/_form.html.haml | 5 + app/views/projects/builds/show.html.haml | 3 + .../commit_statuses/_commit_status.html.haml | 3 + config/initializers/1_settings.rb | 1 + config/routes.rb | 1 + .../20151013092124_add_artifacts_file_to_builds.rb | 5 + ...d_max_artifacts_size_to_application_settings.rb | 5 + db/schema.rb | 4 +- doc/ci/yaml/README.md | 15 ++ doc/install/installation.md | 5 + doc/raketasks/backup_restore.md | 3 +- lib/api/helpers.rb | 44 +++++ lib/backup/artifacts.rb | 13 ++ lib/backup/manager.rb | 2 +- lib/ci/api/api.rb | 1 + lib/ci/api/builds.rb | 102 +++++++++++ lib/ci/api/entities.rb | 7 + lib/ci/api/helpers.rb | 11 ++ lib/ci/gitlab_ci_yaml_processor.rb | 9 +- lib/file_streamer.rb | 16 ++ lib/gitlab/current_settings.rb | 1 + lib/support/nginx/gitlab | 16 ++ lib/support/nginx/gitlab-ssl | 16 ++ lib/tasks/gitlab/backup.rake | 21 +++ lib/uploaded_file.rb | 37 ++++ shared/artifacts/.gitkeep | 0 shared/tmp/artifacts-cache/.gitkeep | 0 shared/tmp/artifacts-uploads/.gitkeep | 0 spec/features/builds_spec.rb | 21 +++ spec/features/commits_spec.rb | 16 +- spec/lib/ci/gitlab_ci_yaml_processor_spec.rb | 38 +++++ spec/models/build_spec.rb | 15 ++ spec/requests/api/users_spec.rb | 15 +- spec/requests/ci/api/builds_spec.rb | 186 ++++++++++++++++++++- spec/tasks/gitlab/backup_rake_spec.rb | 14 +- 46 files changed, 740 insertions(+), 24 deletions(-) create mode 100644 app/uploaders/artifact_uploader.rb create mode 100644 db/migrate/20151013092124_add_artifacts_file_to_builds.rb create mode 100644 db/migrate/20151109100728_add_max_artifacts_size_to_application_settings.rb create mode 100644 lib/backup/artifacts.rb create mode 100644 lib/file_streamer.rb create mode 100644 lib/uploaded_file.rb create mode 100644 shared/artifacts/.gitkeep create mode 100644 shared/tmp/artifacts-cache/.gitkeep create mode 100644 shared/tmp/artifacts-uploads/.gitkeep diff --git a/.gitignore b/.gitignore index 73bde4cc761..fd137a50473 100644 --- a/.gitignore +++ b/.gitignore @@ -37,6 +37,9 @@ nohup.out public/assets/ public/uploads.* public/uploads/ +shared/artifacts/ +shared/tmp/artifacts-uploads/ +shared/tmp/artifacts-cache/ rails_best_practices_output.html /tags tmp/ diff --git a/CHANGELOG b/CHANGELOG index d11076f4848..e54e7329ca1 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -95,6 +95,7 @@ v 8.1.0 (unreleased) - Show CI status on Your projects page and Starred projects page - Remove "Continuous Integration" page from dashboard - Add notes and SSL verification entries to hook APIs (Ben Boeckel) + - Added build artifacts - Fix grammar in admin area "labels" .nothing-here-block when no labels exist. - Move CI runners page to project settings area - Move CI variables page to project settings area diff --git a/Gemfile b/Gemfile index 51848621b64..49e35e873ba 100644 --- a/Gemfile +++ b/Gemfile @@ -54,7 +54,7 @@ gem 'gollum-lib', '~> 4.0.2' gem "github-linguist", "~> 4.7.0", require: "linguist" # API -gem 'grape', '~> 0.6.1' +gem 'grape', '~> 0.13.0' gem 'grape-entity', '~> 0.4.2' gem 'rack-cors', '~> 0.4.0', require: 'rack/cors' diff --git a/Gemfile.lock b/Gemfile.lock index d358e236302..310694ff6af 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -306,10 +306,10 @@ GEM gon (5.0.4) actionpack (>= 2.3.0) json - grape (0.6.1) + grape (0.13.0) activesupport builder - hashie (>= 1.2.0) + hashie (>= 2.1.0) multi_json (>= 1.3.2) multi_xml (>= 0.5.2) rack (>= 1.3.0) @@ -829,7 +829,7 @@ DEPENDENCIES gitlab_omniauth-ldap (~> 1.2.1) gollum-lib (~> 4.0.2) gon (~> 5.0.0) - grape (~> 0.6.1) + grape (~> 0.13.0) grape-entity (~> 0.4.2) haml-rails (~> 0.9.0) hipchat (~> 1.5.0) diff --git a/app/controllers/admin/application_settings_controller.rb b/app/controllers/admin/application_settings_controller.rb index 3d9c59050ff..a9bcfc7456a 100644 --- a/app/controllers/admin/application_settings_controller.rb +++ b/app/controllers/admin/application_settings_controller.rb @@ -58,6 +58,7 @@ class Admin::ApplicationSettingsController < Admin::ApplicationController :admin_notification_email, :user_oauth_applications, :shared_runners_enabled, + :max_artifacts_size, restricted_visibility_levels: [], import_sources: [] ) diff --git a/app/controllers/projects/builds_controller.rb b/app/controllers/projects/builds_controller.rb index 953f30e7c03..4638f77b887 100644 --- a/app/controllers/projects/builds_controller.rb +++ b/app/controllers/projects/builds_controller.rb @@ -3,6 +3,7 @@ class Projects::BuildsController < Projects::ApplicationController before_action :build, except: [:index, :cancel_all] before_action :authorize_manage_builds!, except: [:index, :show, :status] + before_action :authorize_download_build_artifacts!, only: [:download] layout "project" @@ -51,6 +52,18 @@ class Projects::BuildsController < Projects::ApplicationController redirect_to build_path(build) end + def download + unless artifacts_file.file_storage? + return redirect_to artifacts_file.url + end + + unless artifacts_file.exists? + return not_found! + end + + send_file artifacts_file.path, disposition: 'attachment' + end + def status render json: @build.to_json(only: [:status, :id, :sha, :coverage], methods: :sha) end @@ -67,6 +80,10 @@ class Projects::BuildsController < Projects::ApplicationController @build ||= ci_project.builds.unscoped.find_by!(id: params[:id]) end + def artifacts_file + build.artifacts_file + end + def build_path(build) namespace_project_build_path(build.gl_project.namespace, build.gl_project, build) end @@ -76,4 +93,14 @@ class Projects::BuildsController < Projects::ApplicationController return page_404 end end + + def authorize_download_build_artifacts! + unless can?(current_user, :download_build_artifacts, @project) + if current_user.nil? + return authenticate_user! + else + return render_404 + end + end + end end diff --git a/app/models/ability.rb b/app/models/ability.rb index b72178fa126..5ae28d5133e 100644 --- a/app/models/ability.rb +++ b/app/models/ability.rb @@ -154,6 +154,7 @@ class Ability :create_merge_request, :create_wiki, :manage_builds, + :download_build_artifacts, :push_code ] end diff --git a/app/models/application_setting.rb b/app/models/application_setting.rb index 266045f7afa..fa7cf2464ad 100644 --- a/app/models/application_setting.rb +++ b/app/models/application_setting.rb @@ -89,6 +89,7 @@ class ApplicationSetting < ActiveRecord::Base restricted_signup_domains: Settings.gitlab['restricted_signup_domains'], import_sources: ['github','bitbucket','gitlab','gitorious','google_code','fogbugz','git'], shared_runners_enabled: Settings.gitlab_ci['shared_runners_enabled'], + max_artifacts_size: Settings.gitlab_ci['max_artifacts_size'], ) end diff --git a/app/models/ci/build.rb b/app/models/ci/build.rb index 7f185ae7cc3..0ec7e210321 100644 --- a/app/models/ci/build.rb +++ b/app/models/ci/build.rb @@ -39,6 +39,8 @@ module Ci scope :ignore_failures, ->() { where(allow_failure: false) } scope :similar, ->(build) { where(ref: build.ref, tag: build.tag, trigger_request_id: build.trigger_request_id) } + mount_uploader :artifacts_file, ArtifactUploader + acts_as_taggable # To prevent db load megabytes of data from trace @@ -217,6 +219,14 @@ module Ci "#{dir_to_trace}/#{id}.log" end + def token + project.token + end + + def valid_token? token + project.valid_token? token + end + def target_url Gitlab::Application.routes.url_helpers. namespace_project_build_url(gl_project.namespace, gl_project, self) @@ -248,6 +258,13 @@ module Ci pending? && !any_runners_online? end + def download_url + if artifacts_file.exists? + Gitlab::Application.routes.url_helpers. + download_namespace_project_build_path(gl_project.namespace, gl_project, self) + end + end + private def yaml_variables diff --git a/app/models/commit_status.rb b/app/models/commit_status.rb index 7d54d83974a..d346c5d35d2 100644 --- a/app/models/commit_status.rb +++ b/app/models/commit_status.rb @@ -92,4 +92,8 @@ class CommitStatus < ActiveRecord::Base def show_warning? false end + + def download_url + nil + end end diff --git a/app/uploaders/artifact_uploader.rb b/app/uploaders/artifact_uploader.rb new file mode 100644 index 00000000000..848e0bcbde1 --- /dev/null +++ b/app/uploaders/artifact_uploader.rb @@ -0,0 +1,50 @@ +# encoding: utf-8 +class ArtifactUploader < CarrierWave::Uploader::Base + storage :file + + attr_accessor :build, :field + + def self.artifacts_path + File.expand_path('shared/artifacts/', Rails.root) + end + + def self.artifacts_upload_path + File.expand_path('shared/tmp/artifacts-uploads/', Rails.root) + end + + def self.artifacts_cache_path + File.expand_path('shared/tmp/artifacts-cache/', Rails.root) + end + + def initialize(build, field) + @build, @field = build, field + end + + def artifacts_path + File.join(build.created_at.utc.strftime('%Y_%m'), build.project.id.to_s, build.id.to_s) + end + + def store_dir + File.join(ArtifactUploader.artifacts_path, artifacts_path) + end + + def cache_dir + File.join(ArtifactUploader.artifacts_cache_path, artifacts_path) + end + + def file_storage? + self.class.storage == CarrierWave::Storage::File + end + + def exists? + file.try(:exists?) + end + + def move_to_cache + true + end + + def move_to_store + true + end +end diff --git a/app/views/admin/application_settings/_form.html.haml b/app/views/admin/application_settings/_form.html.haml index 7253218c2e9..ddaf0e0e8ff 100644 --- a/app/views/admin/application_settings/_form.html.haml +++ b/app/views/admin/application_settings/_form.html.haml @@ -139,5 +139,10 @@ = f.check_box :shared_runners_enabled Enable shared runners for a new projects + .form-group + = f.label :max_artifacts_size, 'Maximum artifacts size (MB)', class: 'control-label col-sm-2' + .col-sm-10 + = f.number_field :max_artifacts_size, class: 'form-control' + .form-actions = f.submit 'Save', class: 'btn btn-primary' diff --git a/app/views/projects/builds/show.html.haml b/app/views/projects/builds/show.html.haml index 3374d5432a5..7661452e6ec 100644 --- a/app/views/projects/builds/show.html.haml +++ b/app/views/projects/builds/show.html.haml @@ -87,6 +87,9 @@ Test coverage %h1 #{@build.coverage}% + - if current_user && can?(current_user, :download_build_artifacts, @project) && @build.download_url + .build-widget.center + = link_to "Download artifacts", @build.download_url, class: 'btn btn-sm btn-primary' .build-widget %h4.title diff --git a/app/views/projects/commit_statuses/_commit_status.html.haml b/app/views/projects/commit_statuses/_commit_status.html.haml index c255559b88c..9a0e7bff3f1 100644 --- a/app/views/projects/commit_statuses/_commit_status.html.haml +++ b/app/views/projects/commit_statuses/_commit_status.html.haml @@ -61,6 +61,9 @@ %td .pull-right + - if current_user && can?(current_user, :download_build_artifacts, @project) && commit_status.download_url + = link_to commit_status.download_url, title: 'Download artifacts' do + %i.fa.fa-download - if current_user && can?(current_user, :manage_builds, commit_status.gl_project) - if commit_status.active? - if commit_status.cancel_url diff --git a/config/initializers/1_settings.rb b/config/initializers/1_settings.rb index 8192d727f2a..b39e263e39a 100644 --- a/config/initializers/1_settings.rb +++ b/config/initializers/1_settings.rb @@ -186,6 +186,7 @@ Settings.gitlab_ci['all_broken_builds'] = true if Settings.gitlab_ci['all_br Settings.gitlab_ci['add_pusher'] = false if Settings.gitlab_ci['add_pusher'].nil? Settings.gitlab_ci['url'] ||= Settings.send(:build_gitlab_ci_url) Settings.gitlab_ci['builds_path'] = File.expand_path(Settings.gitlab_ci['builds_path'] || "builds/", Rails.root) +Settings.gitlab_ci['max_artifacts_size'] ||= 100 # # Reply by email diff --git a/config/routes.rb b/config/routes.rb index 2028ea938e4..c892c034f01 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -611,6 +611,7 @@ Gitlab::Application.routes.draw do member do get :status post :cancel + get :download post :retry end end diff --git a/db/migrate/20151013092124_add_artifacts_file_to_builds.rb b/db/migrate/20151013092124_add_artifacts_file_to_builds.rb new file mode 100644 index 00000000000..5a299f7b26d --- /dev/null +++ b/db/migrate/20151013092124_add_artifacts_file_to_builds.rb @@ -0,0 +1,5 @@ +class AddArtifactsFileToBuilds < ActiveRecord::Migration + def change + add_column :ci_builds, :artifacts_file, :text + end +end diff --git a/db/migrate/20151109100728_add_max_artifacts_size_to_application_settings.rb b/db/migrate/20151109100728_add_max_artifacts_size_to_application_settings.rb new file mode 100644 index 00000000000..01d8c0f043e --- /dev/null +++ b/db/migrate/20151109100728_add_max_artifacts_size_to_application_settings.rb @@ -0,0 +1,5 @@ +class AddMaxArtifactsSizeToApplicationSettings < ActiveRecord::Migration + def change + add_column :application_settings, :max_artifacts_size, :integer, default: 100, null: false + end +end diff --git a/db/schema.rb b/db/schema.rb index 116c0c8d97d..f631d73f334 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -11,7 +11,7 @@ # # It's strongly recommended that you check this file into your version control system. -ActiveRecord::Schema.define(version: 20151105094515) do +ActiveRecord::Schema.define(version: 20151109100728) do # These are extensions that must be enabled in order to support this database enable_extension "plpgsql" @@ -48,6 +48,7 @@ ActiveRecord::Schema.define(version: 20151105094515) do t.text "help_page_text" t.string "admin_notification_email" t.boolean "shared_runners_enabled", default: true, null: false + t.integer "max_artifacts_size", default: 100, null: false end create_table "audit_events", force: true do |t| @@ -108,6 +109,7 @@ ActiveRecord::Schema.define(version: 20151105094515) do t.string "type" t.string "target_url" t.string "description" + t.text "artifacts_file" end add_index "ci_builds", ["commit_id", "stage_idx", "created_at"], name: "index_ci_builds_on_commit_id_and_stage_idx_and_created_at", using: :btree diff --git a/doc/ci/yaml/README.md b/doc/ci/yaml/README.md index d117a2969be..d8504aca86a 100644 --- a/doc/ci/yaml/README.md +++ b/doc/ci/yaml/README.md @@ -141,6 +141,7 @@ job_name: | tags | optional | Defines a list of tags which are used to select runner | | allow_failure | optional | Allow build to fail. Failed build doesn't contribute to commit status | | when | optional | Define when to run build. Can be `on_success`, `on_failure` or `always` | +| artifacts | optional | Define list build artifacts | ### script `script` is a shell script which is executed by runner. The shell script is prepended with `before_script`. @@ -258,6 +259,20 @@ The above script will: 1. Execute `cleanup_build` only when the `build` failed, 2. Always execute `cleanup` as the last step in pipeline. +### artifacts +`artifacts` is used to specify list of files and directories which should be attached to build after success. + +``` +artifacts: +- binaries/ +- .config +``` + +The above definition will archive all files in `binaries/` and `.config`. +The artifacts will be send after the build success to GitLab and will be accessible in GitLab interface to download. + +This feature requires GitLab Runner v 0.7.0. + ## Validate the .gitlab-ci.yml Each instance of GitLab CI has an embedded debug tool called Lint. You can find the link to the Lint in the project's settings page or use short url `/lint`. diff --git a/doc/install/installation.md b/doc/install/installation.md index f17477a3218..0ece8bd9315 100644 --- a/doc/install/installation.md +++ b/doc/install/installation.md @@ -246,6 +246,11 @@ We recommend using a PostgreSQL database. For MySQL check [MySQL setup guide](da # Change the permissions of the directory where CI build traces are stored sudo chmod -R u+rwX builds/ + # Change the permissions of the directory where CI artifacts are stored + sudo chmod -R u+rwX shared/artifacts/ + sudo chmod -R u+rwX shared/tmp/artifacts-uploads/ + sudo chmod -R u+rwX shared/tmp/artifacts-cache/ + # Copy the example Unicorn config sudo -u git -H cp config/unicorn.rb.example config/unicorn.rb diff --git a/doc/raketasks/backup_restore.md b/doc/raketasks/backup_restore.md index 606532a6fbe..1a5442cdac7 100644 --- a/doc/raketasks/backup_restore.md +++ b/doc/raketasks/backup_restore.md @@ -29,7 +29,8 @@ sudo -u git -H bundle exec rake gitlab:backup:create RAILS_ENV=production ``` Also you can choose what should be backed up by adding environment variable SKIP. Available options: db, -uploads (attachments), repositories, builds(CI build output logs). Use a comma to specify several options at the same time. +uploads (attachments), repositories, builds(CI build output logs), artifacts (CI build artifacts). +Use a comma to specify several options at the same time. ``` sudo gitlab-rake gitlab:backup:create SKIP=db,uploads diff --git a/lib/api/helpers.rb b/lib/api/helpers.rb index 652bdf9b278..b980cd8391e 100644 --- a/lib/api/helpers.rb +++ b/lib/api/helpers.rb @@ -133,6 +133,12 @@ module API authorize! :admin_project, user_project end + def require_gitlab_workhorse! + unless headers['Gitlab-Git-Http-Server'].present? || headers['GitLab-Git-HTTP-Server'].present? + forbidden!('Request should be executed via GitLab Workhorse') + end + end + def can?(object, action, subject) abilities.allowed?(object, action, subject) end @@ -234,6 +240,10 @@ module API render_api_error!(message || '409 Conflict', 409) end + def file_to_large! + render_api_error!('413 Request Entity Too Large', 413) + end + def render_validation_error!(model) if model.errors.any? render_api_error!(model.errors.messages || '400 Bad Request', 400) @@ -282,6 +292,40 @@ module API end end + # file helpers + + def uploaded_file!(uploads_path) + required_attributes! [:file] + + # sanitize file paths + # this requires for all paths to exist + uploads_path = File.realpath(uploads_path) + file_path = File.realpath(params[:file]) + bad_request!('Bad file path') unless file_path.start_with?(uploads_path) + + UploadedFile.new( + file_path, + params[:filename], + params[:filetype] || 'application/octet-stream', + ) + end + + def present_file!(path, filename, content_type = 'application/octet-stream') + filename ||= File.basename(path) + header['Content-Disposition'] = "attachment; filename=#{filename}" + header['Content-Transfer-Encoding'] = 'binary' + content_type content_type + + # Support download acceleration + case headers['X-Sendfile-Type'] + when 'X-Sendfile' + header['X-Sendfile'] = path + body + else + file FileStreamer.new(path) + end + end + private def add_pagination_headers(paginated, per_page) diff --git a/lib/backup/artifacts.rb b/lib/backup/artifacts.rb new file mode 100644 index 00000000000..51fa3867e67 --- /dev/null +++ b/lib/backup/artifacts.rb @@ -0,0 +1,13 @@ +require 'backup/files' + +module Backup + class Artifacts < Files + def initialize + super('artifacts', ArtifactUploader.artifacts_path) + end + + def create_files_dir + Dir.mkdir(app_files_dir, 0700) + end + end +end diff --git a/lib/backup/manager.rb b/lib/backup/manager.rb index f011fd03de0..9e15d5411a1 100644 --- a/lib/backup/manager.rb +++ b/lib/backup/manager.rb @@ -150,7 +150,7 @@ module Backup private def backup_contents - folders_to_backup + ["uploads.tar.gz", "builds.tar.gz", "backup_information.yml"] + folders_to_backup + ["uploads.tar.gz", "builds.tar.gz", "artifacts.tar.gz", "backup_information.yml"] end def folders_to_backup diff --git a/lib/ci/api/api.rb b/lib/ci/api/api.rb index 0a4cbf69b63..07e68216d7f 100644 --- a/lib/ci/api/api.rb +++ b/lib/ci/api/api.rb @@ -27,6 +27,7 @@ module Ci helpers Helpers helpers ::API::Helpers + helpers Gitlab::CurrentSettings mount Builds mount Commits diff --git a/lib/ci/api/builds.rb b/lib/ci/api/builds.rb index 83ca1e6481c..622849c4b11 100644 --- a/lib/ci/api/builds.rb +++ b/lib/ci/api/builds.rb @@ -47,6 +47,108 @@ module Ci build.drop end end + + # Authorize artifacts uploading for build - Runners only + # + # Parameters: + # id (required) - The ID of a build + # token (required) - The build authorization token + # size (optional) - the size of uploaded file + # Example Request: + # POST /builds/:id/artifacts/authorize + post ":id/artifacts/authorize" do + require_gitlab_workhorse! + build = Ci::Build.find_by_id(params[:id]) + not_found! unless build + authenticate_build_token!(build) + forbidden!('build is not running') unless build.running? + + if params[:filesize] + file_size = params[:filesize].to_i + file_to_large! unless file_size < max_artifacts_size + end + + status 200 + { temp_path: ArtifactUploader.artifacts_upload_path } + end + + # Upload artifacts to build - Runners only + # + # Parameters: + # id (required) - The ID of a build + # token (required) - The build authorization token + # Headers: + # Content-Type - File content type + # Content-Disposition - File media type and real name + # BUILD-TOKEN (required) - The build authorization token, the same as token + # Body: + # The file content + # + # Parameters (set by GitLab Workhorse): + # file - path to locally stored body (generated by Workhorse) + # filename - real filename as send in Content-Disposition + # filetype - real content type as send in Content-Type + # filesize - real file size as send in Content-Length + # Example Request: + # POST /builds/:id/artifacts + post ":id/artifacts" do + require_gitlab_workhorse! + build = Ci::Build.find_by_id(params[:id]) + not_found! unless build + authenticate_build_token!(build) + forbidden!('build is not running') unless build.running? + + file = uploaded_file!(ArtifactUploader.artifacts_upload_path) + file_to_large! unless file.size < max_artifacts_size + + if build.update_attributes(artifacts_file: file) + present build, with: Entities::Build + else + render_validation_error!(build) + end + end + + # Download the artifacts file from build - Runners only + # + # Parameters: + # id (required) - The ID of a build + # token (required) - The build authorization token + # Headers: + # BUILD-TOKEN (required) - The build authorization token, the same as token + # Example Request: + # GET /builds/:id/artifacts + get ":id/artifacts" do + build = Ci::Build.find_by_id(params[:id]) + not_found! unless build + authenticate_build_token!(build) + artifacts_file = build.artifacts_file + + unless artifacts_file.file_storage? + return redirect_to build.artifacts_file.url + end + + unless artifacts_file.exists? + not_found! + end + + present_file!(artifacts_file.path, artifacts_file.filename) + end + + # Remove the artifacts file from build + # + # Parameters: + # id (required) - The ID of a build + # token (required) - The build authorization token + # Headers: + # BUILD-TOKEN (required) - The build authorization token, the same as token + # Example Request: + # DELETE /builds/:id/artifacts + delete ":id/artifacts" do + build = Ci::Build.find_by_id(params[:id]) + not_found! unless build + authenticate_build_token!(build) + build.remove_artifacts_file! + end end end end diff --git a/lib/ci/api/entities.rb b/lib/ci/api/entities.rb index b80c0b8b273..750f421872d 100644 --- a/lib/ci/api/entities.rb +++ b/lib/ci/api/entities.rb @@ -11,10 +11,16 @@ module Ci expose :builds end + class ArtifactFile < Grape::Entity + expose :filename, :size + end + class Build < Grape::Entity expose :id, :commands, :ref, :sha, :status, :project_id, :repo_url, :before_sha, :allow_git_fetch, :project_name + expose :name, :token, :stage + expose :options do |model| model.options end @@ -24,6 +30,7 @@ module Ci end expose :variables + expose :artifacts_file, using: ArtifactFile end class Runner < Grape::Entity diff --git a/lib/ci/api/helpers.rb b/lib/ci/api/helpers.rb index 7e4986b6af3..02502333756 100644 --- a/lib/ci/api/helpers.rb +++ b/lib/ci/api/helpers.rb @@ -1,6 +1,8 @@ module Ci module API module Helpers + BUILD_TOKEN_HEADER = "HTTP_BUILD_TOKEN" + BUILD_TOKEN_PARAM = :token UPDATE_RUNNER_EVERY = 60 def authenticate_runners! @@ -15,6 +17,11 @@ module Ci forbidden! unless project.valid_token?(params[:project_token]) end + def authenticate_build_token!(build) + token = (params[BUILD_TOKEN_PARAM] || env[BUILD_TOKEN_HEADER]).to_s + forbidden! unless token && build.valid_token?(token) + end + def update_runner_last_contact # Use a random threshold to prevent beating DB updates contacted_at_max_age = UPDATE_RUNNER_EVERY + Random.rand(UPDATE_RUNNER_EVERY) @@ -32,6 +39,10 @@ module Ci info = attributes_for_keys(["name", "version", "revision", "platform", "architecture"], params["info"]) current_runner.update(info) end + + def max_artifacts_size + current_application_settings.max_artifacts_size.megabytes.to_i + end end end end diff --git a/lib/ci/gitlab_ci_yaml_processor.rb b/lib/ci/gitlab_ci_yaml_processor.rb index 0f57a4f53ab..6f9af5388ca 100644 --- a/lib/ci/gitlab_ci_yaml_processor.rb +++ b/lib/ci/gitlab_ci_yaml_processor.rb @@ -5,7 +5,7 @@ module Ci DEFAULT_STAGES = %w(build test deploy) DEFAULT_STAGE = 'test' ALLOWED_YAML_KEYS = [:before_script, :image, :services, :types, :stages, :variables] - ALLOWED_JOB_KEYS = [:tags, :script, :only, :except, :type, :image, :services, :allow_failure, :type, :stage, :when] + ALLOWED_JOB_KEYS = [:tags, :script, :only, :except, :type, :image, :services, :allow_failure, :type, :stage, :when, :artifacts] attr_reader :before_script, :image, :services, :variables, :path @@ -77,7 +77,8 @@ module Ci when: job[:when] || 'on_success', options: { image: job[:image] || @image, - services: job[:services] || @services + services: job[:services] || @services, + artifacts: job[:artifacts] }.compact } end @@ -159,6 +160,10 @@ module Ci raise ValidationError, "#{name} job: except parameter should be an array of strings" end + if job[:artifacts] && !validate_array_of_strings(job[:artifacts]) + raise ValidationError, "#{name}: artifacts parameter should be an array of strings" + end + if job[:allow_failure] && !job[:allow_failure].in?([true, false]) raise ValidationError, "#{name} job: allow_failure parameter should be an boolean" end diff --git a/lib/file_streamer.rb b/lib/file_streamer.rb new file mode 100644 index 00000000000..4e3c6d3c773 --- /dev/null +++ b/lib/file_streamer.rb @@ -0,0 +1,16 @@ +class FileStreamer #:nodoc: + attr_reader :to_path + + def initialize(path) + @to_path = path + end + + # Stream the file's contents if Rack::Sendfile isn't present. + def each + File.open(to_path, 'rb') do |file| + while chunk = file.read(16384) + yield chunk + end + end + end +end diff --git a/lib/gitlab/current_settings.rb b/lib/gitlab/current_settings.rb index cd84afa31d5..2d3e32d9539 100644 --- a/lib/gitlab/current_settings.rb +++ b/lib/gitlab/current_settings.rb @@ -25,6 +25,7 @@ module Gitlab session_expire_delay: Settings.gitlab['session_expire_delay'], import_sources: Settings.gitlab['import_sources'], shared_runners_enabled: Settings.gitlab_ci['shared_runners_enabled'], + max_artifacts_size: Ci::Settings.gitlab_ci['max_artifacts_size'], ) end diff --git a/lib/support/nginx/gitlab b/lib/support/nginx/gitlab index e767027dc29..e511d5e4b4b 100644 --- a/lib/support/nginx/gitlab +++ b/lib/support/nginx/gitlab @@ -131,6 +131,22 @@ server { return 418; } + # Build artifacts should be submitted to this location + location ~ ^/[\w\.-]+/[\w\.-]+/builds/download { + client_max_body_size 0; + # 'Error' 418 is a hack to re-use the @gitlab-git-http-server block + error_page 418 = @gitlab-git-http-server; + return 418; + } + + # Build artifacts should be submitted to this location + location ~ /ci/api/v1/builds/[0-9]+/artifacts { + client_max_body_size 0; + # 'Error' 418 is a hack to re-use the @gitlab-git-http-server block + error_page 418 = @gitlab-git-http-server; + return 418; + } + location @gitlab-workhorse { ## If you use HTTPS make sure you disable gzip compression ## to be safe against BREACH attack. diff --git a/lib/support/nginx/gitlab-ssl b/lib/support/nginx/gitlab-ssl index 4d31e31f8d5..47b1ec8cb0c 100644 --- a/lib/support/nginx/gitlab-ssl +++ b/lib/support/nginx/gitlab-ssl @@ -178,6 +178,22 @@ server { return 418; } + # Build artifacts should be submitted to this location + location ~ ^/[\w\.-]+/[\w\.-]+/builds/download { + client_max_body_size 0; + # 'Error' 418 is a hack to re-use the @gitlab-git-http-server block + error_page 418 = @gitlab-git-http-server; + return 418; + } + + # Build artifacts should be submitted to this location + location ~ /ci/api/v1/builds/[0-9]+/artifacts { + client_max_body_size 0; + # 'Error' 418 is a hack to re-use the @gitlab-git-http-server block + error_page 418 = @gitlab-git-http-server; + return 418; + } + location @gitlab-workhorse { ## If you use HTTPS make sure you disable gzip compression ## to be safe against BREACH attack. diff --git a/lib/tasks/gitlab/backup.rake b/lib/tasks/gitlab/backup.rake index f20c7f71ba5..3c46bcea40e 100644 --- a/lib/tasks/gitlab/backup.rake +++ b/lib/tasks/gitlab/backup.rake @@ -12,6 +12,7 @@ namespace :gitlab do Rake::Task["gitlab:backup:repo:create"].invoke Rake::Task["gitlab:backup:uploads:create"].invoke Rake::Task["gitlab:backup:builds:create"].invoke + Rake::Task["gitlab:backup:artifacts:create"].invoke backup = Backup::Manager.new backup.pack @@ -32,6 +33,7 @@ namespace :gitlab do Rake::Task["gitlab:backup:repo:restore"].invoke unless backup.skipped?("repositories") Rake::Task["gitlab:backup:uploads:restore"].invoke unless backup.skipped?("uploads") Rake::Task["gitlab:backup:builds:restore"].invoke unless backup.skipped?("builds") + Rake::Task["gitlab:backup:artifacts:restore"].invoke unless backup.skipped?("artifacts") Rake::Task["gitlab:shell:setup"].invoke backup.cleanup @@ -113,6 +115,25 @@ namespace :gitlab do end end + namespace :artifacts do + task create: :environment do + $progress.puts "Dumping artifacts ... ".blue + + if ENV["SKIP"] && ENV["SKIP"].include?("artifacts") + $progress.puts "[SKIPPED]".cyan + else + Backup::Artifacts.new.dump + $progress.puts "done".green + end + end + + task restore: :environment do + $progress.puts "Restoring artifacts ... ".blue + Backup::Artifacts.new.restore + $progress.puts "done".green + end + end + def configure_cron_mode if ENV['CRON'] # We need an object we can say 'puts' and 'print' to; let's use a diff --git a/lib/uploaded_file.rb b/lib/uploaded_file.rb new file mode 100644 index 00000000000..d4291f012d3 --- /dev/null +++ b/lib/uploaded_file.rb @@ -0,0 +1,37 @@ +require "tempfile" +require "fileutils" + +# Taken from: Rack::Test::UploadedFile +class UploadedFile + + # The filename, *not* including the path, of the "uploaded" file + attr_reader :original_filename + + # The tempfile + attr_reader :tempfile + + # The content type of the "uploaded" file + attr_accessor :content_type + + def initialize(path, filename, content_type = "text/plain") + raise "#{path} file does not exist" unless ::File.exist?(path) + + @content_type = content_type + @original_filename = filename || ::File.basename(path) + @tempfile = File.new(path, 'rb') + end + + def path + @tempfile.path + end + + alias_method :local_path, :path + + def method_missing(method_name, *args, &block) #:nodoc: + @tempfile.__send__(method_name, *args, &block) + end + + def respond_to?(method_name, include_private = false) #:nodoc: + @tempfile.respond_to?(method_name, include_private) || super + end +end diff --git a/shared/artifacts/.gitkeep b/shared/artifacts/.gitkeep new file mode 100644 index 00000000000..e69de29bb2d diff --git a/shared/tmp/artifacts-cache/.gitkeep b/shared/tmp/artifacts-cache/.gitkeep new file mode 100644 index 00000000000..e69de29bb2d diff --git a/shared/tmp/artifacts-uploads/.gitkeep b/shared/tmp/artifacts-uploads/.gitkeep new file mode 100644 index 00000000000..e69de29bb2d diff --git a/spec/features/builds_spec.rb b/spec/features/builds_spec.rb index 158e85e598f..5213ce1099f 100644 --- a/spec/features/builds_spec.rb +++ b/spec/features/builds_spec.rb @@ -1,6 +1,8 @@ require 'spec_helper' describe "Builds" do + let(:artifacts_file) { fixture_file_upload(Rails.root + 'spec/fixtures/banana_sample.gif', 'image/gif') } + before do login_as(:user) @commit = FactoryGirl.create :ci_commit @@ -66,6 +68,15 @@ describe "Builds" do it { expect(page).to have_content @commit.sha[0..7] } it { expect(page).to have_content @commit.git_commit_message } it { expect(page).to have_content @commit.git_author_name } + + context "Download artifacts" do + before do + @build.update_attributes(artifacts_file: artifacts_file) + visit namespace_project_build_path(@gl_project.namespace, @gl_project, @build) + end + + it { expect(page).to have_content 'Download artifacts' } + end end describe "POST /:project/builds/:id/cancel" do @@ -90,4 +101,14 @@ describe "Builds" do it { expect(page).to have_content 'pending' } it { expect(page).to have_content 'Cancel' } end + + describe "GET /:project/builds/:id/download" do + before do + @build.update_attributes(artifacts_file: artifacts_file) + visit namespace_project_build_path(@gl_project.namespace, @gl_project, @build) + click_link 'Download artifacts' + end + + it { expect(page.response_headers['Content-Type']).to eq(artifacts_file.content_type) } + end end diff --git a/spec/features/commits_spec.rb b/spec/features/commits_spec.rb index 340924fafe7..90739cd6a28 100644 --- a/spec/features/commits_spec.rb +++ b/spec/features/commits_spec.rb @@ -19,7 +19,7 @@ describe "Commits" do stub_ci_commit_to_return_yaml_file end - describe "GET /:project/commits/:sha" do + describe "GET /:project/commits/:sha/ci" do before do visit ci_status_path(@commit) end @@ -29,6 +29,20 @@ describe "Commits" do it { expect(page).to have_content @commit.git_author_name } end + context "Download artifacts" do + let(:artifacts_file) { fixture_file_upload(Rails.root + 'spec/fixtures/banana_sample.gif', 'image/gif') } + + before do + @build.update_attributes(artifacts_file: artifacts_file) + end + + it do + visit ci_status_path(@commit) + click_on "Download artifacts" + expect(page.response_headers['Content-Type']).to eq(artifacts_file.content_type) + end + end + describe "Cancel all builds" do it "cancels commit" do visit ci_status_path(@commit) diff --git a/spec/lib/ci/gitlab_ci_yaml_processor_spec.rb b/spec/lib/ci/gitlab_ci_yaml_processor_spec.rb index 9963f76f993..5e3779af19e 100644 --- a/spec/lib/ci/gitlab_ci_yaml_processor_spec.rb +++ b/spec/lib/ci/gitlab_ci_yaml_processor_spec.rb @@ -333,6 +333,37 @@ module Ci end end + describe "Artifacts" do + it "returns artifacts when defined" do + config = YAML.dump({ + image: "ruby:2.1", + services: ["mysql"], + before_script: ["pwd"], + rspec: { artifacts: ["logs/", "binaries/"], script: "rspec" } + }) + + config_processor = GitlabCiYamlProcessor.new(config) + + expect(config_processor.builds_for_stage_and_ref("test", "master").size).to eq(1) + expect(config_processor.builds_for_stage_and_ref("test", "master").first).to eq({ + except: nil, + stage: "test", + stage_idx: 1, + name: :rspec, + only: nil, + commands: "pwd\nrspec", + tag_list: [], + options: { + image: "ruby:2.1", + services: ["mysql"], + artifacts: ["logs/", "binaries/"] + }, + when: "on_success", + allow_failure: false + }) + end + end + describe "Error handling" do it "indicates that object is invalid" do expect{GitlabCiYamlProcessor.new("invalid_yaml\n!ccdvlf%612334@@@@")}.to raise_error(GitlabCiYamlProcessor::ValidationError) @@ -491,6 +522,13 @@ module Ci GitlabCiYamlProcessor.new(config, path) end.to raise_error(GitlabCiYamlProcessor::ValidationError, "rspec job: when parameter should be on_success, on_failure or always") end + + it "returns errors if job artifacts is not an array of strings" do + config = YAML.dump({ types: ["build", "test"], rspec: { script: "test", artifacts: "string" } }) + expect do + GitlabCiYamlProcessor.new(config) + end.to raise_error(GitlabCiYamlProcessor::ValidationError, "rspec job: artifacts parameter should be an array of strings") + end end end end diff --git a/spec/models/build_spec.rb b/spec/models/build_spec.rb index 7f5abb83ac2..839b4c6b16e 100644 --- a/spec/models/build_spec.rb +++ b/spec/models/build_spec.rb @@ -400,4 +400,19 @@ describe Ci::Build do end end end + + describe :download_url do + subject { build.download_url } + + it "should be nil if artifact doesn't exist" do + build.update_attributes(artifacts_file: nil) + is_expected.to be_nil + end + + it 'should be nil if artifact exist' do + gif = fixture_file_upload(Rails.root + 'spec/fixtures/banana_sample.gif', 'image/gif') + build.update_attributes(artifacts_file: gif) + is_expected.to_not be_nil + end + end end diff --git a/spec/requests/api/users_spec.rb b/spec/requests/api/users_spec.rb index d26a300ed82..a9ef2fe5885 100644 --- a/spec/requests/api/users_spec.rb +++ b/spec/requests/api/users_spec.rb @@ -343,8 +343,9 @@ describe API::API, api: true do end.to change{ user.keys.count }.by(1) end - it "should raise error for invalid ID" do - expect{post api("/users/ASDF/keys", admin) }.to raise_error(ActionController::RoutingError) + it "should return 405 for invalid ID" do + post api("/users/ASDF/keys", admin) + expect(response.status).to eq(405) end end @@ -374,9 +375,9 @@ describe API::API, api: true do expect(json_response.first['title']).to eq(key.title) end - it "should return 404 for invalid ID" do + it "should return 405 for invalid ID" do get api("/users/ASDF/keys", admin) - expect(response.status).to eq(404) + expect(response.status).to eq(405) end end end @@ -434,7 +435,8 @@ describe API::API, api: true do end it "should raise error for invalid ID" do - expect{post api("/users/ASDF/emails", admin) }.to raise_error(ActionController::RoutingError) + post api("/users/ASDF/emails", admin) + expect(response.status).to eq(405) end end @@ -465,7 +467,8 @@ describe API::API, api: true do end it "should raise error for invalid ID" do - expect{put api("/users/ASDF/emails", admin) }.to raise_error(ActionController::RoutingError) + put api("/users/ASDF/emails", admin) + expect(response.status).to eq(405) end end end diff --git a/spec/requests/ci/api/builds_spec.rb b/spec/requests/ci/api/builds_spec.rb index 88218a93e1f..92ea25a3723 100644 --- a/spec/requests/ci/api/builds_spec.rb +++ b/spec/requests/ci/api/builds_spec.rb @@ -41,7 +41,7 @@ describe Ci::API::API do it "should return 404 error if no builds for specific runner" do commit = FactoryGirl.create(:ci_commit, gl_project: shared_gl_project) - FactoryGirl.create(:ci_build, commit: commit, status: 'pending' ) + FactoryGirl.create(:ci_build, commit: commit, status: 'pending') post ci_api("/builds/register"), token: runner.token @@ -50,7 +50,7 @@ describe Ci::API::API do it "should return 404 error if no builds for shared runner" do commit = FactoryGirl.create(:ci_commit, gl_project: gl_project) - FactoryGirl.create(:ci_build, commit: commit, status: 'pending' ) + FactoryGirl.create(:ci_build, commit: commit, status: 'pending') post ci_api("/builds/register"), token: shared_runner.token @@ -79,7 +79,7 @@ describe Ci::API::API do { "key" => "CI_BUILD_NAME", "value" => "spinach", "public" => true }, { "key" => "CI_BUILD_STAGE", "value" => "test", "public" => true }, { "key" => "DB_NAME", "value" => "postgres", "public" => true }, - { "key" => "SECRET_KEY", "value" => "secret_value", "public" => false }, + { "key" => "SECRET_KEY", "value" => "secret_value", "public" => false } ]) end @@ -122,5 +122,185 @@ describe Ci::API::API do expect(build.reload.trace).to eq 'hello_world' end end + + context "Artifacts" do + let(:file_upload) { fixture_file_upload(Rails.root + 'spec/fixtures/banana_sample.gif', 'image/gif') } + let(:file_upload2) { fixture_file_upload(Rails.root + 'spec/fixtures/dk.png', 'image/gif') } + let(:commit) { FactoryGirl.create(:ci_commit, gl_project: gl_project) } + let(:build) { FactoryGirl.create(:ci_build, commit: commit, runner_id: runner.id) } + let(:authorize_url) { ci_api("/builds/#{build.id}/artifacts/authorize") } + let(:post_url) { ci_api("/builds/#{build.id}/artifacts") } + let(:delete_url) { ci_api("/builds/#{build.id}/artifacts") } + let(:get_url) { ci_api("/builds/#{build.id}/artifacts") } + let(:headers) { { "Gitlab-Git-Http-Server" => "1.0" } } + let(:headers_with_token) { headers.merge(Ci::API::Helpers::BUILD_TOKEN_HEADER => build.project.token) } + + describe "POST /builds/:id/artifacts/authorize" do + context "should authorize posting artifact to running build" do + before do + build.run! + end + + it "using token as parameter" do + post authorize_url, { token: build.project.token }, headers + expect(response.status).to eq(200) + expect(json_response["temp_path"]).to_not be_nil + end + + it "using token as header" do + post authorize_url, {}, headers_with_token + expect(response.status).to eq(200) + expect(json_response["temp_path"]).to_not be_nil + end + end + + context "should fail to post too large artifact" do + before do + build.run! + end + + it "using token as parameter" do + settings = Gitlab::CurrentSettings::current_application_settings + settings.update_attributes(max_artifacts_size: 0) + post authorize_url, { token: build.project.token, filesize: 100 }, headers + expect(response.status).to eq(413) + end + + it "using token as header" do + settings = Gitlab::CurrentSettings::current_application_settings + settings.update_attributes(max_artifacts_size: 0) + post authorize_url, { filesize: 100 }, headers_with_token + expect(response.status).to eq(413) + end + end + + context "should get denied" do + it do + post authorize_url, { token: 'invalid', filesize: 100 } + expect(response.status).to eq(403) + end + end + end + + describe "POST /builds/:id/artifacts" do + context "Disable sanitizer" do + before do + # by configuring this path we allow to pass temp file from any path + allow(ArtifactUploader).to receive(:artifacts_upload_path).and_return('/') + end + + context "should post artifact to running build" do + before do + build.run! + end + + it do + upload_artifacts(file_upload, headers_with_token) + expect(response.status).to eq(201) + expect(json_response["artifacts_file"]["filename"]).to eq(file_upload.original_filename) + end + + it "updates artifact" do + upload_artifacts(file_upload, headers_with_token) + upload_artifacts(file_upload2, headers_with_token) + expect(response.status).to eq(201) + expect(json_response["artifacts_file"]["filename"]).to eq(file_upload2.original_filename) + end + end + + context "should fail to post too large artifact" do + before do + build.run! + end + + it do + settings = Gitlab::CurrentSettings::current_application_settings + settings.update_attributes(max_artifacts_size: 0) + upload_artifacts(file_upload, headers_with_token) + expect(response.status).to eq(413) + end + end + + context "should fail to post artifacts without file" do + before do + build.run! + end + + it do + post post_url, {}, headers_with_token + expect(response.status).to eq(400) + end + end + + context "should fail to post artifacts without GitLab-Workhorse" do + before do + build.run! + end + + it do + post post_url, { token: build.project.token }, {} + expect(response.status).to eq(403) + end + end + end + + context "should fail to post artifacts for outside of tmp path" do + before do + # by configuring this path we allow to pass file from @tmpdir only + # but all temporary files are stored in system tmp directory + @tmpdir = Dir.mktmpdir + allow(ArtifactUploader).to receive(:artifacts_upload_path).and_return(@tmpdir) + build.run! + end + + after do + FileUtils.remove_entry @tmpdir + end + + it do + upload_artifacts(file_upload, headers_with_token) + expect(response.status).to eq(400) + end + end + + def upload_artifacts(file, headers = {}) + params = { + file: file.path, + filename: file.original_filename, + } + post post_url, params, headers + end + end + + describe "DELETE /builds/:id/artifacts" do + before do + build.run! + post delete_url, token: build.project.token, file: file_upload + end + + it "should delete artifact build" do + build.success + delete delete_url, token: build.project.token + expect(response.status).to eq(200) + end + end + + describe "GET /builds/:id/artifacts" do + before do + build.run! + end + + it "should download artifact" do + build.update_attributes(artifacts_file: file_upload) + get get_url, token: build.project.token + expect(response.status).to eq(200) + end + + it "should fail to download if no artifact uploaded" do + get get_url, token: build.project.token + expect(response.status).to eq(404) + end + end + end end end diff --git a/spec/tasks/gitlab/backup_rake_spec.rb b/spec/tasks/gitlab/backup_rake_spec.rb index 386ac9c8372..06559c3925d 100644 --- a/spec/tasks/gitlab/backup_rake_spec.rb +++ b/spec/tasks/gitlab/backup_rake_spec.rb @@ -16,7 +16,7 @@ describe 'gitlab:app namespace rake task' do end def reenable_backup_sub_tasks - %w{db repo uploads builds}.each do |subtask| + %w{db repo uploads builds artifacts}.each do |subtask| Rake::Task["gitlab:backup:#{subtask}:create"].reenable end end @@ -56,6 +56,7 @@ describe 'gitlab:app namespace rake task' do expect(Rake::Task["gitlab:backup:repo:restore"]).to receive(:invoke) expect(Rake::Task["gitlab:backup:builds:restore"]).to receive(:invoke) expect(Rake::Task["gitlab:backup:uploads:restore"]).to receive(:invoke) + expect(Rake::Task["gitlab:backup:artifacts:restore"]).to receive(:invoke) expect(Rake::Task["gitlab:shell:setup"]).to receive(:invoke) expect { run_rake_task('gitlab:backup:restore') }.not_to raise_error end @@ -113,19 +114,20 @@ describe 'gitlab:app namespace rake task' do it 'should set correct permissions on the tar contents' do tar_contents, exit_status = Gitlab::Popen.popen( - %W{tar -tvf #{@backup_tar} db uploads.tar.gz repositories builds.tar.gz} + %W{tar -tvf #{@backup_tar} db uploads.tar.gz repositories builds.tar.gz artifacts.tar.gz} ) expect(exit_status).to eq(0) expect(tar_contents).to match('db/') expect(tar_contents).to match('uploads.tar.gz') expect(tar_contents).to match('repositories/') expect(tar_contents).to match('builds.tar.gz') - expect(tar_contents).not_to match(/^.{4,9}[rwx].* (database.sql.gz|uploads.tar.gz|repositories|builds.tar.gz)\/$/) + expect(tar_contents).to match('artifacts.tar.gz') + expect(tar_contents).not_to match(/^.{4,9}[rwx].* (database.sql.gz|uploads.tar.gz|repositories|builds.tar.gz|artifacts.tar.gz)\/$/) end it 'should delete temp directories' do temp_dirs = Dir.glob( - File.join(Gitlab.config.backup.path, '{db,repositories,uploads,builds}') + File.join(Gitlab.config.backup.path, '{db,repositories,uploads,builds,artifacts}') ) expect(temp_dirs).to be_empty @@ -161,12 +163,13 @@ describe 'gitlab:app namespace rake task' do it "does not contain skipped item" do tar_contents, _exit_status = Gitlab::Popen.popen( - %W{tar -tvf #{@backup_tar} db uploads.tar.gz repositories builds.tar.gz} + %W{tar -tvf #{@backup_tar} db uploads.tar.gz repositories builds.tar.gz artifacts.tar.gz} ) expect(tar_contents).to match('db/') expect(tar_contents).to match('uploads.tar.gz') expect(tar_contents).to match('builds.tar.gz') + expect(tar_contents).to match('artifacts.tar.gz') expect(tar_contents).not_to match('repositories/') end @@ -178,6 +181,7 @@ describe 'gitlab:app namespace rake task' do expect(Rake::Task["gitlab:backup:db:restore"]).to receive :invoke expect(Rake::Task["gitlab:backup:repo:restore"]).not_to receive :invoke expect(Rake::Task["gitlab:backup:builds:restore"]).to receive :invoke + expect(Rake::Task["gitlab:backup:artifacts:restore"]).to receive :invoke expect(Rake::Task["gitlab:shell:setup"]).to receive :invoke expect { run_rake_task('gitlab:backup:restore') }.not_to raise_error end -- cgit v1.2.1 From 97f58bae87dfcfb36d5a7a490b1c0983435a19f4 Mon Sep 17 00:00:00 2001 From: Kamil Trzcinski Date: Mon, 9 Nov 2015 12:18:00 +0100 Subject: Change artifacts syntax to allow uploading untracked files --- doc/ci/yaml/README.md | 21 ++++++++++++++++++--- lib/ci/gitlab_ci_yaml_processor.rb | 16 +++++++++++++--- spec/lib/ci/gitlab_ci_yaml_processor_spec.rb | 23 ++++++++++++++++++----- 3 files changed, 49 insertions(+), 11 deletions(-) diff --git a/doc/ci/yaml/README.md b/doc/ci/yaml/README.md index d8504aca86a..11065fee012 100644 --- a/doc/ci/yaml/README.md +++ b/doc/ci/yaml/README.md @@ -262,13 +262,28 @@ The above script will: ### artifacts `artifacts` is used to specify list of files and directories which should be attached to build after success. +1. Send all files in `binaries` and `.config`: ``` artifacts: -- binaries/ -- .config + paths: + - binaries/ + - .config +``` + +2. Send all git untracked files: +``` +artifacts: + untracked: true +``` + +3. Send all git untracked files and files in `binaries`: +``` +artifacts: + untracked: true + paths: + - binaries/ ``` -The above definition will archive all files in `binaries/` and `.config`. The artifacts will be send after the build success to GitLab and will be accessible in GitLab interface to download. This feature requires GitLab Runner v 0.7.0. diff --git a/lib/ci/gitlab_ci_yaml_processor.rb b/lib/ci/gitlab_ci_yaml_processor.rb index 6f9af5388ca..2e2209031ee 100644 --- a/lib/ci/gitlab_ci_yaml_processor.rb +++ b/lib/ci/gitlab_ci_yaml_processor.rb @@ -160,11 +160,17 @@ module Ci raise ValidationError, "#{name} job: except parameter should be an array of strings" end - if job[:artifacts] && !validate_array_of_strings(job[:artifacts]) - raise ValidationError, "#{name}: artifacts parameter should be an array of strings" + if job[:artifacts] + if job[:artifacts][:untracked] && !validate_boolean(job[:artifacts][:untracked]) + raise ValidationError, "#{name} job: artifacts:untracked parameter should be an boolean" + end + + if job[:artifacts][:paths] && !validate_array_of_strings(job[:artifacts][:paths]) + raise ValidationError, "#{name} job: artifacts:paths parameter should be an array of strings" + end end - if job[:allow_failure] && !job[:allow_failure].in?([true, false]) + if job[:allow_failure] && !validate_boolean(job[:allow_failure]) raise ValidationError, "#{name} job: allow_failure parameter should be an boolean" end @@ -187,6 +193,10 @@ module Ci value.is_a?(String) || value.is_a?(Symbol) end + def validate_boolean(value) + value.in?([true, false]) + end + def process?(only_params, except_params, ref, tag) if only_params.present? return false unless matching?(only_params, ref, tag) diff --git a/spec/lib/ci/gitlab_ci_yaml_processor_spec.rb b/spec/lib/ci/gitlab_ci_yaml_processor_spec.rb index 5e3779af19e..29fc2713821 100644 --- a/spec/lib/ci/gitlab_ci_yaml_processor_spec.rb +++ b/spec/lib/ci/gitlab_ci_yaml_processor_spec.rb @@ -339,7 +339,10 @@ module Ci image: "ruby:2.1", services: ["mysql"], before_script: ["pwd"], - rspec: { artifacts: ["logs/", "binaries/"], script: "rspec" } + rspec: { + artifacts: { paths: ["logs/", "binaries/"], untracked: true }, + script: "rspec" + } }) config_processor = GitlabCiYamlProcessor.new(config) @@ -356,7 +359,10 @@ module Ci options: { image: "ruby:2.1", services: ["mysql"], - artifacts: ["logs/", "binaries/"] + artifacts: { + paths: ["logs/", "binaries/"], + untracked: true + } }, when: "on_success", allow_failure: false @@ -523,11 +529,18 @@ module Ci end.to raise_error(GitlabCiYamlProcessor::ValidationError, "rspec job: when parameter should be on_success, on_failure or always") end - it "returns errors if job artifacts is not an array of strings" do - config = YAML.dump({ types: ["build", "test"], rspec: { script: "test", artifacts: "string" } }) + it "returns errors if job artifacts:untracked is not an array of strings" do + config = YAML.dump({ types: ["build", "test"], rspec: { script: "test", artifacts: { untracked: "string" } } }) expect do GitlabCiYamlProcessor.new(config) - end.to raise_error(GitlabCiYamlProcessor::ValidationError, "rspec job: artifacts parameter should be an array of strings") + end.to raise_error(GitlabCiYamlProcessor::ValidationError, "rspec job: artifacts:untracked parameter should be an boolean") + end + + it "returns errors if job artifacts:paths is not an array of strings" do + config = YAML.dump({ types: ["build", "test"], rspec: { script: "test", artifacts: { paths: "string" } } }) + expect do + GitlabCiYamlProcessor.new(config) + end.to raise_error(GitlabCiYamlProcessor::ValidationError, "rspec job: artifacts:paths parameter should be an array of strings") end end end -- cgit v1.2.1 From 445cdb7579792d0d76c2562b971583bd7d05429b Mon Sep 17 00:00:00 2001 From: Kamil Trzcinski Date: Mon, 9 Nov 2015 12:49:47 +0100 Subject: Move tmp artifacts to shared/artifacts/tmp/. Check for GitLab-Workhorse now --- .gitignore | 2 -- app/uploaders/artifact_uploader.rb | 4 ++-- doc/install/installation.md | 2 -- lib/api/helpers.rb | 2 +- shared/artifacts/tmp/cache/.gitkeep | 0 shared/artifacts/tmp/uploads/.gitkeep | 0 shared/tmp/artifacts-cache/.gitkeep | 0 shared/tmp/artifacts-uploads/.gitkeep | 0 spec/requests/ci/api/builds_spec.rb | 2 +- 9 files changed, 4 insertions(+), 8 deletions(-) create mode 100644 shared/artifacts/tmp/cache/.gitkeep create mode 100644 shared/artifacts/tmp/uploads/.gitkeep delete mode 100644 shared/tmp/artifacts-cache/.gitkeep delete mode 100644 shared/tmp/artifacts-uploads/.gitkeep diff --git a/.gitignore b/.gitignore index fd137a50473..39ff95c50ee 100644 --- a/.gitignore +++ b/.gitignore @@ -38,8 +38,6 @@ public/assets/ public/uploads.* public/uploads/ shared/artifacts/ -shared/tmp/artifacts-uploads/ -shared/tmp/artifacts-cache/ rails_best_practices_output.html /tags tmp/ diff --git a/app/uploaders/artifact_uploader.rb b/app/uploaders/artifact_uploader.rb index 848e0bcbde1..b4e0fc5772d 100644 --- a/app/uploaders/artifact_uploader.rb +++ b/app/uploaders/artifact_uploader.rb @@ -9,11 +9,11 @@ class ArtifactUploader < CarrierWave::Uploader::Base end def self.artifacts_upload_path - File.expand_path('shared/tmp/artifacts-uploads/', Rails.root) + File.expand_path('shared/artifacts/tmp/uploads/', Rails.root) end def self.artifacts_cache_path - File.expand_path('shared/tmp/artifacts-cache/', Rails.root) + File.expand_path('shared/artifacts/tmp/cache/', Rails.root) end def initialize(build, field) diff --git a/doc/install/installation.md b/doc/install/installation.md index 0ece8bd9315..8028e51dbcd 100644 --- a/doc/install/installation.md +++ b/doc/install/installation.md @@ -248,8 +248,6 @@ We recommend using a PostgreSQL database. For MySQL check [MySQL setup guide](da # Change the permissions of the directory where CI artifacts are stored sudo chmod -R u+rwX shared/artifacts/ - sudo chmod -R u+rwX shared/tmp/artifacts-uploads/ - sudo chmod -R u+rwX shared/tmp/artifacts-cache/ # Copy the example Unicorn config sudo -u git -H cp config/unicorn.rb.example config/unicorn.rb diff --git a/lib/api/helpers.rb b/lib/api/helpers.rb index b980cd8391e..077537959d7 100644 --- a/lib/api/helpers.rb +++ b/lib/api/helpers.rb @@ -134,7 +134,7 @@ module API end def require_gitlab_workhorse! - unless headers['Gitlab-Git-Http-Server'].present? || headers['GitLab-Git-HTTP-Server'].present? + unless env['HTTP_GITLAB_WORKHORSE'].present? forbidden!('Request should be executed via GitLab Workhorse') end end diff --git a/shared/artifacts/tmp/cache/.gitkeep b/shared/artifacts/tmp/cache/.gitkeep new file mode 100644 index 00000000000..e69de29bb2d diff --git a/shared/artifacts/tmp/uploads/.gitkeep b/shared/artifacts/tmp/uploads/.gitkeep new file mode 100644 index 00000000000..e69de29bb2d diff --git a/shared/tmp/artifacts-cache/.gitkeep b/shared/tmp/artifacts-cache/.gitkeep deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/shared/tmp/artifacts-uploads/.gitkeep b/shared/tmp/artifacts-uploads/.gitkeep deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/spec/requests/ci/api/builds_spec.rb b/spec/requests/ci/api/builds_spec.rb index 92ea25a3723..0076730ef2f 100644 --- a/spec/requests/ci/api/builds_spec.rb +++ b/spec/requests/ci/api/builds_spec.rb @@ -132,7 +132,7 @@ describe Ci::API::API do let(:post_url) { ci_api("/builds/#{build.id}/artifacts") } let(:delete_url) { ci_api("/builds/#{build.id}/artifacts") } let(:get_url) { ci_api("/builds/#{build.id}/artifacts") } - let(:headers) { { "Gitlab-Git-Http-Server" => "1.0" } } + let(:headers) { { "GitLab-Workhorse" => "1.0" } } let(:headers_with_token) { headers.merge(Ci::API::Helpers::BUILD_TOKEN_HEADER => build.project.token) } describe "POST /builds/:id/artifacts/authorize" do -- cgit v1.2.1 From 7e4e3fb3b6177d2863580786e9ef6ee3a4ccf037 Mon Sep 17 00:00:00 2001 From: Kamil Trzcinski Date: Mon, 9 Nov 2015 12:55:32 +0100 Subject: Fix nginx config to use @gitlab-workhorse --- lib/support/nginx/gitlab | 8 ++++---- lib/support/nginx/gitlab-ssl | 8 ++++---- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/lib/support/nginx/gitlab b/lib/support/nginx/gitlab index e511d5e4b4b..0a7a4118077 100644 --- a/lib/support/nginx/gitlab +++ b/lib/support/nginx/gitlab @@ -134,16 +134,16 @@ server { # Build artifacts should be submitted to this location location ~ ^/[\w\.-]+/[\w\.-]+/builds/download { client_max_body_size 0; - # 'Error' 418 is a hack to re-use the @gitlab-git-http-server block - error_page 418 = @gitlab-git-http-server; + # 'Error' 418 is a hack to re-use the @gitlab-workhorse block + error_page 418 = @gitlab-workhorse; return 418; } # Build artifacts should be submitted to this location location ~ /ci/api/v1/builds/[0-9]+/artifacts { client_max_body_size 0; - # 'Error' 418 is a hack to re-use the @gitlab-git-http-server block - error_page 418 = @gitlab-git-http-server; + # 'Error' 418 is a hack to re-use the @gitlab-workhorse block + error_page 418 = @gitlab-workhorse; return 418; } diff --git a/lib/support/nginx/gitlab-ssl b/lib/support/nginx/gitlab-ssl index 47b1ec8cb0c..b463d5b6aa9 100644 --- a/lib/support/nginx/gitlab-ssl +++ b/lib/support/nginx/gitlab-ssl @@ -181,16 +181,16 @@ server { # Build artifacts should be submitted to this location location ~ ^/[\w\.-]+/[\w\.-]+/builds/download { client_max_body_size 0; - # 'Error' 418 is a hack to re-use the @gitlab-git-http-server block - error_page 418 = @gitlab-git-http-server; + # 'Error' 418 is a hack to re-use the @gitlab-workhorse block + error_page 418 = @gitlab-workhorse; return 418; } # Build artifacts should be submitted to this location location ~ /ci/api/v1/builds/[0-9]+/artifacts { client_max_body_size 0; - # 'Error' 418 is a hack to re-use the @gitlab-git-http-server block - error_page 418 = @gitlab-git-http-server; + # 'Error' 418 is a hack to re-use the @gitlab-workhorse block + error_page 418 = @gitlab-workhorse; return 418; } -- cgit v1.2.1 From db3213fc1c653b20783f9a41074eaf17132010de Mon Sep 17 00:00:00 2001 From: Kamil Trzcinski Date: Mon, 9 Nov 2015 22:01:26 +0100 Subject: Use normal file upload mechanism to upload artifacts --- lib/api/helpers.rb | 16 ++++++++++------ lib/ci/api/builds.rb | 16 +++++++--------- spec/requests/ci/api/builds_spec.rb | 25 +++++++++++++++++-------- 3 files changed, 34 insertions(+), 23 deletions(-) diff --git a/lib/api/helpers.rb b/lib/api/helpers.rb index 077537959d7..92540ccf2b1 100644 --- a/lib/api/helpers.rb +++ b/lib/api/helpers.rb @@ -294,19 +294,23 @@ module API # file helpers - def uploaded_file!(uploads_path) - required_attributes! [:file] + def uploaded_file!(field, uploads_path) + if params[field] + bad_request!("#{field} is not a file") unless params[field].respond_to?(:filename) + return params[field] + end # sanitize file paths - # this requires for all paths to exist + # this requires all paths to exist + required_attributes! %W(#{field}.path) uploads_path = File.realpath(uploads_path) - file_path = File.realpath(params[:file]) + file_path = File.realpath(params["#{field}.path"]) bad_request!('Bad file path') unless file_path.start_with?(uploads_path) UploadedFile.new( file_path, - params[:filename], - params[:filetype] || 'application/octet-stream', + params["#{field}.name"], + params["#{field}.type"] || 'application/octet-stream', ) end diff --git a/lib/ci/api/builds.rb b/lib/ci/api/builds.rb index 622849c4b11..dab0df12635 100644 --- a/lib/ci/api/builds.rb +++ b/lib/ci/api/builds.rb @@ -53,7 +53,7 @@ module Ci # Parameters: # id (required) - The ID of a build # token (required) - The build authorization token - # size (optional) - the size of uploaded file + # filesize (optional) - the size of uploaded file # Example Request: # POST /builds/:id/artifacts/authorize post ":id/artifacts/authorize" do @@ -77,18 +77,16 @@ module Ci # Parameters: # id (required) - The ID of a build # token (required) - The build authorization token + # file (required) - The uploaded file + # Parameters (accelerated by GitLab Workhorse): + # file.path - path to locally stored body (generated by Workhorse) + # file.name - real filename as send in Content-Disposition + # file.type - real content type as send in Content-Type # Headers: - # Content-Type - File content type - # Content-Disposition - File media type and real name # BUILD-TOKEN (required) - The build authorization token, the same as token # Body: # The file content # - # Parameters (set by GitLab Workhorse): - # file - path to locally stored body (generated by Workhorse) - # filename - real filename as send in Content-Disposition - # filetype - real content type as send in Content-Type - # filesize - real file size as send in Content-Length # Example Request: # POST /builds/:id/artifacts post ":id/artifacts" do @@ -98,7 +96,7 @@ module Ci authenticate_build_token!(build) forbidden!('build is not running') unless build.running? - file = uploaded_file!(ArtifactUploader.artifacts_upload_path) + file = uploaded_file!(:file, ArtifactUploader.artifacts_upload_path) file_to_large! unless file.size < max_artifacts_size if build.update_attributes(artifacts_file: file) diff --git a/spec/requests/ci/api/builds_spec.rb b/spec/requests/ci/api/builds_spec.rb index 0076730ef2f..233c15f87fe 100644 --- a/spec/requests/ci/api/builds_spec.rb +++ b/spec/requests/ci/api/builds_spec.rb @@ -194,8 +194,14 @@ describe Ci::API::API do build.run! end - it do - upload_artifacts(file_upload, headers_with_token) + it "uses regual file post" do + upload_artifacts(file_upload, headers_with_token, false) + expect(response.status).to eq(201) + expect(json_response["artifacts_file"]["filename"]).to eq(file_upload.original_filename) + end + + it "uses accelerated file post" do + upload_artifacts(file_upload, headers_with_token, true) expect(response.status).to eq(201) expect(json_response["artifacts_file"]["filename"]).to eq(file_upload.original_filename) end @@ -263,12 +269,15 @@ describe Ci::API::API do end end - def upload_artifacts(file, headers = {}) - params = { - file: file.path, - filename: file.original_filename, - } - post post_url, params, headers + def upload_artifacts(file, headers = {}, accelerated = true) + if accelerated + post post_url, { + 'file.path' => file.path, + 'file.name' => file.original_filename + }, headers + else + post post_url, { file: file }, headers + end end end -- cgit v1.2.1 From 99c05363ea8ff53cfa9620b626325773d17bb575 Mon Sep 17 00:00:00 2001 From: Stan Hu Date: Tue, 10 Nov 2015 07:19:31 -0800 Subject: Remove CSS property preventing hard tabs from rendering in Chromium 45 This is to workaround a bug in Chromium 45 (https://code.google.com/p/chromium/issues/detail?id=446434), which is the default browser in Ubuntu 14.04 and older. Closes #3220 --- CHANGELOG | 1 + app/assets/stylesheets/framework/typography.scss | 1 - 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG b/CHANGELOG index 668ea87b28f..c6bacab6a5e 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,6 +1,7 @@ Please view this file on the master branch, on stable branches it's out of date. v 8.2.0 (unreleased) + - Remove CSS property preventing hard tabs from rendering in Chromium 45 (Stan Hu) - Added a GitLab specific profiling tool called "Sherlock" (see GitLab CE merge request #1749) - Upgrade gitlab_git to 7.2.20 and rugged to 0.23.3 (Stan Hu) - Fix bug where manually merged branches in a MR would end up with an empty diff (Stan Hu) diff --git a/app/assets/stylesheets/framework/typography.scss b/app/assets/stylesheets/framework/typography.scss index e6558a23858..ba0312ba0db 100644 --- a/app/assets/stylesheets/framework/typography.scss +++ b/app/assets/stylesheets/framework/typography.scss @@ -173,7 +173,6 @@ * */ body { - text-rendering:optimizeLegibility; -webkit-text-shadow: rgba(255,255,255,0.01) 0 0 1px; } -- cgit v1.2.1 From 802b8fceb444f02fb8c2f67c5c433832baa33be7 Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Tue, 10 Nov 2015 16:27:50 +0100 Subject: Fix graph description and text Signed-off-by: Dmitriy Zaporozhets --- app/views/projects/graphs/ci/_builds.haml | 4 ++-- features/steps/project/graph.rb | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/app/views/projects/graphs/ci/_builds.haml b/app/views/projects/graphs/ci/_builds.haml index 84247455403..8fca07114fa 100644 --- a/app/views/projects/graphs/ci/_builds.haml +++ b/app/views/projects/graphs/ci/_builds.haml @@ -17,13 +17,13 @@ .prepend-top-default %p.light - Builds chart for last month + Builds for last month (#{date_from_to(Date.today - 30.days, Date.today)}) %canvas#monthChart{height: 200} .prepend-top-default %p.light - Builds chart for last year + Builds for last year %canvas#yearChart.padded{height: 250} - [:week, :month, :year].each do |scope| diff --git a/features/steps/project/graph.rb b/features/steps/project/graph.rb index 4abd5288d51..98f31f3b76a 100644 --- a/features/steps/project/graph.rb +++ b/features/steps/project/graph.rb @@ -25,9 +25,9 @@ class Spinach::Features::ProjectGraph < Spinach::FeatureSteps step 'page should have CI graphs' do expect(page).to have_content 'Overall' - expect(page).to have_content 'Builds chart for last week' - expect(page).to have_content 'Builds chart for last month' - expect(page).to have_content 'Builds chart for last year' + expect(page).to have_content 'Builds for last week' + expect(page).to have_content 'Builds for last month' + expect(page).to have_content 'Builds for last year' expect(page).to have_content 'Commit duration in minutes for last 30 commits' end -- cgit v1.2.1 From 78966d4ca635506ee5323a88423275bc44d84a49 Mon Sep 17 00:00:00 2001 From: Stan Hu Date: Tue, 10 Nov 2015 07:36:10 -0800 Subject: Bump rugged version to be in line with gitlab_git requirements --- Gemfile.lock | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Gemfile.lock b/Gemfile.lock index 1688ea4d9d8..aae1ec7610c 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -611,7 +611,7 @@ GEM sexp_processor (~> 4.1) rubyntlm (0.5.2) rubypants (0.2.0) - rugged (0.22.2) + rugged (0.23.3) safe_yaml (1.0.4) sanitize (2.1.0) nokogiri (>= 1.4.4) -- cgit v1.2.1 From ffa8d84a6ef27dea6d87650390821d42f3d1b38a Mon Sep 17 00:00:00 2001 From: Stan Hu Date: Tue, 10 Nov 2015 07:56:05 -0800 Subject: Bump charlock_holmes version --- Gemfile.lock | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Gemfile.lock b/Gemfile.lock index aae1ec7610c..dca8606806a 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -107,7 +107,7 @@ GEM json (>= 1.7) celluloid (0.16.0) timers (~> 4.0.0) - charlock_holmes (0.6.9.4) + charlock_holmes (0.7.3) chunky_png (1.3.4) cliver (0.3.2) coderay (1.1.0) -- cgit v1.2.1 From b0452f26c0c3274d9d16c4b7e6f170737de4e31e Mon Sep 17 00:00:00 2001 From: Stan Hu Date: Tue, 10 Nov 2015 08:16:33 -0800 Subject: Remove duplicate CHANGELOG etnries [ci skip] --- CHANGELOG | 2 -- 1 file changed, 2 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index 668ea87b28f..168c4b50e4a 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -3,8 +3,6 @@ Please view this file on the master branch, on stable branches it's out of date. v 8.2.0 (unreleased) - Added a GitLab specific profiling tool called "Sherlock" (see GitLab CE merge request #1749) - Upgrade gitlab_git to 7.2.20 and rugged to 0.23.3 (Stan Hu) - - Fix bug where manually merged branches in a MR would end up with an empty diff (Stan Hu) - - Force update refs/merge-requests/X/head upon a push to the source branch of a merge request (Stan Hu) - Improved performance of finding users by one of their Email addresses - Improved performance of replacing references in comments - Show last project commit to default branch on project home page -- cgit v1.2.1 From 58429d9b26b2f2b62fecab012fce0ebe36571129 Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Tue, 10 Nov 2015 18:34:05 +0100 Subject: Add method complexity check to CI Signed-off-by: Dmitriy Zaporozhets --- .gitlab-ci.yml | 7 +++++++ Gemfile | 1 + Gemfile.lock | 4 ++++ lib/tasks/flog.rake | 24 ++++++++++++++++++++++++ 4 files changed, 36 insertions(+) create mode 100644 lib/tasks/flog.rake diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index cf6d28b01af..476dabe5e3d 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -73,3 +73,10 @@ brakeman: tags: - ruby - mysql + +flog: + script: + - bundle exec rake flog + tags: + - ruby + - mysql diff --git a/Gemfile b/Gemfile index c73aa26bd0a..91a93215336 100644 --- a/Gemfile +++ b/Gemfile @@ -259,6 +259,7 @@ group :development, :test do gem 'rubocop', '~> 0.28.0', require: false gem 'coveralls', '~> 0.8.2', require: false gem 'simplecov', '~> 0.10.0', require: false + gem 'flog', require: false gem 'benchmark-ips', require: false end diff --git a/Gemfile.lock b/Gemfile.lock index dca8606806a..0fc22829cfd 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -194,6 +194,9 @@ GEM ffi (1.9.10) fission (0.5.0) CFPropertyList (~> 2.2) + flog (4.3.2) + ruby_parser (~> 3.1, > 3.1.0) + sexp_processor (~> 4.4) flowdock (0.7.0) httparty (~> 0.7) multi_json @@ -821,6 +824,7 @@ DEPENDENCIES enumerize (~> 0.7.0) factory_girl_rails (~> 4.3.0) ffaker (~> 2.0.0) + flog fog (~> 1.25.0) font-awesome-rails (~> 4.2) foreman diff --git a/lib/tasks/flog.rake b/lib/tasks/flog.rake new file mode 100644 index 00000000000..4cb19c0c937 --- /dev/null +++ b/lib/tasks/flog.rake @@ -0,0 +1,24 @@ +desc 'Code complexity analyze via flog' +task :flog do + output = %x(bundle exec flog -m app/ lib/gitlab) + exit_code = 0 + output = output.lines + + # Skip total complexity score + output.shift + + # Skip some trash info + output.shift + + output.each do |line| + score, method = line.split(" ") + score = score.to_i + + if score > 40 + exit_code = 1 + puts "High complexity in #{method}. Score: #{score}" + end + end + + exit exit_code +end -- cgit v1.2.1 From afcced01e579cb75d876c4612fc09e87d1502da6 Mon Sep 17 00:00:00 2001 From: Robert Speicher Date: Tue, 10 Nov 2015 13:15:18 -0500 Subject: Remove text-rendering property Closes #3220 [ci skip] --- app/assets/stylesheets/framework/layout.scss | 1 - 1 file changed, 1 deletion(-) diff --git a/app/assets/stylesheets/framework/layout.scss b/app/assets/stylesheets/framework/layout.scss index c7b3b60e769..b91c15d8910 100644 --- a/app/assets/stylesheets/framework/layout.scss +++ b/app/assets/stylesheets/framework/layout.scss @@ -5,7 +5,6 @@ html { body { padding-top: $header-height; - text-rendering: geometricPrecision; } } -- cgit v1.2.1 From 5aa142212fc4fb7765aad801c1a25696fb752fba Mon Sep 17 00:00:00 2001 From: Stan Hu Date: Tue, 10 Nov 2015 00:27:01 -0800 Subject: Fix Drone CI service template not saving properly Closes #3419 --- CHANGELOG | 1 + app/models/project_services/drone_ci_service.rb | 1 - 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG b/CHANGELOG index d82cab6f36c..7567e25b891 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -2,6 +2,7 @@ Please view this file on the master branch, on stable branches it's out of date. v 8.2.0 (unreleased) - Remove CSS property preventing hard tabs from rendering in Chromium 45 (Stan Hu) + - Fix Drone CI service template not saving properly (Stan Hu) - Added a GitLab specific profiling tool called "Sherlock" (see GitLab CE merge request #1749) - Upgrade gitlab_git to 7.2.20 and rugged to 0.23.3 (Stan Hu) - Improved performance of finding users by one of their Email addresses diff --git a/app/models/project_services/drone_ci_service.rb b/app/models/project_services/drone_ci_service.rb index c73c4b058a1..c240213200d 100644 --- a/app/models/project_services/drone_ci_service.rb +++ b/app/models/project_services/drone_ci_service.rb @@ -32,7 +32,6 @@ class DroneCiService < CiService def compose_service_hook hook = service_hook || build_service_hook - hook.url = [drone_url, "/api/hook", "?owner=#{project.namespace.path}", "&name=#{project.path}", "&access_token=#{token}"].join hook.enable_ssl_verification = enable_ssl_verification hook.save end -- cgit v1.2.1 From ca25289b78e1b49148438831ad6bf165fa0ce56e Mon Sep 17 00:00:00 2001 From: Robert Speicher Date: Tue, 10 Nov 2015 15:44:23 -0500 Subject: Update CHANGELOG [ci skip] --- CHANGELOG | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index 2b96a0a171b..9cfcd23a9fc 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -34,7 +34,9 @@ v 8.2.0 (unreleased) v 8.1.4 - Fix bug where manually merged branches in a MR would end up with an empty diff (Stan Hu) - Prevent redirect loop when home_page_url is set to the root URL - - Ability to add release notes (markdown text and attachments) to git tags + - Fix incoming email config defaults + - Make color of "Accept Merge Request" button consistent with current build status + - Remove CSS property preventing hard tabs from rendering in Chromium 45 (Stan Hu) v 8.1.3 - Force update refs/merge-requests/X/head upon a push to the source branch of a merge request (Stan Hu) @@ -42,7 +44,7 @@ v 8.1.3 - Use issue editor as cross reference comment author when issue is edited with a new mention - Add Facebook authentication -v 8.1.1 +v 8.1.2 - Fix cloning Wiki repositories via HTTP (Stan Hu) - Add migration to remove satellites directory - Fix specific runners visibility @@ -52,6 +54,9 @@ v 8.1.1 - Fix CI badge - Allow developer to manage builds +v 8.1.1 + - Removed, see 8.1.2 + v 8.1.0 - Ensure MySQL CI limits DB migrations occur after the fields have been created (Stan Hu) - Fix duplicate repositories in GitHub import page (Stan Hu) -- cgit v1.2.1 From eef129bd4ad41665cf5c1f1631e80b2f1bb3e4af Mon Sep 17 00:00:00 2001 From: Kamil Trzcinski Date: Tue, 10 Nov 2015 22:21:15 +0100 Subject: Final fixes --- config/initializers/1_settings.rb | 2 +- doc/ci/yaml/README.md | 2 +- lib/ci/api/builds.rb | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/config/initializers/1_settings.rb b/config/initializers/1_settings.rb index b39e263e39a..302124bd977 100644 --- a/config/initializers/1_settings.rb +++ b/config/initializers/1_settings.rb @@ -186,7 +186,7 @@ Settings.gitlab_ci['all_broken_builds'] = true if Settings.gitlab_ci['all_br Settings.gitlab_ci['add_pusher'] = false if Settings.gitlab_ci['add_pusher'].nil? Settings.gitlab_ci['url'] ||= Settings.send(:build_gitlab_ci_url) Settings.gitlab_ci['builds_path'] = File.expand_path(Settings.gitlab_ci['builds_path'] || "builds/", Rails.root) -Settings.gitlab_ci['max_artifacts_size'] ||= 100 +Settings.gitlab_ci['max_artifacts_size'] ||= 100 # in megabytes # # Reply by email diff --git a/doc/ci/yaml/README.md b/doc/ci/yaml/README.md index 11065fee012..5d35d1da4ee 100644 --- a/doc/ci/yaml/README.md +++ b/doc/ci/yaml/README.md @@ -286,7 +286,7 @@ artifacts: The artifacts will be send after the build success to GitLab and will be accessible in GitLab interface to download. -This feature requires GitLab Runner v 0.7.0. +This feature requires GitLab Runner v0.7.0 or higher. ## Validate the .gitlab-ci.yml Each instance of GitLab CI has an embedded debug tool called Lint. diff --git a/lib/ci/api/builds.rb b/lib/ci/api/builds.rb index dab0df12635..0a586672807 100644 --- a/lib/ci/api/builds.rb +++ b/lib/ci/api/builds.rb @@ -69,7 +69,7 @@ module Ci end status 200 - { temp_path: ArtifactUploader.artifacts_upload_path } + { TempPath: ArtifactUploader.artifacts_upload_path } end # Upload artifacts to build - Runners only -- cgit v1.2.1 From d70f1f35b13411adf184fafb750ae8d8fb6badea Mon Sep 17 00:00:00 2001 From: Kamil Trzcinski Date: Tue, 10 Nov 2015 23:00:05 +0100 Subject: Fix tests --- spec/requests/ci/api/builds_spec.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/spec/requests/ci/api/builds_spec.rb b/spec/requests/ci/api/builds_spec.rb index 233c15f87fe..7886a6feca2 100644 --- a/spec/requests/ci/api/builds_spec.rb +++ b/spec/requests/ci/api/builds_spec.rb @@ -144,13 +144,13 @@ describe Ci::API::API do it "using token as parameter" do post authorize_url, { token: build.project.token }, headers expect(response.status).to eq(200) - expect(json_response["temp_path"]).to_not be_nil + expect(json_response["TempPath"]).to_not be_nil end it "using token as header" do post authorize_url, {}, headers_with_token expect(response.status).to eq(200) - expect(json_response["temp_path"]).to_not be_nil + expect(json_response["TempPath"]).to_not be_nil end end -- cgit v1.2.1 From 26fab9cb95bda08a044f5500ef0b74854b293a54 Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Wed, 11 Nov 2015 13:40:47 +0000 Subject: Fix typo in email comment: hone -> one --- app/views/layouts/notify.html.haml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/views/layouts/notify.html.haml b/app/views/layouts/notify.html.haml index a02dd955186..3ca4c340406 100644 --- a/app/views/layouts/notify.html.haml +++ b/app/views/layouts/notify.html.haml @@ -42,8 +42,8 @@ - else #{link_to "View it on GitLab", @target_url}. %br - -# Don't link the host is the line below, hone link in the email is easier to quickly click than two. + -# Don't link the host is the line below, one link in the email is easier to quickly click than two. You're receiving this email because of your account on #{Gitlab.config.gitlab.host}. If you'd like to receive fewer emails, you can adjust your notification settings. - = email_action @target_url + = email_action @target_url \ No newline at end of file -- cgit v1.2.1 From 7eb502c036f412e9e802600cd67c6520a1f3bff1 Mon Sep 17 00:00:00 2001 From: Yorick Peterse Date: Wed, 11 Nov 2015 15:17:12 +0100 Subject: Change "recent" scopes to sort by "id" These scopes can just sort by the "id" column in descending order to achieve the same result. An added benefit is being able to perform a backwards index scan (depending on the rest of the final query) instead of having to actually sort data. --- app/models/concerns/issuable.rb | 2 +- app/models/event.rb | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/app/models/concerns/issuable.rb b/app/models/concerns/issuable.rb index 5e964f04ef5..492a026add9 100644 --- a/app/models/concerns/issuable.rb +++ b/app/models/concerns/issuable.rb @@ -24,7 +24,7 @@ module Issuable scope :authored, ->(user) { where(author_id: user) } scope :assigned_to, ->(u) { where(assignee_id: u.id)} - scope :recent, -> { order("created_at DESC") } + scope :recent, -> { reorder(id: :desc) } scope :assigned, -> { where("assignee_id IS NOT NULL") } scope :unassigned, -> { where("assignee_id IS NULL") } scope :of_projects, ->(ids) { where(project_id: ids) } diff --git a/app/models/event.rb b/app/models/event.rb index 47600c57e35..bf64ac29d32 100644 --- a/app/models/event.rb +++ b/app/models/event.rb @@ -45,7 +45,7 @@ class Event < ActiveRecord::Base after_create :reset_project_activity # Scopes - scope :recent, -> { order(created_at: :desc) } + scope :recent, -> { reorder(id: :desc) } scope :code_push, -> { where(action: PUSHED) } scope :in_projects, ->(project_ids) { where(project_id: project_ids).recent } scope :with_associations, -> { includes(project: :namespace) } -- cgit v1.2.1 From 6748dd2fd0b2cf694661e910c6c1bb6ac2be69a1 Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Wed, 11 Nov 2015 15:30:23 +0100 Subject: Allow flog failure for now Signed-off-by: Dmitriy Zaporozhets --- .gitlab-ci.yml | 1 + lib/tasks/flog.rake | 3 ++- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 476dabe5e3d..062fda322a6 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -80,3 +80,4 @@ flog: tags: - ruby - mysql + allow_failure: true diff --git a/lib/tasks/flog.rake b/lib/tasks/flog.rake index 4cb19c0c937..3bfe999ae74 100644 --- a/lib/tasks/flog.rake +++ b/lib/tasks/flog.rake @@ -2,6 +2,7 @@ desc 'Code complexity analyze via flog' task :flog do output = %x(bundle exec flog -m app/ lib/gitlab) exit_code = 0 + minimum_score = 70 output = output.lines # Skip total complexity score @@ -14,7 +15,7 @@ task :flog do score, method = line.split(" ") score = score.to_i - if score > 40 + if score > minimum_score exit_code = 1 puts "High complexity in #{method}. Score: #{score}" end -- cgit v1.2.1 From 98c954ee815823f27cf021b34684c2c3d5bb0917 Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Wed, 11 Nov 2015 16:29:00 +0100 Subject: Add flay: tool to find duplicate code Signed-off-by: Dmitriy Zaporozhets --- .flayignore | 1 + .gitlab-ci.yml | 8 ++++++++ Gemfile | 1 + Gemfile.lock | 4 ++++ lib/tasks/flay.rake | 9 +++++++++ 5 files changed, 23 insertions(+) create mode 100644 .flayignore create mode 100644 lib/tasks/flay.rake diff --git a/.flayignore b/.flayignore new file mode 100644 index 00000000000..9c9875d4f9e --- /dev/null +++ b/.flayignore @@ -0,0 +1 @@ +*.erb diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 062fda322a6..128faa07db8 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -81,3 +81,11 @@ flog: - ruby - mysql allow_failure: true + +flay: + script: + - bundle exec rake flay + tags: + - ruby + - mysql + allow_failure: true diff --git a/Gemfile b/Gemfile index 91a93215336..67aef0c3a8d 100644 --- a/Gemfile +++ b/Gemfile @@ -260,6 +260,7 @@ group :development, :test do gem 'coveralls', '~> 0.8.2', require: false gem 'simplecov', '~> 0.10.0', require: false gem 'flog', require: false + gem 'flay', require: false gem 'benchmark-ips', require: false end diff --git a/Gemfile.lock b/Gemfile.lock index 0fc22829cfd..5f95637966e 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -194,6 +194,9 @@ GEM ffi (1.9.10) fission (0.5.0) CFPropertyList (~> 2.2) + flay (2.6.1) + ruby_parser (~> 3.0) + sexp_processor (~> 4.0) flog (4.3.2) ruby_parser (~> 3.1, > 3.1.0) sexp_processor (~> 4.4) @@ -824,6 +827,7 @@ DEPENDENCIES enumerize (~> 0.7.0) factory_girl_rails (~> 4.3.0) ffaker (~> 2.0.0) + flay flog fog (~> 1.25.0) font-awesome-rails (~> 4.2) diff --git a/lib/tasks/flay.rake b/lib/tasks/flay.rake new file mode 100644 index 00000000000..5efffc2cdac --- /dev/null +++ b/lib/tasks/flay.rake @@ -0,0 +1,9 @@ +desc 'Code duplication analyze via flay' +task :flay do + output = %x(bundle exec flay app/ lib/gitlab/) + + if output.include? "Similar code found" + puts output + exit 1 + end +end -- cgit v1.2.1 From d59a82118128cb8ecd14008f59e6cd73a1b0a71b Mon Sep 17 00:00:00 2001 From: Robert Speicher Date: Wed, 11 Nov 2015 11:02:52 -0500 Subject: Update CHANGELOG [ci skip] --- CHANGELOG | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG b/CHANGELOG index 3da194510bd..71300769fe6 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -32,12 +32,12 @@ v 8.2.0 (unreleased) - Fix incoming email config defaults - MR target branch is now visible on a list view when it is different from project's default one - Improve Continuous Integration graphs page + - Make color of "Accept Merge Request" button consistent with current build status v 8.1.4 - Fix bug where manually merged branches in a MR would end up with an empty diff (Stan Hu) - Prevent redirect loop when home_page_url is set to the root URL - Fix incoming email config defaults - - Make color of "Accept Merge Request" button consistent with current build status - Remove CSS property preventing hard tabs from rendering in Chromium 45 (Stan Hu) v 8.1.3 -- cgit v1.2.1