From 4f0a38f1a833cab8c83e77a6c5d323057883188d Mon Sep 17 00:00:00 2001 From: Jeroen Nijhof Date: Wed, 21 Oct 2015 15:15:54 +0200 Subject: Added housekeeping for git repositories --- app/controllers/projects_controller.rb | 8 ++++++++ app/services/projects/housekeeping_service.rb | 22 ++++++++++++++++++++++ app/views/projects/edit.html.haml | 11 +++++++++++ config/routes.rb | 1 + lib/gitlab/backend/shell.rb | 12 ++++++++++++ 5 files changed, 54 insertions(+) create mode 100644 app/services/projects/housekeeping_service.rb diff --git a/app/controllers/projects_controller.rb b/app/controllers/projects_controller.rb index 82119022cf9..c3efdffe563 100644 --- a/app/controllers/projects_controller.rb +++ b/app/controllers/projects_controller.rb @@ -171,6 +171,14 @@ class ProjectsController < ApplicationController end end + def housekeeping + ::Projects::HousekeepingService.new(@project).execute + + respond_to do |format| + format.html { redirect_to project_path(@project) } + end + end + def toggle_star current_user.toggle_star(@project) @project.reload diff --git a/app/services/projects/housekeeping_service.rb b/app/services/projects/housekeeping_service.rb new file mode 100644 index 00000000000..48875ac3449 --- /dev/null +++ b/app/services/projects/housekeeping_service.rb @@ -0,0 +1,22 @@ +# Projects::HousekeepingService class +# +# Used for git housekeeping +# +# Ex. +# Projects::HousekeepingService.new(project, user).execute +# +module Projects + class HousekeepingService < BaseService + include Gitlab::ShellAdapter + + def initialize(project) + @project = project + end + + def execute + if gitlab_shell.exists?(@project.path_with_namespace + '.git') + gitlab_shell.gc(@project.path_with_namespace) + end + end + end +end diff --git a/app/views/projects/edit.html.haml b/app/views/projects/edit.html.haml index afbf88b5507..8e49299223c 100644 --- a/app/views/projects/edit.html.haml +++ b/app/views/projects/edit.html.haml @@ -141,6 +141,17 @@ - else .nothing-here-block Only the project owner can archive a project + .panel.panel-default.panel.panel-warning + .panel-heading Housekeeping + .errors-holder + .panel-body + %p + Runs a number of housekeeping tasks within the current repository, + such as compressing file revisions and removing unreachable objects. + %br + = link_to 'Housekeeping', housekeeping_namespace_project_path(@project.namespace, @project), + method: :post, class: "btn btn-warning" + .panel.panel-default.panel.panel-warning .panel-heading Rename repository .errors-holder diff --git a/config/routes.rb b/config/routes.rb index f6812c9280a..f6e17a21479 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -381,6 +381,7 @@ Gitlab::Application.routes.draw do delete :remove_fork post :archive post :unarchive + post :housekeeping post :toggle_star post :markdown_preview get :autocomplete_sources diff --git a/lib/gitlab/backend/shell.rb b/lib/gitlab/backend/shell.rb index 01b8bda05c6..59f7a45b791 100644 --- a/lib/gitlab/backend/shell.rb +++ b/lib/gitlab/backend/shell.rb @@ -149,6 +149,18 @@ module Gitlab "#{path}.git", tag_name]) end + # Gc repository + # + # path - project path with namespace + # + # Ex. + # gc("gitlab/gitlab-ci") + # + def gc(path) + Gitlab::Utils.system_silent([gitlab_shell_projects_path, 'gc', + "#{path}.git"]) + end + # Add new key to gitlab-shell # # Ex. -- cgit v1.2.1 From c843722de2d778b6ec8fef0656797fd5a8074666 Mon Sep 17 00:00:00 2001 From: Jeff Stubler Date: Mon, 20 Jul 2015 20:34:19 -0500 Subject: Add graphs showing commits ahead and behind default to branches page --- CHANGELOG | 1 + app/assets/stylesheets/pages/commits.scss | 59 +++++++++++++++++++++++++ app/controllers/projects/branches_controller.rb | 6 +++ app/models/project.rb | 2 + app/models/repository.rb | 42 +++++++++++++++++- app/views/projects/branches/_branch.html.haml | 14 ++++++ 6 files changed, 122 insertions(+), 2 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index 6bec4f606e7..98702088199 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -16,6 +16,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. + - Add graphs of commits ahead and behind default branch (Jeff Stubler) v 8.1.1 - Fix cloning Wiki repositories via HTTP (Stan Hu) diff --git a/app/assets/stylesheets/pages/commits.scss b/app/assets/stylesheets/pages/commits.scss index 4e121b95d13..4a080db7464 100644 --- a/app/assets/stylesheets/pages/commits.scss +++ b/app/assets/stylesheets/pages/commits.scss @@ -113,3 +113,62 @@ li.commit { } } } + +.divergence-graph { + padding: 12px 12px 0 0; + float: right; + + .graph-side { + position: relative; + width: 80px; + height: 22px; + padding: 5px 0 13px; + float: left; + + .bar { + position: absolute; + height: 4px; + background-color: #ccc; + } + + .bar-behind { + right: 0; + border-radius: 3px 0 0 3px; + } + + .bar-ahead { + left: 0; + border-radius: 0 3px 3px 0; + } + + .count { + padding-top: 6px; + padding-bottom: 0px; + font-size: 12px; + color: #333; + display: block; + } + + .count-behind { + padding-right: 4px; + text-align: right; + } + + .count-ahead { + padding-left: 4px; + text-align: left; + } + } + + .graph-separator { + position: relative; + width: 1px; + height: 18px; + margin: 5px 0 0; + float: left; + background-color: #ccc; + } +} + + + diff --git a/app/controllers/projects/branches_controller.rb b/app/controllers/projects/branches_controller.rb index 3ac0a75fa70..c3cd7642dd2 100644 --- a/app/controllers/projects/branches_controller.rb +++ b/app/controllers/projects/branches_controller.rb @@ -9,6 +9,12 @@ class Projects::BranchesController < Projects::ApplicationController @sort = params[:sort] || 'name' @branches = @repository.branches_sorted_by(@sort) @branches = Kaminari.paginate_array(@branches).page(params[:page]).per(PER_PAGE) + + @max_commits = @branches.reduce(0) do + |memo, branch| + diverging_commit_counts = repository.diverging_commit_counts(branch) + [memo, diverging_commit_counts[:behind], diverging_commit_counts[:ahead]].max + end end def recent diff --git a/app/models/project.rb b/app/models/project.rb index 74b89aad499..e73a856c289 100644 --- a/app/models/project.rb +++ b/app/models/project.rb @@ -714,6 +714,8 @@ class Project < ActiveRecord::Base end def change_head(branch) + # Cached divergent commit counts are based on repository head + repository.expire_branch_cache gitlab_shell.update_repository_head(self.path_with_namespace, branch) reload_default_branch end diff --git a/app/models/repository.rb b/app/models/repository.rb index c9b36bd8170..9b270bc9d18 100644 --- a/app/models/repository.rb +++ b/app/models/repository.rb @@ -146,10 +146,27 @@ class Repository def size cache.fetch(:size) { raw_repository.size } end + + def diverging_commit_counts(branch) + branch_cache_key = ('diverging_commit_counts_' + branch.name).to_sym + cache.fetch(branch_cache_key) do + number_commits_behind = commits_between(branch.name, root_ref).size + number_commits_ahead = commits_between(root_ref, branch.name).size + + { behind: number_commits_behind, ahead: number_commits_ahead } + end + end def cache_keys - %i(size branch_names tag_names commit_count - readme version contribution_guide changelog license) + %i(size branch_names tag_names commit_count readme + contribution_guide changelog license) + end + + def branch_cache_keys + branches.map do + |branch| + ('diverging_commit_counts_' + branch.name).to_sym + end end def build_cache @@ -158,12 +175,28 @@ class Repository send(key) end end + + branches.each do |branch| + unless cache.exist?(('diverging_commit_counts_' + branch.name).to_sym) + send(:diverging_commit_counts, branch) + end + end end def expire_cache cache_keys.each do |key| cache.expire(key) end + + branches.each do |branch| + cache.expire(('diverging_commit_counts_' + branch.name).to_sym) + end + end + + def expire_branch_cache + branches.each do |branch| + cache.expire(('diverging_commit_counts_' + branch.name).to_sym) + end end def rebuild_cache @@ -171,6 +204,11 @@ class Repository cache.expire(key) send(key) end + + branches.each do |branch| + cache.expire(('diverging_commit_counts_' + branch.name).to_sym) + send(:diverging_commit_counts, branch) + end end def lookup_cache diff --git a/app/views/projects/branches/_branch.html.haml b/app/views/projects/branches/_branch.html.haml index cc0ec9483d2..9ddb10a1c74 100644 --- a/app/views/projects/branches/_branch.html.haml +++ b/app/views/projects/branches/_branch.html.haml @@ -1,4 +1,7 @@ - commit = @repository.commit(branch.target) +- bar_graph_width_factor = @max_commits > 0 ? 100.0/@max_commits : 0 +- number_commits_behind = @repository.diverging_commit_counts(branch)[:behind] +- number_commits_ahead = @repository.diverging_commit_counts(branch)[:ahead] %li(class="js-branch-#{branch.name}") %div = link_to namespace_project_tree_path(@project.namespace, @project, branch.name) do @@ -29,6 +32,17 @@ = link_to namespace_project_branch_path(@project.namespace, @project, branch.name), class: 'btn btn-grouped btn-xs btn-remove remove-row', method: :delete, data: { confirm: 'Removed branch cannot be restored. Are you sure?'}, remote: true do = icon("trash-o") + - if branch.name != @repository.root_ref + .divergence-graph{ :title => "#{number_commits_ahead} commits ahead, #{number_commits_behind} commits behind #{@repository.root_ref}" } + .graph-side + .bar.bar-behind{ :style => "width: #{number_commits_behind * bar_graph_width_factor}%" } + %span.count.count-behind= number_commits_behind + .graph-separator + .graph-side + .bar.bar-ahead{ :style => "width: #{number_commits_ahead * bar_graph_width_factor}%" } + %span.count.count-ahead= number_commits_ahead + + - if commit = render 'projects/branches/commit', commit: commit, project: @project - else -- cgit v1.2.1 From e0c64fac68b4b3acc48300956146b85e03b426ce Mon Sep 17 00:00:00 2001 From: Jeff Stubler Date: Wed, 11 Nov 2015 16:29:29 -0600 Subject: Refactor for style issues --- app/controllers/projects/branches_controller.rb | 3 +-- app/models/repository.rb | 24 ++++++++++-------------- app/views/projects/branches/_branch.html.haml | 11 ++++++----- 3 files changed, 17 insertions(+), 21 deletions(-) diff --git a/app/controllers/projects/branches_controller.rb b/app/controllers/projects/branches_controller.rb index c3cd7642dd2..87884420952 100644 --- a/app/controllers/projects/branches_controller.rb +++ b/app/controllers/projects/branches_controller.rb @@ -10,8 +10,7 @@ class Projects::BranchesController < Projects::ApplicationController @branches = @repository.branches_sorted_by(@sort) @branches = Kaminari.paginate_array(@branches).page(params[:page]).per(PER_PAGE) - @max_commits = @branches.reduce(0) do - |memo, branch| + @max_commits = @branches.reduce(0) do |memo, branch| diverging_commit_counts = repository.diverging_commit_counts(branch) [memo, diverging_commit_counts[:behind], diverging_commit_counts[:ahead]].max end diff --git a/app/models/repository.rb b/app/models/repository.rb index 9b270bc9d18..0e2d4ea1fb8 100644 --- a/app/models/repository.rb +++ b/app/models/repository.rb @@ -148,8 +148,7 @@ class Repository end def diverging_commit_counts(branch) - branch_cache_key = ('diverging_commit_counts_' + branch.name).to_sym - cache.fetch(branch_cache_key) do + cache.fetch(:"diverging_commit_counts_#{branch.name}") do number_commits_behind = commits_between(branch.name, root_ref).size number_commits_ahead = commits_between(root_ref, branch.name).size @@ -158,14 +157,13 @@ class Repository end def cache_keys - %i(size branch_names tag_names commit_count readme - contribution_guide changelog license) + %i(size branch_names tag_names commit_count + readme version contribution_guide changelog license) end def branch_cache_keys - branches.map do - |branch| - ('diverging_commit_counts_' + branch.name).to_sym + branches.map do |branch| + :"diverging_commit_counts_#{branch.name}" end end @@ -177,7 +175,7 @@ class Repository end branches.each do |branch| - unless cache.exist?(('diverging_commit_counts_' + branch.name).to_sym) + unless cache.exist?(:"diverging_commit_counts_#{branch.name}") send(:diverging_commit_counts, branch) end end @@ -188,14 +186,12 @@ class Repository cache.expire(key) end - branches.each do |branch| - cache.expire(('diverging_commit_counts_' + branch.name).to_sym) - end + expire_branch_cache end def expire_branch_cache branches.each do |branch| - cache.expire(('diverging_commit_counts_' + branch.name).to_sym) + cache.expire(:"diverging_commit_counts_#{branch.name}") end end @@ -206,8 +202,8 @@ class Repository end branches.each do |branch| - cache.expire(('diverging_commit_counts_' + branch.name).to_sym) - send(:diverging_commit_counts, branch) + cache.expire(:"diverging_commit_counts_#{branch.name}") + diverging_commit_counts(branch) end end diff --git a/app/views/projects/branches/_branch.html.haml b/app/views/projects/branches/_branch.html.haml index 9ddb10a1c74..a4202d1120d 100644 --- a/app/views/projects/branches/_branch.html.haml +++ b/app/views/projects/branches/_branch.html.haml @@ -1,7 +1,8 @@ - commit = @repository.commit(branch.target) - bar_graph_width_factor = @max_commits > 0 ? 100.0/@max_commits : 0 -- number_commits_behind = @repository.diverging_commit_counts(branch)[:behind] -- number_commits_ahead = @repository.diverging_commit_counts(branch)[:ahead] +- diverging_commit_counts = @repository.diverging_commit_counts(branch) +- number_commits_behind = diverging_commit_counts[:behind] +- number_commits_ahead = diverging_commit_counts[:ahead] %li(class="js-branch-#{branch.name}") %div = link_to namespace_project_tree_path(@project.namespace, @project, branch.name) do @@ -33,13 +34,13 @@ = icon("trash-o") - if branch.name != @repository.root_ref - .divergence-graph{ :title => "#{number_commits_ahead} commits ahead, #{number_commits_behind} commits behind #{@repository.root_ref}" } + .divergence-graph{ title: "#{number_commits_ahead} commits ahead, #{number_commits_behind} commits behind #{@repository.root_ref}" } .graph-side - .bar.bar-behind{ :style => "width: #{number_commits_behind * bar_graph_width_factor}%" } + .bar.bar-behind{ style: "width: #{number_commits_behind * bar_graph_width_factor}%" } %span.count.count-behind= number_commits_behind .graph-separator .graph-side - .bar.bar-ahead{ :style => "width: #{number_commits_ahead * bar_graph_width_factor}%" } + .bar.bar-ahead{ style: "width: #{number_commits_ahead * bar_graph_width_factor}%" } %span.count.count-ahead= number_commits_ahead -- cgit v1.2.1 From 839aae0e473e85042f76391b44eaeb099235a813 Mon Sep 17 00:00:00 2001 From: Jeroen Nijhof Date: Thu, 19 Nov 2015 15:16:54 +0100 Subject: Added housekeeping status and moved path check to gitlab-shell --- app/controllers/projects_controller.rb | 9 +++++++-- app/services/projects/housekeeping_service.rb | 6 ++---- 2 files changed, 9 insertions(+), 6 deletions(-) diff --git a/app/controllers/projects_controller.rb b/app/controllers/projects_controller.rb index c3efdffe563..27b723fae6a 100644 --- a/app/controllers/projects_controller.rb +++ b/app/controllers/projects_controller.rb @@ -8,7 +8,7 @@ class ProjectsController < ApplicationController before_action :assign_ref_vars, :tree, only: [:show], if: :repo_exists? # Authorize - before_action :authorize_admin_project!, only: [:edit, :update] + before_action :authorize_admin_project!, only: [:edit, :update, :housekeeping] before_action :event_filter, only: [:show, :activity] layout :determine_layout @@ -172,9 +172,14 @@ class ProjectsController < ApplicationController end def housekeeping - ::Projects::HousekeepingService.new(@project).execute + status = ::Projects::HousekeepingService.new(@project).execute respond_to do |format| + if status + flash[:notice] = "Housekeeping finished successfully." + else + flash[:alert] = "Housekeeping failed." + end format.html { redirect_to project_path(@project) } end end diff --git a/app/services/projects/housekeeping_service.rb b/app/services/projects/housekeeping_service.rb index 48875ac3449..bea91b5f180 100644 --- a/app/services/projects/housekeeping_service.rb +++ b/app/services/projects/housekeeping_service.rb @@ -3,7 +3,7 @@ # Used for git housekeeping # # Ex. -# Projects::HousekeepingService.new(project, user).execute +# Projects::HousekeepingService.new(project).execute # module Projects class HousekeepingService < BaseService @@ -14,9 +14,7 @@ module Projects end def execute - if gitlab_shell.exists?(@project.path_with_namespace + '.git') - gitlab_shell.gc(@project.path_with_namespace) - end + gitlab_shell.gc(@project.path_with_namespace) end end end -- cgit v1.2.1 From d4690af8bc283c402e49cb8b3056c7de9d57e886 Mon Sep 17 00:00:00 2001 From: Jeroen Nijhof Date: Thu, 19 Nov 2015 16:04:07 +0100 Subject: Use GitlabShellWorker.perform_async for housekeeping --- app/controllers/projects_controller.rb | 8 ++------ app/services/projects/housekeeping_service.rb | 2 +- 2 files changed, 3 insertions(+), 7 deletions(-) diff --git a/app/controllers/projects_controller.rb b/app/controllers/projects_controller.rb index 27b723fae6a..ecaf4476246 100644 --- a/app/controllers/projects_controller.rb +++ b/app/controllers/projects_controller.rb @@ -172,14 +172,10 @@ class ProjectsController < ApplicationController end def housekeeping - status = ::Projects::HousekeepingService.new(@project).execute + ::Projects::HousekeepingService.new(@project).execute respond_to do |format| - if status - flash[:notice] = "Housekeeping finished successfully." - else - flash[:alert] = "Housekeeping failed." - end + flash[:notice] = "Housekeeping successfully started." format.html { redirect_to project_path(@project) } end end diff --git a/app/services/projects/housekeeping_service.rb b/app/services/projects/housekeeping_service.rb index bea91b5f180..0db85ac2142 100644 --- a/app/services/projects/housekeeping_service.rb +++ b/app/services/projects/housekeeping_service.rb @@ -14,7 +14,7 @@ module Projects end def execute - gitlab_shell.gc(@project.path_with_namespace) + GitlabShellWorker.perform_async(:gc, @project.path_with_namespace) end end end -- cgit v1.2.1 From c12514fc2d3996e7cfc3553d8e2bac04d0c5afec Mon Sep 17 00:00:00 2001 From: The rugged tests are fragile Date: Tue, 15 Dec 2015 15:05:57 +0800 Subject: Ignore config/sidekiq.yml [ci skip] --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index f5b6427ca03..91ea81bfc4e 100644 --- a/.gitignore +++ b/.gitignore @@ -26,6 +26,7 @@ config/initializers/smtp_settings.rb config/resque.yml config/unicorn.rb config/secrets.yml +config/sidekiq.yml coverage/* db/*.sqlite3 db/*.sqlite3-journal -- cgit v1.2.1 From 2e8ec7e7204b2876218db34439584204b1062265 Mon Sep 17 00:00:00 2001 From: Jeff Stubler Date: Tue, 15 Dec 2015 16:23:52 -0600 Subject: Fix diverging commit count calculation Rugged seemed to stop accepting branch names as valid refs, throwing `Rugged::ReferenceError` exceptions. Now the branch target rather than branch name is used, and the default branch's hash is also calculated, and these work properly. This used to work and might be something worth re-investigating in the future. --- app/models/repository.rb | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/app/models/repository.rb b/app/models/repository.rb index 4186ef295c9..77e5bd975ec 100644 --- a/app/models/repository.rb +++ b/app/models/repository.rb @@ -157,9 +157,12 @@ class Repository end def diverging_commit_counts(branch) + root_ref_hash = raw_repository.rev_parse_target(root_ref).oid cache.fetch(:"diverging_commit_counts_#{branch.name}") do - number_commits_behind = commits_between(branch.name, root_ref).size - number_commits_ahead = commits_between(root_ref, branch.name).size + # Rugged seems to throw a `ReferenceError` when given branch_names rather + # than SHA-1 hashes + number_commits_behind = commits_between(branch.target, root_ref_hash).size + number_commits_ahead = commits_between(root_ref_hash, branch.target).size { behind: number_commits_behind, ahead: number_commits_ahead } end -- cgit v1.2.1 From b45ee2c314e2c26f4574f2e973dfa40204860c66 Mon Sep 17 00:00:00 2001 From: Mike Wyatt Date: Wed, 16 Dec 2015 10:08:05 -0400 Subject: better support for referencing and closing issues in asana_service.rb --- app/models/project_services/asana_service.rb | 28 +++++++++++++++------- spec/models/project_services/asana_service_spec.rb | 21 ++++++++++++++++ 2 files changed, 41 insertions(+), 8 deletions(-) diff --git a/app/models/project_services/asana_service.rb b/app/models/project_services/asana_service.rb index e6e16058d41..bbc508e8f8e 100644 --- a/app/models/project_services/asana_service.rb +++ b/app/models/project_services/asana_service.rb @@ -98,17 +98,29 @@ automatically inspected. Leave blank to include all branches.' task_list = [] close_list = [] - message.split("\n").each do |line| - # look for a task ID or a full Asana url - task_list.concat(line.scan(/#(\d+)/)) - task_list.concat(line.scan(/https:\/\/app\.asana\.com\/\d+\/\d+\/(\d+)/)) - # look for a word starting with 'fix' followed by a task ID - close_list.concat(line.scan(/(fix\w*)\W*#(\d+)/i)) + # matches either: + # - #1234 + # - https://app.asana.com/0/0/1234 + # optionally preceded with: + # - fix/ed/es/ing + # - close/s/d + # - closing + issue_finder = /(fix\w*|clos[ei]\w*+)?\W*(?:https:\/\/app\.asana\.com\/\d+\/\d+\/(\d+)|#(\d+))/i + + message.scan(issue_finder).each do |tuple| + # tuple will be + # [ 'fix', 'id_from_url', 'id_from_pound' ] + taskid = tuple[2] || tuple[1] + task_list.push(taskid) + + if tuple[0] + close_list.push(taskid) + end end # post commit to every taskid found task_list.each do |taskid| - task = Asana::Task.find(taskid[0]) + task = Asana::Task.find(taskid) if task task.create_story(text: push_msg + ' ' + message) @@ -117,7 +129,7 @@ automatically inspected. Leave blank to include all branches.' # close all tasks that had 'fix(ed/es/ing) #:id' in them close_list.each do |taskid| - task = Asana::Task.find(taskid.last) + task = Asana::Task.find(taskid) if task task.modify(completed: true) diff --git a/spec/models/project_services/asana_service_spec.rb b/spec/models/project_services/asana_service_spec.rb index 64bb92fba95..e368b03206e 100644 --- a/spec/models/project_services/asana_service_spec.rb +++ b/spec/models/project_services/asana_service_spec.rb @@ -62,5 +62,26 @@ describe AsanaService, models: true do @asana.check_commit('fix #456789', 'pushed') end + + it 'should be able to close via url' do + expect(Asana::Task).to receive(:find).with('42').twice + + @asana.check_commit('closes https://app.asana.com/19292/956299/42', 'pushed') + end + + it 'should allow multiple matches per line' do + expect(Asana::Task).to receive(:find).with('123').twice + expect(Asana::Task).to receive(:find).with('456').twice + expect(Asana::Task).to receive(:find).with('789').once + + expect(Asana::Task).to receive(:find).with('42').once + expect(Asana::Task).to receive(:find).with('12').twice + + message = <<-EOF + minor bigfix, refactoring, fixed #123 and Closes #456 work on #789 + ref https://app.asana.com/19292/956299/42 and closing https://app.asana.com/19292/956299/12 + EOF + @asana.check_commit(message, 'pushed') + end end end -- cgit v1.2.1 From 331154ffdf899a82c67487a70436ce49e494256b Mon Sep 17 00:00:00 2001 From: Douwe Maan Date: Thu, 24 Dec 2015 14:38:23 +0100 Subject: Escape reference link text --- lib/banzai/filter/abstract_reference_filter.rb | 17 ++++++++++------- lib/banzai/filter/reference_filter.rb | 2 +- 2 files changed, 11 insertions(+), 8 deletions(-) diff --git a/lib/banzai/filter/abstract_reference_filter.rb b/lib/banzai/filter/abstract_reference_filter.rb index bdaa4721b4b..6b200dc2017 100644 --- a/lib/banzai/filter/abstract_reference_filter.rb +++ b/lib/banzai/filter/abstract_reference_filter.rb @@ -110,13 +110,7 @@ module Banzai url = matches[:url] if matches.names.include?("url") url ||= url_for_object(object, project) - text = link_text - unless text - text = object.reference_link_text(context[:project]) - - extras = object_link_text_extras(object, matches) - text += " (#{extras.join(", ")})" if extras.any? - end + text = link_text || escape_once(object_link_text(object, matches)) %( Date: Thu, 24 Dec 2015 14:43:07 +0100 Subject: Render milestone links as references --- app/models/milestone.rb | 18 ++++++ lib/banzai/filter/abstract_reference_filter.rb | 38 ++++++----- lib/banzai/filter/milestone_reference_filter.rb | 24 +++++++ lib/banzai/pipeline/gfm_pipeline.rb | 1 + lib/gitlab/reference_extractor.rb | 2 +- spec/features/markdown_spec.rb | 1 + spec/fixtures/markdown.md.erb | 8 +++ .../filter/milestone_reference_filter_spec.rb | 73 ++++++++++++++++++++++ spec/support/markdown_feature.rb | 8 +++ spec/support/matchers/markdown_matchers.rb | 9 +++ 10 files changed, 164 insertions(+), 18 deletions(-) create mode 100644 lib/banzai/filter/milestone_reference_filter.rb create mode 100644 spec/lib/banzai/filter/milestone_reference_filter_spec.rb diff --git a/app/models/milestone.rb b/app/models/milestone.rb index d8c7536cd31..e47b6440746 100644 --- a/app/models/milestone.rb +++ b/app/models/milestone.rb @@ -22,6 +22,7 @@ class Milestone < ActiveRecord::Base include InternalId include Sortable + include Referable include StripAttribute belongs_to :project @@ -61,6 +62,23 @@ class Milestone < ActiveRecord::Base end end + def self.reference_pattern + nil + end + + def self.link_reference_pattern + super("milestones", /(?\d+)/) + end + + def to_reference(from_project = nil) + h = Gitlab::Application.routes.url_helpers + h.namespace_project_milestone_url(self.project.namespace, self.project, self) + end + + def reference_link_text(from_project = nil) + %Q{ }.html_safe + self.title + end + def expired? if due_date due_date.past? diff --git a/lib/banzai/filter/abstract_reference_filter.rb b/lib/banzai/filter/abstract_reference_filter.rb index 6b200dc2017..36d8c12e2b3 100644 --- a/lib/banzai/filter/abstract_reference_filter.rb +++ b/lib/banzai/filter/abstract_reference_filter.rb @@ -60,27 +60,31 @@ module Banzai end def call - # `#123` - replace_text_nodes_matching(object_class.reference_pattern) do |content| - object_link_filter(content, object_class.reference_pattern) - end + if object_class.reference_pattern + # `#123` + replace_text_nodes_matching(object_class.reference_pattern) do |content| + object_link_filter(content, object_class.reference_pattern) + end - # `[Issue](#123)`, which is turned into - # `Issue` - replace_link_nodes_with_href(object_class.reference_pattern) do |link, text| - object_link_filter(link, object_class.reference_pattern, link_text: text) + # `[Issue](#123)`, which is turned into + # `Issue` + replace_link_nodes_with_href(object_class.reference_pattern) do |link, text| + object_link_filter(link, object_class.reference_pattern, link_text: text) + end end - # `http://gitlab.example.com/namespace/project/issues/123`, which is turned into - # `http://gitlab.example.com/namespace/project/issues/123` - replace_link_nodes_with_text(object_class.link_reference_pattern) do |text| - object_link_filter(text, object_class.link_reference_pattern) - end + if object_class.link_reference_pattern + # `http://gitlab.example.com/namespace/project/issues/123`, which is turned into + # `http://gitlab.example.com/namespace/project/issues/123` + replace_link_nodes_with_text(object_class.link_reference_pattern) do |text| + object_link_filter(text, object_class.link_reference_pattern) + end - # `[Issue](http://gitlab.example.com/namespace/project/issues/123)`, which is turned into - # `Issue` - replace_link_nodes_with_href(object_class.link_reference_pattern) do |link, text| - object_link_filter(link, object_class.link_reference_pattern, link_text: text) + # `[Issue](http://gitlab.example.com/namespace/project/issues/123)`, which is turned into + # `Issue` + replace_link_nodes_with_href(object_class.link_reference_pattern) do |link, text| + object_link_filter(link, object_class.link_reference_pattern, link_text: text) + end end end diff --git a/lib/banzai/filter/milestone_reference_filter.rb b/lib/banzai/filter/milestone_reference_filter.rb new file mode 100644 index 00000000000..f99202af5e8 --- /dev/null +++ b/lib/banzai/filter/milestone_reference_filter.rb @@ -0,0 +1,24 @@ +require 'banzai' + +module Banzai + module Filter + # HTML filter that replaces milestone references with links. + # + # This filter supports cross-project references. + class MilestoneReferenceFilter < AbstractReferenceFilter + def self.object_class + Milestone + end + + def find_object(project, id) + project.milestones.find_by(iid: id) + end + + def url_for_object(issue, project) + h = Gitlab::Application.routes.url_helpers + h.namespace_project_milestone_url(project.namespace, project, milestone, + only_path: context[:only_path]) + end + end + end +end diff --git a/lib/banzai/pipeline/gfm_pipeline.rb b/lib/banzai/pipeline/gfm_pipeline.rb index 38750b55ec7..838155e8831 100644 --- a/lib/banzai/pipeline/gfm_pipeline.rb +++ b/lib/banzai/pipeline/gfm_pipeline.rb @@ -22,6 +22,7 @@ module Banzai Filter::CommitRangeReferenceFilter, Filter::CommitReferenceFilter, Filter::LabelReferenceFilter, + Filter::MilestoneReferenceFilter, Filter::TaskListFilter ] diff --git a/lib/gitlab/reference_extractor.rb b/lib/gitlab/reference_extractor.rb index 0a70d21b1ce..c87068051ab 100644 --- a/lib/gitlab/reference_extractor.rb +++ b/lib/gitlab/reference_extractor.rb @@ -18,7 +18,7 @@ module Gitlab super(text, context.merge(project: project)) end - %i(user label merge_request snippet commit commit_range).each do |type| + %i(user label milestone merge_request snippet commit commit_range).each do |type| define_method("#{type}s") do @references[type] ||= references(type, project: project, current_user: current_user) end diff --git a/spec/features/markdown_spec.rb b/spec/features/markdown_spec.rb index fdd8cf07b12..e836d81c40b 100644 --- a/spec/features/markdown_spec.rb +++ b/spec/features/markdown_spec.rb @@ -212,6 +212,7 @@ describe 'GitLab Markdown', feature: true do expect(doc).to reference_commit_ranges expect(doc).to reference_commits expect(doc).to reference_labels + expect(doc).to reference_milestones end end diff --git a/spec/fixtures/markdown.md.erb b/spec/fixtures/markdown.md.erb index e8dfc5c0eb1..302b750aee5 100644 --- a/spec/fixtures/markdown.md.erb +++ b/spec/fixtures/markdown.md.erb @@ -214,6 +214,14 @@ References should be parseable even inside _<%= merge_request.to_reference %>_ e - Ignored in links: [Link to <%= simple_label.to_reference %>](#label-link) - Link to label by reference: [Label](<%= label.to_reference %>) +#### MilestoneReferenceFilter + +- Milestone: <%= milestone.to_reference %> +- Milestone in another project: <%= xmilestone.to_reference(project) %> +- Ignored in code: `<%= milestone.to_reference %>` +- Ignored in links: [Link to <%= milestone.to_reference %>](#milestone-link) +- Link to milestone by URL: [Milestone](<%= urls.namespace_project_milestone_url(milestone.project.namespace, milestone.project, milestone) %>) + ### Task Lists - [ ] Incomplete task 1 diff --git a/spec/lib/banzai/filter/milestone_reference_filter_spec.rb b/spec/lib/banzai/filter/milestone_reference_filter_spec.rb new file mode 100644 index 00000000000..c53e780d354 --- /dev/null +++ b/spec/lib/banzai/filter/milestone_reference_filter_spec.rb @@ -0,0 +1,73 @@ +require 'spec_helper' + +describe Banzai::Filter::MilestoneReferenceFilter, lib: true do + include FilterSpecHelper + + let(:project) { create(:project, :public) } + let(:milestone) { create(:milestone, project: project) } + + it 'requires project context' do + expect { described_class.call('') }.to raise_error(ArgumentError, /:project/) + end + + %w(pre code a style).each do |elem| + it "ignores valid references contained inside '#{elem}' element" do + exp = act = "<#{elem}>milestone #{milestone.to_reference}" + expect(reference_filter(act).to_html).to eq exp + end + end + + context 'internal reference' do + let(:reference) { milestone.to_reference } + + it 'links to a valid reference' do + doc = reference_filter("See #{reference}") + + expect(doc.css('a').first.attr('href')).to eq urls. + namespace_project_milestone_url(project.namespace, project, milestone) + end + + it 'links with adjacent text' do + doc = reference_filter("milestone (#{reference}.)") + expect(doc.to_html).to match(/\(<\/i> #{Regexp.escape(milestone.title)}<\/a>\.\)/) + end + + it 'includes a title attribute' do + doc = reference_filter("milestone #{reference}") + expect(doc.css('a').first.attr('title')).to eq "Milestone: #{milestone.title}" + end + + it 'escapes the title attribute' do + milestone.update_attribute(:title, %{">whatever Date: Thu, 24 Dec 2015 14:43:26 +0100 Subject: Link to milestone in "Milestone changed" system note --- app/services/system_note_service.rb | 4 ++-- app/views/shared/issuable/_sidebar.html.haml | 3 +-- spec/services/system_note_service_spec.rb | 2 +- 3 files changed, 4 insertions(+), 5 deletions(-) diff --git a/app/services/system_note_service.rb b/app/services/system_note_service.rb index 98a71cbf1ad..955a28b5a7e 100644 --- a/app/services/system_note_service.rb +++ b/app/services/system_note_service.rb @@ -41,7 +41,7 @@ class SystemNoteService # # Returns the created Note object def self.change_assignee(noteable, project, author, assignee) - body = assignee.nil? ? 'Assignee removed' : "Reassigned to @#{assignee.username}" + body = assignee.nil? ? 'Assignee removed' : "Reassigned to #{assignee.to_reference}" create_note(noteable: noteable, project: project, author: author, note: body) end @@ -103,7 +103,7 @@ class SystemNoteService # Returns the created Note object def self.change_milestone(noteable, project, author, milestone) body = 'Milestone ' - body += milestone.nil? ? 'removed' : "changed to #{milestone.title}" + body += milestone.nil? ? 'removed' : "changed to #{milestone.to_reference(project)}" create_note(noteable: noteable, project: project, author: author, note: body) end diff --git a/app/views/shared/issuable/_sidebar.html.haml b/app/views/shared/issuable/_sidebar.html.haml index 79c5cc7f40a..9d65a621e53 100644 --- a/app/views/shared/issuable/_sidebar.html.haml +++ b/app/views/shared/issuable/_sidebar.html.haml @@ -28,8 +28,7 @@ %span.back-to-milestone = link_to namespace_project_milestone_path(@project.namespace, @project, issuable.milestone) do %strong - = icon('clock-o') - = issuable.milestone.title + = issuable.milestone.reference_link_text - else .light None .selectbox diff --git a/spec/services/system_note_service_spec.rb b/spec/services/system_note_service_spec.rb index c9f828ae2f7..d3364a71022 100644 --- a/spec/services/system_note_service_spec.rb +++ b/spec/services/system_note_service_spec.rb @@ -171,7 +171,7 @@ describe SystemNoteService, services: true do context 'when milestone added' do it 'sets the note text' do - expect(subject.note).to eq "Milestone changed to #{milestone.title}" + expect(subject.note).to eq "Milestone changed to #{milestone.to_reference}" end end -- cgit v1.2.1 From 88c35095a8dafd722de63422fdfefd3db65532fe Mon Sep 17 00:00:00 2001 From: Douwe Maan Date: Thu, 24 Dec 2015 15:34:47 +0100 Subject: Add changelog item --- CHANGELOG | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG b/CHANGELOG index 0f9ae1e3b52..30cd589fddd 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -4,6 +4,7 @@ v 8.4.0 (unreleased) - Fix Error 500 when doing a search in dashboard before visiting any project (Stan Hu) - Implement new UI for group page - Add project permissions to all project API endpoints (Stan Hu) + - Link to milestone in "Milestone changed" system note v 8.3.0 - Add CAS support (tduehr) -- cgit v1.2.1 From 0ca74f7aad0d5b63955c86397fffdd9e670c56f3 Mon Sep 17 00:00:00 2001 From: Douwe Maan Date: Thu, 24 Dec 2015 15:40:59 +0100 Subject: Use `to_reference` in system notes. --- app/services/system_note_service.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/services/system_note_service.rb b/app/services/system_note_service.rb index 955a28b5a7e..1083bcec054 100644 --- a/app/services/system_note_service.rb +++ b/app/services/system_note_service.rb @@ -66,7 +66,7 @@ class SystemNoteService def self.change_label(noteable, project, author, added_labels, removed_labels) labels_count = added_labels.count + removed_labels.count - references = ->(label) { "~#{label.id}" } + references = ->(label) { label.to_reference(:id) } added_labels = added_labels.map(&references).join(' ') removed_labels = removed_labels.map(&references).join(' ') -- cgit v1.2.1 From 32543f3bd94b1b66dd949b0fb1f57bff3732eb45 Mon Sep 17 00:00:00 2001 From: Douwe Maan Date: Thu, 24 Dec 2015 21:19:03 +0100 Subject: More escaping! --- lib/banzai/filter/abstract_reference_filter.rb | 8 ++++---- lib/banzai/filter/reference_filter.rb | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/lib/banzai/filter/abstract_reference_filter.rb b/lib/banzai/filter/abstract_reference_filter.rb index 36d8c12e2b3..b99ccd98624 100644 --- a/lib/banzai/filter/abstract_reference_filter.rb +++ b/lib/banzai/filter/abstract_reference_filter.rb @@ -102,7 +102,7 @@ module Banzai project = project_from_ref(project_ref) if project && object = find_object(project, id) - title = escape_once(object_link_title(object)) + title = object_link_title(object) klass = reference_class(object_sym) data = data_attribute( @@ -114,11 +114,11 @@ module Banzai url = matches[:url] if matches.names.include?("url") url ||= url_for_object(object, project) - text = link_text || escape_once(object_link_text(object, matches)) + text = link_text || object_link_text(object, matches) %(#{text}) + title="#{escape_once(title)}" + class="#{klass}">#{escape_once(text)}) else match end diff --git a/lib/banzai/filter/reference_filter.rb b/lib/banzai/filter/reference_filter.rb index c183702516a..a22a7a7afd3 100644 --- a/lib/banzai/filter/reference_filter.rb +++ b/lib/banzai/filter/reference_filter.rb @@ -44,7 +44,7 @@ module Banzai # Returns a String def data_attribute(attributes = {}) attributes[:reference_filter] = self.class.name.demodulize - attributes.map { |key, value| %Q(data-#{key.to_s.dasherize}="#{value}") }.join(" ") + attributes.map { |key, value| %Q(data-#{key.to_s.dasherize}="#{escape_once(value)}") }.join(" ") end def escape_once(html) -- cgit v1.2.1 From bd21e3d7319dce4600881f7f8677b28f3f55cc5e Mon Sep 17 00:00:00 2001 From: Douwe Maan Date: Fri, 25 Dec 2015 16:41:02 +0100 Subject: Add Open Graph data for group, project and commit. --- app/helpers/page_layout_helper.rb | 2 ++ app/views/groups/show.html.haml | 2 ++ app/views/layouts/_head.html.haml | 10 +++++----- app/views/projects/commit/show.html.haml | 4 +++- app/views/projects/show.html.haml | 2 ++ 5 files changed, 14 insertions(+), 6 deletions(-) diff --git a/app/helpers/page_layout_helper.rb b/app/helpers/page_layout_helper.rb index 791cb9e50bd..b84644d6996 100644 --- a/app/helpers/page_layout_helper.rb +++ b/app/helpers/page_layout_helper.rb @@ -53,6 +53,8 @@ module PageLayoutHelper @project.avatar_url || default elsif @user avatar_icon(@user) + elsif @group + @group.avatar_url || default else default end diff --git a/app/views/groups/show.html.haml b/app/views/groups/show.html.haml index c2c7c581b3e..8179cdfac80 100644 --- a/app/views/groups/show.html.haml +++ b/app/views/groups/show.html.haml @@ -1,3 +1,5 @@ +- page_description @group.description + - unless can?(current_user, :read_group, @group) - @disable_search_panel = true diff --git a/app/views/layouts/_head.html.haml b/app/views/layouts/_head.html.haml index 2e0bd2007a3..2e9a34a8807 100644 --- a/app/views/layouts/_head.html.haml +++ b/app/views/layouts/_head.html.haml @@ -1,13 +1,11 @@ +- site_name = "GitLab" %head{prefix: "og: http://ogp.me/ns#"} %meta{charset: "utf-8"} %meta{'http-equiv' => 'X-UA-Compatible', content: 'IE=edge'} - %meta{name: 'referrer', content: 'origin-when-cross-origin'} - - %meta{name: "description", content: page_description} -# Open Graph - http://ogp.me/ %meta{property: 'og:type', content: "object"} - %meta{property: 'og:site_name', content: "GitLab"} + %meta{property: 'og:site_name', content: site_name} %meta{property: 'og:title', content: page_title} %meta{property: 'og:description', content: page_description} %meta{property: 'og:image', content: page_image} @@ -20,8 +18,9 @@ %meta{property: 'twitter:image', content: page_image} = page_card_meta_tags - - page_title "GitLab" + - page_title site_name %title= page_title + %meta{name: "description", content: page_description} = favicon_link_tag 'favicon.ico' @@ -34,6 +33,7 @@ = include_gon + %meta{name: 'referrer', content: 'origin-when-cross-origin'} %meta{name: 'viewport', content: 'width=device-width, initial-scale=1, maximum-scale=1'} %meta{name: 'theme-color', content: '#474D57'} diff --git a/app/views/projects/commit/show.html.haml b/app/views/projects/commit/show.html.haml index 069b8b1f169..58aa45e8d2c 100644 --- a/app/views/projects/commit/show.html.haml +++ b/app/views/projects/commit/show.html.haml @@ -1,4 +1,6 @@ -- page_title "#{@commit.title} (#{@commit.short_id})", "Commits" +- page_title "#{@commit.title} (#{@commit.short_id})", "Commits" +- page_description @commit.description + = render "projects/commits/header_title" = render "commit_box" - if @ci_commit diff --git a/app/views/projects/show.html.haml b/app/views/projects/show.html.haml index 7466a098e24..74ce005eaa2 100644 --- a/app/views/projects/show.html.haml +++ b/app/views/projects/show.html.haml @@ -1,3 +1,5 @@ +- page_description @project.description + = content_for :meta_tags do - if current_user = auto_discovery_link_tag(:atom, namespace_project_path(@project.namespace, @project, format: :atom, private_token: current_user.private_token), title: "#{@project.name} activity") -- cgit v1.2.1 From a7756a4b51b0127caa19d1fb20953cb27c4c62a8 Mon Sep 17 00:00:00 2001 From: Robert Speicher Date: Sun, 27 Dec 2015 19:49:48 -0500 Subject: Add specs for page_image using a Group's avatar --- spec/helpers/page_layout_helper_spec.rb | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/spec/helpers/page_layout_helper_spec.rb b/spec/helpers/page_layout_helper_spec.rb index fd7107779f6..60c4eb21814 100644 --- a/spec/helpers/page_layout_helper_spec.rb +++ b/spec/helpers/page_layout_helper_spec.rb @@ -96,6 +96,22 @@ describe PageLayoutHelper do helper.page_image end end + + context 'with @group' do + it 'uses Group avatar if available' do + group = double(avatar_url: 'http://example.com/uploads/avatar.png') + helper.instance_variable_set(:@group, group) + + expect(helper.page_image).to eq group.avatar_url + end + + it 'falls back to the default' do + group = double(avatar_url: nil) + helper.instance_variable_set(:@group, group) + + expect(helper.page_image).to end_with 'assets/gitlab_logo.png' + end + end end describe 'page_card_attributes' do -- cgit v1.2.1 From dcca64a5230bbfd53ef5db8403d132deac4667f2 Mon Sep 17 00:00:00 2001 From: Robert Speicher Date: Sun, 27 Dec 2015 19:58:44 -0500 Subject: Use `assign` instead of `instance_variable_set` --- spec/helpers/page_layout_helper_spec.rb | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/spec/helpers/page_layout_helper_spec.rb b/spec/helpers/page_layout_helper_spec.rb index 60c4eb21814..300dccf50ec 100644 --- a/spec/helpers/page_layout_helper_spec.rb +++ b/spec/helpers/page_layout_helper_spec.rb @@ -45,14 +45,14 @@ describe PageLayoutHelper do describe 'page_description_default' do it 'uses Project description when available' do project = double(description: 'Project Description') - helper.instance_variable_set(:@project, project) + assign(:project, project) expect(helper.page_description_default).to eq 'Project Description' end it 'uses brand_title when Project description is nil' do project = double(description: nil) - helper.instance_variable_set(:@project, project) + assign(:project, project) expect(helper).to receive(:brand_title).and_return('Brand Title') expect(helper.page_description_default).to eq 'Brand Title' @@ -73,14 +73,14 @@ describe PageLayoutHelper do context 'with @project' do it 'uses Project avatar if available' do project = double(avatar_url: 'http://example.com/uploads/avatar.png') - helper.instance_variable_set(:@project, project) + assign(:project, project) expect(helper.page_image).to eq project.avatar_url end it 'falls back to the default' do project = double(avatar_url: nil) - helper.instance_variable_set(:@project, project) + assign(:project, project) expect(helper.page_image).to end_with 'assets/gitlab_logo.png' end @@ -89,7 +89,7 @@ describe PageLayoutHelper do context 'with @user' do it 'delegates to avatar_icon helper' do user = double('User') - helper.instance_variable_set(:@user, user) + assign(:user, user) expect(helper).to receive(:avatar_icon).with(user) @@ -100,14 +100,14 @@ describe PageLayoutHelper do context 'with @group' do it 'uses Group avatar if available' do group = double(avatar_url: 'http://example.com/uploads/avatar.png') - helper.instance_variable_set(:@group, group) + assign(:group, group) expect(helper.page_image).to eq group.avatar_url end it 'falls back to the default' do group = double(avatar_url: nil) - helper.instance_variable_set(:@group, group) + assign(:group, group) expect(helper.page_image).to end_with 'assets/gitlab_logo.png' end -- cgit v1.2.1 From 141b8b67ff4cbe67778ff6815a51f49834e290b9 Mon Sep 17 00:00:00 2001 From: Michi302 Date: Mon, 28 Dec 2015 15:50:44 +0100 Subject: Make single user API endpoint return Entities::User instead of Entities::UserBasic --- doc/api/users.md | 7 +++++++ lib/api/users.rb | 2 +- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/doc/api/users.md b/doc/api/users.md index 66d2fd52526..773fe36d277 100644 --- a/doc/api/users.md +++ b/doc/api/users.md @@ -123,6 +123,13 @@ Parameters: "name": "John Smith", "state": "active", "avatar_url": "http://localhost:3000/uploads/user/avatar/1/cd8.jpeg", + "created_at": "2012-05-23T08:00:58Z", + "is_admin": false, + "bio": null, + "skype": "", + "linkedin": "", + "twitter": "", + "website_url": "" } ``` diff --git a/lib/api/users.rb b/lib/api/users.rb index 3400f0713ef..0d7813428e2 100644 --- a/lib/api/users.rb +++ b/lib/api/users.rb @@ -39,7 +39,7 @@ module API if current_user.is_admin? present @user, with: Entities::UserFull else - present @user, with: Entities::UserBasic + present @user, with: Entities::User end end -- cgit v1.2.1 From 2cd2c54bd1c83f8545b5f903d7717c4848453f0c Mon Sep 17 00:00:00 2001 From: Mike Wyatt Date: Tue, 29 Dec 2015 15:37:48 -0400 Subject: Update Asana field descriptions --- app/models/project_services/asana_service.rb | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/app/models/project_services/asana_service.rb b/app/models/project_services/asana_service.rb index bbc508e8f8e..a16adf10432 100644 --- a/app/models/project_services/asana_service.rb +++ b/app/models/project_services/asana_service.rb @@ -53,14 +53,12 @@ http://developer.asana.com/documentation/#api_keys' { type: 'text', name: 'api_key', - placeholder: 'User API token. User must have access to task, -all comments will be attributed to this user.' + placeholder: 'User Personal Access Token. User must have access to task, all comments will be attributed to this user.' }, { type: 'text', name: 'restrict_to_branch', - placeholder: 'Comma-separated list of branches which will be -automatically inspected. Leave blank to include all branches.' + placeholder: 'Comma-separated list of branches which will be automatically inspected. Leave blank to include all branches.' } ] end -- cgit v1.2.1 From 12ec1e3c407a4b72f670483a558a9cb95449c838 Mon Sep 17 00:00:00 2001 From: Mike Wyatt Date: Tue, 29 Dec 2015 15:39:58 -0400 Subject: Update Asana service to work with Personal Access Token, lessen number of requests to Asana API --- app/models/project_services/asana_service.rb | 52 +++++++++++----------------- 1 file changed, 21 insertions(+), 31 deletions(-) diff --git a/app/models/project_services/asana_service.rb b/app/models/project_services/asana_service.rb index a16adf10432..111a60431b1 100644 --- a/app/models/project_services/asana_service.rb +++ b/app/models/project_services/asana_service.rb @@ -67,35 +67,34 @@ http://developer.asana.com/documentation/#api_keys' %w(push) end + def client + @_client ||= begin + Asana::Client.new do |c| + c.authentication :access_token, api_key + end + end + end + def execute(data) return unless supported_events.include?(data[:object_kind]) - Asana.configure do |client| - client.api_key = api_key - end - - user = data[:user_name] + # check the branch restriction is poplulated and branch is not included branch = Gitlab::Git.ref_name(data[:ref]) - branch_restriction = restrict_to_branch.to_s - - # check the branch restriction is poplulated and branch is not included if branch_restriction.length > 0 && branch_restriction.index(branch).nil? return end + user = data[:user_name] project_name = project.name_with_namespace - push_msg = user + ' pushed to branch ' + branch + ' of ' + project_name + push_msg = "#{user} pushed to branch #{branch} of #{project_name} ( #{commit[:url]} )" data[:commits].each do |commit| - check_commit(' ( ' + commit[:url] + ' ): ' + commit[:message], push_msg) + check_commit(commit[:message], push_msg) end end def check_commit(message, push_msg) - task_list = [] - close_list = [] - # matches either: # - #1234 # - https://app.asana.com/0/0/1234 @@ -109,28 +108,19 @@ http://developer.asana.com/documentation/#api_keys' # tuple will be # [ 'fix', 'id_from_url', 'id_from_pound' ] taskid = tuple[2] || tuple[1] - task_list.push(taskid) - - if tuple[0] - close_list.push(taskid) - end - end - - # post commit to every taskid found - task_list.each do |taskid| - task = Asana::Task.find(taskid) - if task - task.create_story(text: push_msg + ' ' + message) + begin + task = Asana::Task.find_by_id(client, taskid) + rescue Exception => e + puts e.message + puts e.backtrace.inspect + next end - end - # close all tasks that had 'fix(ed/es/ing) #:id' in them - close_list.each do |taskid| - task = Asana::Task.find(taskid) + task.add_comment(text: "#{push_msg} #{message}") - if task - task.modify(completed: true) + if tuple[0] + task.update(completed: true) end end end -- cgit v1.2.1 From 4c1f1c2c91a1a43f0ee38fc0f5e8c92dea996f04 Mon Sep 17 00:00:00 2001 From: Mike Wyatt Date: Tue, 29 Dec 2015 15:40:50 -0400 Subject: Update Asana specs --- spec/models/project_services/asana_service_spec.rb | 40 +++++++++++++++++----- 1 file changed, 32 insertions(+), 8 deletions(-) diff --git a/spec/models/project_services/asana_service_spec.rb b/spec/models/project_services/asana_service_spec.rb index e368b03206e..306d18171be 100644 --- a/spec/models/project_services/asana_service_spec.rb +++ b/spec/models/project_services/asana_service_spec.rb @@ -52,30 +52,54 @@ describe AsanaService, models: true do end it 'should call Asana service to created a story' do - expect(Asana::Task).to receive(:find).with('123456').once + d1 = double('Asana::Task', add_comment: true) + expect(d1).to receive(:add_comment) + expect(Asana::Task).to receive(:find_by_id).with(anything, '123456').once.and_return(d1) @asana.check_commit('related to #123456', 'pushed') end it 'should call Asana service to created a story and close a task' do - expect(Asana::Task).to receive(:find).with('456789').twice + d1 = double('Asana::Task', add_comment: true) + expect(d1).to receive(:add_comment) + expect(d1).to receive(:update).with(completed: true) + expect(Asana::Task).to receive(:find_by_id).with(anything, '456789').once.and_return(d1) @asana.check_commit('fix #456789', 'pushed') end it 'should be able to close via url' do - expect(Asana::Task).to receive(:find).with('42').twice + d1 = double('Asana::Task', add_comment: true) + expect(d1).to receive(:add_comment) + expect(d1).to receive(:update).with(completed: true) + expect(Asana::Task).to receive(:find_by_id).with(anything, '42').once.and_return(d1) @asana.check_commit('closes https://app.asana.com/19292/956299/42', 'pushed') end it 'should allow multiple matches per line' do - expect(Asana::Task).to receive(:find).with('123').twice - expect(Asana::Task).to receive(:find).with('456').twice - expect(Asana::Task).to receive(:find).with('789').once + d1 = double('Asana::Task', add_comment: true) + expect(d1).to receive(:add_comment) + expect(d1).to receive(:update).with(completed: true) + expect(Asana::Task).to receive(:find_by_id).with(anything, '123').once.and_return(d1) - expect(Asana::Task).to receive(:find).with('42').once - expect(Asana::Task).to receive(:find).with('12').twice + d2 = double('Asana::Task', add_comment: true) + expect(d2).to receive(:add_comment) + expect(d2).to receive(:update).with(completed: true) + expect(Asana::Task).to receive(:find_by_id).with(anything, '456').once.and_return(d2) + + d3 = double('Asana::Task', add_comment: true) + expect(d3).to receive(:add_comment) + expect(Asana::Task).to receive(:find_by_id).with(anything, '789').once.and_return(d3) + + d4 = double('Asana::Task', add_comment: true) + expect(d4).to receive(:add_comment) + expect(Asana::Task).to receive(:find_by_id).with(anything, '42').once.and_return(d4) + + d5 = double('Asana::Task', add_comment: true) + expect(d5).to receive(:add_comment) + expect(d5).to receive(:update).with(completed: true) + expect(Asana::Task).to receive(:find_by_id).with(anything, '12').once.and_return(d5) message = <<-EOF minor bigfix, refactoring, fixed #123 and Closes #456 work on #789 -- cgit v1.2.1 From e8080fc8fb216fb6da7d3f056e8b4417f807d09e Mon Sep 17 00:00:00 2001 From: Mike Wyatt Date: Tue, 29 Dec 2015 16:00:36 -0400 Subject: Fix error in Asana service --- app/models/project_services/asana_service.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/models/project_services/asana_service.rb b/app/models/project_services/asana_service.rb index 111a60431b1..80c56b9097b 100644 --- a/app/models/project_services/asana_service.rb +++ b/app/models/project_services/asana_service.rb @@ -87,9 +87,9 @@ http://developer.asana.com/documentation/#api_keys' user = data[:user_name] project_name = project.name_with_namespace - push_msg = "#{user} pushed to branch #{branch} of #{project_name} ( #{commit[:url]} )" data[:commits].each do |commit| + push_msg = "#{user} pushed to branch #{branch} of #{project_name} ( #{commit[:url]} )" check_commit(commit[:message], push_msg) end end -- cgit v1.2.1 From 6eb273a11cf7521448f4bcb5f9376df24c2f9f3f Mon Sep 17 00:00:00 2001 From: Mike Wyatt Date: Wed, 30 Dec 2015 00:50:44 -0400 Subject: Restore colon in Asana comment --- app/models/project_services/asana_service.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/models/project_services/asana_service.rb b/app/models/project_services/asana_service.rb index 80c56b9097b..183ce2df787 100644 --- a/app/models/project_services/asana_service.rb +++ b/app/models/project_services/asana_service.rb @@ -89,7 +89,7 @@ http://developer.asana.com/documentation/#api_keys' project_name = project.name_with_namespace data[:commits].each do |commit| - push_msg = "#{user} pushed to branch #{branch} of #{project_name} ( #{commit[:url]} )" + push_msg = "#{user} pushed to branch #{branch} of #{project_name} ( #{commit[:url]} ):" check_commit(commit[:message], push_msg) end end -- cgit v1.2.1 From 7b98d0e1a24645df802ad65911c290ad057d1422 Mon Sep 17 00:00:00 2001 From: Mike Wyatt Date: Wed, 30 Dec 2015 00:51:05 -0400 Subject: Update Asana service documentation --- app/models/project_services/asana_service.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/models/project_services/asana_service.rb b/app/models/project_services/asana_service.rb index 183ce2df787..ab5772356f1 100644 --- a/app/models/project_services/asana_service.rb +++ b/app/models/project_services/asana_service.rb @@ -40,8 +40,8 @@ get the commit comment added to it. You can also close a task with a message containing: `fix #123456`. -You can find your Api Keys here: -http://developer.asana.com/documentation/#api_keys' +You can create a Personal Access Token here: +http://app.asana.com/-/account_api' end def to_param -- cgit v1.2.1 From 9e7a88f089323964088945829523b798ea6b78b5 Mon Sep 17 00:00:00 2001 From: Mike Wyatt Date: Wed, 30 Dec 2015 00:52:56 -0400 Subject: Better handling of errors in Asana service [ci skip] --- app/models/project_services/asana_service.rb | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/app/models/project_services/asana_service.rb b/app/models/project_services/asana_service.rb index ab5772356f1..cb4f6ddb3a5 100644 --- a/app/models/project_services/asana_service.rb +++ b/app/models/project_services/asana_service.rb @@ -111,17 +111,16 @@ http://app.asana.com/-/account_api' begin task = Asana::Task.find_by_id(client, taskid) - rescue Exception => e - puts e.message - puts e.backtrace.inspect + task.add_comment(text: "#{push_msg} #{message}") + + if tuple[0] + task.update(completed: true) + end + rescue => e + Rails.logger.error(e.message) + Rails.logger.error(e.backtrace.join("\n")) next end - - task.add_comment(text: "#{push_msg} #{message}") - - if tuple[0] - task.update(completed: true) - end end end end -- cgit v1.2.1 From 90029a5caaef1fd9d41a8ac02a7e9840ce3ac7b5 Mon Sep 17 00:00:00 2001 From: Mike Wyatt Date: Thu, 31 Dec 2015 18:27:34 -0400 Subject: Actually test the posted comment in Asana service --- spec/models/project_services/asana_service_spec.rb | 25 ++++++++++++++++++---- 1 file changed, 21 insertions(+), 4 deletions(-) diff --git a/spec/models/project_services/asana_service_spec.rb b/spec/models/project_services/asana_service_spec.rb index 306d18171be..a7b32ac07a9 100644 --- a/spec/models/project_services/asana_service_spec.rb +++ b/spec/models/project_services/asana_service_spec.rb @@ -40,6 +40,20 @@ describe AsanaService, models: true do let(:user) { create(:user) } let(:project) { create(:project) } + def create_data_for_commits(*messages) + data = { + object_kind: 'push', + ref: 'master', + user_name: user.name, + commits: messages.map do |m| + { + message: m, + url: 'https://gitlab.com/', + } + end + } + end + before do @asana = AsanaService.new allow(@asana).to receive_messages( @@ -51,12 +65,15 @@ describe AsanaService, models: true do ) end - it 'should call Asana service to created a story' do - d1 = double('Asana::Task', add_comment: true) - expect(d1).to receive(:add_comment) + it 'should call Asana service to create a story' do + data = create_data_for_commits('Message from commit. related to #123456') + expected_message = "#{data[:user_name]} pushed to branch #{data[:ref]} of #{project.name_with_namespace} ( #{data[:commits][0][:url]} ): #{data[:commits][0][:message]}" + + d1 = double('Asana::Task') + expect(d1).to receive(:add_comment).with(text: expected_message) expect(Asana::Task).to receive(:find_by_id).with(anything, '123456').once.and_return(d1) - @asana.check_commit('related to #123456', 'pushed') + @asana.execute(data) end it 'should call Asana service to created a story and close a task' do -- cgit v1.2.1 From 571df5f44bfec89b21bdce0f91f9acfdda6d7660 Mon Sep 17 00:00:00 2001 From: Mike Wyatt Date: Thu, 31 Dec 2015 18:29:00 -0400 Subject: Use `execute` in Asana specs --- spec/models/project_services/asana_service_spec.rb | 33 ++++++++++++---------- 1 file changed, 18 insertions(+), 15 deletions(-) diff --git a/spec/models/project_services/asana_service_spec.rb b/spec/models/project_services/asana_service_spec.rb index a7b32ac07a9..0db48c75d1d 100644 --- a/spec/models/project_services/asana_service_spec.rb +++ b/spec/models/project_services/asana_service_spec.rb @@ -76,53 +76,56 @@ describe AsanaService, models: true do @asana.execute(data) end - it 'should call Asana service to created a story and close a task' do - d1 = double('Asana::Task', add_comment: true) + it 'should call Asana service to create a story and close a task' do + data = create_data_for_commits('fix #456789') + d1 = double('Asana::Task') expect(d1).to receive(:add_comment) expect(d1).to receive(:update).with(completed: true) expect(Asana::Task).to receive(:find_by_id).with(anything, '456789').once.and_return(d1) - @asana.check_commit('fix #456789', 'pushed') + @asana.execute(data) end it 'should be able to close via url' do - d1 = double('Asana::Task', add_comment: true) + data = create_data_for_commits('closes https://app.asana.com/19292/956299/42') + d1 = double('Asana::Task') expect(d1).to receive(:add_comment) expect(d1).to receive(:update).with(completed: true) expect(Asana::Task).to receive(:find_by_id).with(anything, '42').once.and_return(d1) - @asana.check_commit('closes https://app.asana.com/19292/956299/42', 'pushed') + @asana.execute(data) end it 'should allow multiple matches per line' do - d1 = double('Asana::Task', add_comment: true) + message = <<-EOF + minor bigfix, refactoring, fixed #123 and Closes #456 work on #789 + ref https://app.asana.com/19292/956299/42 and closing https://app.asana.com/19292/956299/12 + EOF + data = create_data_for_commits(message) + d1 = double('Asana::Task') expect(d1).to receive(:add_comment) expect(d1).to receive(:update).with(completed: true) expect(Asana::Task).to receive(:find_by_id).with(anything, '123').once.and_return(d1) - d2 = double('Asana::Task', add_comment: true) + d2 = double('Asana::Task') expect(d2).to receive(:add_comment) expect(d2).to receive(:update).with(completed: true) expect(Asana::Task).to receive(:find_by_id).with(anything, '456').once.and_return(d2) - d3 = double('Asana::Task', add_comment: true) + d3 = double('Asana::Task') expect(d3).to receive(:add_comment) expect(Asana::Task).to receive(:find_by_id).with(anything, '789').once.and_return(d3) - d4 = double('Asana::Task', add_comment: true) + d4 = double('Asana::Task') expect(d4).to receive(:add_comment) expect(Asana::Task).to receive(:find_by_id).with(anything, '42').once.and_return(d4) - d5 = double('Asana::Task', add_comment: true) + d5 = double('Asana::Task') expect(d5).to receive(:add_comment) expect(d5).to receive(:update).with(completed: true) expect(Asana::Task).to receive(:find_by_id).with(anything, '12').once.and_return(d5) - message = <<-EOF - minor bigfix, refactoring, fixed #123 and Closes #456 work on #789 - ref https://app.asana.com/19292/956299/42 and closing https://app.asana.com/19292/956299/12 - EOF - @asana.check_commit(message, 'pushed') + @asana.execute(data) end end end -- cgit v1.2.1 From 8bfc46451eae5bd92380b9fbdf91b9636d55066c Mon Sep 17 00:00:00 2001 From: Josh Frye Date: Wed, 23 Dec 2015 10:20:07 -0500 Subject: Show 'New Merge Request' buttons on canonical repo. --- CHANGELOG | 2 ++ app/views/projects/buttons/_dropdown.html.haml | 7 ++++--- app/views/projects/merge_requests/index.html.haml | 5 +++-- features/project/fork.feature | 10 ++++++++++ features/steps/project/fork.rb | 10 ++++++++++ 5 files changed, 29 insertions(+), 5 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index 2b7d5808e7e..e4245060489 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -91,6 +91,8 @@ v 8.3.0 - Do not show build status unless builds are enabled and `.gitlab-ci.yml` is present - Persist runners registration token in database - Fix online editor should not remove newlines at the end of the file + - Expose Git's version in the admin area + - Show "New Merge Request" buttons on canonical repos when you have a fork (Josh Frye) v 8.2.3 - Fix application settings cache not expiring after changes (Stan Hu) diff --git a/app/views/projects/buttons/_dropdown.html.haml b/app/views/projects/buttons/_dropdown.html.haml index 1f639fecc30..459e6da2fe2 100644 --- a/app/views/projects/buttons/_dropdown.html.haml +++ b/app/views/projects/buttons/_dropdown.html.haml @@ -8,11 +8,12 @@ = link_to url_for_new_issue(@project, only_path: true) do = icon('exclamation-circle fw') New issue - - if can?(current_user, :create_merge_request, @project) + - merge_project = can?(current_user, :create_merge_request, @project) ? @project : current_user.fork_of(@project) + - if merge_project %li - = link_to new_namespace_project_merge_request_path(@project.namespace, @project) do + = link_to new_namespace_project_merge_request_path(merge_project.namespace, merge_project) do = icon('tasks fw') - New merge request + New Merge Request - if can?(current_user, :create_snippet, @project) %li = link_to new_namespace_project_snippet_path(@project.namespace, @project) do diff --git a/app/views/projects/merge_requests/index.html.haml b/app/views/projects/merge_requests/index.html.haml index 086298e5af1..972fce9ad3d 100644 --- a/app/views/projects/merge_requests/index.html.haml +++ b/app/views/projects/merge_requests/index.html.haml @@ -6,9 +6,10 @@ .controls = render 'shared/issuable/search_form', path: namespace_project_merge_requests_path(@project.namespace, @project) - - if can? current_user, :create_merge_request, @project + - merge_project = can?(current_user, :create_merge_request, @project) ? @project : current_user.fork_of(@project) + - if merge_project .pull-left.hidden-xs - = link_to new_namespace_project_merge_request_path(@project.namespace, @project), class: "btn btn-new", title: "New Merge Request" do + = link_to new_namespace_project_merge_request_path(merge_project.namespace, merge_project), class: "btn btn-new", title: "New Merge Request" do %i.fa.fa-plus New Merge Request = render 'shared/issuable/filter', type: :merge_requests diff --git a/features/project/fork.feature b/features/project/fork.feature index 22f68e5b340..40849352370 100644 --- a/features/project/fork.feature +++ b/features/project/fork.feature @@ -1,3 +1,4 @@ +@forks Feature: Project Fork Background: Given I sign in as a user @@ -14,3 +15,12 @@ Feature: Project Fork And I click link "Fork" When I fork to my namespace Then I should see a "Name has already been taken" warning + + Scenario: Merge request on canonical repo goes to fork merge request page + Given I click link "Fork" + And I fork to my namespace + Then I should see the forked project page + When I visit project "Shop" page + Then I should see "New merge request" + And I goto the Merge Requests page + Then I should see "New merge request" diff --git a/features/steps/project/fork.rb b/features/steps/project/fork.rb index b0230add34f..878ddea46ff 100644 --- a/features/steps/project/fork.rb +++ b/features/steps/project/fork.rb @@ -30,4 +30,14 @@ class Spinach::Features::ProjectFork < Spinach::FeatureSteps click_link current_user.name end end + + step 'I should see "New Merge Request"' do + expect(page).to have_content "New Merge Request" + end + + step 'I goto the Merge Requests page' do + page.within '.page-sidebar-expanded' do + click_link "Merge Requests" + end + end end -- cgit v1.2.1 From 95e6327b85b8230dc834c781203c72b318551b5d Mon Sep 17 00:00:00 2001 From: Josh Frye Date: Wed, 23 Dec 2015 12:24:25 -0500 Subject: Fix tests --- app/views/projects/buttons/_dropdown.html.haml | 2 +- app/views/projects/merge_requests/index.html.haml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/app/views/projects/buttons/_dropdown.html.haml b/app/views/projects/buttons/_dropdown.html.haml index 459e6da2fe2..35a9d3223a6 100644 --- a/app/views/projects/buttons/_dropdown.html.haml +++ b/app/views/projects/buttons/_dropdown.html.haml @@ -8,7 +8,7 @@ = link_to url_for_new_issue(@project, only_path: true) do = icon('exclamation-circle fw') New issue - - merge_project = can?(current_user, :create_merge_request, @project) ? @project : current_user.fork_of(@project) + - merge_project = can?(current_user, :create_merge_request, @project) ? @project : (current_user && current_user.fork_of(@project)) - if merge_project %li = link_to new_namespace_project_merge_request_path(merge_project.namespace, merge_project) do diff --git a/app/views/projects/merge_requests/index.html.haml b/app/views/projects/merge_requests/index.html.haml index 972fce9ad3d..8d5d0394a82 100644 --- a/app/views/projects/merge_requests/index.html.haml +++ b/app/views/projects/merge_requests/index.html.haml @@ -6,7 +6,7 @@ .controls = render 'shared/issuable/search_form', path: namespace_project_merge_requests_path(@project.namespace, @project) - - merge_project = can?(current_user, :create_merge_request, @project) ? @project : current_user.fork_of(@project) + - merge_project = can?(current_user, :create_merge_request, @project) ? @project : (current_user && current_user.fork_of(@project)) - if merge_project .pull-left.hidden-xs = link_to new_namespace_project_merge_request_path(merge_project.namespace, merge_project), class: "btn btn-new", title: "New Merge Request" do -- cgit v1.2.1 From 796c11e9a7d955ac40c3d1f8427f3f65063ac8c4 Mon Sep 17 00:00:00 2001 From: Josh Frye Date: Wed, 23 Dec 2015 12:36:49 -0500 Subject: Remove feature tag from testing locally --- features/project/fork.feature | 1 - 1 file changed, 1 deletion(-) diff --git a/features/project/fork.feature b/features/project/fork.feature index 40849352370..1182f493e34 100644 --- a/features/project/fork.feature +++ b/features/project/fork.feature @@ -1,4 +1,3 @@ -@forks Feature: Project Fork Background: Given I sign in as a user -- cgit v1.2.1 From edd2ce38369e5a332b1b9932647d670862ffddbf Mon Sep 17 00:00:00 2001 From: Josh Frye Date: Fri, 25 Dec 2015 11:30:48 -0500 Subject: Change text back. Add additional tests. --- app/views/projects/buttons/_dropdown.html.haml | 2 +- features/project/fork.feature | 2 ++ features/steps/project/fork.rb | 13 +++++++++++-- 3 files changed, 14 insertions(+), 3 deletions(-) diff --git a/app/views/projects/buttons/_dropdown.html.haml b/app/views/projects/buttons/_dropdown.html.haml index 35a9d3223a6..f9ab78e7874 100644 --- a/app/views/projects/buttons/_dropdown.html.haml +++ b/app/views/projects/buttons/_dropdown.html.haml @@ -13,7 +13,7 @@ %li = link_to new_namespace_project_merge_request_path(merge_project.namespace, merge_project) do = icon('tasks fw') - New Merge Request + New merge request - if can?(current_user, :create_snippet, @project) %li = link_to new_namespace_project_snippet_path(@project.namespace, @project) do diff --git a/features/project/fork.feature b/features/project/fork.feature index 1182f493e34..37cd53ee977 100644 --- a/features/project/fork.feature +++ b/features/project/fork.feature @@ -23,3 +23,5 @@ Feature: Project Fork Then I should see "New merge request" And I goto the Merge Requests page Then I should see "New merge request" + And I click link "New merge request" + Then I should see the new merge request page for my namespace diff --git a/features/steps/project/fork.rb b/features/steps/project/fork.rb index 878ddea46ff..e98bd51ca89 100644 --- a/features/steps/project/fork.rb +++ b/features/steps/project/fork.rb @@ -31,8 +31,8 @@ class Spinach::Features::ProjectFork < Spinach::FeatureSteps end end - step 'I should see "New Merge Request"' do - expect(page).to have_content "New Merge Request" + step 'I should see "New merge request"' do + expect(page).to have_content(/new merge request/i) end step 'I goto the Merge Requests page' do @@ -40,4 +40,13 @@ class Spinach::Features::ProjectFork < Spinach::FeatureSteps click_link "Merge Requests" end end + + step 'I click link "New merge request"' do + expect(page).to have_content(/new merge request/i) + click_link "New Merge Request" + end + + step 'I should see the new merge request page for my namespace' do + current_path.should have_content(/#{current_user.namespace.name}/i) + end end -- cgit v1.2.1 From bb6b793c55150ecbe072456bc4b151191764b642 Mon Sep 17 00:00:00 2001 From: Mike Wyatt Date: Mon, 4 Jan 2016 11:19:39 -0400 Subject: Don't log backtrace in Asana service --- app/models/project_services/asana_service.rb | 1 - 1 file changed, 1 deletion(-) diff --git a/app/models/project_services/asana_service.rb b/app/models/project_services/asana_service.rb index cb4f6ddb3a5..7d367e40037 100644 --- a/app/models/project_services/asana_service.rb +++ b/app/models/project_services/asana_service.rb @@ -118,7 +118,6 @@ http://app.asana.com/-/account_api' end rescue => e Rails.logger.error(e.message) - Rails.logger.error(e.backtrace.join("\n")) next end end -- cgit v1.2.1 From 57a68c722c180be04dfe1682b1fbced11c8d735b Mon Sep 17 00:00:00 2001 From: Achilleas Pipinellis Date: Tue, 5 Jan 2016 13:59:32 +0100 Subject: Update project services to include all supported ones [ci skip] --- doc/project_services/project_services.md | 42 ++++++++++++++++++++------------ 1 file changed, 26 insertions(+), 16 deletions(-) diff --git a/doc/project_services/project_services.md b/doc/project_services/project_services.md index 03937d20728..2d3e899383f 100644 --- a/doc/project_services/project_services.md +++ b/doc/project_services/project_services.md @@ -1,20 +1,30 @@ # Project Services - -__Project integrations with external services for continuous integration and more.__ + +Project services allow you to integrate GitLab with other applications. Below +is list of the currently supported ones. Click on the service links to see +further configuration instructions and details. Contributions are welcome. ## Services -- Assembla -- [Atlassian Bamboo CI](bamboo.md) An Atlassian product for continuous integration. -- Build box -- Campfire -- Emails on push -- Flowdock -- Gemnasium -- GitLab CI -- [HipChat](hipchat.md) An Atlassian product for private group chat and instant messaging. -- [Irker](irker.md) An IRC gateway to receive messages on repository updates. -- Pivotal Tracker -- Pushover -- Slack -- TeamCity +| Service | Description | +| ------- | ----------- | +| Asana | Asana - Teamwork without email | +| Assembla | Project Management Software (Source Commits Endpoint) | +| [Atlassian Bamboo CI](bamboo.md) | A continuous integration and build server | +| Buildkite | Continuous integration and deployments | +| Builds emails | Email the builds status to a list of recipients | +| Campfire | Simple web-based real-time group chat | +| Custom Issue Tracker | Custom issue tracker | +| Drone CI | Continuous Integration platform built on Docker, written in Go | +| Emails on push | Email the commits and diff of each push to a list of recipients | +| External Wiki | Replaces the link to the internal wiki with a link to an external wiki | +| Flowdock | Flowdock is a collaboration web app for technical teams | +| Gemnasium | Gemnasium monitors your project dependencies and alerts you about updates and security vulnerabilities | +| [HipChat](hipchat.md) | Private group chat and IM | +| [Irker (IRC gateway)](irker.md) | Send IRC messages, on update, to a list of recipients through an Irker gateway | +| JIRA | Jira issue tracker | +| JetBrains TeamCity CI | A continuous integration and build server | +| PivotalTracker | Project Management Software (Source Commits Endpoint) | +| Pushover | Pushover makes it easy to get real-time notifications on your Android device, iPhone, iPad, and Desktop | +| Redmine | Redmine issue tracker | +| Slack | A team communication tool for the 21st century | -- cgit v1.2.1 From 6ce01ca3ece007f135c6b5a9bc258fdd9e8d71de Mon Sep 17 00:00:00 2001 From: Douglas Barbosa Alexandre Date: Tue, 5 Jan 2016 11:00:10 -0200 Subject: Validate README format before displaying MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Take the first previewable README file as project’s README, otherwise if none file is available, or we can’t preview any of them, we assume that project doesn’t have a README file. --- app/models/tree.rb | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/app/models/tree.rb b/app/models/tree.rb index 93b3246a668..e0e04d8859f 100644 --- a/app/models/tree.rb +++ b/app/models/tree.rb @@ -17,18 +17,16 @@ class Tree def readme return @readme if defined?(@readme) - available_readmes = blobs.select(&:readme?) + # Take the first previewable readme, or return nil if none is available or + # we can't preview any of them + readme_tree = blobs.find do |blob| + blob.readme? && (previewable?(blob.name) || plain?(blob.name)) + end - if available_readmes.count == 0 + if readme_tree.nil? return @readme = nil end - # Take the first previewable readme, or the first available readme, if we - # can't preview any of them - readme_tree = available_readmes.find do |readme| - previewable?(readme.name) - end || available_readmes.first - readme_path = path == '/' ? readme_tree.name : File.join(path, readme_tree.name) git_repo = repository.raw_repository -- cgit v1.2.1 From e57b506222f535774059cbb0f986621384c5a8f7 Mon Sep 17 00:00:00 2001 From: Stan Hu Date: Tue, 5 Jan 2016 05:30:01 -0800 Subject: Suggest prefacing find command with sudo when base permissions are wrong Closes #5872 --- lib/tasks/gitlab/check.rake | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/tasks/gitlab/check.rake b/lib/tasks/gitlab/check.rake index 0469c5a61c3..2dc2953e328 100644 --- a/lib/tasks/gitlab/check.rake +++ b/lib/tasks/gitlab/check.rake @@ -431,7 +431,7 @@ namespace :gitlab do try_fixing_it( "sudo chmod -R ug+rwX,o-rwx #{repo_base_path}", "sudo chmod -R ug-s #{repo_base_path}", - "find #{repo_base_path} -type d -print0 | sudo xargs -0 chmod g+s" + "sudo find #{repo_base_path} -type d -print0 | sudo xargs -0 chmod g+s" ) for_more_information( see_installation_guide_section "GitLab Shell" -- cgit v1.2.1 From 8e33ec1deea60a176cd43092c913200d28ea04fe Mon Sep 17 00:00:00 2001 From: Douglas Barbosa Alexandre Date: Tue, 5 Jan 2016 11:30:30 -0200 Subject: [ci skip] Update CHANGELOG --- CHANGELOG | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG b/CHANGELOG index 47ef06bee54..72698e4fe3f 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -18,6 +18,7 @@ v 8.4.0 (unreleased) - Fix version check image in Safari - Show 'All' tab by default in the builds page - Fix API project lookups when querying with a namespace with dots (Stan Hu) + - Validate README format before displaying v 8.3.3 (unreleased) - Fix project transfer e-mail sending incorrect paths in e-mail notification (Stan Hu) -- cgit v1.2.1 From 097faeb481db2a4956b41049c041d55f5da4e2c1 Mon Sep 17 00:00:00 2001 From: Douwe Maan Date: Tue, 5 Jan 2016 16:24:42 +0100 Subject: Get "Merge when build succeeds" to work when commits were pushed to MR target branch while builds were running --- CHANGELOG | 1 + app/controllers/projects/merge_requests_controller.rb | 2 +- app/models/merge_request.rb | 16 +++++++++++----- app/views/projects/merge_requests/_show.html.haml | 2 +- lib/api/merge_requests.rb | 2 +- 5 files changed, 15 insertions(+), 8 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index d841b149615..240fa43d6cb 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -20,6 +20,7 @@ v 8.4.0 (unreleased) - Fix API project lookups when querying with a namespace with dots (Stan Hu) v 8.3.3 (unreleased) + - Get "Merge when build succeeds" to work when commits were pushed to MR target branch while builds were running - Fix project transfer e-mail sending incorrect paths in e-mail notification (Stan Hu) - Enable "Add key" button when user fills in a proper key (Stan Hu) diff --git a/app/controllers/projects/merge_requests_controller.rb b/app/controllers/projects/merge_requests_controller.rb index ab5c953189c..de948d271c8 100644 --- a/app/controllers/projects/merge_requests_controller.rb +++ b/app/controllers/projects/merge_requests_controller.rb @@ -153,7 +153,7 @@ class Projects::MergeRequestsController < Projects::ApplicationController end def merge_check - @merge_request.check_if_can_be_merged if @merge_request.unchecked? + @merge_request.check_if_can_be_merged render partial: "projects/merge_requests/widget/show.html.haml", layout: false end diff --git a/app/models/merge_request.rb b/app/models/merge_request.rb index ac25d38eb63..30d0c2b5961 100644 --- a/app/models/merge_request.rb +++ b/app/models/merge_request.rb @@ -229,6 +229,8 @@ class MergeRequest < ActiveRecord::Base end def check_if_can_be_merged + return unless unchecked? + can_be_merged = project.repository.can_be_merged?(source_sha, target_branch) @@ -252,7 +254,11 @@ class MergeRequest < ActiveRecord::Base end def mergeable? - open? && !work_in_progress? && can_be_merged? + return false unless open? && !work_in_progress? + + check_if_can_be_merged + + can_be_merged? end def gitlab_merge_status @@ -452,6 +458,10 @@ class MergeRequest < ActiveRecord::Base !source_branch_exists? || !target_branch_exists? end + def broken? + self.commits.blank? || branch_missing? || cannot_be_merged? + end + def can_be_merged_by?(user) ::Gitlab::GitAccess.new(user, project).can_push_to_branch?(target_branch) end @@ -507,8 +517,4 @@ class MergeRequest < ActiveRecord::Base def ci_commit @ci_commit ||= source_project.ci_commit(last_commit.id) if last_commit && source_project end - - def broken? - self.commits.blank? || branch_missing? || cannot_be_merged? - end end diff --git a/app/views/projects/merge_requests/_show.html.haml b/app/views/projects/merge_requests/_show.html.haml index ba7c2c01e93..095876450a0 100644 --- a/app/views/projects/merge_requests/_show.html.haml +++ b/app/views/projects/merge_requests/_show.html.haml @@ -38,7 +38,7 @@ = render "projects/merge_requests/show/how_to_merge" = render "projects/merge_requests/widget/show.html.haml" - - if @merge_request.open? && @merge_request.source_branch_exists? && @merge_request.can_be_merged? && @merge_request.can_be_merged_by?(current_user) + - if @merge_request.source_branch_exists? && @merge_request.mergeable? && @merge_request.can_be_merged_by?(current_user) .light.prepend-top-default You can also accept this merge request manually using the = succeed '.' do diff --git a/lib/api/merge_requests.rb b/lib/api/merge_requests.rb index 3c1c6bda260..5c97fe1c88c 100644 --- a/lib/api/merge_requests.rb +++ b/lib/api/merge_requests.rb @@ -211,7 +211,7 @@ module API unauthorized! unless merge_request.can_be_merged_by?(current_user) not_allowed! if !merge_request.open? || merge_request.work_in_progress? - merge_request.check_if_can_be_merged if merge_request.unchecked? + merge_request.check_if_can_be_merged render_api_error!('Branch cannot be merged', 406) unless merge_request.can_be_merged? -- cgit v1.2.1 From 0bab4788ef870945feccbb102834fd89433dfef2 Mon Sep 17 00:00:00 2001 From: Douwe Maan Date: Tue, 5 Jan 2016 16:31:05 +0100 Subject: Satisfy Rubocop --- spec/models/project_services/asana_service_spec.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spec/models/project_services/asana_service_spec.rb b/spec/models/project_services/asana_service_spec.rb index 0db48c75d1d..f3d15f3c1ea 100644 --- a/spec/models/project_services/asana_service_spec.rb +++ b/spec/models/project_services/asana_service_spec.rb @@ -41,7 +41,7 @@ describe AsanaService, models: true do let(:project) { create(:project) } def create_data_for_commits(*messages) - data = { + { object_kind: 'push', ref: 'master', user_name: user.name, -- cgit v1.2.1 From 0b661516324862506d5ec30c44cac704346a90ad Mon Sep 17 00:00:00 2001 From: Douwe Maan Date: Tue, 5 Jan 2016 16:45:53 +0100 Subject: Remove icon from milestone reference. --- app/models/milestone.rb | 2 +- app/views/shared/issuable/_sidebar.html.haml | 3 ++- lib/banzai/filter/milestone_reference_filter.rb | 2 -- spec/lib/banzai/filter/milestone_reference_filter_spec.rb | 4 ++-- 4 files changed, 5 insertions(+), 6 deletions(-) diff --git a/app/models/milestone.rb b/app/models/milestone.rb index e47b6440746..eaa2db2e247 100644 --- a/app/models/milestone.rb +++ b/app/models/milestone.rb @@ -76,7 +76,7 @@ class Milestone < ActiveRecord::Base end def reference_link_text(from_project = nil) - %Q{ }.html_safe + self.title + self.title end def expired? diff --git a/app/views/shared/issuable/_sidebar.html.haml b/app/views/shared/issuable/_sidebar.html.haml index 9d65a621e53..79c5cc7f40a 100644 --- a/app/views/shared/issuable/_sidebar.html.haml +++ b/app/views/shared/issuable/_sidebar.html.haml @@ -28,7 +28,8 @@ %span.back-to-milestone = link_to namespace_project_milestone_path(@project.namespace, @project, issuable.milestone) do %strong - = issuable.milestone.reference_link_text + = icon('clock-o') + = issuable.milestone.title - else .light None .selectbox diff --git a/lib/banzai/filter/milestone_reference_filter.rb b/lib/banzai/filter/milestone_reference_filter.rb index f99202af5e8..e88b27c1fae 100644 --- a/lib/banzai/filter/milestone_reference_filter.rb +++ b/lib/banzai/filter/milestone_reference_filter.rb @@ -3,8 +3,6 @@ require 'banzai' module Banzai module Filter # HTML filter that replaces milestone references with links. - # - # This filter supports cross-project references. class MilestoneReferenceFilter < AbstractReferenceFilter def self.object_class Milestone diff --git a/spec/lib/banzai/filter/milestone_reference_filter_spec.rb b/spec/lib/banzai/filter/milestone_reference_filter_spec.rb index c53e780d354..86b71210100 100644 --- a/spec/lib/banzai/filter/milestone_reference_filter_spec.rb +++ b/spec/lib/banzai/filter/milestone_reference_filter_spec.rb @@ -29,7 +29,7 @@ describe Banzai::Filter::MilestoneReferenceFilter, lib: true do it 'links with adjacent text' do doc = reference_filter("milestone (#{reference}.)") - expect(doc.to_html).to match(/\(<\/i> #{Regexp.escape(milestone.title)}<\/a>\.\)/) + expect(doc.to_html).to match(/\(#{Regexp.escape(milestone.title)}<\/a>\.\)/) end it 'includes a title attribute' do @@ -41,7 +41,7 @@ describe Banzai::Filter::MilestoneReferenceFilter, lib: true do milestone.update_attribute(:title, %{">whatever Date: Tue, 5 Jan 2016 18:17:55 +0100 Subject: Fix notification spec --- spec/services/notification_service_spec.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spec/services/notification_service_spec.rb b/spec/services/notification_service_spec.rb index b5c7b01357a..6d219f35895 100644 --- a/spec/services/notification_service_spec.rb +++ b/spec/services/notification_service_spec.rb @@ -53,7 +53,7 @@ describe NotificationService, services: true do add_users_with_subscription(note.project, issue) # Ensure create SentNotification by noteable = issue 6 times, not noteable = note - expect(SentNotification).to receive(:record).with(issue, any_args).exactly(6).times + expect(SentNotification).to receive(:record).with(issue, any_args).exactly(7).times ActionMailer::Base.deliveries.clear -- cgit v1.2.1 From 95f1fe724a47b12b1d66a722be13d15c5fbd2688 Mon Sep 17 00:00:00 2001 From: Douglas Barbosa Alexandre Date: Mon, 21 Dec 2015 16:52:45 -0200 Subject: Import GitHub Pull Requests into GitLab --- lib/gitlab/github_import/importer.rb | 64 ++++++++++++++++++++++++++++++++---- 1 file changed, 57 insertions(+), 7 deletions(-) diff --git a/lib/gitlab/github_import/importer.rb b/lib/gitlab/github_import/importer.rb index b5720f6e2cb..656fac9ac7e 100644 --- a/lib/gitlab/github_import/importer.rb +++ b/lib/gitlab/github_import/importer.rb @@ -12,7 +12,16 @@ module Gitlab end def execute - #Issues && Comments + import_issues + import_pull_requests + + true + end + + private + + def import_issues + # Issues && Comments client.list_issues(project.import_source, state: :all, sort: :created, direction: :asc).each do |issue| @@ -33,18 +42,59 @@ module Gitlab description: body, title: issue.title, state: issue.state == 'closed' ? 'closed' : 'opened', - author_id: gl_user_id(project, issue.user.id) + author_id: gl_author_id(project, issue.user.id) ) end end end - private + def import_pull_requests + client.pull_requests(project.import_source, state: :all, + sort: :created, + direction: :asc).each do |pull_request| + body = @formatter.author_line(pull_request.user.login) + body += pull_request.body || "" + + source_branch = pull_request.head.ref + target_branch = pull_request.base.ref + + merge_request = MergeRequest.create!( + title: pull_request.title, + description: body, + source_project: project, + source_branch: source_branch, + target_project: project, + target_branch: target_branch, + state: merge_request_state(pull_request), + author_id: gl_author_id(project, pull_request.user.id), + assignee_id: gl_user_id(pull_request.assignee.try(:id)), + created_at: pull_request.created_at, + updated_at: pull_request.updated_at + ) + end + end + + def merge_request_state(pull_request) + case true + when pull_request.state == 'closed' && pull_request.merged_at.present? + 'merged' + when pull_request.state == 'closed' + 'closed' + else + 'opened' + end + end + + def gl_author_id(project, github_id) + gl_user_id(github_id) || project.creator_id + end - def gl_user_id(project, github_id) - user = User.joins(:identities). - find_by("identities.extern_uid = ? AND identities.provider = 'github'", github_id.to_s) - (user && user.id) || project.creator_id + def gl_user_id(github_id) + if github_id + User.joins(:identities). + find_by("identities.extern_uid = ? AND identities.provider = 'github'", github_id.to_s). + try(:id) + end end end end -- cgit v1.2.1 From 223f7f53453d544a8c46c75ca9c54b8b60620961 Mon Sep 17 00:00:00 2001 From: Douglas Barbosa Alexandre Date: Mon, 21 Dec 2015 19:08:54 -0200 Subject: Import comments on GitHub Pull Request into GitLab --- lib/gitlab/github_import/importer.rb | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/lib/gitlab/github_import/importer.rb b/lib/gitlab/github_import/importer.rb index 656fac9ac7e..35a2930d4a1 100644 --- a/lib/gitlab/github_import/importer.rb +++ b/lib/gitlab/github_import/importer.rb @@ -71,9 +71,23 @@ module Gitlab created_at: pull_request.created_at, updated_at: pull_request.updated_at ) + + client.issue_comments(project.import_source, pull_request.number).each do |c| + merge_request.notes.create!( + project: project, + note: format_body(c.user.login, c.body), + author_id: gl_author_id(project, c.user.id), + created_at: c.created_at, + updated_at: c.updated_at + ) + end end end + def format_body(author, body) + @formatter.author_line(author) + (body || "") + end + def merge_request_state(pull_request) case true when pull_request.state == 'closed' && pull_request.merged_at.present? -- cgit v1.2.1 From f19bf0eaa73007081f2ab10f6a0fb176d5356e36 Mon Sep 17 00:00:00 2001 From: Douglas Barbosa Alexandre Date: Mon, 21 Dec 2015 19:09:09 -0200 Subject: Import comments on the diff of a GitHub Pull Request into GitLab --- lib/gitlab/github_import/importer.rb | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/lib/gitlab/github_import/importer.rb b/lib/gitlab/github_import/importer.rb index 35a2930d4a1..4b753d24601 100644 --- a/lib/gitlab/github_import/importer.rb +++ b/lib/gitlab/github_import/importer.rb @@ -81,6 +81,18 @@ module Gitlab updated_at: c.updated_at ) end + + client.pull_request_comments(project.import_source, pull_request.number).each do |c| + merge_request.notes.create!( + project: project, + note: format_body(c.user.login, c.body), + commit_id: c.commit_id, + line_code: generate_line_code(c.path, c.position), + author_id: gl_author_id(project, c.user.id), + created_at: c.created_at, + updated_at: c.updated_at + ) + end end end @@ -99,6 +111,10 @@ module Gitlab end end + def generate_line_code(file_path, position) + Gitlab::Diff::LineCode.generate(file_path, position, 0) + end + def gl_author_id(project, github_id) gl_user_id(github_id) || project.creator_id end -- cgit v1.2.1 From d72b25811e3f0b722ae1c0906e2fe7dffd312403 Mon Sep 17 00:00:00 2001 From: Douglas Barbosa Alexandre Date: Mon, 21 Dec 2015 19:42:56 -0200 Subject: Doesn't import GitHub PR where branches were no longer available --- lib/gitlab/github_import/importer.rb | 82 +++++++++++++++++++----------------- 1 file changed, 44 insertions(+), 38 deletions(-) diff --git a/lib/gitlab/github_import/importer.rb b/lib/gitlab/github_import/importer.rb index 4b753d24601..f8a9e0d55ab 100644 --- a/lib/gitlab/github_import/importer.rb +++ b/lib/gitlab/github_import/importer.rb @@ -52,50 +52,56 @@ module Gitlab client.pull_requests(project.import_source, state: :all, sort: :created, direction: :asc).each do |pull_request| - body = @formatter.author_line(pull_request.user.login) - body += pull_request.body || "" - - source_branch = pull_request.head.ref - target_branch = pull_request.base.ref - - merge_request = MergeRequest.create!( - title: pull_request.title, - description: body, - source_project: project, - source_branch: source_branch, - target_project: project, - target_branch: target_branch, - state: merge_request_state(pull_request), - author_id: gl_author_id(project, pull_request.user.id), - assignee_id: gl_user_id(pull_request.assignee.try(:id)), - created_at: pull_request.created_at, - updated_at: pull_request.updated_at - ) - - client.issue_comments(project.import_source, pull_request.number).each do |c| - merge_request.notes.create!( - project: project, - note: format_body(c.user.login, c.body), - author_id: gl_author_id(project, c.user.id), - created_at: c.created_at, - updated_at: c.updated_at + source_branch = find_branch(pull_request.head.ref) + target_branch = find_branch(pull_request.base.ref) + + if source_branch && target_branch + # Pull Request + merge_request = MergeRequest.create!( + title: pull_request.title, + description: format_body(pull_request.user.login, pull_request.body), + source_project: project, + source_branch: source_branch.name, + target_project: project, + target_branch: target_branch.name, + state: merge_request_state(pull_request), + author_id: gl_author_id(project, pull_request.user.id), + assignee_id: gl_user_id(pull_request.assignee.try(:id)), + created_at: pull_request.created_at, + updated_at: pull_request.updated_at ) - end - client.pull_request_comments(project.import_source, pull_request.number).each do |c| - merge_request.notes.create!( - project: project, - note: format_body(c.user.login, c.body), - commit_id: c.commit_id, - line_code: generate_line_code(c.path, c.position), - author_id: gl_author_id(project, c.user.id), - created_at: c.created_at, - updated_at: c.updated_at - ) + # Comments on Pull Request + client.issue_comments(project.import_source, pull_request.number).each do |c| + merge_request.notes.create!( + project: project, + note: format_body(c.user.login, c.body), + author_id: gl_author_id(project, c.user.id), + created_at: c.created_at, + updated_at: c.updated_at + ) + end + + # Comments on Pull Request diff + client.pull_request_comments(project.import_source, pull_request.number).each do |c| + merge_request.notes.create!( + project: project, + note: format_body(c.user.login, c.body), + commit_id: c.commit_id, + line_code: generate_line_code(c.path, c.position), + author_id: gl_author_id(project, c.user.id), + created_at: c.created_at, + updated_at: c.updated_at + ) + end end end end + def find_branch(name) + project.repository.find_branch(name) + end + def format_body(author, body) @formatter.author_line(author) + (body || "") end -- cgit v1.2.1 From 6c846ef83d51a176002027e89245a4ea62b4f2bf Mon Sep 17 00:00:00 2001 From: Douglas Barbosa Alexandre Date: Mon, 21 Dec 2015 21:17:57 -0200 Subject: Extract methods to import comments on a GitHub Pull Request --- lib/gitlab/github_import/importer.rb | 52 +++++++++++++++++++----------------- 1 file changed, 28 insertions(+), 24 deletions(-) diff --git a/lib/gitlab/github_import/importer.rb b/lib/gitlab/github_import/importer.rb index f8a9e0d55ab..2c64f5cebc7 100644 --- a/lib/gitlab/github_import/importer.rb +++ b/lib/gitlab/github_import/importer.rb @@ -56,7 +56,6 @@ module Gitlab target_branch = find_branch(pull_request.base.ref) if source_branch && target_branch - # Pull Request merge_request = MergeRequest.create!( title: pull_request.title, description: format_body(pull_request.user.login, pull_request.body), @@ -71,33 +70,38 @@ module Gitlab updated_at: pull_request.updated_at ) - # Comments on Pull Request - client.issue_comments(project.import_source, pull_request.number).each do |c| - merge_request.notes.create!( - project: project, - note: format_body(c.user.login, c.body), - author_id: gl_author_id(project, c.user.id), - created_at: c.created_at, - updated_at: c.updated_at - ) - end - - # Comments on Pull Request diff - client.pull_request_comments(project.import_source, pull_request.number).each do |c| - merge_request.notes.create!( - project: project, - note: format_body(c.user.login, c.body), - commit_id: c.commit_id, - line_code: generate_line_code(c.path, c.position), - author_id: gl_author_id(project, c.user.id), - created_at: c.created_at, - updated_at: c.updated_at - ) - end + import_comments_on_pull_request(merge_request, pull_request) + import_comments_on_pull_request_diff(merge_request, pull_request) end end end + def import_comments_on_pull_request(merge_request, pull_request) + client.issue_comments(project.import_source, pull_request.number).each do |c| + merge_request.notes.create!( + project: project, + note: format_body(c.user.login, c.body), + author_id: gl_author_id(project, c.user.id), + created_at: c.created_at, + updated_at: c.updated_at + ) + end + end + + def import_comments_on_pull_request_diff(merge_request, pull_request) + client.pull_request_comments(project.import_source, pull_request.number).each do |c| + merge_request.notes.create!( + project: project, + note: format_body(c.user.login, c.body), + commit_id: c.commit_id, + line_code: generate_line_code(c.path, c.position), + author_id: gl_author_id(project, c.user.id), + created_at: c.created_at, + updated_at: c.updated_at + ) + end + end + def find_branch(name) project.repository.find_branch(name) end -- cgit v1.2.1 From dc72a8b30502dd28bf850c2dfdbf31b687fde5d3 Mon Sep 17 00:00:00 2001 From: Douglas Barbosa Alexandre Date: Wed, 23 Dec 2015 15:04:46 -0200 Subject: Refactoring GithubImport::Importer --- lib/gitlab/github_import/comment.rb | 59 ++++++++ lib/gitlab/github_import/importer.rb | 73 ++-------- lib/gitlab/github_import/pull_request.rb | 103 ++++++++++++++ spec/lib/gitlab/github_import/comment_spec.rb | 80 +++++++++++ spec/lib/gitlab/github_import/pull_request_spec.rb | 153 +++++++++++++++++++++ 5 files changed, 407 insertions(+), 61 deletions(-) create mode 100644 lib/gitlab/github_import/comment.rb create mode 100644 lib/gitlab/github_import/pull_request.rb create mode 100644 spec/lib/gitlab/github_import/comment_spec.rb create mode 100644 spec/lib/gitlab/github_import/pull_request_spec.rb diff --git a/lib/gitlab/github_import/comment.rb b/lib/gitlab/github_import/comment.rb new file mode 100644 index 00000000000..55de78f889d --- /dev/null +++ b/lib/gitlab/github_import/comment.rb @@ -0,0 +1,59 @@ +module Gitlab + module GithubImport + class Comment + attr_reader :project, :raw_data + + def initialize(project, raw_data) + @project = project + @raw_data = raw_data + @formatter = Gitlab::ImportFormatter.new + end + + def attributes + { + project: project, + note: note, + commit_id: raw_data.commit_id, + line_code: line_code, + author_id: author_id, + created_at: raw_data.created_at, + updated_at: raw_data.updated_at + } + end + + private + + def author + raw_data.user.login + end + + def author_id + gl_user_id(raw_data.user.id) || project.creator_id + end + + def body + raw_data.body || "" + end + + def line_code + if on_diff? + Gitlab::Diff::LineCode.generate(raw_data.path, raw_data.position, 0) + end + end + + def on_diff? + raw_data.path && raw_data.position + end + + def note + @formatter.author_line(author) + body + end + + def gl_user_id(github_id) + User.joins(:identities). + find_by("identities.extern_uid = ? AND identities.provider = 'github'", github_id.to_s). + try(:id) + end + end + end +end diff --git a/lib/gitlab/github_import/importer.rb b/lib/gitlab/github_import/importer.rb index 2c64f5cebc7..7c495655012 100644 --- a/lib/gitlab/github_import/importer.rb +++ b/lib/gitlab/github_import/importer.rb @@ -51,80 +51,31 @@ module Gitlab def import_pull_requests client.pull_requests(project.import_source, state: :all, sort: :created, - direction: :asc).each do |pull_request| - source_branch = find_branch(pull_request.head.ref) - target_branch = find_branch(pull_request.base.ref) + direction: :asc).each do |raw_data| + pull_request = PullRequest.new(project, raw_data) - if source_branch && target_branch - merge_request = MergeRequest.create!( - title: pull_request.title, - description: format_body(pull_request.user.login, pull_request.body), - source_project: project, - source_branch: source_branch.name, - target_project: project, - target_branch: target_branch.name, - state: merge_request_state(pull_request), - author_id: gl_author_id(project, pull_request.user.id), - assignee_id: gl_user_id(pull_request.assignee.try(:id)), - created_at: pull_request.created_at, - updated_at: pull_request.updated_at - ) - - import_comments_on_pull_request(merge_request, pull_request) - import_comments_on_pull_request_diff(merge_request, pull_request) + if pull_request.valid? + merge_request = MergeRequest.create!(pull_request.attributes) + import_comments_on_pull_request(merge_request, raw_data) + import_comments_on_pull_request_diff(merge_request, raw_data) end end end def import_comments_on_pull_request(merge_request, pull_request) - client.issue_comments(project.import_source, pull_request.number).each do |c| - merge_request.notes.create!( - project: project, - note: format_body(c.user.login, c.body), - author_id: gl_author_id(project, c.user.id), - created_at: c.created_at, - updated_at: c.updated_at - ) + client.issue_comments(project.import_source, pull_request.number).each do |raw_data| + comment = Comment.new(project, raw_data) + merge_request.notes.create!(comment.attributes) end end def import_comments_on_pull_request_diff(merge_request, pull_request) - client.pull_request_comments(project.import_source, pull_request.number).each do |c| - merge_request.notes.create!( - project: project, - note: format_body(c.user.login, c.body), - commit_id: c.commit_id, - line_code: generate_line_code(c.path, c.position), - author_id: gl_author_id(project, c.user.id), - created_at: c.created_at, - updated_at: c.updated_at - ) + client.pull_request_comments(project.import_source, pull_request.number).each do |raw_data| + comment = Comment.new(project, raw_data) + merge_request.notes.create!(comment.attributes) end end - def find_branch(name) - project.repository.find_branch(name) - end - - def format_body(author, body) - @formatter.author_line(author) + (body || "") - end - - def merge_request_state(pull_request) - case true - when pull_request.state == 'closed' && pull_request.merged_at.present? - 'merged' - when pull_request.state == 'closed' - 'closed' - else - 'opened' - end - end - - def generate_line_code(file_path, position) - Gitlab::Diff::LineCode.generate(file_path, position, 0) - end - def gl_author_id(project, github_id) gl_user_id(github_id) || project.creator_id end diff --git a/lib/gitlab/github_import/pull_request.rb b/lib/gitlab/github_import/pull_request.rb new file mode 100644 index 00000000000..61e846472f2 --- /dev/null +++ b/lib/gitlab/github_import/pull_request.rb @@ -0,0 +1,103 @@ +module Gitlab + module GithubImport + class PullRequest + attr_reader :project, :raw_data + + def initialize(project, raw_data) + @project = project + @raw_data = raw_data + @formatter = Gitlab::ImportFormatter.new + end + + def attributes + { + title: raw_data.title, + description: description, + source_project: source_project, + source_branch: source_branch.name, + target_project: target_project, + target_branch: target_branch.name, + state: state, + author_id: author_id, + assignee_id: assignee_id, + created_at: raw_data.created_at, + updated_at: updated_at + } + end + + def valid? + source_branch.present? && target_branch.present? + end + + private + + def assigned? + raw_data.assignee.present? + end + + def assignee_id + if assigned? + gl_user_id(raw_data.assignee.id) + end + end + + def author + raw_data.user.login + end + + def author_id + gl_user_id(raw_data.user.id) || project.creator_id + end + + def body + raw_data.body || "" + end + + def description + @formatter.author_line(author) + body + end + + def source_project + project + end + + def source_branch + source_project.repository.find_branch(raw_data.head.ref) + end + + def target_project + project + end + + def target_branch + target_project.repository.find_branch(raw_data.base.ref) + end + + def state + @state ||= case true + when raw_data.state == 'closed' && raw_data.merged_at.present? + 'merged' + when raw_data.state == 'closed' + 'closed' + else + 'opened' + end + end + + def updated_at + case state + when 'merged' then raw_data.merged_at + when 'closed' then raw_data.closed_at + else + raw_data.updated_at + end + end + + def gl_user_id(github_id) + User.joins(:identities). + find_by("identities.extern_uid = ? AND identities.provider = 'github'", github_id.to_s). + try(:id) + end + end + end +end diff --git a/spec/lib/gitlab/github_import/comment_spec.rb b/spec/lib/gitlab/github_import/comment_spec.rb new file mode 100644 index 00000000000..ff6b115574b --- /dev/null +++ b/spec/lib/gitlab/github_import/comment_spec.rb @@ -0,0 +1,80 @@ +require 'spec_helper' + +describe Gitlab::GithubImport::Comment, lib: true do + let(:project) { create(:project) } + let(:octocat) { OpenStruct.new(id: 123456, login: 'octocat') } + let(:created_at) { DateTime.strptime('2013-04-10T20:09:31Z') } + let(:updated_at) { DateTime.strptime('2014-03-03T18:58:10Z') } + let(:base_data) do + { + body: "I'm having a problem with this.", + user: octocat, + created_at: created_at, + updated_at: updated_at + } + end + + subject(:comment) { described_class.new(project, raw_data)} + + describe '#attributes' do + context 'when do not reference a portion of the diff' do + let(:raw_data) { OpenStruct.new(base_data) } + + it 'returns formatted attributes' do + expected = { + project: project, + note: "*Created by: octocat*\n\nI'm having a problem with this.", + commit_id: nil, + line_code: nil, + author_id: project.creator_id, + created_at: created_at, + updated_at: updated_at + } + + expect(comment.attributes).to eq(expected) + end + end + + context 'when on a portion of the diff' do + let(:diff_data) do + { + body: 'Great stuff', + commit_id: '6dcb09b5b57875f334f61aebed695e2e4193db5e', + diff_hunk: '@@ -16,33 +16,40 @@ public class Connection : IConnection...', + path: 'file1.txt', + position: 1 + } + end + + let(:raw_data) { OpenStruct.new(base_data.merge(diff_data)) } + + it 'returns formatted attributes' do + expected = { + project: project, + note: "*Created by: octocat*\n\nGreat stuff", + commit_id: '6dcb09b5b57875f334f61aebed695e2e4193db5e', + line_code: 'ce1be0ff4065a6e9415095c95f25f47a633cef2b_0_1', + author_id: project.creator_id, + created_at: created_at, + updated_at: updated_at + } + + expect(comment.attributes).to eq(expected) + end + end + + context 'when author is a GitLab user' do + let(:raw_data) { OpenStruct.new(base_data.merge(user: octocat)) } + + it 'returns project#creator_id as author_id when is not a GitLab user' do + expect(comment.attributes.fetch(:author_id)).to eq project.creator_id + end + + it 'returns GitLab user id as author_id when is a GitLab user' do + gl_user = create(:omniauth_user, extern_uid: octocat.id, provider: 'github') + + expect(comment.attributes.fetch(:author_id)).to eq gl_user.id + end + end + end +end diff --git a/spec/lib/gitlab/github_import/pull_request_spec.rb b/spec/lib/gitlab/github_import/pull_request_spec.rb new file mode 100644 index 00000000000..6ac32a78955 --- /dev/null +++ b/spec/lib/gitlab/github_import/pull_request_spec.rb @@ -0,0 +1,153 @@ +require 'spec_helper' + +describe Gitlab::GithubImport::PullRequest, lib: true do + let(:project) { create(:project) } + let(:source_branch) { OpenStruct.new(ref: 'feature') } + let(:target_branch) { OpenStruct.new(ref: 'master') } + let(:octocat) { OpenStruct.new(id: 123456, login: 'octocat') } + let(:created_at) { DateTime.strptime('2011-01-26T19:01:12Z') } + let(:updated_at) { DateTime.strptime('2011-01-27T19:01:12Z') } + let(:base_data) do + { + state: 'open', + title: 'New feature', + body: 'Please pull these awesome changes', + head: source_branch, + base: target_branch, + assignee: nil, + user: octocat, + created_at: created_at, + updated_at: updated_at, + closed_at: nil, + merged_at: nil + } + end + + subject(:pull_request) { described_class.new(project, raw_data)} + + describe '#attributes' do + context 'when pull request is open' do + let(:raw_data) { OpenStruct.new(base_data.merge(state: 'open')) } + + it 'returns formatted attributes' do + expected = { + title: 'New feature', + description: "*Created by: octocat*\n\nPlease pull these awesome changes", + source_project: project, + source_branch: 'feature', + target_project: project, + target_branch: 'master', + state: 'opened', + author_id: project.creator_id, + assignee_id: nil, + created_at: created_at, + updated_at: updated_at + } + + expect(pull_request.attributes).to eq(expected) + end + end + + context 'when pull request is closed' do + let(:closed_at) { DateTime.strptime('2011-01-28T19:01:12Z') } + let(:raw_data) { OpenStruct.new(base_data.merge(state: 'closed', closed_at: closed_at)) } + + it 'returns formatted attributes' do + expected = { + title: 'New feature', + description: "*Created by: octocat*\n\nPlease pull these awesome changes", + source_project: project, + source_branch: 'feature', + target_project: project, + target_branch: 'master', + state: 'closed', + author_id: project.creator_id, + assignee_id: nil, + created_at: created_at, + updated_at: closed_at + } + + expect(pull_request.attributes).to eq(expected) + end + end + + context 'when pull request is merged' do + let(:merged_at) { DateTime.strptime('2011-01-28T13:01:12Z') } + let(:raw_data) { OpenStruct.new(base_data.merge(state: 'closed', merged_at: merged_at)) } + + it 'returns formatted attributes' do + expected = { + title: 'New feature', + description: "*Created by: octocat*\n\nPlease pull these awesome changes", + source_project: project, + source_branch: 'feature', + target_project: project, + target_branch: 'master', + state: 'merged', + author_id: project.creator_id, + assignee_id: nil, + created_at: created_at, + updated_at: merged_at + } + + expect(pull_request.attributes).to eq(expected) + end + end + + context 'when it is assigned to someone' do + let(:raw_data) { OpenStruct.new(base_data.merge(assignee: octocat)) } + + it 'returns nil as assigned_id when is not a GitLab user' do + expect(pull_request.attributes.fetch(:assignee_id)).to be_nil + end + + it 'returns GitLab user id as assigned_id when is a GitLab user' do + gl_user = create(:omniauth_user, extern_uid: octocat.id, provider: 'github') + + expect(pull_request.attributes.fetch(:assignee_id)).to eq gl_user.id + end + end + + context 'when author is a GitLab user' do + let(:raw_data) { OpenStruct.new(base_data.merge(user: octocat)) } + + it 'returns project#creator_id as author_id when is not a GitLab user' do + expect(pull_request.attributes.fetch(:author_id)).to eq project.creator_id + end + + it 'returns GitLab user id as author_id when is a GitLab user' do + gl_user = create(:omniauth_user, extern_uid: octocat.id, provider: 'github') + + expect(pull_request.attributes.fetch(:author_id)).to eq gl_user.id + end + end + end + + describe '#valid?' do + let(:invalid_branch) { OpenStruct.new(ref: 'invalid-branch') } + + context 'when source and target branches exists' do + let(:raw_data) { OpenStruct.new(base_data.merge(head: source_branch, base: target_branch)) } + + it 'returns true' do + expect(pull_request.valid?).to eq true + end + end + + context 'when source branch doesn not exists' do + let(:raw_data) { OpenStruct.new(base_data.merge(head: invalid_branch, base: target_branch)) } + + it 'returns false' do + expect(pull_request.valid?).to eq false + end + end + + context 'when target branch doesn not exists' do + let(:raw_data) { OpenStruct.new(base_data.merge(head: source_branch, base: invalid_branch)) } + + it 'returns false' do + expect(pull_request.valid?).to eq false + end + end + end +end -- cgit v1.2.1 From 98909dd12cd27b85921962326bcaf651c092dcd5 Mon Sep 17 00:00:00 2001 From: Douglas Barbosa Alexandre Date: Wed, 23 Dec 2015 20:02:59 -0200 Subject: Generate separate comments when importing GitHub Issues into GitLab --- lib/gitlab/github_import/base_formatter.rb | 21 +++ lib/gitlab/github_import/comment.rb | 59 -------- lib/gitlab/github_import/comment_formatter.rb | 45 ++++++ lib/gitlab/github_import/importer.rb | 59 +++----- lib/gitlab/github_import/issue_formatter.rb | 66 +++++++++ lib/gitlab/github_import/pull_request.rb | 103 ------------- lib/gitlab/github_import/pull_request_formatter.rb | 93 ++++++++++++ .../gitlab/github_import/comment_formatter_spec.rb | 80 ++++++++++ spec/lib/gitlab/github_import/comment_spec.rb | 80 ---------- .../gitlab/github_import/issue_formatter_spec.rb | 139 ++++++++++++++++++ .../github_import/pull_request_formatter_spec.rb | 162 +++++++++++++++++++++ spec/lib/gitlab/github_import/pull_request_spec.rb | 153 ------------------- 12 files changed, 625 insertions(+), 435 deletions(-) create mode 100644 lib/gitlab/github_import/base_formatter.rb delete mode 100644 lib/gitlab/github_import/comment.rb create mode 100644 lib/gitlab/github_import/comment_formatter.rb create mode 100644 lib/gitlab/github_import/issue_formatter.rb delete mode 100644 lib/gitlab/github_import/pull_request.rb create mode 100644 lib/gitlab/github_import/pull_request_formatter.rb create mode 100644 spec/lib/gitlab/github_import/comment_formatter_spec.rb delete mode 100644 spec/lib/gitlab/github_import/comment_spec.rb create mode 100644 spec/lib/gitlab/github_import/issue_formatter_spec.rb create mode 100644 spec/lib/gitlab/github_import/pull_request_formatter_spec.rb delete mode 100644 spec/lib/gitlab/github_import/pull_request_spec.rb diff --git a/lib/gitlab/github_import/base_formatter.rb b/lib/gitlab/github_import/base_formatter.rb new file mode 100644 index 00000000000..202263c6742 --- /dev/null +++ b/lib/gitlab/github_import/base_formatter.rb @@ -0,0 +1,21 @@ +module Gitlab + module GithubImport + class BaseFormatter + attr_reader :formatter, :project, :raw_data + + def initialize(project, raw_data) + @project = project + @raw_data = raw_data + @formatter = Gitlab::ImportFormatter.new + end + + private + + def gl_user_id(github_id) + User.joins(:identities). + find_by("identities.extern_uid = ? AND identities.provider = 'github'", github_id.to_s). + try(:id) + end + end + end +end diff --git a/lib/gitlab/github_import/comment.rb b/lib/gitlab/github_import/comment.rb deleted file mode 100644 index 55de78f889d..00000000000 --- a/lib/gitlab/github_import/comment.rb +++ /dev/null @@ -1,59 +0,0 @@ -module Gitlab - module GithubImport - class Comment - attr_reader :project, :raw_data - - def initialize(project, raw_data) - @project = project - @raw_data = raw_data - @formatter = Gitlab::ImportFormatter.new - end - - def attributes - { - project: project, - note: note, - commit_id: raw_data.commit_id, - line_code: line_code, - author_id: author_id, - created_at: raw_data.created_at, - updated_at: raw_data.updated_at - } - end - - private - - def author - raw_data.user.login - end - - def author_id - gl_user_id(raw_data.user.id) || project.creator_id - end - - def body - raw_data.body || "" - end - - def line_code - if on_diff? - Gitlab::Diff::LineCode.generate(raw_data.path, raw_data.position, 0) - end - end - - def on_diff? - raw_data.path && raw_data.position - end - - def note - @formatter.author_line(author) + body - end - - def gl_user_id(github_id) - User.joins(:identities). - find_by("identities.extern_uid = ? AND identities.provider = 'github'", github_id.to_s). - try(:id) - end - end - end -end diff --git a/lib/gitlab/github_import/comment_formatter.rb b/lib/gitlab/github_import/comment_formatter.rb new file mode 100644 index 00000000000..7d58e53991a --- /dev/null +++ b/lib/gitlab/github_import/comment_formatter.rb @@ -0,0 +1,45 @@ +module Gitlab + module GithubImport + class CommentFormatter < BaseFormatter + def attributes + { + project: project, + note: note, + commit_id: raw_data.commit_id, + line_code: line_code, + author_id: author_id, + created_at: raw_data.created_at, + updated_at: raw_data.updated_at + } + end + + private + + def author + raw_data.user.login + end + + def author_id + gl_user_id(raw_data.user.id) || project.creator_id + end + + def body + raw_data.body || "" + end + + def line_code + if on_diff? + Gitlab::Diff::LineCode.generate(raw_data.path, raw_data.position, 0) + end + end + + def on_diff? + raw_data.path && raw_data.position + end + + def note + formatter.author_line(author) + body + end + end + end +end diff --git a/lib/gitlab/github_import/importer.rb b/lib/gitlab/github_import/importer.rb index 7c495655012..38ca7372202 100644 --- a/lib/gitlab/github_import/importer.rb +++ b/lib/gitlab/github_import/importer.rb @@ -21,29 +21,17 @@ module Gitlab private def import_issues - # Issues && Comments client.list_issues(project.import_source, state: :all, sort: :created, - direction: :asc).each do |issue| - if issue.pull_request.nil? + direction: :asc).each do |raw_data| + gh_issue = IssueFormatter.new(project, raw_data) - body = @formatter.author_line(issue.user.login) - body += issue.body || "" + if gh_issue.valid? + issue = Issue.create!(gh_issue.attributes) - if issue.comments > 0 - body += @formatter.comments_header - - client.issue_comments(project.import_source, issue.number).each do |c| - body += @formatter.comment(c.user.login, c.created_at, c.body) - end + if gh_issue.has_comments? + import_comments(gh_issue.number, issue) end - - project.issues.create!( - description: body, - title: issue.title, - state: issue.state == 'closed' ? 'closed' : 'opened', - author_id: gl_author_id(project, issue.user.id) - ) end end end @@ -52,39 +40,30 @@ module Gitlab client.pull_requests(project.import_source, state: :all, sort: :created, direction: :asc).each do |raw_data| - pull_request = PullRequest.new(project, raw_data) + pull_request = PullRequestFormatter.new(project, raw_data) if pull_request.valid? merge_request = MergeRequest.create!(pull_request.attributes) - import_comments_on_pull_request(merge_request, raw_data) - import_comments_on_pull_request_diff(merge_request, raw_data) + import_comments(pull_request.number, merge_request) + import_comments_on_diff(pull_request.number, merge_request) end end end - def import_comments_on_pull_request(merge_request, pull_request) - client.issue_comments(project.import_source, pull_request.number).each do |raw_data| - comment = Comment.new(project, raw_data) - merge_request.notes.create!(comment.attributes) - end - end - - def import_comments_on_pull_request_diff(merge_request, pull_request) - client.pull_request_comments(project.import_source, pull_request.number).each do |raw_data| - comment = Comment.new(project, raw_data) - merge_request.notes.create!(comment.attributes) - end + def import_comments(issue_number, noteable) + comments = client.issue_comments(project.import_source, issue_number) + create_comments(comments, noteable) end - def gl_author_id(project, github_id) - gl_user_id(github_id) || project.creator_id + def import_comments_on_diff(pull_request_number, merge_request) + comments = client.pull_request_comments(project.import_source, pull_request_number) + create_comments(comments, merge_request) end - def gl_user_id(github_id) - if github_id - User.joins(:identities). - find_by("identities.extern_uid = ? AND identities.provider = 'github'", github_id.to_s). - try(:id) + def create_comments(comments, noteable) + comments.each do |raw_data| + comment = CommentFormatter.new(project, raw_data) + noteable.notes.create!(comment.attributes) end end end diff --git a/lib/gitlab/github_import/issue_formatter.rb b/lib/gitlab/github_import/issue_formatter.rb new file mode 100644 index 00000000000..1e3ba44f27c --- /dev/null +++ b/lib/gitlab/github_import/issue_formatter.rb @@ -0,0 +1,66 @@ +module Gitlab + module GithubImport + class IssueFormatter < BaseFormatter + def attributes + { + project: project, + title: raw_data.title, + description: description, + state: state, + author_id: author_id, + assignee_id: assignee_id, + created_at: raw_data.created_at, + updated_at: updated_at + } + end + + def has_comments? + raw_data.comments > 0 + end + + def number + raw_data.number + end + + def valid? + raw_data.pull_request.nil? + end + + private + + def assigned? + raw_data.assignee.present? + end + + def assignee_id + if assigned? + gl_user_id(raw_data.assignee.id) + end + end + + def author + raw_data.user.login + end + + def author_id + gl_user_id(raw_data.user.id) || project.creator_id + end + + def body + raw_data.body || "" + end + + def description + @formatter.author_line(author) + body + end + + def state + raw_data.state == 'closed' ? 'closed' : 'opened' + end + + def updated_at + state == 'closed' ? raw_data.closed_at : raw_data.updated_at + end + end + end +end diff --git a/lib/gitlab/github_import/pull_request.rb b/lib/gitlab/github_import/pull_request.rb deleted file mode 100644 index 61e846472f2..00000000000 --- a/lib/gitlab/github_import/pull_request.rb +++ /dev/null @@ -1,103 +0,0 @@ -module Gitlab - module GithubImport - class PullRequest - attr_reader :project, :raw_data - - def initialize(project, raw_data) - @project = project - @raw_data = raw_data - @formatter = Gitlab::ImportFormatter.new - end - - def attributes - { - title: raw_data.title, - description: description, - source_project: source_project, - source_branch: source_branch.name, - target_project: target_project, - target_branch: target_branch.name, - state: state, - author_id: author_id, - assignee_id: assignee_id, - created_at: raw_data.created_at, - updated_at: updated_at - } - end - - def valid? - source_branch.present? && target_branch.present? - end - - private - - def assigned? - raw_data.assignee.present? - end - - def assignee_id - if assigned? - gl_user_id(raw_data.assignee.id) - end - end - - def author - raw_data.user.login - end - - def author_id - gl_user_id(raw_data.user.id) || project.creator_id - end - - def body - raw_data.body || "" - end - - def description - @formatter.author_line(author) + body - end - - def source_project - project - end - - def source_branch - source_project.repository.find_branch(raw_data.head.ref) - end - - def target_project - project - end - - def target_branch - target_project.repository.find_branch(raw_data.base.ref) - end - - def state - @state ||= case true - when raw_data.state == 'closed' && raw_data.merged_at.present? - 'merged' - when raw_data.state == 'closed' - 'closed' - else - 'opened' - end - end - - def updated_at - case state - when 'merged' then raw_data.merged_at - when 'closed' then raw_data.closed_at - else - raw_data.updated_at - end - end - - def gl_user_id(github_id) - User.joins(:identities). - find_by("identities.extern_uid = ? AND identities.provider = 'github'", github_id.to_s). - try(:id) - end - end - end -end diff --git a/lib/gitlab/github_import/pull_request_formatter.rb b/lib/gitlab/github_import/pull_request_formatter.rb new file mode 100644 index 00000000000..42dc09c2ac5 --- /dev/null +++ b/lib/gitlab/github_import/pull_request_formatter.rb @@ -0,0 +1,93 @@ +module Gitlab + module GithubImport + class PullRequestFormatter < BaseFormatter + def attributes + { + title: raw_data.title, + description: description, + source_project: source_project, + source_branch: source_branch.name, + target_project: target_project, + target_branch: target_branch.name, + state: state, + author_id: author_id, + assignee_id: assignee_id, + created_at: raw_data.created_at, + updated_at: updated_at + } + end + + def number + raw_data.number + end + + def valid? + source_branch.present? && target_branch.present? + end + + private + + def assigned? + raw_data.assignee.present? + end + + def assignee_id + if assigned? + gl_user_id(raw_data.assignee.id) + end + end + + def author + raw_data.user.login + end + + def author_id + gl_user_id(raw_data.user.id) || project.creator_id + end + + def body + raw_data.body || "" + end + + def description + formatter.author_line(author) + body + end + + def source_project + project + end + + def source_branch + source_project.repository.find_branch(raw_data.head.ref) + end + + def target_project + project + end + + def target_branch + target_project.repository.find_branch(raw_data.base.ref) + end + + def state + @state ||= case true + when raw_data.state == 'closed' && raw_data.merged_at.present? + 'merged' + when raw_data.state == 'closed' + 'closed' + else + 'opened' + end + end + + def updated_at + case state + when 'merged' then raw_data.merged_at + when 'closed' then raw_data.closed_at + else + raw_data.updated_at + end + end + end + end +end diff --git a/spec/lib/gitlab/github_import/comment_formatter_spec.rb b/spec/lib/gitlab/github_import/comment_formatter_spec.rb new file mode 100644 index 00000000000..a324a82e69f --- /dev/null +++ b/spec/lib/gitlab/github_import/comment_formatter_spec.rb @@ -0,0 +1,80 @@ +require 'spec_helper' + +describe Gitlab::GithubImport::CommentFormatter, lib: true do + let(:project) { create(:project) } + let(:octocat) { OpenStruct.new(id: 123456, login: 'octocat') } + let(:created_at) { DateTime.strptime('2013-04-10T20:09:31Z') } + let(:updated_at) { DateTime.strptime('2014-03-03T18:58:10Z') } + let(:base_data) do + { + body: "I'm having a problem with this.", + user: octocat, + created_at: created_at, + updated_at: updated_at + } + end + + subject(:comment) { described_class.new(project, raw_data)} + + describe '#attributes' do + context 'when do not reference a portion of the diff' do + let(:raw_data) { OpenStruct.new(base_data) } + + it 'returns formatted attributes' do + expected = { + project: project, + note: "*Created by: octocat*\n\nI'm having a problem with this.", + commit_id: nil, + line_code: nil, + author_id: project.creator_id, + created_at: created_at, + updated_at: updated_at + } + + expect(comment.attributes).to eq(expected) + end + end + + context 'when on a portion of the diff' do + let(:diff_data) do + { + body: 'Great stuff', + commit_id: '6dcb09b5b57875f334f61aebed695e2e4193db5e', + diff_hunk: '@@ -16,33 +16,40 @@ public class Connection : IConnection...', + path: 'file1.txt', + position: 1 + } + end + + let(:raw_data) { OpenStruct.new(base_data.merge(diff_data)) } + + it 'returns formatted attributes' do + expected = { + project: project, + note: "*Created by: octocat*\n\nGreat stuff", + commit_id: '6dcb09b5b57875f334f61aebed695e2e4193db5e', + line_code: 'ce1be0ff4065a6e9415095c95f25f47a633cef2b_0_1', + author_id: project.creator_id, + created_at: created_at, + updated_at: updated_at + } + + expect(comment.attributes).to eq(expected) + end + end + + context 'when author is a GitLab user' do + let(:raw_data) { OpenStruct.new(base_data.merge(user: octocat)) } + + it 'returns project#creator_id as author_id when is not a GitLab user' do + expect(comment.attributes.fetch(:author_id)).to eq project.creator_id + end + + it 'returns GitLab user id as author_id when is a GitLab user' do + gl_user = create(:omniauth_user, extern_uid: octocat.id, provider: 'github') + + expect(comment.attributes.fetch(:author_id)).to eq gl_user.id + end + end + end +end diff --git a/spec/lib/gitlab/github_import/comment_spec.rb b/spec/lib/gitlab/github_import/comment_spec.rb deleted file mode 100644 index ff6b115574b..00000000000 --- a/spec/lib/gitlab/github_import/comment_spec.rb +++ /dev/null @@ -1,80 +0,0 @@ -require 'spec_helper' - -describe Gitlab::GithubImport::Comment, lib: true do - let(:project) { create(:project) } - let(:octocat) { OpenStruct.new(id: 123456, login: 'octocat') } - let(:created_at) { DateTime.strptime('2013-04-10T20:09:31Z') } - let(:updated_at) { DateTime.strptime('2014-03-03T18:58:10Z') } - let(:base_data) do - { - body: "I'm having a problem with this.", - user: octocat, - created_at: created_at, - updated_at: updated_at - } - end - - subject(:comment) { described_class.new(project, raw_data)} - - describe '#attributes' do - context 'when do not reference a portion of the diff' do - let(:raw_data) { OpenStruct.new(base_data) } - - it 'returns formatted attributes' do - expected = { - project: project, - note: "*Created by: octocat*\n\nI'm having a problem with this.", - commit_id: nil, - line_code: nil, - author_id: project.creator_id, - created_at: created_at, - updated_at: updated_at - } - - expect(comment.attributes).to eq(expected) - end - end - - context 'when on a portion of the diff' do - let(:diff_data) do - { - body: 'Great stuff', - commit_id: '6dcb09b5b57875f334f61aebed695e2e4193db5e', - diff_hunk: '@@ -16,33 +16,40 @@ public class Connection : IConnection...', - path: 'file1.txt', - position: 1 - } - end - - let(:raw_data) { OpenStruct.new(base_data.merge(diff_data)) } - - it 'returns formatted attributes' do - expected = { - project: project, - note: "*Created by: octocat*\n\nGreat stuff", - commit_id: '6dcb09b5b57875f334f61aebed695e2e4193db5e', - line_code: 'ce1be0ff4065a6e9415095c95f25f47a633cef2b_0_1', - author_id: project.creator_id, - created_at: created_at, - updated_at: updated_at - } - - expect(comment.attributes).to eq(expected) - end - end - - context 'when author is a GitLab user' do - let(:raw_data) { OpenStruct.new(base_data.merge(user: octocat)) } - - it 'returns project#creator_id as author_id when is not a GitLab user' do - expect(comment.attributes.fetch(:author_id)).to eq project.creator_id - end - - it 'returns GitLab user id as author_id when is a GitLab user' do - gl_user = create(:omniauth_user, extern_uid: octocat.id, provider: 'github') - - expect(comment.attributes.fetch(:author_id)).to eq gl_user.id - end - end - end -end diff --git a/spec/lib/gitlab/github_import/issue_formatter_spec.rb b/spec/lib/gitlab/github_import/issue_formatter_spec.rb new file mode 100644 index 00000000000..fd05428b322 --- /dev/null +++ b/spec/lib/gitlab/github_import/issue_formatter_spec.rb @@ -0,0 +1,139 @@ +require 'spec_helper' + +describe Gitlab::GithubImport::IssueFormatter, lib: true do + let!(:project) { create(:project, namespace: create(:namespace, path: 'octocat')) } + let(:octocat) { OpenStruct.new(id: 123456, login: 'octocat') } + let(:created_at) { DateTime.strptime('2011-01-26T19:01:12Z') } + let(:updated_at) { DateTime.strptime('2011-01-27T19:01:12Z') } + + let(:base_data) do + { + number: 1347, + state: 'open', + title: 'Found a bug', + body: "I'm having a problem with this.", + assignee: nil, + user: octocat, + comments: 0, + pull_request: nil, + created_at: created_at, + updated_at: updated_at, + closed_at: nil + } + end + + subject(:issue) { described_class.new(project, raw_data)} + + describe '#attributes' do + context 'when issue is open' do + let(:raw_data) { OpenStruct.new(base_data.merge(state: 'open')) } + + it 'returns formatted attributes' do + expected = { + project: project, + title: 'Found a bug', + description: "*Created by: octocat*\n\nI'm having a problem with this.", + state: 'opened', + author_id: project.creator_id, + assignee_id: nil, + created_at: created_at, + updated_at: updated_at + } + + expect(issue.attributes).to eq(expected) + end + end + + context 'when issue is closed' do + let(:closed_at) { DateTime.strptime('2011-01-28T19:01:12Z') } + let(:raw_data) { OpenStruct.new(base_data.merge(state: 'closed', closed_at: closed_at)) } + + it 'returns formatted attributes' do + expected = { + project: project, + title: 'Found a bug', + description: "*Created by: octocat*\n\nI'm having a problem with this.", + state: 'closed', + author_id: project.creator_id, + assignee_id: nil, + created_at: created_at, + updated_at: closed_at + } + + expect(issue.attributes).to eq(expected) + end + end + + context 'when it is assigned to someone' do + let(:raw_data) { OpenStruct.new(base_data.merge(assignee: octocat)) } + + it 'returns nil as assignee_id when is not a GitLab user' do + expect(issue.attributes.fetch(:assignee_id)).to be_nil + end + + it 'returns GitLab user id as assignee_id when is a GitLab user' do + gl_user = create(:omniauth_user, extern_uid: octocat.id, provider: 'github') + + expect(issue.attributes.fetch(:assignee_id)).to eq gl_user.id + end + end + + context 'when author is a GitLab user' do + let(:raw_data) { OpenStruct.new(base_data.merge(user: octocat)) } + + it 'returns project#creator_id as author_id when is not a GitLab user' do + expect(issue.attributes.fetch(:author_id)).to eq project.creator_id + end + + it 'returns GitLab user id as author_id when is a GitLab user' do + gl_user = create(:omniauth_user, extern_uid: octocat.id, provider: 'github') + + expect(issue.attributes.fetch(:author_id)).to eq gl_user.id + end + end + end + + describe '#has_comments?' do + context 'when number of comments is greater than zero' do + let(:raw_data) { OpenStruct.new(base_data.merge(comments: 1)) } + + it 'returns true' do + expect(issue.has_comments?).to eq true + end + end + + context 'when number of comments is equal to zero' do + let(:raw_data) { OpenStruct.new(base_data.merge(comments: 0)) } + + it 'returns false' do + expect(issue.has_comments?).to eq false + end + end + end + + describe '#number' do + let(:raw_data) { OpenStruct.new(base_data.merge(number: 1347)) } + + it 'returns pull request number' do + expect(issue.number).to eq 1347 + end + end + + describe '#valid?' do + context 'when mention a pull request' do + let(:raw_data) { OpenStruct.new(base_data.merge(pull_request: OpenStruct.new)) } + + it 'returns false' do + expect(issue.valid?).to eq false + end + end + + context 'when does not mention a pull request' do + let(:raw_data) { OpenStruct.new(base_data.merge(pull_request: nil)) } + + it 'returns true' do + expect(issue.valid?).to eq true + end + end + end +end diff --git a/spec/lib/gitlab/github_import/pull_request_formatter_spec.rb b/spec/lib/gitlab/github_import/pull_request_formatter_spec.rb new file mode 100644 index 00000000000..b4465ef3743 --- /dev/null +++ b/spec/lib/gitlab/github_import/pull_request_formatter_spec.rb @@ -0,0 +1,162 @@ +require 'spec_helper' + +describe Gitlab::GithubImport::PullRequestFormatter, lib: true do + let(:project) { create(:project) } + let(:source_branch) { OpenStruct.new(ref: 'feature') } + let(:target_branch) { OpenStruct.new(ref: 'master') } + let(:octocat) { OpenStruct.new(id: 123456, login: 'octocat') } + let(:created_at) { DateTime.strptime('2011-01-26T19:01:12Z') } + let(:updated_at) { DateTime.strptime('2011-01-27T19:01:12Z') } + let(:base_data) do + { + number: 1347, + state: 'open', + title: 'New feature', + body: 'Please pull these awesome changes', + head: source_branch, + base: target_branch, + assignee: nil, + user: octocat, + created_at: created_at, + updated_at: updated_at, + closed_at: nil, + merged_at: nil + } + end + + subject(:pull_request) { described_class.new(project, raw_data)} + + describe '#attributes' do + context 'when pull request is open' do + let(:raw_data) { OpenStruct.new(base_data.merge(state: 'open')) } + + it 'returns formatted attributes' do + expected = { + title: 'New feature', + description: "*Created by: octocat*\n\nPlease pull these awesome changes", + source_project: project, + source_branch: 'feature', + target_project: project, + target_branch: 'master', + state: 'opened', + author_id: project.creator_id, + assignee_id: nil, + created_at: created_at, + updated_at: updated_at + } + + expect(pull_request.attributes).to eq(expected) + end + end + + context 'when pull request is closed' do + let(:closed_at) { DateTime.strptime('2011-01-28T19:01:12Z') } + let(:raw_data) { OpenStruct.new(base_data.merge(state: 'closed', closed_at: closed_at)) } + + it 'returns formatted attributes' do + expected = { + title: 'New feature', + description: "*Created by: octocat*\n\nPlease pull these awesome changes", + source_project: project, + source_branch: 'feature', + target_project: project, + target_branch: 'master', + state: 'closed', + author_id: project.creator_id, + assignee_id: nil, + created_at: created_at, + updated_at: closed_at + } + + expect(pull_request.attributes).to eq(expected) + end + end + + context 'when pull request is merged' do + let(:merged_at) { DateTime.strptime('2011-01-28T13:01:12Z') } + let(:raw_data) { OpenStruct.new(base_data.merge(state: 'closed', merged_at: merged_at)) } + + it 'returns formatted attributes' do + expected = { + title: 'New feature', + description: "*Created by: octocat*\n\nPlease pull these awesome changes", + source_project: project, + source_branch: 'feature', + target_project: project, + target_branch: 'master', + state: 'merged', + author_id: project.creator_id, + assignee_id: nil, + created_at: created_at, + updated_at: merged_at + } + + expect(pull_request.attributes).to eq(expected) + end + end + + context 'when it is assigned to someone' do + let(:raw_data) { OpenStruct.new(base_data.merge(assignee: octocat)) } + + it 'returns nil as assignee_id when is not a GitLab user' do + expect(pull_request.attributes.fetch(:assignee_id)).to be_nil + end + + it 'returns GitLab user id as assignee_id when is a GitLab user' do + gl_user = create(:omniauth_user, extern_uid: octocat.id, provider: 'github') + + expect(pull_request.attributes.fetch(:assignee_id)).to eq gl_user.id + end + end + + context 'when author is a GitLab user' do + let(:raw_data) { OpenStruct.new(base_data.merge(user: octocat)) } + + it 'returns project#creator_id as author_id when is not a GitLab user' do + expect(pull_request.attributes.fetch(:author_id)).to eq project.creator_id + end + + it 'returns GitLab user id as author_id when is a GitLab user' do + gl_user = create(:omniauth_user, extern_uid: octocat.id, provider: 'github') + + expect(pull_request.attributes.fetch(:author_id)).to eq gl_user.id + end + end + end + + describe '#number' do + let(:raw_data) { OpenStruct.new(base_data.merge(number: 1347)) } + + it 'returns pull request number' do + expect(pull_request.number).to eq 1347 + end + end + + describe '#valid?' do + let(:invalid_branch) { OpenStruct.new(ref: 'invalid-branch') } + + context 'when source and target branches exists' do + let(:raw_data) { OpenStruct.new(base_data.merge(head: source_branch, base: target_branch)) } + + it 'returns true' do + expect(pull_request.valid?).to eq true + end + end + + context 'when source branch doesn not exists' do + let(:raw_data) { OpenStruct.new(base_data.merge(head: invalid_branch, base: target_branch)) } + + it 'returns false' do + expect(pull_request.valid?).to eq false + end + end + + context 'when target branch doesn not exists' do + let(:raw_data) { OpenStruct.new(base_data.merge(head: source_branch, base: invalid_branch)) } + + it 'returns false' do + expect(pull_request.valid?).to eq false + end + end + end +end diff --git a/spec/lib/gitlab/github_import/pull_request_spec.rb b/spec/lib/gitlab/github_import/pull_request_spec.rb deleted file mode 100644 index 6ac32a78955..00000000000 --- a/spec/lib/gitlab/github_import/pull_request_spec.rb +++ /dev/null @@ -1,153 +0,0 @@ -require 'spec_helper' - -describe Gitlab::GithubImport::PullRequest, lib: true do - let(:project) { create(:project) } - let(:source_branch) { OpenStruct.new(ref: 'feature') } - let(:target_branch) { OpenStruct.new(ref: 'master') } - let(:octocat) { OpenStruct.new(id: 123456, login: 'octocat') } - let(:created_at) { DateTime.strptime('2011-01-26T19:01:12Z') } - let(:updated_at) { DateTime.strptime('2011-01-27T19:01:12Z') } - let(:base_data) do - { - state: 'open', - title: 'New feature', - body: 'Please pull these awesome changes', - head: source_branch, - base: target_branch, - assignee: nil, - user: octocat, - created_at: created_at, - updated_at: updated_at, - closed_at: nil, - merged_at: nil - } - end - - subject(:pull_request) { described_class.new(project, raw_data)} - - describe '#attributes' do - context 'when pull request is open' do - let(:raw_data) { OpenStruct.new(base_data.merge(state: 'open')) } - - it 'returns formatted attributes' do - expected = { - title: 'New feature', - description: "*Created by: octocat*\n\nPlease pull these awesome changes", - source_project: project, - source_branch: 'feature', - target_project: project, - target_branch: 'master', - state: 'opened', - author_id: project.creator_id, - assignee_id: nil, - created_at: created_at, - updated_at: updated_at - } - - expect(pull_request.attributes).to eq(expected) - end - end - - context 'when pull request is closed' do - let(:closed_at) { DateTime.strptime('2011-01-28T19:01:12Z') } - let(:raw_data) { OpenStruct.new(base_data.merge(state: 'closed', closed_at: closed_at)) } - - it 'returns formatted attributes' do - expected = { - title: 'New feature', - description: "*Created by: octocat*\n\nPlease pull these awesome changes", - source_project: project, - source_branch: 'feature', - target_project: project, - target_branch: 'master', - state: 'closed', - author_id: project.creator_id, - assignee_id: nil, - created_at: created_at, - updated_at: closed_at - } - - expect(pull_request.attributes).to eq(expected) - end - end - - context 'when pull request is merged' do - let(:merged_at) { DateTime.strptime('2011-01-28T13:01:12Z') } - let(:raw_data) { OpenStruct.new(base_data.merge(state: 'closed', merged_at: merged_at)) } - - it 'returns formatted attributes' do - expected = { - title: 'New feature', - description: "*Created by: octocat*\n\nPlease pull these awesome changes", - source_project: project, - source_branch: 'feature', - target_project: project, - target_branch: 'master', - state: 'merged', - author_id: project.creator_id, - assignee_id: nil, - created_at: created_at, - updated_at: merged_at - } - - expect(pull_request.attributes).to eq(expected) - end - end - - context 'when it is assigned to someone' do - let(:raw_data) { OpenStruct.new(base_data.merge(assignee: octocat)) } - - it 'returns nil as assigned_id when is not a GitLab user' do - expect(pull_request.attributes.fetch(:assignee_id)).to be_nil - end - - it 'returns GitLab user id as assigned_id when is a GitLab user' do - gl_user = create(:omniauth_user, extern_uid: octocat.id, provider: 'github') - - expect(pull_request.attributes.fetch(:assignee_id)).to eq gl_user.id - end - end - - context 'when author is a GitLab user' do - let(:raw_data) { OpenStruct.new(base_data.merge(user: octocat)) } - - it 'returns project#creator_id as author_id when is not a GitLab user' do - expect(pull_request.attributes.fetch(:author_id)).to eq project.creator_id - end - - it 'returns GitLab user id as author_id when is a GitLab user' do - gl_user = create(:omniauth_user, extern_uid: octocat.id, provider: 'github') - - expect(pull_request.attributes.fetch(:author_id)).to eq gl_user.id - end - end - end - - describe '#valid?' do - let(:invalid_branch) { OpenStruct.new(ref: 'invalid-branch') } - - context 'when source and target branches exists' do - let(:raw_data) { OpenStruct.new(base_data.merge(head: source_branch, base: target_branch)) } - - it 'returns true' do - expect(pull_request.valid?).to eq true - end - end - - context 'when source branch doesn not exists' do - let(:raw_data) { OpenStruct.new(base_data.merge(head: invalid_branch, base: target_branch)) } - - it 'returns false' do - expect(pull_request.valid?).to eq false - end - end - - context 'when target branch doesn not exists' do - let(:raw_data) { OpenStruct.new(base_data.merge(head: source_branch, base: invalid_branch)) } - - it 'returns false' do - expect(pull_request.valid?).to eq false - end - end - end -end -- cgit v1.2.1 From 2dc74b48a32c64b18ca684e3adfb51ab9d87cf2b Mon Sep 17 00:00:00 2001 From: Douglas Barbosa Alexandre Date: Wed, 23 Dec 2015 20:04:44 -0200 Subject: Update CHANGELOG --- CHANGELOG | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG b/CHANGELOG index b0972ceab68..6c04f3967b0 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -33,6 +33,7 @@ v 8.3.1 - Fix LDAP identity and user retrieval when special characters are used - Move Sidekiq-cron configuration to gitlab.yml - Enable forcing Two-Factor authentication sitewide, with optional grace period + - Import GitHub Pull Requests into GitLab v 8.3.0 - Bump rack-attack to 4.3.1 for security fix (Stan Hu) -- cgit v1.2.1 From 837a9065f0ff192d2efd55edcc2658a92c127b21 Mon Sep 17 00:00:00 2001 From: Douglas Barbosa Alexandre Date: Tue, 5 Jan 2016 15:15:36 -0200 Subject: Ensure that we're only importing local pull requests --- lib/gitlab/github_import/importer.rb | 2 +- lib/gitlab/github_import/pull_request_formatter.rb | 8 ++++++++ .../github_import/pull_request_formatter_spec.rb | 22 ++++++++++++++++++++++ 3 files changed, 31 insertions(+), 1 deletion(-) diff --git a/lib/gitlab/github_import/importer.rb b/lib/gitlab/github_import/importer.rb index 38ca7372202..2b0afbc7b39 100644 --- a/lib/gitlab/github_import/importer.rb +++ b/lib/gitlab/github_import/importer.rb @@ -42,7 +42,7 @@ module Gitlab direction: :asc).each do |raw_data| pull_request = PullRequestFormatter.new(project, raw_data) - if pull_request.valid? + if !pull_request.cross_project? && pull_request.valid? merge_request = MergeRequest.create!(pull_request.attributes) import_comments(pull_request.number, merge_request) import_comments_on_diff(pull_request.number, merge_request) diff --git a/lib/gitlab/github_import/pull_request_formatter.rb b/lib/gitlab/github_import/pull_request_formatter.rb index 42dc09c2ac5..b7c47958cc7 100644 --- a/lib/gitlab/github_import/pull_request_formatter.rb +++ b/lib/gitlab/github_import/pull_request_formatter.rb @@ -17,6 +17,10 @@ module Gitlab } end + def cross_project? + source_repo.fork == true + end + def number raw_data.number end @@ -57,6 +61,10 @@ module Gitlab project end + def source_repo + raw_data.head.repo + end + def source_branch source_project.repository.find_branch(raw_data.head.ref) end diff --git a/spec/lib/gitlab/github_import/pull_request_formatter_spec.rb b/spec/lib/gitlab/github_import/pull_request_formatter_spec.rb index b4465ef3743..9aefec77f6d 100644 --- a/spec/lib/gitlab/github_import/pull_request_formatter_spec.rb +++ b/spec/lib/gitlab/github_import/pull_request_formatter_spec.rb @@ -124,6 +124,28 @@ describe Gitlab::GithubImport::PullRequestFormatter, lib: true do end end + describe '#cross_project?' do + context 'when source repo is not a fork' do + let(:local_repo) { OpenStruct.new(fork: false) } + let(:source_branch) { OpenStruct.new(ref: 'feature', repo: local_repo) } + let(:raw_data) { OpenStruct.new(base_data.merge(head: source_branch)) } + + it 'returns false' do + expect(pull_request.cross_project?).to eq false + end + end + + context 'when source repo is a fork' do + let(:forked_repo) { OpenStruct.new(fork: true) } + let(:source_branch) { OpenStruct.new(ref: 'feature', repo: forked_repo) } + let(:raw_data) { OpenStruct.new(base_data.merge(head: source_branch)) } + + it 'returns true' do + expect(pull_request.cross_project?).to eq true + end + end + end + describe '#number' do let(:raw_data) { OpenStruct.new(base_data.merge(number: 1347)) } -- cgit v1.2.1 From e194b962d3cd638e72d3ea7144e20fe8a9093574 Mon Sep 17 00:00:00 2001 From: Douglas Barbosa Alexandre Date: Tue, 5 Jan 2016 15:23:48 -0200 Subject: Update doc for importing existing GitHub projects to GitLab --- doc/workflow/importing/import_projects_from_github.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/doc/workflow/importing/import_projects_from_github.md b/doc/workflow/importing/import_projects_from_github.md index 2d77c6d1172..2027a055c37 100644 --- a/doc/workflow/importing/import_projects_from_github.md +++ b/doc/workflow/importing/import_projects_from_github.md @@ -14,7 +14,7 @@ If you want to import from a GitHub Enterprise instance, you need to use GitLab ![Importer page](github_importer/importer.png) -* To import a project, you can simple click "Add". The importer will import your repository and issues. Once the importer is done, a new GitLab project will be created with your imported data. +* To import a project, you can simple click "Add". The importer will import your repository, issues, and pull requests. Once the importer is done, a new GitLab project will be created with your imported data. ### Note -When you import your projects from GitHub, it is not possible to keep your labels and milestones. We are working on improving this in the near future. +When you import your projects from GitHub, it is not possible to keep your labels, milestones, and cross-repository pull requests. We are working on improving this in the near future. -- cgit v1.2.1 From 8393e3e04b8b336ec80cb0da49d273f709043120 Mon Sep 17 00:00:00 2001 From: Michi302 Date: Tue, 5 Jan 2016 19:05:41 +0100 Subject: Add missing changelog entry --- CHANGELOG | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG b/CHANGELOG index 57f0b9f30d5..698f4e5f1cf 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -12,6 +12,7 @@ v 8.4.0 (unreleased) - Add CAS support (tduehr) - Add link to merge request on build detail page. - Revert back upvote and downvote button to the issue and MR pages + - Change single user API endpoint to return more detailed data (Michael Potthoff) v 8.3.2 (unreleased) - Disable --follow in `git log` to avoid loading duplicate commit data in infinite scroll (Stan Hu) -- cgit v1.2.1 From 045e8cc38c608b46924ce1ef4de3e8c2adefb1ba Mon Sep 17 00:00:00 2001 From: Robert Speicher Date: Tue, 29 Dec 2015 20:23:07 -0500 Subject: Update version check images to use SVG --- CHANGELOG | 1 + lib/version_check.rb | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/CHANGELOG b/CHANGELOG index b0972ceab68..ed45042eb13 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -18,6 +18,7 @@ v 8.4.0 (unreleased) - Fix version check image in Safari - Show 'All' tab by default in the builds page - Fix API project lookups when querying with a namespace with dots (Stan Hu) + - Update version check images to use SVG v 8.3.3 (unreleased) - Fix project transfer e-mail sending incorrect paths in e-mail notification (Stan Hu) diff --git a/lib/version_check.rb b/lib/version_check.rb index ea23344948c..91ad07feee5 100644 --- a/lib/version_check.rb +++ b/lib/version_check.rb @@ -13,6 +13,6 @@ class VersionCheck end def host - 'https://version.gitlab.com/check.png' + 'https://version.gitlab.com/check.svg' end end -- cgit v1.2.1 From db2d067eecc5d40e5f5b4e50a9d8ab505b207e54 Mon Sep 17 00:00:00 2001 From: Grzegorz Bizon Date: Tue, 5 Jan 2016 20:38:35 +0100 Subject: Fix project destroy callback See gitlab-org/gitlab-ee!107. --- app/models/ci/build.rb | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/app/models/ci/build.rb b/app/models/ci/build.rb index 3e67b2771c1..d7fccb2197d 100644 --- a/app/models/ci/build.rb +++ b/app/models/ci/build.rb @@ -54,6 +54,8 @@ module Ci # To prevent db load megabytes of data from trace default_scope -> { select(Ci::Build.columns_without_lazy) } + before_destroy { project } + class << self def columns_without_lazy (column_names - LAZY_ATTRIBUTES).map do |column_name| @@ -145,10 +147,6 @@ module Ci end end - def project - commit.project - end - def project_id commit.project.id end -- cgit v1.2.1 From a298f694327b1241fc0d06618228e3750c20c5a1 Mon Sep 17 00:00:00 2001 From: Robert Speicher Date: Tue, 5 Jan 2016 14:50:52 -0500 Subject: Use `User#avatar_url` instead of `avatar_icon` helper --- app/helpers/page_layout_helper.rb | 10 +++---- spec/helpers/page_layout_helper_spec.rb | 51 +++++++++++---------------------- 2 files changed, 20 insertions(+), 41 deletions(-) diff --git a/app/helpers/page_layout_helper.rb b/app/helpers/page_layout_helper.rb index b84644d6996..f2a4afebbd1 100644 --- a/app/helpers/page_layout_helper.rb +++ b/app/helpers/page_layout_helper.rb @@ -49,12 +49,10 @@ module PageLayoutHelper def page_image default = image_url('gitlab_logo.png') - if @project - @project.avatar_url || default - elsif @user - avatar_icon(@user) - elsif @group - @group.avatar_url || default + subject = @project || @user || @group + + if subject.present? + subject.avatar_url || default else default end diff --git a/spec/helpers/page_layout_helper_spec.rb b/spec/helpers/page_layout_helper_spec.rb index 300dccf50ec..83aeafcf31a 100644 --- a/spec/helpers/page_layout_helper_spec.rb +++ b/spec/helpers/page_layout_helper_spec.rb @@ -70,46 +70,27 @@ describe PageLayoutHelper do expect(helper.page_image).to end_with 'assets/gitlab_logo.png' end - context 'with @project' do - it 'uses Project avatar if available' do - project = double(avatar_url: 'http://example.com/uploads/avatar.png') - assign(:project, project) + %w(project user group).each do |type| + context "with @#{type} assigned" do + it "uses #{type.titlecase} avatar if available" do + object = double(avatar_url: 'http://example.com/uploads/avatar.png') + assign(type, object) - expect(helper.page_image).to eq project.avatar_url - end - - it 'falls back to the default' do - project = double(avatar_url: nil) - assign(:project, project) - - expect(helper.page_image).to end_with 'assets/gitlab_logo.png' - end - end - - context 'with @user' do - it 'delegates to avatar_icon helper' do - user = double('User') - assign(:user, user) + expect(helper.page_image).to eq object.avatar_url + end - expect(helper).to receive(:avatar_icon).with(user) + it 'falls back to the default when avatar_url is nil' do + object = double(avatar_url: nil) + assign(type, object) - helper.page_image + expect(helper.page_image).to end_with 'assets/gitlab_logo.png' + end end - end - - context 'with @group' do - it 'uses Group avatar if available' do - group = double(avatar_url: 'http://example.com/uploads/avatar.png') - assign(:group, group) - - expect(helper.page_image).to eq group.avatar_url - end - - it 'falls back to the default' do - group = double(avatar_url: nil) - assign(:group, group) - expect(helper.page_image).to end_with 'assets/gitlab_logo.png' + context "with no assignments" do + it 'falls back to the default' do + expect(helper.page_image).to end_with 'assets/gitlab_logo.png' + end end end end -- cgit v1.2.1 From 43053c2e6f03ad60f85728f36c46588979f68024 Mon Sep 17 00:00:00 2001 From: Robert Speicher Date: Tue, 5 Jan 2016 14:54:59 -0500 Subject: Make `page_description` less magical :sparkles: --- app/helpers/page_layout_helper.rb | 12 +----------- app/views/layouts/group.html.haml | 7 ++++--- app/views/layouts/project.html.haml | 7 ++++--- spec/helpers/page_layout_helper_spec.rb | 27 ++------------------------- 4 files changed, 11 insertions(+), 42 deletions(-) diff --git a/app/helpers/page_layout_helper.rb b/app/helpers/page_layout_helper.rb index f2a4afebbd1..5c0dd36252e 100644 --- a/app/helpers/page_layout_helper.rb +++ b/app/helpers/page_layout_helper.rb @@ -27,7 +27,7 @@ module PageLayoutHelper # # Returns an HTML-safe String. def page_description(description = nil) - @page_description ||= page_description_default + @page_description ||= brand_title if description.present? @page_description = description.squish @@ -36,16 +36,6 @@ module PageLayoutHelper end end - # Default value for page_description when one hasn't been defined manually by - # a view - def page_description_default - if @project - @project.description || brand_title - else - brand_title - end - end - def page_image default = image_url('gitlab_logo.png') diff --git a/app/views/layouts/group.html.haml b/app/views/layouts/group.html.haml index 31888c5580e..1ce8d0ef7b5 100644 --- a/app/views/layouts/group.html.haml +++ b/app/views/layouts/group.html.haml @@ -1,5 +1,6 @@ -- page_title @group.name -- header_title group_title(@group) unless header_title -- sidebar "group" unless sidebar +- page_title @group.name +- page_description @group.description +- header_title group_title(@group) unless header_title +- sidebar "group" unless sidebar = render template: "layouts/application" diff --git a/app/views/layouts/project.html.haml b/app/views/layouts/project.html.haml index abf73bcc709..f81283a5ddb 100644 --- a/app/views/layouts/project.html.haml +++ b/app/views/layouts/project.html.haml @@ -1,6 +1,7 @@ -- page_title @project.name_with_namespace -- header_title project_title(@project) unless header_title -- sidebar "project" unless sidebar +- page_title @project.name_with_namespace +- page_description @project.description +- header_title project_title(@project) unless header_title +- sidebar "project" unless sidebar - content_for :scripts_body_top do - project = @target_project || @project diff --git a/spec/helpers/page_layout_helper_spec.rb b/spec/helpers/page_layout_helper_spec.rb index 83aeafcf31a..a097786ba6d 100644 --- a/spec/helpers/page_layout_helper_spec.rb +++ b/spec/helpers/page_layout_helper_spec.rb @@ -2,8 +2,8 @@ require 'rails_helper' describe PageLayoutHelper do describe 'page_description' do - it 'defaults to value returned by page_description_default helper' do - allow(helper).to receive(:page_description_default).and_return('Foo') + it 'defaults to value returned by brand_title helper' do + allow(helper).to receive(:brand_title).and_return('Foo') expect(helper.page_description).to eq 'Foo' end @@ -42,29 +42,6 @@ describe PageLayoutHelper do end end - describe 'page_description_default' do - it 'uses Project description when available' do - project = double(description: 'Project Description') - assign(:project, project) - - expect(helper.page_description_default).to eq 'Project Description' - end - - it 'uses brand_title when Project description is nil' do - project = double(description: nil) - assign(:project, project) - - expect(helper).to receive(:brand_title).and_return('Brand Title') - expect(helper.page_description_default).to eq 'Brand Title' - end - - it 'falls back to brand_title' do - allow(helper).to receive(:brand_title).and_return('Brand Title') - - expect(helper.page_description_default).to eq 'Brand Title' - end - end - describe 'page_image' do it 'defaults to the GitLab logo' do expect(helper.page_image).to end_with 'assets/gitlab_logo.png' -- cgit v1.2.1 From a0793d69c538cbb6a2b9ff4389192862f6d16962 Mon Sep 17 00:00:00 2001 From: Robert Speicher Date: Tue, 5 Jan 2016 15:02:42 -0500 Subject: Remove now-redundant `page_description` call from Projects#show --- app/views/projects/show.html.haml | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/app/views/projects/show.html.haml b/app/views/projects/show.html.haml index a8f924bbb7c..8436be433b1 100644 --- a/app/views/projects/show.html.haml +++ b/app/views/projects/show.html.haml @@ -1,5 +1,3 @@ -- page_description @project.description - = content_for :meta_tags do - if current_user = auto_discovery_link_tag(:atom, namespace_project_path(@project.namespace, @project, format: :atom, private_token: current_user.private_token), title: "#{@project.name} activity") @@ -70,4 +68,4 @@ = render 'projects/last_commit', commit: @repository.commit, project: @project %div{class: "project-show-#{default_project_view}"} - = render default_project_view \ No newline at end of file + = render default_project_view -- cgit v1.2.1 From 6d3b5ea2a9611dc7d87bd48043f34f9e0930e052 Mon Sep 17 00:00:00 2001 From: Robert Speicher Date: Tue, 5 Jan 2016 16:47:09 -0500 Subject: Remove now-redundant `page_description` call from Groups#show --- app/views/groups/show.html.haml | 2 -- 1 file changed, 2 deletions(-) diff --git a/app/views/groups/show.html.haml b/app/views/groups/show.html.haml index e7f619d2d6b..a607d860d7d 100644 --- a/app/views/groups/show.html.haml +++ b/app/views/groups/show.html.haml @@ -1,5 +1,3 @@ -- page_description @group.description - - unless can?(current_user, :read_group, @group) - @disable_search_panel = true -- cgit v1.2.1 From 1e6fc0c6a440ad707d990282ab7a93c178e35cfa Mon Sep 17 00:00:00 2001 From: Robert Speicher Date: Wed, 30 Dec 2015 16:44:22 -0500 Subject: Define a limited set of filters for SingleLinePipeline Removes the following filters from its parent GfmPipeline: - SyntaxHighlightFilter - UploadLinkFilter - TableOfContentsFilter - LabelReferenceFilter - TaskListFilter Closes #1697 --- lib/banzai/pipeline/single_line_pipeline.rb | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/lib/banzai/pipeline/single_line_pipeline.rb b/lib/banzai/pipeline/single_line_pipeline.rb index 6725c9039a9..a3c9d4f43aa 100644 --- a/lib/banzai/pipeline/single_line_pipeline.rb +++ b/lib/banzai/pipeline/single_line_pipeline.rb @@ -3,7 +3,23 @@ require 'banzai' module Banzai module Pipeline class SingleLinePipeline < GfmPipeline + def self.filters + @filters ||= [ + Filter::SanitizationFilter, + Filter::EmojiFilter, + Filter::AutolinkFilter, + Filter::ExternalLinkFilter, + + Filter::UserReferenceFilter, + Filter::IssueReferenceFilter, + Filter::ExternalIssueReferenceFilter, + Filter::MergeRequestReferenceFilter, + Filter::SnippetReferenceFilter, + Filter::CommitRangeReferenceFilter, + Filter::CommitReferenceFilter, + ] + end end end end -- cgit v1.2.1 From 52e41dcac4d0f76de77029aae07fce60b61d86ef Mon Sep 17 00:00:00 2001 From: Robert Speicher Date: Tue, 5 Jan 2016 18:02:12 -0500 Subject: Fix the abuse report detail URL in the HTML email template --- app/views/abuse_report_mailer/notify.html.haml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/views/abuse_report_mailer/notify.html.haml b/app/views/abuse_report_mailer/notify.html.haml index 619533e09a7..2741eb44357 100644 --- a/app/views/abuse_report_mailer/notify.html.haml +++ b/app/views/abuse_report_mailer/notify.html.haml @@ -8,4 +8,4 @@ = @abuse_report.message %p - = link_to "View details", abuse_reports_url + = link_to "View details", admin_abuse_reports_url -- cgit v1.2.1 From 987989b632d4f610f0ec17b65f1c7d24530c99ff Mon Sep 17 00:00:00 2001 From: Kelvin Date: Wed, 6 Jan 2016 14:41:26 +0300 Subject: Remove block button on abuse reports if user is already blocked --- app/views/admin/abuse_reports/_abuse_report.html.haml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/views/admin/abuse_reports/_abuse_report.html.haml b/app/views/admin/abuse_reports/_abuse_report.html.haml index cf50a376e11..8aa34c0ffac 100644 --- a/app/views/admin/abuse_reports/_abuse_report.html.haml +++ b/app/views/admin/abuse_reports/_abuse_report.html.haml @@ -23,6 +23,6 @@ data: { confirm: "USER #{user.name} WILL BE REMOVED! Are you sure?" }, remote: true, method: :delete, class: "btn btn-xs btn-remove js-remove-tr" %td - - if user + - if user && !user.blocked? = link_to 'Block user', block_admin_user_path(user), data: {confirm: 'USER WILL BE BLOCKED! Are you sure?'}, method: :put, class: "btn btn-xs" = link_to 'Remove report', [:admin, abuse_report], remote: true, method: :delete, class: "btn btn-xs btn-close js-remove-tr" -- cgit v1.2.1 From e16d9edf9995735da7a900c35bc7be73cc481473 Mon Sep 17 00:00:00 2001 From: Kelvin Date: Wed, 6 Jan 2016 14:48:52 +0300 Subject: Show that user is already blocked on Abuse Reports --- app/views/admin/abuse_reports/_abuse_report.html.haml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/app/views/admin/abuse_reports/_abuse_report.html.haml b/app/views/admin/abuse_reports/_abuse_report.html.haml index 8aa34c0ffac..853a780c576 100644 --- a/app/views/admin/abuse_reports/_abuse_report.html.haml +++ b/app/views/admin/abuse_reports/_abuse_report.html.haml @@ -25,4 +25,7 @@ %td - if user && !user.blocked? = link_to 'Block user', block_admin_user_path(user), data: {confirm: 'USER WILL BE BLOCKED! Are you sure?'}, method: :put, class: "btn btn-xs" + - else + .btn.btn-xs + Already Blocked = link_to 'Remove report', [:admin, abuse_report], remote: true, method: :delete, class: "btn btn-xs btn-close js-remove-tr" -- cgit v1.2.1 From 384445eca6249363c0da6d8b96e7ee030dc6fab3 Mon Sep 17 00:00:00 2001 From: Douwe Maan Date: Wed, 6 Jan 2016 13:02:51 +0100 Subject: Don't override issue page description in project layout. --- app/helpers/page_layout_helper.rb | 11 +++-------- app/views/layouts/_head.html.haml | 2 ++ app/views/layouts/group.html.haml | 2 +- app/views/layouts/project.html.haml | 2 +- spec/helpers/page_layout_helper_spec.rb | 6 ++---- 5 files changed, 9 insertions(+), 14 deletions(-) diff --git a/app/helpers/page_layout_helper.rb b/app/helpers/page_layout_helper.rb index 5c0dd36252e..82f805fa444 100644 --- a/app/helpers/page_layout_helper.rb +++ b/app/helpers/page_layout_helper.rb @@ -27,11 +27,9 @@ module PageLayoutHelper # # Returns an HTML-safe String. def page_description(description = nil) - @page_description ||= brand_title - if description.present? @page_description = description.squish - else + elsif @page_description.present? sanitize(@page_description, tags: []).truncate_words(30) end end @@ -41,11 +39,8 @@ module PageLayoutHelper subject = @project || @user || @group - if subject.present? - subject.avatar_url || default - else - default - end + image = subject.avatar_url if subject.present? + image || default end # Define or get attributes to be used as Twitter card metadata diff --git a/app/views/layouts/_head.html.haml b/app/views/layouts/_head.html.haml index 1a2187e551b..38ca4f91c4d 100644 --- a/app/views/layouts/_head.html.haml +++ b/app/views/layouts/_head.html.haml @@ -1,3 +1,5 @@ +- page_description brand_title unless page_description + - site_name = "GitLab" %head{prefix: "og: http://ogp.me/ns#"} %meta{charset: "utf-8"} diff --git a/app/views/layouts/group.html.haml b/app/views/layouts/group.html.haml index 1ce8d0ef7b5..2e483b7148d 100644 --- a/app/views/layouts/group.html.haml +++ b/app/views/layouts/group.html.haml @@ -1,5 +1,5 @@ - page_title @group.name -- page_description @group.description +- page_description @group.description unless page_description - header_title group_title(@group) unless header_title - sidebar "group" unless sidebar diff --git a/app/views/layouts/project.html.haml b/app/views/layouts/project.html.haml index f81283a5ddb..ab527e8e438 100644 --- a/app/views/layouts/project.html.haml +++ b/app/views/layouts/project.html.haml @@ -1,5 +1,5 @@ - page_title @project.name_with_namespace -- page_description @project.description +- page_description @project.description unless page_description - header_title project_title(@project) unless header_title - sidebar "project" unless sidebar diff --git a/spec/helpers/page_layout_helper_spec.rb b/spec/helpers/page_layout_helper_spec.rb index a097786ba6d..cf632f594c7 100644 --- a/spec/helpers/page_layout_helper_spec.rb +++ b/spec/helpers/page_layout_helper_spec.rb @@ -2,10 +2,8 @@ require 'rails_helper' describe PageLayoutHelper do describe 'page_description' do - it 'defaults to value returned by brand_title helper' do - allow(helper).to receive(:brand_title).and_return('Foo') - - expect(helper.page_description).to eq 'Foo' + it 'defaults to nil' do + expect(helper.page_description).to eq nil end it 'returns the last-pushed description' do -- cgit v1.2.1 From b9ed3961b55cf3dbc1a6d4c841d295dd23161c90 Mon Sep 17 00:00:00 2001 From: Douwe Maan Date: Wed, 6 Jan 2016 13:25:13 +0100 Subject: Revert "Add DEBUG_BANZAI_CACHE env var to debug Banzai cache issue." This reverts commit 4b027bc93a7875c3937f6b90ac1049b4a4d72da5. --- lib/banzai/renderer.rb | 21 +++++++-------------- 1 file changed, 7 insertions(+), 14 deletions(-) diff --git a/lib/banzai/renderer.rb b/lib/banzai/renderer.rb index 910e1c6994e..115ae914524 100644 --- a/lib/banzai/renderer.rb +++ b/lib/banzai/renderer.rb @@ -1,5 +1,7 @@ module Banzai module Renderer + CACHE_ENABLED = false + # Convert a Markdown String into an HTML-safe String of HTML # # Note that while the returned HTML will have been sanitized of dangerous @@ -18,22 +20,13 @@ module Banzai cache_key = context.delete(:cache_key) cache_key = full_cache_key(cache_key, context[:pipeline]) - cacheless = cacheless_render(text, context) - - if cache_key && ENV["DEBUG_BANZAI_CACHE"] - cached = Rails.cache.fetch(cache_key) { cacheless } - - if cached != cacheless - Rails.logger.warn "Banzai cache mismatch" - Rails.logger.warn "Text: #{text.inspect}" - Rails.logger.warn "Context: #{context.inspect}" - Rails.logger.warn "Cache key: #{cache_key.inspect}" - Rails.logger.warn "Cacheless: #{cacheless.inspect}" - Rails.logger.warn "With cache: #{cached.inspect}" + if cache_key && CACHE_ENABLED + Rails.cache.fetch(cache_key) do + cacheless_render(text, context) end + else + cacheless_render(text, context) end - - cacheless end def self.render_result(text, context = {}) -- cgit v1.2.1 From cf19efec3ac0ab4510359dd71df3d511762230c3 Mon Sep 17 00:00:00 2001 From: Douwe Maan Date: Wed, 6 Jan 2016 13:26:02 +0100 Subject: Revert "Temporarily disable Markdown caching" This reverts commit d337d5e7137d9b3fd0f9b8890a3ba9296323acc7. --- lib/banzai/renderer.rb | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/lib/banzai/renderer.rb b/lib/banzai/renderer.rb index 115ae914524..891c0fd7749 100644 --- a/lib/banzai/renderer.rb +++ b/lib/banzai/renderer.rb @@ -1,7 +1,5 @@ module Banzai module Renderer - CACHE_ENABLED = false - # Convert a Markdown String into an HTML-safe String of HTML # # Note that while the returned HTML will have been sanitized of dangerous @@ -20,7 +18,7 @@ module Banzai cache_key = context.delete(:cache_key) cache_key = full_cache_key(cache_key, context[:pipeline]) - if cache_key && CACHE_ENABLED + if cache_key Rails.cache.fetch(cache_key) do cacheless_render(text, context) end -- cgit v1.2.1 From 37ce5f312eabf95deff7aac68f6bce6ba6e106b9 Mon Sep 17 00:00:00 2001 From: Douwe Maan Date: Wed, 6 Jan 2016 13:33:11 +0100 Subject: Fix mentionable reference extraction caching. --- app/models/concerns/mentionable.rb | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/app/models/concerns/mentionable.rb b/app/models/concerns/mentionable.rb index 6316ee208b5..98f71ae8cb0 100644 --- a/app/models/concerns/mentionable.rb +++ b/app/models/concerns/mentionable.rb @@ -51,8 +51,11 @@ module Mentionable else self.class.mentionable_attrs.each do |attr, options| text = send(attr) - options[:cache_key] = [self, attr] if options.delete(:cache) && self.persisted? - ext.analyze(text, options) + + context = options.dup + context[:cache_key] = [self, attr] if context.delete(:cache) && self.persisted? + + ext.analyze(text, context) end end -- cgit v1.2.1 From 18b17072c6cc7eb199d1da34a3ea481dcd53a8cf Mon Sep 17 00:00:00 2001 From: Douwe Maan Date: Wed, 6 Jan 2016 13:33:47 +0100 Subject: Add regression test. --- spec/models/note_spec.rb | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/spec/models/note_spec.rb b/spec/models/note_spec.rb index 593d8f76215..151a29e974b 100644 --- a/spec/models/note_spec.rb +++ b/spec/models/note_spec.rb @@ -125,6 +125,19 @@ describe Note, models: true do let(:set_mentionable_text) { ->(txt) { subject.note = txt } } end + describe "#all_references" do + let!(:note1) { create(:note) } + let!(:note2) { create(:note) } + + it "reads the rendered note body from the cache" do + expect(Banzai::Renderer).to receive(:render).with(note1.note, pipeline: :note, cache_key: [note1, "note"], project: note1.project) + expect(Banzai::Renderer).to receive(:render).with(note2.note, pipeline: :note, cache_key: [note2, "note"], project: note2.project) + + note1.all_references + note2.all_references + end + end + describe :search do let!(:note) { create(:note, note: "WoW") } @@ -164,7 +177,7 @@ describe Note, models: true do expect(note.editable?).to be_falsy end end - + describe "set_award!" do let(:issue) { create :issue } -- cgit v1.2.1 From 79c0e7212af0a6b0243bc0512a75eb936fb8d862 Mon Sep 17 00:00:00 2001 From: Stan Hu Date: Wed, 6 Jan 2016 02:30:59 +0000 Subject: Annotate models --- app/models/application_setting.rb | 15 ++- app/models/ci/build.rb | 1 + app/models/ci/runner_project.rb | 11 +- app/models/ci/trigger.rb | 13 +-- app/models/ci/variable.rb | 3 +- app/models/commit_status.rb | 55 +++++----- app/models/generic_commit_status.rb | 1 + app/models/group.rb | 1 - app/models/hooks/project_hook.rb | 1 + app/models/hooks/service_hook.rb | 1 + app/models/hooks/system_hook.rb | 1 + app/models/hooks/web_hook.rb | 1 + app/models/merge_request.rb | 44 ++++---- app/models/namespace.rb | 1 - app/models/project.rb | 7 ++ app/models/project_services/asana_service.rb | 2 + app/models/project_services/assembla_service.rb | 1 + app/models/project_services/bamboo_service.rb | 1 + app/models/project_services/buildkite_service.rb | 1 + .../project_services/builds_email_service.rb | 1 + app/models/project_services/campfire_service.rb | 1 + app/models/project_services/ci_service.rb | 1 + .../custom_issue_tracker_service.rb | 1 + app/models/project_services/drone_ci_service.rb | 1 + .../project_services/emails_on_push_service.rb | 1 + .../project_services/external_wiki_service.rb | 1 + app/models/project_services/flowdock_service.rb | 1 + app/models/project_services/gemnasium_service.rb | 1 + app/models/project_services/gitlab_ci_service.rb | 1 + .../gitlab_issue_tracker_service.rb | 1 + app/models/project_services/hipchat_service.rb | 1 + app/models/project_services/irker_service.rb | 1 + .../project_services/issue_tracker_service.rb | 1 + app/models/project_services/jira_service.rb | 1 + .../project_services/pivotaltracker_service.rb | 1 + app/models/project_services/pushover_service.rb | 1 + app/models/project_services/redmine_service.rb | 1 + app/models/project_services/slack_service.rb | 1 + app/models/project_services/teamcity_service.rb | 1 + app/models/service.rb | 1 + app/models/user.rb | 113 +++++++++++---------- spec/factories/merge_requests.rb | 41 ++++---- spec/factories/projects.rb | 7 ++ spec/models/application_setting_spec.rb | 65 +++++++----- spec/models/ci/commit_spec.rb | 2 +- spec/models/ci/runner_project_spec.rb | 11 +- spec/models/ci/trigger_spec.rb | 13 +-- spec/models/ci/variable_spec.rb | 3 +- spec/models/commit_status_spec.rb | 1 + spec/models/external_wiki_service_spec.rb | 1 + spec/models/generic_commit_status_spec.rb | 1 + spec/models/group_spec.rb | 1 - spec/models/merge_request_spec.rb | 41 ++++---- spec/models/namespace_spec.rb | 1 - spec/models/project_spec.rb | 7 ++ spec/models/service_spec.rb | 1 + spec/models/user_spec.rb | 113 +++++++++++---------- 57 files changed, 350 insertions(+), 254 deletions(-) diff --git a/app/models/application_setting.rb b/app/models/application_setting.rb index be69d317d73..6c6c2468374 100644 --- a/app/models/application_setting.rb +++ b/app/models/application_setting.rb @@ -27,9 +27,20 @@ # admin_notification_email :string(255) # shared_runners_enabled :boolean default(TRUE), not null # max_artifacts_size :integer default(100), not null -# runners_registration_token :string(255) -# require_two_factor_authentication :boolean default(TRUE) +# runners_registration_token :string +# require_two_factor_authentication :boolean default(FALSE) # two_factor_grace_period :integer default(48) +# metrics_enabled :boolean default(FALSE) +# metrics_host :string default("localhost") +# metrics_username :string +# metrics_password :string +# metrics_pool_size :integer default(16) +# metrics_timeout :integer default(10) +# metrics_method_call_threshold :integer default(10) +# recaptcha_enabled :boolean default(FALSE) +# recaptcha_site_key :string +# recaptcha_private_key :string +# metrics_port :integer default(8089) # class ApplicationSetting < ActiveRecord::Base diff --git a/app/models/ci/build.rb b/app/models/ci/build.rb index d7fccb2197d..30f79fd3bfa 100644 --- a/app/models/ci/build.rb +++ b/app/models/ci/build.rb @@ -29,6 +29,7 @@ # target_url :string(255) # description :string(255) # artifacts_file :text +# gl_project_id :integer # module Ci diff --git a/app/models/ci/runner_project.rb b/app/models/ci/runner_project.rb index 93d9be144e8..7b16f207a26 100644 --- a/app/models/ci/runner_project.rb +++ b/app/models/ci/runner_project.rb @@ -2,11 +2,12 @@ # # Table name: ci_runner_projects # -# id :integer not null, primary key -# runner_id :integer not null -# project_id :integer not null -# created_at :datetime -# updated_at :datetime +# id :integer not null, primary key +# runner_id :integer not null +# project_id :integer +# created_at :datetime +# updated_at :datetime +# gl_project_id :integer # module Ci diff --git a/app/models/ci/trigger.rb b/app/models/ci/trigger.rb index 23516709a41..bb98cd5c7da 100644 --- a/app/models/ci/trigger.rb +++ b/app/models/ci/trigger.rb @@ -2,12 +2,13 @@ # # Table name: ci_triggers # -# id :integer not null, primary key -# token :string(255) -# project_id :integer not null -# deleted_at :datetime -# created_at :datetime -# updated_at :datetime +# id :integer not null, primary key +# token :string(255) +# project_id :integer +# deleted_at :datetime +# created_at :datetime +# updated_at :datetime +# gl_project_id :integer # module Ci diff --git a/app/models/ci/variable.rb b/app/models/ci/variable.rb index 56759d3e50f..7f6f497f325 100644 --- a/app/models/ci/variable.rb +++ b/app/models/ci/variable.rb @@ -3,12 +3,13 @@ # Table name: ci_variables # # id :integer not null, primary key -# project_id :integer not null +# project_id :integer # key :string(255) # value :text # encrypted_value :text # encrypted_value_salt :string(255) # encrypted_value_iv :string(255) +# gl_project_id :integer # module Ci diff --git a/app/models/commit_status.rb b/app/models/commit_status.rb index 21c5c87bc3d..ff479493474 100644 --- a/app/models/commit_status.rb +++ b/app/models/commit_status.rb @@ -1,30 +1,35 @@ # == Schema Information # -# project_id integer -# status string -# finished_at datetime -# trace text -# created_at datetime -# updated_at datetime -# started_at datetime -# runner_id integer -# coverage float -# commit_id integer -# commands text -# job_id integer -# name string -# deploy boolean default: false -# options text -# allow_failure boolean default: false, null: false -# stage string -# trigger_request_id integer -# stage_idx integer -# tag boolean -# ref string -# user_id integer -# type string -# target_url string -# description string +# Table name: ci_builds +# +# id :integer not null, primary key +# project_id :integer +# status :string(255) +# finished_at :datetime +# trace :text +# created_at :datetime +# updated_at :datetime +# started_at :datetime +# runner_id :integer +# coverage :float +# commit_id :integer +# commands :text +# job_id :integer +# name :string(255) +# deploy :boolean default(FALSE) +# options :text +# allow_failure :boolean default(FALSE), not null +# stage :string(255) +# trigger_request_id :integer +# stage_idx :integer +# tag :boolean +# ref :string(255) +# user_id :integer +# type :string(255) +# target_url :string(255) +# description :string(255) +# artifacts_file :text +# gl_project_id :integer # class CommitStatus < ActiveRecord::Base diff --git a/app/models/generic_commit_status.rb b/app/models/generic_commit_status.rb index 12c934e2494..97f4f03a9a5 100644 --- a/app/models/generic_commit_status.rb +++ b/app/models/generic_commit_status.rb @@ -29,6 +29,7 @@ # target_url :string(255) # description :string(255) # artifacts_file :text +# gl_project_id :integer # class GenericCommitStatus < CommitStatus diff --git a/app/models/group.rb b/app/models/group.rb index b8f2ab6ae5d..5a31b46920c 100644 --- a/app/models/group.rb +++ b/app/models/group.rb @@ -11,7 +11,6 @@ # type :string(255) # description :string(255) default(""), not null # avatar :string(255) -# public :boolean default(FALSE) # require 'carrierwave/orm/activerecord' diff --git a/app/models/hooks/project_hook.rb b/app/models/hooks/project_hook.rb index 22638057773..fa18ba5dbbe 100644 --- a/app/models/hooks/project_hook.rb +++ b/app/models/hooks/project_hook.rb @@ -15,6 +15,7 @@ # tag_push_events :boolean default(FALSE) # note_events :boolean default(FALSE), not null # enable_ssl_verification :boolean default(TRUE) +# build_events :boolean default(FALSE), not null # class ProjectHook < WebHook diff --git a/app/models/hooks/service_hook.rb b/app/models/hooks/service_hook.rb index 09bb3ee52a2..b333a337347 100644 --- a/app/models/hooks/service_hook.rb +++ b/app/models/hooks/service_hook.rb @@ -15,6 +15,7 @@ # tag_push_events :boolean default(FALSE) # note_events :boolean default(FALSE), not null # enable_ssl_verification :boolean default(TRUE) +# build_events :boolean default(FALSE), not null # class ServiceHook < WebHook diff --git a/app/models/hooks/system_hook.rb b/app/models/hooks/system_hook.rb index 2f63c59b07e..d81512fae5d 100644 --- a/app/models/hooks/system_hook.rb +++ b/app/models/hooks/system_hook.rb @@ -15,6 +15,7 @@ # tag_push_events :boolean default(FALSE) # note_events :boolean default(FALSE), not null # enable_ssl_verification :boolean default(TRUE) +# build_events :boolean default(FALSE), not null # class SystemHook < WebHook diff --git a/app/models/hooks/web_hook.rb b/app/models/hooks/web_hook.rb index 40eb0e20b4b..7164c0e1e90 100644 --- a/app/models/hooks/web_hook.rb +++ b/app/models/hooks/web_hook.rb @@ -15,6 +15,7 @@ # tag_push_events :boolean default(FALSE) # note_events :boolean default(FALSE), not null # enable_ssl_verification :boolean default(TRUE) +# build_events :boolean default(FALSE), not null # class WebHook < ActiveRecord::Base diff --git a/app/models/merge_request.rb b/app/models/merge_request.rb index ac25d38eb63..1b98474fc55 100644 --- a/app/models/merge_request.rb +++ b/app/models/merge_request.rb @@ -2,28 +2,28 @@ # # Table name: merge_requests # -# id :integer not null, primary key -# target_branch :string(255) not null -# source_branch :string(255) not null -# source_project_id :integer not null -# author_id :integer -# assignee_id :integer -# title :string(255) -# created_at :datetime -# updated_at :datetime -# milestone_id :integer -# state :string(255) -# merge_status :string(255) -# target_project_id :integer not null -# iid :integer -# description :text -# position :integer default(0) -# locked_at :datetime -# updated_by_id :integer -# merge_error :string(255) -# merge_params :text (serialized to hash) -# merge_when_build_succeeds :boolean default(false), not null -# merge_user_id :integer +# id :integer not null, primary key +# target_branch :string(255) not null +# source_branch :string(255) not null +# source_project_id :integer not null +# author_id :integer +# assignee_id :integer +# title :string(255) +# created_at :datetime +# updated_at :datetime +# milestone_id :integer +# state :string(255) +# merge_status :string(255) +# target_project_id :integer not null +# iid :integer +# description :text +# position :integer default(0) +# locked_at :datetime +# updated_by_id :integer +# merge_error :string(255) +# merge_params :text +# merge_when_build_succeeds :boolean default(FALSE), not null +# merge_user_id :integer # require Rails.root.join("app/models/commit") diff --git a/app/models/namespace.rb b/app/models/namespace.rb index adafabbec07..bdb33f37495 100644 --- a/app/models/namespace.rb +++ b/app/models/namespace.rb @@ -11,7 +11,6 @@ # type :string(255) # description :string(255) default(""), not null # avatar :string(255) -# public :boolean default(FALSE) # class Namespace < ActiveRecord::Base diff --git a/app/models/project.rb b/app/models/project.rb index b1a6cfa86af..7626c698816 100644 --- a/app/models/project.rb +++ b/app/models/project.rb @@ -29,6 +29,13 @@ # import_source :string(255) # commit_count :integer default(0) # import_error :text +# ci_id :integer +# builds_enabled :boolean default(TRUE), not null +# shared_runners_enabled :boolean default(TRUE), not null +# runners_token :string +# build_coverage_regex :string +# build_allow_git_fetch :boolean default(TRUE), not null +# build_timeout :integer default(3600), not null # require 'carrierwave/orm/activerecord' diff --git a/app/models/project_services/asana_service.rb b/app/models/project_services/asana_service.rb index 7d367e40037..792ad804575 100644 --- a/app/models/project_services/asana_service.rb +++ b/app/models/project_services/asana_service.rb @@ -16,7 +16,9 @@ # merge_requests_events :boolean default(TRUE) # tag_push_events :boolean default(TRUE) # note_events :boolean default(TRUE), not null +# build_events :boolean default(FALSE), not null # + require 'asana' class AsanaService < Service diff --git a/app/models/project_services/assembla_service.rb b/app/models/project_services/assembla_service.rb index fb7e0c0fb0d..29d841faed8 100644 --- a/app/models/project_services/assembla_service.rb +++ b/app/models/project_services/assembla_service.rb @@ -16,6 +16,7 @@ # merge_requests_events :boolean default(TRUE) # tag_push_events :boolean default(TRUE) # note_events :boolean default(TRUE), not null +# build_events :boolean default(FALSE), not null # class AssemblaService < Service diff --git a/app/models/project_services/bamboo_service.rb b/app/models/project_services/bamboo_service.rb index aa8746beb80..9e7f642180e 100644 --- a/app/models/project_services/bamboo_service.rb +++ b/app/models/project_services/bamboo_service.rb @@ -16,6 +16,7 @@ # merge_requests_events :boolean default(TRUE) # tag_push_events :boolean default(TRUE) # note_events :boolean default(TRUE), not null +# build_events :boolean default(FALSE), not null # class BambooService < CiService diff --git a/app/models/project_services/buildkite_service.rb b/app/models/project_services/buildkite_service.rb index 199ee3a9d0d..3efbfd2eec3 100644 --- a/app/models/project_services/buildkite_service.rb +++ b/app/models/project_services/buildkite_service.rb @@ -16,6 +16,7 @@ # merge_requests_events :boolean default(TRUE) # tag_push_events :boolean default(TRUE) # note_events :boolean default(TRUE), not null +# build_events :boolean default(FALSE), not null # require "addressable/uri" diff --git a/app/models/project_services/builds_email_service.rb b/app/models/project_services/builds_email_service.rb index 8247c79fc33..92c9b13c9b9 100644 --- a/app/models/project_services/builds_email_service.rb +++ b/app/models/project_services/builds_email_service.rb @@ -16,6 +16,7 @@ # merge_requests_events :boolean default(TRUE) # tag_push_events :boolean default(TRUE) # note_events :boolean default(TRUE), not null +# build_events :boolean default(FALSE), not null # class BuildsEmailService < Service diff --git a/app/models/project_services/campfire_service.rb b/app/models/project_services/campfire_service.rb index e591afdda64..6e8f0842524 100644 --- a/app/models/project_services/campfire_service.rb +++ b/app/models/project_services/campfire_service.rb @@ -16,6 +16,7 @@ # merge_requests_events :boolean default(TRUE) # tag_push_events :boolean default(TRUE) # note_events :boolean default(TRUE), not null +# build_events :boolean default(FALSE), not null # class CampfireService < Service diff --git a/app/models/project_services/ci_service.rb b/app/models/project_services/ci_service.rb index 88186113c68..c3f70d1f972 100644 --- a/app/models/project_services/ci_service.rb +++ b/app/models/project_services/ci_service.rb @@ -16,6 +16,7 @@ # merge_requests_events :boolean default(TRUE) # tag_push_events :boolean default(TRUE) # note_events :boolean default(TRUE), not null +# build_events :boolean default(FALSE), not null # # Base class for CI services diff --git a/app/models/project_services/custom_issue_tracker_service.rb b/app/models/project_services/custom_issue_tracker_service.rb index 7c2027c18e6..88a3e9218cb 100644 --- a/app/models/project_services/custom_issue_tracker_service.rb +++ b/app/models/project_services/custom_issue_tracker_service.rb @@ -16,6 +16,7 @@ # merge_requests_events :boolean default(TRUE) # tag_push_events :boolean default(TRUE) # note_events :boolean default(TRUE), not null +# build_events :boolean default(FALSE), not null # class CustomIssueTrackerService < IssueTrackerService diff --git a/app/models/project_services/drone_ci_service.rb b/app/models/project_services/drone_ci_service.rb index 08e5ccb3855..b4724bb647e 100644 --- a/app/models/project_services/drone_ci_service.rb +++ b/app/models/project_services/drone_ci_service.rb @@ -16,6 +16,7 @@ # merge_requests_events :boolean default(TRUE) # tag_push_events :boolean default(TRUE) # note_events :boolean default(TRUE), not null +# build_events :boolean default(FALSE), not null # class DroneCiService < CiService diff --git a/app/models/project_services/emails_on_push_service.rb b/app/models/project_services/emails_on_push_service.rb index 8f5d8b086eb..b831577cd97 100644 --- a/app/models/project_services/emails_on_push_service.rb +++ b/app/models/project_services/emails_on_push_service.rb @@ -16,6 +16,7 @@ # merge_requests_events :boolean default(TRUE) # tag_push_events :boolean default(TRUE) # note_events :boolean default(TRUE), not null +# build_events :boolean default(FALSE), not null # class EmailsOnPushService < Service diff --git a/app/models/project_services/external_wiki_service.rb b/app/models/project_services/external_wiki_service.rb index 74c57949b4d..b402b68665a 100644 --- a/app/models/project_services/external_wiki_service.rb +++ b/app/models/project_services/external_wiki_service.rb @@ -16,6 +16,7 @@ # merge_requests_events :boolean default(TRUE) # tag_push_events :boolean default(TRUE) # note_events :boolean default(TRUE), not null +# build_events :boolean default(FALSE), not null # class ExternalWikiService < Service diff --git a/app/models/project_services/flowdock_service.rb b/app/models/project_services/flowdock_service.rb index 15c7c907f7e..8605ce66e48 100644 --- a/app/models/project_services/flowdock_service.rb +++ b/app/models/project_services/flowdock_service.rb @@ -16,6 +16,7 @@ # merge_requests_events :boolean default(TRUE) # tag_push_events :boolean default(TRUE) # note_events :boolean default(TRUE), not null +# build_events :boolean default(FALSE), not null # require "flowdock-git-hook" diff --git a/app/models/project_services/gemnasium_service.rb b/app/models/project_services/gemnasium_service.rb index 202fee042e3..61babe9cfe5 100644 --- a/app/models/project_services/gemnasium_service.rb +++ b/app/models/project_services/gemnasium_service.rb @@ -16,6 +16,7 @@ # merge_requests_events :boolean default(TRUE) # tag_push_events :boolean default(TRUE) # note_events :boolean default(TRUE), not null +# build_events :boolean default(FALSE), not null # require "gemnasium/gitlab_service" diff --git a/app/models/project_services/gitlab_ci_service.rb b/app/models/project_services/gitlab_ci_service.rb index b64d97ce75d..33f0d7ea01a 100644 --- a/app/models/project_services/gitlab_ci_service.rb +++ b/app/models/project_services/gitlab_ci_service.rb @@ -16,6 +16,7 @@ # merge_requests_events :boolean default(TRUE) # tag_push_events :boolean default(TRUE) # note_events :boolean default(TRUE), not null +# build_events :boolean default(FALSE), not null # # TODO(ayufan): The GitLabCiService is deprecated and the type should be removed when the database entries are removed diff --git a/app/models/project_services/gitlab_issue_tracker_service.rb b/app/models/project_services/gitlab_issue_tracker_service.rb index 9558292fea3..7aa04309f54 100644 --- a/app/models/project_services/gitlab_issue_tracker_service.rb +++ b/app/models/project_services/gitlab_issue_tracker_service.rb @@ -16,6 +16,7 @@ # merge_requests_events :boolean default(TRUE) # tag_push_events :boolean default(TRUE) # note_events :boolean default(TRUE), not null +# build_events :boolean default(FALSE), not null # class GitlabIssueTrackerService < IssueTrackerService diff --git a/app/models/project_services/hipchat_service.rb b/app/models/project_services/hipchat_service.rb index 1e1686a11c6..32a81808930 100644 --- a/app/models/project_services/hipchat_service.rb +++ b/app/models/project_services/hipchat_service.rb @@ -16,6 +16,7 @@ # merge_requests_events :boolean default(TRUE) # tag_push_events :boolean default(TRUE) # note_events :boolean default(TRUE), not null +# build_events :boolean default(FALSE), not null # class HipchatService < Service diff --git a/app/models/project_services/irker_service.rb b/app/models/project_services/irker_service.rb index d24aa317cf3..bd9b580038f 100644 --- a/app/models/project_services/irker_service.rb +++ b/app/models/project_services/irker_service.rb @@ -16,6 +16,7 @@ # merge_requests_events :boolean default(TRUE) # tag_push_events :boolean default(TRUE) # note_events :boolean default(TRUE), not null +# build_events :boolean default(FALSE), not null # require 'uri' diff --git a/app/models/project_services/issue_tracker_service.rb b/app/models/project_services/issue_tracker_service.rb index 936e574cccd..ed201979d39 100644 --- a/app/models/project_services/issue_tracker_service.rb +++ b/app/models/project_services/issue_tracker_service.rb @@ -16,6 +16,7 @@ # merge_requests_events :boolean default(TRUE) # tag_push_events :boolean default(TRUE) # note_events :boolean default(TRUE), not null +# build_events :boolean default(FALSE), not null # class IssueTrackerService < Service diff --git a/app/models/project_services/jira_service.rb b/app/models/project_services/jira_service.rb index e216f406e1c..a1b77c61576 100644 --- a/app/models/project_services/jira_service.rb +++ b/app/models/project_services/jira_service.rb @@ -16,6 +16,7 @@ # merge_requests_events :boolean default(TRUE) # tag_push_events :boolean default(TRUE) # note_events :boolean default(TRUE), not null +# build_events :boolean default(FALSE), not null # class JiraService < IssueTrackerService diff --git a/app/models/project_services/pivotaltracker_service.rb b/app/models/project_services/pivotaltracker_service.rb index ade9ee97873..c9a890c7e3f 100644 --- a/app/models/project_services/pivotaltracker_service.rb +++ b/app/models/project_services/pivotaltracker_service.rb @@ -16,6 +16,7 @@ # merge_requests_events :boolean default(TRUE) # tag_push_events :boolean default(TRUE) # note_events :boolean default(TRUE), not null +# build_events :boolean default(FALSE), not null # class PivotaltrackerService < Service diff --git a/app/models/project_services/pushover_service.rb b/app/models/project_services/pushover_service.rb index 53edf522e9a..3d7e8bbee61 100644 --- a/app/models/project_services/pushover_service.rb +++ b/app/models/project_services/pushover_service.rb @@ -16,6 +16,7 @@ # merge_requests_events :boolean default(TRUE) # tag_push_events :boolean default(TRUE) # note_events :boolean default(TRUE), not null +# build_events :boolean default(FALSE), not null # class PushoverService < Service diff --git a/app/models/project_services/redmine_service.rb b/app/models/project_services/redmine_service.rb index dd9ba97ee1f..de974354c77 100644 --- a/app/models/project_services/redmine_service.rb +++ b/app/models/project_services/redmine_service.rb @@ -16,6 +16,7 @@ # merge_requests_events :boolean default(TRUE) # tag_push_events :boolean default(TRUE) # note_events :boolean default(TRUE), not null +# build_events :boolean default(FALSE), not null # class RedmineService < IssueTrackerService diff --git a/app/models/project_services/slack_service.rb b/app/models/project_services/slack_service.rb index 375b4534d07..d89cf6d17b2 100644 --- a/app/models/project_services/slack_service.rb +++ b/app/models/project_services/slack_service.rb @@ -16,6 +16,7 @@ # merge_requests_events :boolean default(TRUE) # tag_push_events :boolean default(TRUE) # note_events :boolean default(TRUE), not null +# build_events :boolean default(FALSE), not null # class SlackService < Service diff --git a/app/models/project_services/teamcity_service.rb b/app/models/project_services/teamcity_service.rb index a63700693d7..b8e9416131a 100644 --- a/app/models/project_services/teamcity_service.rb +++ b/app/models/project_services/teamcity_service.rb @@ -16,6 +16,7 @@ # merge_requests_events :boolean default(TRUE) # tag_push_events :boolean default(TRUE) # note_events :boolean default(TRUE), not null +# build_events :boolean default(FALSE), not null # class TeamcityService < CiService diff --git a/app/models/service.rb b/app/models/service.rb index d3bf7f0ebd1..24f4bf7646e 100644 --- a/app/models/service.rb +++ b/app/models/service.rb @@ -16,6 +16,7 @@ # merge_requests_events :boolean default(TRUE) # tag_push_events :boolean default(TRUE) # note_events :boolean default(TRUE), not null +# build_events :boolean default(FALSE), not null # # To add new service you should build a class inherited from Service diff --git a/app/models/user.rb b/app/models/user.rb index 20f907e4347..46b36c605b0 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -2,62 +2,63 @@ # # Table name: users # -# id :integer not null, primary key -# email :string(255) default(""), not null -# encrypted_password :string(255) default(""), not null -# reset_password_token :string(255) -# reset_password_sent_at :datetime -# remember_created_at :datetime -# sign_in_count :integer default(0) -# current_sign_in_at :datetime -# last_sign_in_at :datetime -# current_sign_in_ip :string(255) -# last_sign_in_ip :string(255) -# created_at :datetime -# updated_at :datetime -# name :string(255) -# admin :boolean default(FALSE), not null -# projects_limit :integer default(10) -# skype :string(255) default(""), not null -# linkedin :string(255) default(""), not null -# twitter :string(255) default(""), not null -# authentication_token :string(255) -# theme_id :integer default(1), not null -# bio :string(255) -# failed_attempts :integer default(0) -# locked_at :datetime -# unlock_token :string(255) -# username :string(255) -# can_create_group :boolean default(TRUE), not null -# can_create_team :boolean default(TRUE), not null -# state :string(255) -# color_scheme_id :integer default(1), not null -# notification_level :integer default(1), not null -# password_expires_at :datetime -# created_by_id :integer -# last_credential_check_at :datetime -# avatar :string(255) -# confirmation_token :string(255) -# confirmed_at :datetime -# confirmation_sent_at :datetime -# unconfirmed_email :string(255) -# hide_no_ssh_key :boolean default(FALSE) -# website_url :string(255) default(""), not null -# notification_email :string(255) -# hide_no_password :boolean default(FALSE) -# password_automatically_set :boolean default(FALSE) -# location :string(255) -# encrypted_otp_secret :string(255) -# encrypted_otp_secret_iv :string(255) -# encrypted_otp_secret_salt :string(255) -# otp_required_for_login :boolean default(FALSE), not null -# otp_backup_codes :text -# public_email :string(255) default(""), not null -# dashboard :integer default(0) -# project_view :integer default(0) -# consumed_timestep :integer -# layout :integer default(0) -# hide_project_limit :boolean default(FALSE) +# id :integer not null, primary key +# email :string(255) default(""), not null +# encrypted_password :string(255) default(""), not null +# reset_password_token :string(255) +# reset_password_sent_at :datetime +# remember_created_at :datetime +# sign_in_count :integer default(0) +# current_sign_in_at :datetime +# last_sign_in_at :datetime +# current_sign_in_ip :string(255) +# last_sign_in_ip :string(255) +# created_at :datetime +# updated_at :datetime +# name :string(255) +# admin :boolean default(FALSE), not null +# projects_limit :integer default(10) +# skype :string(255) default(""), not null +# linkedin :string(255) default(""), not null +# twitter :string(255) default(""), not null +# authentication_token :string(255) +# theme_id :integer default(1), not null +# bio :string(255) +# failed_attempts :integer default(0) +# locked_at :datetime +# username :string(255) +# can_create_group :boolean default(TRUE), not null +# can_create_team :boolean default(TRUE), not null +# state :string(255) +# color_scheme_id :integer default(1), not null +# notification_level :integer default(1), not null +# password_expires_at :datetime +# created_by_id :integer +# last_credential_check_at :datetime +# avatar :string(255) +# confirmation_token :string(255) +# confirmed_at :datetime +# confirmation_sent_at :datetime +# unconfirmed_email :string(255) +# hide_no_ssh_key :boolean default(FALSE) +# website_url :string(255) default(""), not null +# notification_email :string(255) +# hide_no_password :boolean default(FALSE) +# password_automatically_set :boolean default(FALSE) +# location :string(255) +# encrypted_otp_secret :string(255) +# encrypted_otp_secret_iv :string(255) +# encrypted_otp_secret_salt :string(255) +# otp_required_for_login :boolean default(FALSE), not null +# otp_backup_codes :text +# public_email :string(255) default(""), not null +# dashboard :integer default(0) +# project_view :integer default(0) +# consumed_timestep :integer +# layout :integer default(0) +# hide_project_limit :boolean default(FALSE) +# unlock_token :string +# otp_grace_period_started_at :datetime # require 'carrierwave/orm/activerecord' diff --git a/spec/factories/merge_requests.rb b/spec/factories/merge_requests.rb index 5b4d7f41bc4..0c6a881f868 100644 --- a/spec/factories/merge_requests.rb +++ b/spec/factories/merge_requests.rb @@ -2,25 +2,28 @@ # # Table name: merge_requests # -# id :integer not null, primary key -# target_branch :string(255) not null -# source_branch :string(255) not null -# source_project_id :integer not null -# author_id :integer -# assignee_id :integer -# title :string(255) -# created_at :datetime -# updated_at :datetime -# milestone_id :integer -# state :string(255) -# merge_status :string(255) -# target_project_id :integer not null -# iid :integer -# description :text -# position :integer default(0) -# locked_at :datetime -# updated_by_id :integer -# merge_error :string(255) +# id :integer not null, primary key +# target_branch :string(255) not null +# source_branch :string(255) not null +# source_project_id :integer not null +# author_id :integer +# assignee_id :integer +# title :string(255) +# created_at :datetime +# updated_at :datetime +# milestone_id :integer +# state :string(255) +# merge_status :string(255) +# target_project_id :integer not null +# iid :integer +# description :text +# position :integer default(0) +# locked_at :datetime +# updated_by_id :integer +# merge_error :string(255) +# merge_params :text +# merge_when_build_succeeds :boolean default(FALSE), not null +# merge_user_id :integer # FactoryGirl.define do diff --git a/spec/factories/projects.rb b/spec/factories/projects.rb index 112213377ff..c14b99606ba 100644 --- a/spec/factories/projects.rb +++ b/spec/factories/projects.rb @@ -29,6 +29,13 @@ # import_source :string(255) # commit_count :integer default(0) # import_error :text +# ci_id :integer +# builds_enabled :boolean default(TRUE), not null +# shared_runners_enabled :boolean default(TRUE), not null +# runners_token :string +# build_coverage_regex :string +# build_allow_git_fetch :boolean default(TRUE), not null +# build_timeout :integer default(3600), not null # FactoryGirl.define do diff --git a/spec/models/application_setting_spec.rb b/spec/models/application_setting_spec.rb index 35d8220ae54..91b250265e6 100644 --- a/spec/models/application_setting_spec.rb +++ b/spec/models/application_setting_spec.rb @@ -2,32 +2,45 @@ # # Table name: application_settings # -# id :integer not null, primary key -# default_projects_limit :integer -# signup_enabled :boolean -# signin_enabled :boolean -# gravatar_enabled :boolean -# sign_in_text :text -# created_at :datetime -# updated_at :datetime -# home_page_url :string(255) -# default_branch_protection :integer default(2) -# twitter_sharing_enabled :boolean default(TRUE) -# restricted_visibility_levels :text -# version_check_enabled :boolean default(TRUE) -# max_attachment_size :integer default(10), not null -# default_project_visibility :integer -# default_snippet_visibility :integer -# restricted_signup_domains :text -# user_oauth_applications :boolean default(TRUE) -# after_sign_out_path :string(255) -# session_expire_delay :integer default(10080), not null -# import_sources :text -# help_page_text :text -# admin_notification_email :string(255) -# shared_runners_enabled :boolean default(TRUE), not null -# max_artifacts_size :integer default(100), not null -# runners_registration_token :string(255) +# id :integer not null, primary key +# default_projects_limit :integer +# signup_enabled :boolean +# signin_enabled :boolean +# gravatar_enabled :boolean +# sign_in_text :text +# created_at :datetime +# updated_at :datetime +# home_page_url :string(255) +# default_branch_protection :integer default(2) +# twitter_sharing_enabled :boolean default(TRUE) +# restricted_visibility_levels :text +# version_check_enabled :boolean default(TRUE) +# max_attachment_size :integer default(10), not null +# default_project_visibility :integer +# default_snippet_visibility :integer +# restricted_signup_domains :text +# user_oauth_applications :boolean default(TRUE) +# after_sign_out_path :string(255) +# session_expire_delay :integer default(10080), not null +# import_sources :text +# help_page_text :text +# admin_notification_email :string(255) +# shared_runners_enabled :boolean default(TRUE), not null +# max_artifacts_size :integer default(100), not null +# runners_registration_token :string +# require_two_factor_authentication :boolean default(FALSE) +# two_factor_grace_period :integer default(48) +# metrics_enabled :boolean default(FALSE) +# metrics_host :string default("localhost") +# metrics_username :string +# metrics_password :string +# metrics_pool_size :integer default(16) +# metrics_timeout :integer default(10) +# metrics_method_call_threshold :integer default(10) +# recaptcha_enabled :boolean default(FALSE) +# recaptcha_site_key :string +# recaptcha_private_key :string +# metrics_port :integer default(8089) # require 'spec_helper' diff --git a/spec/models/ci/commit_spec.rb b/spec/models/ci/commit_spec.rb index b193e16e7f8..dfc0cc3be1c 100644 --- a/spec/models/ci/commit_spec.rb +++ b/spec/models/ci/commit_spec.rb @@ -13,7 +13,7 @@ # tag :boolean default(FALSE) # yaml_errors :text # committed_at :datetime -# project_id :integer +# gl_project_id :integer # require 'spec_helper' diff --git a/spec/models/ci/runner_project_spec.rb b/spec/models/ci/runner_project_spec.rb index da8491357a5..000a732db77 100644 --- a/spec/models/ci/runner_project_spec.rb +++ b/spec/models/ci/runner_project_spec.rb @@ -2,11 +2,12 @@ # # Table name: ci_runner_projects # -# id :integer not null, primary key -# runner_id :integer not null -# project_id :integer not null -# created_at :datetime -# updated_at :datetime +# id :integer not null, primary key +# runner_id :integer not null +# project_id :integer +# created_at :datetime +# updated_at :datetime +# gl_project_id :integer # require 'spec_helper' diff --git a/spec/models/ci/trigger_spec.rb b/spec/models/ci/trigger_spec.rb index cb2f51e2011..159be939300 100644 --- a/spec/models/ci/trigger_spec.rb +++ b/spec/models/ci/trigger_spec.rb @@ -2,12 +2,13 @@ # # Table name: ci_triggers # -# id :integer not null, primary key -# token :string(255) -# project_id :integer not null -# deleted_at :datetime -# created_at :datetime -# updated_at :datetime +# id :integer not null, primary key +# token :string(255) +# project_id :integer +# deleted_at :datetime +# created_at :datetime +# updated_at :datetime +# gl_project_id :integer # require 'spec_helper' diff --git a/spec/models/ci/variable_spec.rb b/spec/models/ci/variable_spec.rb index 31b56953a13..71e84091cb7 100644 --- a/spec/models/ci/variable_spec.rb +++ b/spec/models/ci/variable_spec.rb @@ -3,12 +3,13 @@ # Table name: ci_variables # # id :integer not null, primary key -# project_id :integer not null +# project_id :integer # key :string(255) # value :text # encrypted_value :text # encrypted_value_salt :string(255) # encrypted_value_iv :string(255) +# gl_project_id :integer # require 'spec_helper' diff --git a/spec/models/commit_status_spec.rb b/spec/models/commit_status_spec.rb index b8f901b3433..82c68ff6cb1 100644 --- a/spec/models/commit_status_spec.rb +++ b/spec/models/commit_status_spec.rb @@ -29,6 +29,7 @@ # target_url :string(255) # description :string(255) # artifacts_file :text +# gl_project_id :integer # require 'spec_helper' diff --git a/spec/models/external_wiki_service_spec.rb b/spec/models/external_wiki_service_spec.rb index b198aa77526..d37978720bf 100644 --- a/spec/models/external_wiki_service_spec.rb +++ b/spec/models/external_wiki_service_spec.rb @@ -16,6 +16,7 @@ # merge_requests_events :boolean default(TRUE) # tag_push_events :boolean default(TRUE) # note_events :boolean default(TRUE), not null +# build_events :boolean default(FALSE), not null # require 'spec_helper' diff --git a/spec/models/generic_commit_status_spec.rb b/spec/models/generic_commit_status_spec.rb index d61c1c96bde..5b0883d8702 100644 --- a/spec/models/generic_commit_status_spec.rb +++ b/spec/models/generic_commit_status_spec.rb @@ -29,6 +29,7 @@ # target_url :string(255) # description :string(255) # artifacts_file :text +# gl_project_id :integer # require 'spec_helper' diff --git a/spec/models/group_spec.rb b/spec/models/group_spec.rb index ba5acceadff..3c995053eec 100644 --- a/spec/models/group_spec.rb +++ b/spec/models/group_spec.rb @@ -11,7 +11,6 @@ # type :string(255) # description :string(255) default(""), not null # avatar :string(255) -# public :boolean default(FALSE) # require 'spec_helper' diff --git a/spec/models/merge_request_spec.rb b/spec/models/merge_request_spec.rb index e0653a8327d..291e6200a5b 100644 --- a/spec/models/merge_request_spec.rb +++ b/spec/models/merge_request_spec.rb @@ -2,25 +2,28 @@ # # Table name: merge_requests # -# id :integer not null, primary key -# target_branch :string(255) not null -# source_branch :string(255) not null -# source_project_id :integer not null -# author_id :integer -# assignee_id :integer -# title :string(255) -# created_at :datetime -# updated_at :datetime -# milestone_id :integer -# state :string(255) -# merge_status :string(255) -# target_project_id :integer not null -# iid :integer -# description :text -# position :integer default(0) -# locked_at :datetime -# updated_by_id :integer -# merge_error :string(255) +# id :integer not null, primary key +# target_branch :string(255) not null +# source_branch :string(255) not null +# source_project_id :integer not null +# author_id :integer +# assignee_id :integer +# title :string(255) +# created_at :datetime +# updated_at :datetime +# milestone_id :integer +# state :string(255) +# merge_status :string(255) +# target_project_id :integer not null +# iid :integer +# description :text +# position :integer default(0) +# locked_at :datetime +# updated_by_id :integer +# merge_error :string(255) +# merge_params :text +# merge_when_build_succeeds :boolean default(FALSE), not null +# merge_user_id :integer # require 'spec_helper' diff --git a/spec/models/namespace_spec.rb b/spec/models/namespace_spec.rb index 4fa2d2bc4d2..e0b3290e416 100644 --- a/spec/models/namespace_spec.rb +++ b/spec/models/namespace_spec.rb @@ -11,7 +11,6 @@ # type :string(255) # description :string(255) default(""), not null # avatar :string(255) -# public :boolean default(FALSE) # require 'spec_helper' diff --git a/spec/models/project_spec.rb b/spec/models/project_spec.rb index 400bdf2d962..a3de23369e1 100644 --- a/spec/models/project_spec.rb +++ b/spec/models/project_spec.rb @@ -29,6 +29,13 @@ # import_source :string(255) # commit_count :integer default(0) # import_error :text +# ci_id :integer +# builds_enabled :boolean default(TRUE), not null +# shared_runners_enabled :boolean default(TRUE), not null +# runners_token :string +# build_coverage_regex :string +# build_allow_git_fetch :boolean default(TRUE), not null +# build_timeout :integer default(3600), not null # require 'spec_helper' diff --git a/spec/models/service_spec.rb b/spec/models/service_spec.rb index 0ca82365b98..173628c08d0 100644 --- a/spec/models/service_spec.rb +++ b/spec/models/service_spec.rb @@ -16,6 +16,7 @@ # merge_requests_events :boolean default(TRUE) # tag_push_events :boolean default(TRUE) # note_events :boolean default(TRUE), not null +# build_events :boolean default(FALSE), not null # require 'spec_helper' diff --git a/spec/models/user_spec.rb b/spec/models/user_spec.rb index a16161e673e..3cd63b2b0e8 100644 --- a/spec/models/user_spec.rb +++ b/spec/models/user_spec.rb @@ -2,62 +2,63 @@ # # Table name: users # -# id :integer not null, primary key -# email :string(255) default(""), not null -# encrypted_password :string(255) default(""), not null -# reset_password_token :string(255) -# reset_password_sent_at :datetime -# remember_created_at :datetime -# sign_in_count :integer default(0) -# current_sign_in_at :datetime -# last_sign_in_at :datetime -# current_sign_in_ip :string(255) -# last_sign_in_ip :string(255) -# created_at :datetime -# updated_at :datetime -# name :string(255) -# admin :boolean default(FALSE), not null -# projects_limit :integer default(10) -# skype :string(255) default(""), not null -# linkedin :string(255) default(""), not null -# twitter :string(255) default(""), not null -# authentication_token :string(255) -# theme_id :integer default(1), not null -# bio :string(255) -# failed_attempts :integer default(0) -# locked_at :datetime -# unlock_token :string(255) -# username :string(255) -# can_create_group :boolean default(TRUE), not null -# can_create_team :boolean default(TRUE), not null -# state :string(255) -# color_scheme_id :integer default(1), not null -# notification_level :integer default(1), not null -# password_expires_at :datetime -# created_by_id :integer -# last_credential_check_at :datetime -# avatar :string(255) -# confirmation_token :string(255) -# confirmed_at :datetime -# confirmation_sent_at :datetime -# unconfirmed_email :string(255) -# hide_no_ssh_key :boolean default(FALSE) -# website_url :string(255) default(""), not null -# notification_email :string(255) -# hide_no_password :boolean default(FALSE) -# password_automatically_set :boolean default(FALSE) -# location :string(255) -# encrypted_otp_secret :string(255) -# encrypted_otp_secret_iv :string(255) -# encrypted_otp_secret_salt :string(255) -# otp_required_for_login :boolean default(FALSE), not null -# otp_backup_codes :text -# public_email :string(255) default(""), not null -# dashboard :integer default(0) -# project_view :integer default(0) -# consumed_timestep :integer -# layout :integer default(0) -# hide_project_limit :boolean default(FALSE) +# id :integer not null, primary key +# email :string(255) default(""), not null +# encrypted_password :string(255) default(""), not null +# reset_password_token :string(255) +# reset_password_sent_at :datetime +# remember_created_at :datetime +# sign_in_count :integer default(0) +# current_sign_in_at :datetime +# last_sign_in_at :datetime +# current_sign_in_ip :string(255) +# last_sign_in_ip :string(255) +# created_at :datetime +# updated_at :datetime +# name :string(255) +# admin :boolean default(FALSE), not null +# projects_limit :integer default(10) +# skype :string(255) default(""), not null +# linkedin :string(255) default(""), not null +# twitter :string(255) default(""), not null +# authentication_token :string(255) +# theme_id :integer default(1), not null +# bio :string(255) +# failed_attempts :integer default(0) +# locked_at :datetime +# username :string(255) +# can_create_group :boolean default(TRUE), not null +# can_create_team :boolean default(TRUE), not null +# state :string(255) +# color_scheme_id :integer default(1), not null +# notification_level :integer default(1), not null +# password_expires_at :datetime +# created_by_id :integer +# last_credential_check_at :datetime +# avatar :string(255) +# confirmation_token :string(255) +# confirmed_at :datetime +# confirmation_sent_at :datetime +# unconfirmed_email :string(255) +# hide_no_ssh_key :boolean default(FALSE) +# website_url :string(255) default(""), not null +# notification_email :string(255) +# hide_no_password :boolean default(FALSE) +# password_automatically_set :boolean default(FALSE) +# location :string(255) +# encrypted_otp_secret :string(255) +# encrypted_otp_secret_iv :string(255) +# encrypted_otp_secret_salt :string(255) +# otp_required_for_login :boolean default(FALSE), not null +# otp_backup_codes :text +# public_email :string(255) default(""), not null +# dashboard :integer default(0) +# project_view :integer default(0) +# consumed_timestep :integer +# layout :integer default(0) +# hide_project_limit :boolean default(FALSE) +# unlock_token :string +# otp_grace_period_started_at :datetime # require 'spec_helper' -- cgit v1.2.1 From da53fcba2d0e46e47a8fd6a79591a6367e863d57 Mon Sep 17 00:00:00 2001 From: Janis Meybohm Date: Wed, 23 Dec 2015 11:17:25 +0100 Subject: Enable Microsoft Azure OAuth2 support --- CHANGELOG | 1 + Gemfile | 1 + Gemfile.lock | 5 ++ app/assets/images/auth_buttons/azure_64.png | Bin 0 -> 986 bytes app/helpers/auth_helper.rb | 2 +- doc/integration/azure.md | 83 ++++++++++++++++++++++++++++ doc/integration/omniauth.md | 1 + 7 files changed, 92 insertions(+), 1 deletion(-) create mode 100644 app/assets/images/auth_buttons/azure_64.png create mode 100644 doc/integration/azure.md diff --git a/CHANGELOG b/CHANGELOG index cd745d3746a..8ee32013772 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -20,6 +20,7 @@ v 8.4.0 (unreleased) - Fix API project lookups when querying with a namespace with dots (Stan Hu) - Update version check images to use SVG - Validate README format before displaying + - Enable Microsoft Azure OAuth2 support (Janis Meybohm) v 8.3.3 (unreleased) - Fix project transfer e-mail sending incorrect paths in e-mail notification (Stan Hu) diff --git a/Gemfile b/Gemfile index 3ce4ba4a2a5..6145745b6f3 100644 --- a/Gemfile +++ b/Gemfile @@ -33,6 +33,7 @@ gem 'omniauth-saml', '~> 1.4.0' gem 'omniauth-shibboleth', '~> 1.2.0' gem 'omniauth-twitter', '~> 1.2.0' gem 'omniauth_crowd' +gem 'omniauth-azure-oauth2' gem 'rack-oauth2', '~> 1.2.1' # reCAPTCHA protection diff --git a/Gemfile.lock b/Gemfile.lock index ffb7cef0aba..2b42f325503 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -488,6 +488,10 @@ GEM activesupport nokogiri (>= 1.4.4) omniauth (~> 1.0) + omniauth-azure-oauth2 (0.0.6) + jwt (~> 1.0) + omniauth (~> 1.0) + omniauth-oauth2 (~> 1.1) opennebula (4.14.2) json nokogiri @@ -927,6 +931,7 @@ DEPENDENCIES omniauth-shibboleth (~> 1.2.0) omniauth-twitter (~> 1.2.0) omniauth_crowd + omniauth-azure-oauth2 org-ruby (~> 0.9.12) paranoia (~> 2.0) pg (~> 0.18.2) diff --git a/app/assets/images/auth_buttons/azure_64.png b/app/assets/images/auth_buttons/azure_64.png new file mode 100644 index 00000000000..a82c751e001 Binary files /dev/null and b/app/assets/images/auth_buttons/azure_64.png differ diff --git a/app/helpers/auth_helper.rb b/app/helpers/auth_helper.rb index 0cfc0565e84..de669e529a7 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 facebook).freeze + PROVIDERS_WITH_ICONS = %w(twitter github gitlab bitbucket google_oauth2 facebook azure_oauth2).freeze FORM_BASED_PROVIDERS = [/\Aldap/, 'crowd'].freeze def ldap_enabled? diff --git a/doc/integration/azure.md b/doc/integration/azure.md new file mode 100644 index 00000000000..48dddf7df44 --- /dev/null +++ b/doc/integration/azure.md @@ -0,0 +1,83 @@ +# Microsoft Azure OAuth2 OmniAuth Provider + +To enable the Microsoft Azure OAuth2 OmniAuth provider you must register your application with Azure. Azure will generate a client ID and secret key for you to use. + +1. Sign in to the [Azure Management Portal](https://manage.windowsazure.com>). + +1. Select "Active Directory" on the left and choose the directory you want to use to register GitLab. + +1. Select "Applications" at the top bar and click the "Add" button the bottom. + +1. Select "Add an application my organization is developing". + +1. Provide the project information and click the "Next" button. + - Name: 'GitLab' works just fine here. + - Type: 'WEB APPLICATION AND/OR WEB API' + +1. On the "App properties" page enter the needed URI's and click the "Complete" button. + - SIGN-IN URL: Enter the URL of your GitLab installation (e.g 'https://gitlab.mycompany.com/') + - APP ID URI: Enter the endpoint URL for Microsoft to use, just has to be unique (e.g 'https://mycompany.onmicrosoft.com/gitlab') + +1. Select "Configure" in the top menu. + +1. Add a "Reply URL" pointing to the Azure OAuth callback of your GitLab installation (e.g. https://gitlab.mycompany.com/users/auth/azure_oauth2/callback). + +1. Create a "Client secret" by selecting a duration, the secret will be generated as soon as you click the "Save" button in the bottom menu.. + +1. Note the "CLIENT ID" and the "CLIENT SECRET". + +1. Select "View endpoints" from the bottom menu. + +1. You will see lots of endpoint URLs in the form 'https://login.microsoftonline.com/TENANT ID/...', note down the TENANT ID part of one of those endpoints. + +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" => "azure_oauth2", + "args" => { + "client_id" => "CLIENT ID", + "client_secret" => "CLIENT SECRET", + "tenant_id" => "TENANT ID", + } + } + ] + ``` + + For installations from source: + + ``` + - { name: 'azure_oauth2', + args: { client_id: "CLIENT ID", + client_secret: "CLIENT SECRET", + tenant_id: "TENANT ID" } } + ``` + +1. Replace 'CLIENT ID', 'CLIENT SECRET' and 'TENANT ID' with the values you got above. + +1. Save the configuration file. + +1. Restart GitLab for the changes to take effect. + +On the sign in page there should now be a Microsoft icon below the regular sign in form. Click the icon to begin the authentication process. Microsoft 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/omniauth.md b/doc/integration/omniauth.md index f2b1721fc03..e9e17eb4165 100644 --- a/doc/integration/omniauth.md +++ b/doc/integration/omniauth.md @@ -78,6 +78,7 @@ Now we can choose one or more of the Supported Providers below to continue confi - [Shibboleth](shibboleth.md) - [SAML](saml.md) - [Crowd](crowd.md) +- [Azure](azure.md) ## Enable OmniAuth for an Existing User -- cgit v1.2.1 From fe19169836e1d7855d0ad5351b3f666dce8fcda1 Mon Sep 17 00:00:00 2001 From: Jeroen Nijhof Date: Wed, 6 Jan 2016 15:51:10 +0100 Subject: Use panel-default and .form-actions --- app/views/projects/edit.html.haml | 24 +++++++++++++----------- 1 file changed, 13 insertions(+), 11 deletions(-) diff --git a/app/views/projects/edit.html.haml b/app/views/projects/edit.html.haml index ef758b5fb7a..31e752c6649 100644 --- a/app/views/projects/edit.html.haml +++ b/app/views/projects/edit.html.haml @@ -174,6 +174,19 @@ .danger-settings + .panel.panel-default + .panel-heading Housekeeping + .errors-holder + .panel-body + %p + Runs a number of housekeeping tasks within the current repository, + such as compressing file revisions and removing unreachable objects. + %br + + .form-actions + = link_to 'Housekeeping', housekeeping_namespace_project_path(@project.namespace, @project), + method: :post, class: "btn btn-default" + - if can? current_user, :archive_project, @project - if @project.archived? .panel.panel-success @@ -210,17 +223,6 @@ - else .nothing-here-block Only the project owner can archive a project - .panel.panel-default.panel.panel-warning - .panel-heading Housekeeping - .errors-holder - .panel-body - %p - Runs a number of housekeeping tasks within the current repository, - such as compressing file revisions and removing unreachable objects. - %br - = link_to 'Housekeeping', housekeeping_namespace_project_path(@project.namespace, @project), - method: :post, class: "btn btn-warning" - .panel.panel-default.panel.panel-warning .panel-heading Rename repository .errors-holder -- cgit v1.2.1 From 0b2fa3bfa4bea00973ad6b8c3dfb8302d84fe4de Mon Sep 17 00:00:00 2001 From: Jose Corcuera Date: Wed, 6 Jan 2016 09:54:43 -0500 Subject: Fix problem with projects ending with .keys #3076 --- CHANGELOG | 1 + config/routes.rb | 6 +++--- spec/routing/project_routing_spec.rb | 1 + 3 files changed, 5 insertions(+), 3 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index cd745d3746a..c0b03a3ed31 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -12,6 +12,7 @@ v 8.4.0 (unreleased) - Add "Frequently used" category to emoji picker - Add CAS support (tduehr) - Add link to merge request on build detail page + - Fix: Problem with projects ending with .keys (Jose Corcuera) - Revert back upvote and downvote button to the issue and MR pages - Swap position of Assignee and Author selector on Issuables (Zeger-Jan van de Weg) - Add system hook messages for project rename and transfer (Steve Norman) diff --git a/config/routes.rb b/config/routes.rb index 3e7d9f78710..d7a9df10eba 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -52,9 +52,6 @@ Rails.application.routes.draw do API::API.logger Rails.logger mount API::API => '/api' - # Get all keys of user - get ':username.keys' => 'profiles/keys#get_keys' , constraints: { username: /.*/ } - constraint = lambda { |request| request.env['warden'].authenticate? and request.env['warden'].user.admin? } constraints constraint do mount Sidekiq::Web, at: '/admin/sidekiq', as: :sidekiq @@ -668,5 +665,8 @@ Rails.application.routes.draw do end end + # Get all keys of user + get ':username.keys' => 'profiles/keys#get_keys' , constraints: { username: /.*/ } + get ':id' => 'namespaces#show', constraints: { id: /(?:[^.]|\.(?!atom$))+/, format: /atom/ } end diff --git a/spec/routing/project_routing_spec.rb b/spec/routing/project_routing_spec.rb index 82f62a8709c..f0f0fbe619c 100644 --- a/spec/routing/project_routing_spec.rb +++ b/spec/routing/project_routing_spec.rb @@ -80,6 +80,7 @@ describe ProjectsController, 'routing' do it 'to #show' do expect(get('/gitlab/gitlabhq')).to route_to('projects#show', namespace_id: 'gitlab', id: 'gitlabhq') + expect(get('/gitlab/gitlabhq.keys')).to route_to('projects#show', namespace_id: 'gitlab', id: 'gitlabhq.keys') end it 'to #update' do -- cgit v1.2.1 From bde76f62fc2bd259dcc37ca649a01a84035ddcd9 Mon Sep 17 00:00:00 2001 From: Jeroen Nijhof Date: Wed, 6 Jan 2016 15:57:49 +0100 Subject: Added CHANGELOG for housekeeping and changed GITLAB_SHELL_VERSION to 2.6.10 --- CHANGELOG | 1 + GITLAB_SHELL_VERSION | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/CHANGELOG b/CHANGELOG index cd745d3746a..394a25cfa06 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.4.0 (unreleased) + - Add housekeeping function to project settings page - Expire view caches when application settings change (e.g. Gravatar disabled) (Stan Hu) - Don't notify users twice if they are both project watchers and subscribers (Stan Hu) - Implement new UI for group page diff --git a/GITLAB_SHELL_VERSION b/GITLAB_SHELL_VERSION index d48d3702aed..a04abec9149 100644 --- a/GITLAB_SHELL_VERSION +++ b/GITLAB_SHELL_VERSION @@ -1 +1 @@ -2.6.9 +2.6.10 -- cgit v1.2.1 From 7549102bb727daecc51da84af39956b32fc41537 Mon Sep 17 00:00:00 2001 From: Yorick Peterse Date: Wed, 6 Jan 2016 15:30:02 +0100 Subject: Store SQL/view timings in milliseconds Transaction timings are also already stored in milliseconds, this keeps things consistent. --- lib/gitlab/metrics/subscribers/action_view.rb | 8 ++++++-- lib/gitlab/metrics/subscribers/active_record.rb | 6 +++++- spec/lib/gitlab/metrics/subscribers/action_view_spec.rb | 4 ++-- spec/lib/gitlab/metrics/subscribers/active_record_spec.rb | 2 +- 4 files changed, 14 insertions(+), 6 deletions(-) diff --git a/lib/gitlab/metrics/subscribers/action_view.rb b/lib/gitlab/metrics/subscribers/action_view.rb index 7c0105d543a..84d9e383625 100644 --- a/lib/gitlab/metrics/subscribers/action_view.rb +++ b/lib/gitlab/metrics/subscribers/action_view.rb @@ -19,7 +19,7 @@ module Gitlab values = values_for(event) tags = tags_for(event) - current_transaction.increment(:view_duration, event.duration) + current_transaction.increment(:view_duration, duration(event)) current_transaction.add_metric(SERIES, values, tags) end @@ -28,7 +28,7 @@ module Gitlab end def values_for(event) - { duration: event.duration } + { duration: duration(event) } end def tags_for(event) @@ -48,6 +48,10 @@ module Gitlab def current_transaction Transaction.current end + + def duration(event) + event.duration * 1000.0 + end end end end diff --git a/lib/gitlab/metrics/subscribers/active_record.rb b/lib/gitlab/metrics/subscribers/active_record.rb index 8008b3bc895..6fa73e7a3be 100644 --- a/lib/gitlab/metrics/subscribers/active_record.rb +++ b/lib/gitlab/metrics/subscribers/active_record.rb @@ -8,7 +8,7 @@ module Gitlab def sql(event) return unless current_transaction - current_transaction.increment(:sql_duration, event.duration) + current_transaction.increment(:sql_duration, duration(event)) end private @@ -16,6 +16,10 @@ module Gitlab def current_transaction Transaction.current end + + def duration(event) + event.duration * 1000.0 + end end end end diff --git a/spec/lib/gitlab/metrics/subscribers/action_view_spec.rb b/spec/lib/gitlab/metrics/subscribers/action_view_spec.rb index 05e4fbbeb51..0a4cc5e929b 100644 --- a/spec/lib/gitlab/metrics/subscribers/action_view_spec.rb +++ b/spec/lib/gitlab/metrics/subscribers/action_view_spec.rb @@ -21,7 +21,7 @@ describe Gitlab::Metrics::Subscribers::ActionView do describe '#render_template' do it 'tracks rendering of a template' do - values = { duration: 2.1 } + values = { duration: 2100 } tags = { view: 'app/views/x.html.haml', file: 'app/views/x.html.haml', @@ -29,7 +29,7 @@ describe Gitlab::Metrics::Subscribers::ActionView do } expect(transaction).to receive(:increment). - with(:view_duration, 2.1) + with(:view_duration, 2100) expect(transaction).to receive(:add_metric). with(described_class::SERIES, values, tags) diff --git a/spec/lib/gitlab/metrics/subscribers/active_record_spec.rb b/spec/lib/gitlab/metrics/subscribers/active_record_spec.rb index 7bc070a4d09..ca86142a2f4 100644 --- a/spec/lib/gitlab/metrics/subscribers/active_record_spec.rb +++ b/spec/lib/gitlab/metrics/subscribers/active_record_spec.rb @@ -26,7 +26,7 @@ describe Gitlab::Metrics::Subscribers::ActiveRecord do and_return(transaction) expect(transaction).to receive(:increment). - with(:sql_duration, 0.2) + with(:sql_duration, 200) subscriber.sql(event) end -- cgit v1.2.1 From 8fdc00bd4c59183a20a60a6b93228268230bbd2e Mon Sep 17 00:00:00 2001 From: Yorick Peterse Date: Wed, 6 Jan 2016 17:49:02 +0100 Subject: Remove InfluxDB username/password InfluxDB over UDP doesn't use authentication, thus there's no need for these settings. --- .../admin/application_settings_controller.rb | 2 -- app/views/admin/application_settings/_form.html.haml | 8 -------- .../20160106164438_remove_influxdb_credentials.rb | 6 ++++++ db/schema.rb | 20 +++++++++----------- lib/gitlab/metrics.rb | 6 +----- 5 files changed, 16 insertions(+), 26 deletions(-) create mode 100644 db/migrate/20160106164438_remove_influxdb_credentials.rb diff --git a/app/controllers/admin/application_settings_controller.rb b/app/controllers/admin/application_settings_controller.rb index 10e736fd362..44d06b6a647 100644 --- a/app/controllers/admin/application_settings_controller.rb +++ b/app/controllers/admin/application_settings_controller.rb @@ -70,8 +70,6 @@ class Admin::ApplicationSettingsController < Admin::ApplicationController :metrics_enabled, :metrics_host, :metrics_port, - :metrics_username, - :metrics_password, :metrics_pool_size, :metrics_timeout, :metrics_method_call_threshold, diff --git a/app/views/admin/application_settings/_form.html.haml b/app/views/admin/application_settings/_form.html.haml index 89b38a0dad0..81337432ab7 100644 --- a/app/views/admin/application_settings/_form.html.haml +++ b/app/views/admin/application_settings/_form.html.haml @@ -179,14 +179,6 @@ your server configuration specifies a database to store data in when sending messages to this port, without it metrics data will not be saved. - .form-group - = f.label :metrics_username, 'InfluxDB username', class: 'control-label col-sm-2' - .col-sm-10 - = f.text_field :metrics_username, class: 'form-control' - .form-group - = f.label :metrics_password, 'InfluxDB password', class: 'control-label col-sm-2' - .col-sm-10 - = f.text_field :metrics_password, class: 'form-control' .form-group = f.label :metrics_pool_size, 'Connection pool size', class: 'control-label col-sm-2' .col-sm-10 diff --git a/db/migrate/20160106164438_remove_influxdb_credentials.rb b/db/migrate/20160106164438_remove_influxdb_credentials.rb new file mode 100644 index 00000000000..47e74400b97 --- /dev/null +++ b/db/migrate/20160106164438_remove_influxdb_credentials.rb @@ -0,0 +1,6 @@ +class RemoveInfluxdbCredentials < ActiveRecord::Migration + def change + remove_column :application_settings, :metrics_username, :string + remove_column :application_settings, :metrics_password, :string + end +end diff --git a/db/schema.rb b/db/schema.rb index 48e6983684a..2ded8a45e18 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: 20151229112614) do +ActiveRecord::Schema.define(version: 20160106164438) do # These are extensions that must be enabled in order to support this database enable_extension "plpgsql" @@ -50,16 +50,14 @@ ActiveRecord::Schema.define(version: 20151229112614) do t.boolean "shared_runners_enabled", default: true, null: false t.integer "max_artifacts_size", default: 100, null: false t.string "runners_registration_token" - t.boolean "require_two_factor_authentication", default: false - t.integer "two_factor_grace_period", default: 48 - t.boolean "metrics_enabled", default: false - t.string "metrics_host", default: "localhost" - t.string "metrics_username" - t.string "metrics_password" - t.integer "metrics_pool_size", default: 16 - t.integer "metrics_timeout", default: 10 - t.integer "metrics_method_call_threshold", default: 10 - t.boolean "recaptcha_enabled", default: false + t.boolean "require_two_factor_authentication", default: false + t.integer "two_factor_grace_period", default: 48 + t.boolean "metrics_enabled", default: false + t.string "metrics_host", default: "localhost" + t.integer "metrics_pool_size", default: 16 + t.integer "metrics_timeout", default: 10 + t.integer "metrics_method_call_threshold", default: 10 + t.boolean "recaptcha_enabled", default: false t.string "recaptcha_site_key" t.string "recaptcha_private_key" t.integer "metrics_port", default: 8089 diff --git a/lib/gitlab/metrics.rb b/lib/gitlab/metrics.rb index ee88ab34d6c..44356a0e42c 100644 --- a/lib/gitlab/metrics.rb +++ b/lib/gitlab/metrics.rb @@ -13,8 +13,6 @@ module Gitlab timeout: current_application_settings[:metrics_timeout], method_call_threshold: current_application_settings[:metrics_method_call_threshold], host: current_application_settings[:metrics_host], - username: current_application_settings[:metrics_username], - password: current_application_settings[:metrics_password], port: current_application_settings[:metrics_port] } end @@ -90,12 +88,10 @@ module Gitlab if enabled? @pool = ConnectionPool.new(size: settings[:pool_size], timeout: settings[:timeout]) do host = settings[:host] - user = settings[:username] - pw = settings[:password] port = settings[:port] InfluxDB::Client. - new(udp: { host: host, port: port }, username: user, password: pw) + new(udp: { host: host, port: port }) end end end -- cgit v1.2.1 From 12e32224c17253f9616cd05d0bce806881fa8db9 Mon Sep 17 00:00:00 2001 From: Achilleas Pipinellis Date: Wed, 6 Jan 2016 20:05:22 +0100 Subject: Add documentation on enabling/disabling GitLab CI [ci skip] --- doc/README.md | 1 + doc/ci/README.md | 1 + doc/ci/enable_or_disable_ci.md | 70 +++++++++++++++++++++++++++++++++++++++ doc/ci/img/features_settings.png | Bin 0 -> 18691 bytes 4 files changed, 72 insertions(+) create mode 100644 doc/ci/enable_or_disable_ci.md create mode 100644 doc/ci/img/features_settings.png diff --git a/doc/README.md b/doc/README.md index f4553a899d3..25fe3abcb9a 100644 --- a/doc/README.md +++ b/doc/README.md @@ -19,6 +19,7 @@ ## CI Documentation - [Quick Start](ci/quick_start/README.md) +- [Enable or disable GitLab CI](ci/enable_or_disable_ci.md) - [Configuring project (.gitlab-ci.yml)](ci/yaml/README.md) - [Configuring runner](ci/runners/README.md) - [Configuring deployment](ci/deployment/README.md) diff --git a/doc/ci/README.md b/doc/ci/README.md index a1f5513d88e..4cdd2e1ad33 100644 --- a/doc/ci/README.md +++ b/doc/ci/README.md @@ -3,6 +3,7 @@ ### User documentation * [Quick Start](quick_start/README.md) +* [Enable or disable GitLab CI](enable_or_disable_ci.md) * [Configuring project (.gitlab-ci.yml)](yaml/README.md) * [Configuring runner](runners/README.md) * [Configuring deployment](deployment/README.md) diff --git a/doc/ci/enable_or_disable_ci.md b/doc/ci/enable_or_disable_ci.md new file mode 100644 index 00000000000..2803bb5f34a --- /dev/null +++ b/doc/ci/enable_or_disable_ci.md @@ -0,0 +1,70 @@ +## Enable or disable GitLab CI + +_To effectively use GitLab CI, you need a valid [`.gitlab-ci.yml`](yaml/README.md) +file present at the root directory of your project and a +[runner](runners/README.md) properly set up. You can read our +[quick start guide](quick_start/README.md) to get you started._ + +If you are using an external CI server like Jenkins or Drone CI, it is advised +to disable GitLab CI in order to not have any conflicts with the commits status +API. + +--- + +As of GitLab 8.2, GitLab CI is mainly exposed via the `/builds` page of a +project. Disabling GitLab CI in a project does not delete any previous builds. +In fact, the `/builds` page can still be accessed, although it's hidden from +the left sidebar menu. + +GitLab CI is enabled by default on new installations and can be disabled either +individually under each project's settings, or site wide by modifying the +settings in `gitlab.yml` and `gitlab.rb` for source and Omnibus installations +respectively. + +### Per project user setting + +The setting to enable or disable GitLab CI can be found with the name **Builds** +under the **Features** area of a project's settings along with **Issues**, +**Merge Requests**, **Wiki** and **Snippets**. Select or deselect the checkbox +and hit **Save** for the settings to take effect. + +![Features settings](img/features_settings.png) + +--- + +### Site wide administrator setting + +You can disable GitLab CI site wide, by modifying the settings in `gitlab.yml` +and `gitlab.rb` for source and Omnibus installations respectively. + +Two things to note. + +1. Disabling GitLab CI, will affect only newly created projects. Projects that + had it enabled prior this modification, will work as before. +1. Even if you disable GitLab CI, users will still be able to enable it in the + project's settings. + +--- + +For installations from source, open `gitlab.yml` with your editor and set +`builds` to `false`: + +```yaml +## Default project features settings +default_projects_features: + issues: true + merge_requests: true + wiki: true + snippets: false + builds: false +``` + +Save the file and restart GitLab: `sudo service gitlab restart`. + +For Omnibus installations, edit `/etc/gitlab/gitlab.rb` and add the line: + +``` +gitlab-rails['gitlab_default_projects_features_builds'] = false +``` + +Save the file and reconfigure GitLab: `sudo gitlab-ctl reconfigure`. diff --git a/doc/ci/img/features_settings.png b/doc/ci/img/features_settings.png new file mode 100644 index 00000000000..17aba5d14d8 Binary files /dev/null and b/doc/ci/img/features_settings.png differ -- cgit v1.2.1 From 7d013f7848ea46e68665a8efcd9d4453584945e1 Mon Sep 17 00:00:00 2001 From: Stan Hu Date: Wed, 6 Jan 2016 21:05:46 -0800 Subject: Fix missing date of month in network graph when commits span a month Closes #3635, #1383 --- CHANGELOG | 1 + app/assets/javascripts/branch-graph.js.coffee | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/CHANGELOG b/CHANGELOG index cd745d3746a..35577e21415 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.4.0 (unreleased) + - Fix missing date of month in network graph when commits span a month (Stan Hu) - Expire view caches when application settings change (e.g. Gravatar disabled) (Stan Hu) - Don't notify users twice if they are both project watchers and subscribers (Stan Hu) - Implement new UI for group page diff --git a/app/assets/javascripts/branch-graph.js.coffee b/app/assets/javascripts/branch-graph.js.coffee index 917228bd276..f2fd2a775a4 100644 --- a/app/assets/javascripts/branch-graph.js.coffee +++ b/app/assets/javascripts/branch-graph.js.coffee @@ -66,7 +66,7 @@ class @BranchGraph r.rect(40, 0, 30, @barHeight).attr fill: "#444" for day, mm in @days - if cuday isnt day[0] + if cuday isnt day[0] || cumonth isnt day[1] # Dates r.text(55, @offsetY + @unitTime * mm, day[0]) .attr( -- cgit v1.2.1 From a8e23bd1b5029fb04ecb22f9c60fe7a8f9d45091 Mon Sep 17 00:00:00 2001 From: Achilleas Pipinellis Date: Thu, 7 Jan 2016 10:10:46 +0100 Subject: Fix hyphenation typos [ci skip] --- doc/ci/enable_or_disable_ci.md | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/doc/ci/enable_or_disable_ci.md b/doc/ci/enable_or_disable_ci.md index 2803bb5f34a..9bd2f5aff22 100644 --- a/doc/ci/enable_or_disable_ci.md +++ b/doc/ci/enable_or_disable_ci.md @@ -17,11 +17,11 @@ In fact, the `/builds` page can still be accessed, although it's hidden from the left sidebar menu. GitLab CI is enabled by default on new installations and can be disabled either -individually under each project's settings, or site wide by modifying the +individually under each project's settings, or site-wide by modifying the settings in `gitlab.yml` and `gitlab.rb` for source and Omnibus installations respectively. -### Per project user setting +### Per-project user setting The setting to enable or disable GitLab CI can be found with the name **Builds** under the **Features** area of a project's settings along with **Issues**, @@ -32,15 +32,15 @@ and hit **Save** for the settings to take effect. --- -### Site wide administrator setting +### Site-wide administrator setting -You can disable GitLab CI site wide, by modifying the settings in `gitlab.yml` +You can disable GitLab CI site-wide, by modifying the settings in `gitlab.yml` and `gitlab.rb` for source and Omnibus installations respectively. -Two things to note. +Two things to note: -1. Disabling GitLab CI, will affect only newly created projects. Projects that - had it enabled prior this modification, will work as before. +1. Disabling GitLab CI, will affect only newly-created projects. Projects that + had it enabled prior to this modification, will work as before. 1. Even if you disable GitLab CI, users will still be able to enable it in the project's settings. -- cgit v1.2.1 From 8884505350c8594e663c5af6feb8eb1b06f3a0c8 Mon Sep 17 00:00:00 2001 From: koreamic Date: Sun, 13 Dec 2015 02:27:48 +0900 Subject: Add new feature to find file Using the fuzzy filter, develop "file finder" feature. - feedback(http://feedback.gitlab.com/forums/176466-general/suggestions/4987909-add-file-finder-fuzzy-input-in-files-tab-to-ju ) - fuzzy filter(https://github.com/jeancroy/fuzzaldrin-plus) - shortcuts(when "t" was hitted at tree view, go to 'file find' page and 'esc' is to go back) - depends on gitlab_git 7.2.22 --- CHANGELOG | 1 + Gemfile | 2 +- Gemfile.lock | 2 +- app/assets/javascripts/application.js.coffee | 1 + app/assets/javascripts/dispatcher.js.coffee | 4 +- app/assets/javascripts/project_find_file.js.coffee | 125 +++++++++++++++++++++ .../javascripts/shortcuts_find_file.js.coffee | 19 ++++ app/assets/javascripts/shortcuts_tree.coffee | 4 + app/assets/stylesheets/pages/tree.scss | 8 ++ app/controllers/projects/find_file_controller.rb | 26 +++++ app/controllers/projects/refs_controller.rb | 2 + app/models/repository.rb | 5 + app/views/help/_shortcuts.html.haml | 26 +++++ app/views/layouts/nav/_project.html.haml | 3 +- app/views/projects/_find_file_link.html.haml | 3 + app/views/projects/find_file/show.html.haml | 27 +++++ app/views/projects/tree/show.html.haml | 8 +- config/routes.rb | 18 +++ doc/workflow/shortcuts.png | Bin 78736 -> 48782 bytes features/project/find_file.feature | 42 +++++++ features/steps/project/project_find_file.rb | 73 ++++++++++++ features/steps/shared/paths.rb | 4 + .../projects/find_file_controller_spec.rb | 66 +++++++++++ spec/routing/project_routing_spec.rb | 12 ++ vendor/assets/javascripts/fuzzaldrin-plus.min.js | 1 + 25 files changed, 473 insertions(+), 9 deletions(-) create mode 100644 app/assets/javascripts/project_find_file.js.coffee create mode 100644 app/assets/javascripts/shortcuts_find_file.js.coffee create mode 100644 app/assets/javascripts/shortcuts_tree.coffee create mode 100644 app/controllers/projects/find_file_controller.rb create mode 100644 app/views/projects/_find_file_link.html.haml create mode 100644 app/views/projects/find_file/show.html.haml create mode 100644 features/project/find_file.feature create mode 100644 features/steps/project/project_find_file.rb create mode 100644 spec/controllers/projects/find_file_controller_spec.rb create mode 100644 vendor/assets/javascripts/fuzzaldrin-plus.min.js diff --git a/CHANGELOG b/CHANGELOG index e7f1d2b67da..22fb91baaf0 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -106,6 +106,7 @@ v 8.3.0 - Fix online editor should not remove newlines at the end of the file - Expose Git's version in the admin area - Show "New Merge Request" buttons on canonical repos when you have a fork (Josh Frye) + - Add file finder feature in tree view v 8.2.3 - Fix application settings cache not expiring after changes (Stan Hu) diff --git a/Gemfile b/Gemfile index 6145745b6f3..6b0bc241494 100644 --- a/Gemfile +++ b/Gemfile @@ -49,7 +49,7 @@ gem "browser", '~> 1.0.0' # Extracting information from a git repository # Provide access to Gitlab::Git library -gem "gitlab_git", '~> 7.2.20' +gem "gitlab_git", '~> 7.2.22' # LDAP Auth # GitLab fork with several improvements to original library. For full list of changes diff --git a/Gemfile.lock b/Gemfile.lock index 2b42f325503..a1168ed3b7a 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -887,7 +887,7 @@ DEPENDENCIES github-markup (~> 1.3.1) gitlab-flowdock-git-hook (~> 1.0.1) gitlab_emoji (~> 0.2.0) - gitlab_git (~> 7.2.20) + gitlab_git (~> 7.2.22) gitlab_meta (= 7.0) gitlab_omniauth-ldap (~> 1.2.1) gollum-lib (~> 4.1.0) diff --git a/app/assets/javascripts/application.js.coffee b/app/assets/javascripts/application.js.coffee index b9b095e004a..c095e5ae2b1 100644 --- a/app/assets/javascripts/application.js.coffee +++ b/app/assets/javascripts/application.js.coffee @@ -40,6 +40,7 @@ #= require shortcuts_network #= require jquery.nicescroll.min #= require_tree . +#= require fuzzaldrin-plus.min window.slugify = (text) -> text.replace(/[^-a-zA-Z0-9]+/g, '_').toLowerCase() diff --git a/app/assets/javascripts/dispatcher.js.coffee b/app/assets/javascripts/dispatcher.js.coffee index 69e061ce6e9..58d6b9d4060 100644 --- a/app/assets/javascripts/dispatcher.js.coffee +++ b/app/assets/javascripts/dispatcher.js.coffee @@ -87,7 +87,9 @@ class Dispatcher new GroupAvatar() when 'projects:tree:show' new TreeView() - shortcut_handler = new ShortcutsNavigation() + shortcut_handler = new ShortcutsTree() + when 'projects:find_file:show' + shortcut_handler = true when 'projects:blob:show' new LineHighlighter() shortcut_handler = new ShortcutsNavigation() diff --git a/app/assets/javascripts/project_find_file.js.coffee b/app/assets/javascripts/project_find_file.js.coffee new file mode 100644 index 00000000000..0dd32352c34 --- /dev/null +++ b/app/assets/javascripts/project_find_file.js.coffee @@ -0,0 +1,125 @@ +class @ProjectFindFile + constructor: (@element, @options)-> + @filePaths = {} + @inputElement = @element.find(".file-finder-input") + + # init event + @initEvent() + + # focus text input box + @inputElement.focus() + + # load file list + @load(@options.url) + + # init event + initEvent: -> + @inputElement.off "keyup" + @inputElement.on "keyup", (event) => + target = $(event.target) + value = target.val() + oldValue = target.data("oldValue") ? "" + + if value != oldValue + target.data("oldValue", value) + @findFile() + @element.find("tr.tree-item").eq(0).addClass("selected").focus() + + @element.find(".tree-content-holder .tree-table").on "click", (event) -> + if (event.target.nodeName != "A") + path = @element.find(".tree-item-file-name a", this).attr("href") + location.href = path if path + + # find file + findFile: -> + searchText = @inputElement.val() + result = if searchText.length > 0 then fuzzaldrinPlus.filter(@filePaths, searchText) else @filePaths + @renderList result, searchText + + # files pathes load + load: (url) -> + $.ajax + url: url + method: "get" + dataType: "json" + success: (data) => + @element.find(".loading").hide() + @filePaths = data + @findFile() + @element.find(".files-slider tr.tree-item").eq(0).addClass("selected").focus() + + # render result + renderList: (filePaths, searchText) -> + @element.find(".tree-table > tbody").empty() + + for filePath, i in filePaths + break if i == 20 + + if searchText + matches = fuzzaldrinPlus.match(filePath, searchText) + + blobItemUrl = "#{@options.blobUrlTemplate}/#{filePath}" + + html = @makeHtml filePath, matches, blobItemUrl + @element.find(".tree-table > tbody").append(html) + + # highlight text(awefwbwgtc -> awefwbwgtc ) + highlighter = (element, text, matches) -> + lastIndex = 0 + highlightText = "" + matchedChars = [] + + for matchIndex in matches + unmatched = text.substring(lastIndex, matchIndex) + + if unmatched + element.append(matchedChars.join("").bold()) if matchedChars.length + matchedChars = [] + element.append(document.createTextNode(unmatched)) + + matchedChars.push(text[matchIndex]) + lastIndex = matchIndex + 1 + + element.append(matchedChars.join("").bold()) if matchedChars.length + element.append(document.createTextNode(text.substring(lastIndex))) + + # make tbody row html + makeHtml: (filePath, matches, blobItemUrl) -> + $tr = $("") + if matches + $tr.find("a").replaceWith(highlighter($tr.find("a"), filePath, matches).attr("href", blobItemUrl)) + else + $tr.find("a").attr("href", blobItemUrl).text(filePath) + + return $tr + + selectRow: (type) -> + rows = @element.find(".files-slider tr.tree-item") + selectedRow = @element.find(".files-slider tr.tree-item.selected") + + if rows && rows.length > 0 + if selectedRow && selectedRow.length > 0 + if type == "UP" + next = selectedRow.prev() + else if type == "DOWN" + next = selectedRow.next() + + if next.length > 0 + selectedRow.removeClass "selected" + selectedRow = next + else + selectedRow = rows.eq(0) + selectedRow.addClass("selected").focus() + + selectRowUp: => + @selectRow "UP" + + selectRowDown: => + @selectRow "DOWN" + + goToTree: => + location.href = @options.treeUrl + + goToBlob: => + path = @element.find(".tree-item.selected .tree-item-file-name a").attr("href") + location.href = path if path diff --git a/app/assets/javascripts/shortcuts_find_file.js.coffee b/app/assets/javascripts/shortcuts_find_file.js.coffee new file mode 100644 index 00000000000..311e80bae19 --- /dev/null +++ b/app/assets/javascripts/shortcuts_find_file.js.coffee @@ -0,0 +1,19 @@ +#= require shortcuts_navigation + +class @ShortcutsFindFile extends ShortcutsNavigation + constructor: (@projectFindFile) -> + super() + _oldStopCallback = Mousetrap.stopCallback + # override to fire shortcuts action when focus in textbox + Mousetrap.stopCallback = (event, element, combo) => + if element == @projectFindFile.inputElement[0] and (combo == 'up' or combo == 'down' or combo == 'esc' or combo == 'enter') + # when press up/down key in textbox, cusor prevent to move to home/end + event.preventDefault() + return false + + return _oldStopCallback(event, element, combo) + + Mousetrap.bind('up', @projectFindFile.selectRowUp) + Mousetrap.bind('down', @projectFindFile.selectRowDown) + Mousetrap.bind('esc', @projectFindFile.goToTree) + Mousetrap.bind('enter', @projectFindFile.goToBlob) diff --git a/app/assets/javascripts/shortcuts_tree.coffee b/app/assets/javascripts/shortcuts_tree.coffee new file mode 100644 index 00000000000..ba0839c9fc0 --- /dev/null +++ b/app/assets/javascripts/shortcuts_tree.coffee @@ -0,0 +1,4 @@ +class @ShortcutsTree extends ShortcutsNavigation + constructor: -> + super() + Mousetrap.bind('t', -> ShortcutsTree.findAndFollowLink('.shortcuts-find-file')) diff --git a/app/assets/stylesheets/pages/tree.scss b/app/assets/stylesheets/pages/tree.scss index d4ab6967ccd..97505edeabf 100644 --- a/app/assets/stylesheets/pages/tree.scss +++ b/app/assets/stylesheets/pages/tree.scss @@ -1,5 +1,13 @@ .tree-holder { + .file-finder { + width: 50%; + .file-finder-input { + width: 95%; + display: inline-block; + } + } + .tree-table { margin-bottom: 0; diff --git a/app/controllers/projects/find_file_controller.rb b/app/controllers/projects/find_file_controller.rb new file mode 100644 index 00000000000..54a0c447aee --- /dev/null +++ b/app/controllers/projects/find_file_controller.rb @@ -0,0 +1,26 @@ +# Controller for viewing a repository's file structure +class Projects::FindFileController < Projects::ApplicationController + include ExtractsPath + include ActionView::Helpers::SanitizeHelper + include TreeHelper + + before_action :require_non_empty_project + before_action :assign_ref_vars + before_action :authorize_download_code! + + def show + return render_404 unless @repository.commit(@ref) + + respond_to do |format| + format.html + end + end + + def list + file_paths = @repo.ls_files(@ref) + + respond_to do |format| + format.json { render json: file_paths } + end + end +end diff --git a/app/controllers/projects/refs_controller.rb b/app/controllers/projects/refs_controller.rb index c4e18c17077..a8f091819ca 100644 --- a/app/controllers/projects/refs_controller.rb +++ b/app/controllers/projects/refs_controller.rb @@ -20,6 +20,8 @@ class Projects::RefsController < Projects::ApplicationController namespace_project_network_path(@project.namespace, @project, @id, @options) when "graphs" namespace_project_graph_path(@project.namespace, @project, @id) + when "find_file" + namespace_project_find_file_path(@project.namespace, @project, @id) when "graphs_commits" commits_namespace_project_graph_path(@project.namespace, @project, @id) else diff --git a/app/models/repository.rb b/app/models/repository.rb index 6ecd2d2f27e..9deb08d93b8 100644 --- a/app/models/repository.rb +++ b/app/models/repository.rb @@ -681,6 +681,11 @@ class Repository end end + def ls_files(ref) + actual_ref = ref || root_ref + raw_repository.ls_files(actual_ref) + end + private def cache diff --git a/app/views/help/_shortcuts.html.haml b/app/views/help/_shortcuts.html.haml index e8e331dd109..9ee6f07b26b 100644 --- a/app/views/help/_shortcuts.html.haml +++ b/app/views/help/_shortcuts.html.haml @@ -40,6 +40,32 @@ %td.shortcut .key enter %td Open Selection + %tr + %td.shortcut + .key t + %td Go to finding file + %tbody + %tr + %th + %th Finding Project File + %tr + %td.shortcut + .key + %i.fa.fa-arrow-up + %td Move selection up + %tr + %td.shortcut + .key + %i.fa.fa-arrow-down + %td Move selection down + %tr + %td.shortcut + .key enter + %td Open Selection + %tr + %td.shortcut + .key esc + %td Go back .col-lg-4 %table.shortcut-mappings diff --git a/app/views/layouts/nav/_project.html.haml b/app/views/layouts/nav/_project.html.haml index d3eaf0f3209..270ccfd387f 100644 --- a/app/views/layouts/nav/_project.html.haml +++ b/app/views/layouts/nav/_project.html.haml @@ -25,7 +25,7 @@ %span Activity - if project_nav_tab? :files - = nav_link(controller: %w(tree blob blame edit_tree new_tree)) do + = nav_link(controller: %w(tree blob blame edit_tree new_tree find_file)) do = link_to project_files_path(@project), title: 'Files', class: 'shortcuts-tree' do = icon('files-o fw') %span @@ -117,4 +117,3 @@ %li.hidden = link_to namespace_project_network_path(@project.namespace, @project, current_ref), title: 'Network', class: 'shortcuts-network' do Network - diff --git a/app/views/projects/_find_file_link.html.haml b/app/views/projects/_find_file_link.html.haml new file mode 100644 index 00000000000..08e2fc48be7 --- /dev/null +++ b/app/views/projects/_find_file_link.html.haml @@ -0,0 +1,3 @@ += link_to namespace_project_find_file_path(@project.namespace, @project, @ref), class: 'btn btn-grouped shortcuts-find-file', rel: 'nofollow' do + = icon('search') + %span Find File diff --git a/app/views/projects/find_file/show.html.haml b/app/views/projects/find_file/show.html.haml new file mode 100644 index 00000000000..2930209fb56 --- /dev/null +++ b/app/views/projects/find_file/show.html.haml @@ -0,0 +1,27 @@ +- page_title "Find File", @ref +- header_title project_title(@project, "Files", project_files_path(@project)) + +.file-finder-holder.tree-holder.clearfix + .gray-content-block.top-block + .tree-ref-holder + = render 'shared/ref_switcher', destination: 'find_file', path: @path + %ul.breadcrumb.repo-breadcrumb + %li + = link_to namespace_project_tree_path(@project.namespace, @project, @ref) do + = @project.path + %li.file-finder + %input#file_find.form-control.file-finder-input{type: "text", placeholder: 'Find by path'} + + %div.tree-content-holder + .table-holder + %table.table.files-slider{class: "table_#{@hex_path} tree-table table-striped" } + %tbody + = spinner nil, true + +:coffeescript + projectFindFile = new ProjectFindFile($(".file-finder-holder"), { + url: "#{escape_javascript(namespace_project_files_path(@project.namespace, @project, @ref, @options.merge(format: :json)))}" + treeUrl: "#{escape_javascript(namespace_project_tree_path(@project.namespace, @project, @ref))}" + blobUrlTemplate: "#{escape_javascript(namespace_project_blob_path(@project.namespace, @project, @id || @commit.id))}" + }) + new ShortcutsFindFile(projectFindFile) diff --git a/app/views/projects/tree/show.html.haml b/app/views/projects/tree/show.html.haml index ec14bd7f65a..c57570afa09 100644 --- a/app/views/projects/tree/show.html.haml +++ b/app/views/projects/tree/show.html.haml @@ -3,12 +3,12 @@ = content_for :meta_tags do - if current_user = auto_discovery_link_tag(:atom, namespace_project_commits_url(@project.namespace, @project, @ref, format: :atom, private_token: current_user.private_token), title: "#{@project.name}:#{@ref} commits") - = render 'projects/last_push' -- if can? current_user, :download_code, @project - .tree-download-holder - = render 'projects/repositories/download_archive', ref: @ref, btn_class: 'btn-group pull-right hidden-xs hidden-sm', split_button: true +.pull-right + = render 'projects/find_file_link' + - if can? current_user, :download_code, @project + = render 'projects/repositories/download_archive', ref: @ref, btn_class: 'hidden-xs hidden-sm btn-grouped', split_button: true #tree-holder.tree-holder.clearfix .gray-content-block.top-block diff --git a/config/routes.rb b/config/routes.rb index 3e7d9f78710..5b69d06eb76 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -440,6 +440,24 @@ Rails.application.routes.draw do ) end + scope do + get( + '/find_file/*id', + to: 'find_file#show', + constraints: { id: /.+/, format: /html/ }, + as: :find_file + ) + end + + scope do + get( + '/files/*id', + to: 'find_file#list', + constraints: { id: /(?:[^.]|\.(?!json$))+/, format: /json/ }, + as: :files + ) + end + scope do post( '/create_dir/*id', diff --git a/doc/workflow/shortcuts.png b/doc/workflow/shortcuts.png index 68756ed1f98..e5914aa8e67 100644 Binary files a/doc/workflow/shortcuts.png and b/doc/workflow/shortcuts.png differ diff --git a/features/project/find_file.feature b/features/project/find_file.feature new file mode 100644 index 00000000000..ae8fa245923 --- /dev/null +++ b/features/project/find_file.feature @@ -0,0 +1,42 @@ +@dashboard +Feature: Project Find File + Background: + Given I sign in as a user + And I own a project + And I visit my project's files page + + @javascript + Scenario: Navigate to find file by shortcut + Given I press "t" + Then I should see "find file" page + + Scenario: Navigate to find file + Given I click Find File button + Then I should see "find file" page + + @javascript + Scenario: I search file + Given I visit project find file page + And I fill in file find with "change" + Then I should not see ".gitignore" in files + And I should not see ".gitmodules" in files + And I should see "CHANGELOG" in files + And I should not see "VERSION" in files + + @javascript + Scenario: I search file that not exist + Given I visit project find file page + And I fill in file find with "asdfghjklqwertyuizxcvbnm" + Then I should not see ".gitignore" in files + And I should not see ".gitmodules" in files + And I should not see "CHANGELOG" in files + And I should not see "VERSION" in files + + @javascript + Scenario: I search file that partially matches + Given I visit project find file page + And I fill in file find with "git" + Then I should see ".gitignore" in files + And I should see ".gitmodules" in files + And I should not see "CHANGELOG" in files + And I should not see "VERSION" in files diff --git a/features/steps/project/project_find_file.rb b/features/steps/project/project_find_file.rb new file mode 100644 index 00000000000..8c1d09d6cc6 --- /dev/null +++ b/features/steps/project/project_find_file.rb @@ -0,0 +1,73 @@ +class Spinach::Features::ProjectFindFile < Spinach::FeatureSteps + include SharedAuthentication + include SharedPaths + include SharedProject + include SharedProjectTab + + step 'I press "t"' do + find('body').native.send_key('t') + end + + step 'I click Find File button' do + click_link 'Find File' + end + + step 'I should see "find file" page' do + ensure_active_main_tab('Files') + expect(page).to have_selector('.file-finder-holder', count: 1) + end + + step 'I fill in Find by path with "git"' do + ensure_active_main_tab('Files') + expect(page).to have_selector('.file-finder-holder', count: 1) + end + + step 'I fill in file find with "git"' do + find_file "git" + end + + step 'I fill in file find with "change"' do + find_file "change" + end + + step 'I fill in file find with "asdfghjklqwertyuizxcvbnm"' do + find_file "asdfghjklqwertyuizxcvbnm" + end + + step 'I should see "VERSION" in files' do + expect(page).to have_content("VERSION") + end + + step 'I should not see "VERSION" in files' do + expect(page).not_to have_content("VERSION") + end + + step 'I should see "CHANGELOG" in files' do + expect(page).to have_content("CHANGELOG") + end + + step 'I should not see "CHANGELOG" in files' do + expect(page).not_to have_content("CHANGELOG") + end + + step 'I should see ".gitmodules" in files' do + expect(page).to have_content(".gitmodules") + end + + step 'I should not see ".gitmodules" in files' do + expect(page).not_to have_content(".gitmodules") + end + + step 'I should see ".gitignore" in files' do + expect(page).to have_content(".gitignore") + end + + step 'I should not see ".gitignore" in files' do + expect(page).not_to have_content(".gitignore") + end + + + def find_file(text) + fill_in 'file_find', with: text + end +end diff --git a/features/steps/shared/paths.rb b/features/steps/shared/paths.rb index b33bd332655..4264c9c6f1a 100644 --- a/features/steps/shared/paths.rb +++ b/features/steps/shared/paths.rb @@ -259,6 +259,10 @@ module SharedPaths visit namespace_project_deploy_keys_path(@project.namespace, @project) end + step 'I visit project find file page' do + visit namespace_project_find_file_path(@project.namespace, @project, root_ref) + end + # ---------------------------------------- # "Shop" Project # ---------------------------------------- diff --git a/spec/controllers/projects/find_file_controller_spec.rb b/spec/controllers/projects/find_file_controller_spec.rb new file mode 100644 index 00000000000..038dfeb8466 --- /dev/null +++ b/spec/controllers/projects/find_file_controller_spec.rb @@ -0,0 +1,66 @@ +require 'spec_helper' + +describe Projects::FindFileController do + let(:project) { create(:project) } + let(:user) { create(:user) } + + before do + sign_in(user) + + project.team << [user, :master] + controller.instance_variable_set(:@project, project) + end + + describe "GET #show" do + # Make sure any errors accessing the tree in our views bubble up to this spec + render_views + + before do + get(:show, + namespace_id: project.namespace.to_param, + project_id: project.to_param, + id: id) + end + + context "valid branch" do + let(:id) { 'master' } + it { is_expected.to respond_with(:success) } + end + + context "invalid branch" do + let(:id) { 'invalid-branch' } + it { is_expected.to respond_with(:not_found) } + end + end + + describe "GET #list" do + def go(format: 'json') + get :list, + namespace_id: project.namespace.to_param, + project_id: project.to_param, + id: id, + format: format + end + + context "valid branch" do + let(:id) { 'master' } + it 'returns an array of file path list' do + go + + json = JSON.parse(response.body) + is_expected.to respond_with(:success) + expect(json).not_to eq(nil) + expect(json.length).to be >= 0 + end + end + + context "invalid branch" do + let(:id) { 'invalid-branch' } + + it 'responds with status 404' do + go + is_expected.to respond_with(:not_found) + end + end + end +end diff --git a/spec/routing/project_routing_spec.rb b/spec/routing/project_routing_spec.rb index 82f62a8709c..2a70c190337 100644 --- a/spec/routing/project_routing_spec.rb +++ b/spec/routing/project_routing_spec.rb @@ -434,6 +434,18 @@ describe Projects::TreeController, 'routing' do end end +# project_find_file GET /:namespace_id/:project_id/find_file/*id(.:format) projects/find_file#show {:id=>/.+/, :namespace_id=>/[a-zA-Z.0-9_\-]+/, :project_id=>/[a-zA-Z.0-9_\-]+(?/html/} +# project_files GET /:namespace_id/:project_id/files/*id(.:format) projects/find_file#list {:id=>/(?:[^.]|\.(?!json$))+/, :namespace_id=>/[a-zA-Z.0-9_\-]+/, :project_id=>/[a-zA-Z.0-9_\-]+(?/json/} +describe Projects::FindFileController, 'routing' do + it 'to #show' do + expect(get('/gitlab/gitlabhq/find_file/master')).to route_to('projects/find_file#show', namespace_id: 'gitlab', project_id: 'gitlabhq', id: 'master') + end + + it 'to #list' do + expect(get('/gitlab/gitlabhq/files/master.json')).to route_to('projects/find_file#list', namespace_id: 'gitlab', project_id: 'gitlabhq', id: 'master', format: 'json') + end +end + describe Projects::BlobController, 'routing' do it 'to #edit' do expect(get('/gitlab/gitlabhq/edit/master/app/models/project.rb')).to( diff --git a/vendor/assets/javascripts/fuzzaldrin-plus.min.js b/vendor/assets/javascripts/fuzzaldrin-plus.min.js new file mode 100644 index 00000000000..3f25c2d8373 --- /dev/null +++ b/vendor/assets/javascripts/fuzzaldrin-plus.min.js @@ -0,0 +1 @@ +(function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o0?maxInners:candidates.length;bAllowErrors=!!allowErrors;bKey=key!=null;prepQuery=scorer.prepQuery(query);if(!legacy){for(i=0,len=candidates.length;i0){scoredCandidates.push({candidate:candidate,score:score});if(!--spotLeft){break}}}}else{queryHasSlashes=prepQuery.depth>0;coreQuery=prepQuery.core;for(j=0,len1=candidates.length;j0){scoredCandidates.push({candidate:candidate,score:score})}}}scoredCandidates.sort(sortCandidates);candidates=scoredCandidates.map(pluckCandidates);if(maxResults!=null){candidates=candidates.slice(0,maxResults)}return candidates}}).call(this)},{"./legacy":4,"./scorer":6,"path":7}],2:[function(require,module,exports){(function(){var PathSeparator,filter,legacy_scorer,matcher,prepQueryCache,scorer;scorer=require('./scorer');legacy_scorer=require('./legacy');filter=require('./filter');matcher=require('./matcher');PathSeparator=require('path').sep;prepQueryCache=null;module.exports={filter:function(candidates,query,options){if(!((query!=null?query.length:void 0)&&(candidates!=null?candidates.length:void 0))){return[]}return filter(candidates,query,options)},prepQuery:function(query){return scorer.prepQuery(query)},score:function(string,query,prepQuery,arg){var allowErrors,coreQuery,legacy,queryHasSlashes,ref,score;ref=arg!=null?arg:{},allowErrors=ref.allowErrors,legacy=ref.legacy;if(!((string!=null?string.length:void 0)&&(query!=null?query.length:void 0))){return 0}if(prepQuery==null){prepQuery=prepQueryCache&&prepQueryCache.query===query?prepQueryCache:(prepQueryCache=scorer.prepQuery(query))}if(!legacy){score=scorer.score(string,query,prepQuery,!!allowErrors)}else{queryHasSlashes=prepQuery.depth>0;coreQuery=prepQuery.core;score=legacy_scorer.score(string,coreQuery,queryHasSlashes);if(!queryHasSlashes){score=legacy_scorer.basenameScore(string,coreQuery,score)}}return score},match:function(string,query,prepQuery,arg){var allowErrors,baseMatches,i,matches,query_lw,ref,results,string_lw;allowErrors=(arg!=null?arg:{}).allowErrors;if(!string){return[]}if(!query){return[]}if(string===query){return(function(){results=[];for(var i=0,ref=string.length;0<=ref?iref;0<=ref?i++:i--){results.push(i)}return results}).apply(this)}if(prepQuery==null){prepQuery=prepQueryCache&&prepQueryCache.query===query?prepQueryCache:(prepQueryCache=scorer.prepQuery(query))}if(!(allowErrors||scorer.isMatch(string,prepQuery.core_lw,prepQuery.core_up))){return[]}string_lw=string.toLowerCase();query_lw=prepQuery.query_lw;matches=matcher.match(string,string_lw,prepQuery);if(matches.length===0){return matches}if(string.indexOf(PathSeparator)>-1){baseMatches=matcher.basenameMatch(string,string_lw,prepQuery);matches=matcher.mergeMatches(matches,baseMatches)}return matches}}}).call(this)},{"./filter":1,"./legacy":4,"./matcher":5,"./scorer":6,"path":7}],3:[function(require,module,exports){fuzzaldrinPlus=require('./fuzzaldrin')},{"./fuzzaldrin":2}],4:[function(require,module,exports){(function(){var PathSeparator,queryIsLastPathSegment;PathSeparator=require('path').sep;exports.basenameScore=function(string,query,score){var base,depth,index,lastCharacter,segmentCount,slashCount;index=string.length-1;while(string[index]===PathSeparator){index--}slashCount=0;lastCharacter=index;base=null;while(index>=0){if(string[index]===PathSeparator){slashCount++;if(base==null){base=string.substring(index+1,lastCharacter+1)}}else if(index===0){if(lastCharacterref;stringOffset<=ref?i++:i--){results.push(i)}return results}).apply(this)}queryLength=query.length;stringLength=string.length;indexInQuery=0;indexInString=0;matches=[];while(indexInQuery0){basePos=subject.lastIndexOf(PathSeparator,basePos-1);if(basePos===-1){return[]}}basePos++;end++;return exports.match(subject.slice(basePos,end),subject_lw.slice(basePos,end),prepQuery,basePos)};exports.mergeMatches=function(a,b){var ai,bj,i,j,m,n,out;m=a.length;n=b.length;if(n===0){return a.slice()}if(m===0){return b.slice()}i=-1;j=0;bj=b[j];out=[];while(++i0?csc_diag:scorer.scoreConsecutives(subject,subject_lw,query,query_lw,i,j,start);align=score_diag+scorer.scoreCharacter(i,j,start,acro_score,csc_score)}score_up=score_row[j];csc_diag=csc_row[j];if(score>score_up){move=LEFT}else{score=score_up;move=UP}if(align>score){score=align;move=DIAGONAL}else{csc_score=0}score_row[j]=score;csc_row[j]=csc_score;trace[++pos]=score>0?move:STOP}}i=m-1;j=n-1;pos=i*n+j;backtrack=true;matches=[];while(backtrack&&i>=0&&j>=0){switch(trace[pos]){case UP:i--;pos-=n;break;case LEFT:j--;pos--;break;case DIAGONAL:matches.push(i+offset);j--;i--;pos-=n+1;break;default:backtrack=false}}matches.reverse();return matches}}).call(this)},{"./scorer":6,"path":7}],6:[function(require,module,exports){(function(){var AcronymResult,PathSeparator,Query,basenameScore,coreChars,countDir,doScore,emptyAcronymResult,file_coeff,isMatch,isSeparator,isWordEnd,isWordStart,miss_coeff,opt_char_re,pos_bonus,scoreAcronyms,scoreCharacter,scoreConsecutives,scoreExact,scoreExactMatch,scorePattern,scorePosition,scoreSize,tau_depth,tau_size,truncatedUpperCase,wm;PathSeparator=require('path').sep;wm=150;pos_bonus=20;tau_depth=13;tau_size=85;file_coeff=1.2;miss_coeff=0.75;opt_char_re=/[ _\-:\/\\]/g;exports.coreChars=coreChars=function(query){return query.replace(opt_char_re,'')};exports.score=function(string,query,prepQuery,allowErrors){var score,string_lw;if(prepQuery==null){prepQuery=new Query(query)}if(allowErrors==null){allowErrors=false}if(!(allowErrors||isMatch(string,prepQuery.core_lw,prepQuery.core_up))){return 0}string_lw=string.toLowerCase();score=doScore(string,string_lw,prepQuery);return Math.ceil(basenameScore(string,string_lw,prepQuery,score))};Query=(function(){function Query(query){if(!(query!=null?query.length:void 0)){return null}this.query=query;this.query_lw=query.toLowerCase();this.core=coreChars(query);this.core_lw=this.core.toLowerCase();this.core_up=truncatedUpperCase(this.core);this.depth=countDir(query,query.length)}return Query})();exports.prepQuery=function(query){return new Query(query)};exports.isMatch=isMatch=function(subject,query_lw,query_up){var i,j,m,n,qj_lw,qj_up,si;m=subject.length;n=query_lw.length;if(!m||!n||n>m){return false}i=-1;j=-1;while(++j-1){return scoreExactMatch(subject,subject_lw,query,query_lw,pos,n,m)}score_row=new Array(n);csc_row=new Array(n);sz=scoreSize(n,m);miss_budget=Math.ceil(miss_coeff*n)+5;miss_left=miss_budget;j=-1;while(++j-1){i--}mm=subject_lw.lastIndexOf(query_lw[n-1],m);if(mm>i){m=mm+1}while(++iscore){score=score_up}csc_score=0;if(query_lw[j]===si_lw){start=isWordStart(i,subject,subject_lw);csc_score=csc_diag>0?csc_diag:scoreConsecutives(subject,subject_lw,query,query_lw,i,j,start);align=score_diag+scoreCharacter(i,j,start,acro_score,csc_score);if(align>score){score=align;miss_left=miss_budget}else{if(record_miss&&--miss_left<=0){return score_row[n-1]*sz}record_miss=false}}score_diag=score_up;csc_diag=csc_row[j];csc_row[j]=csc_score;score_row[j]=score}}return score*sz};exports.isWordStart=isWordStart=function(pos,subject,subject_lw){var curr_s,prev_s;if(pos===0){return true}curr_s=subject[pos];prev_s=subject[pos-1];return isSeparator(curr_s)||isSeparator(prev_s)||(curr_s!==subject_lw[pos]&&prev_s===subject_lw[pos-1])};exports.isWordEnd=isWordEnd=function(pos,subject,subject_lw,len){var curr_s,next_s;if(pos===len-1){return true}curr_s=subject[pos];next_s=subject[pos+1];return isSeparator(curr_s)||isSeparator(next_s)||(curr_s===subject_lw[pos]&&next_s!==subject_lw[pos+1])};isSeparator=function(c){return c===' '||c==='.'||c==='-'||c==='_'||c==='/'||c==='\\'};scorePosition=function(pos){var sc;if(poscsc_score?acro_score:csc_score)+10)}return posBonus+wm*csc_score};exports.scoreConsecutives=scoreConsecutives=function(subject,subject_lw,query,query_lw,i,j,start){var k,m,mi,n,nj,sameCase,startPos,sz;m=subject.length;n=query.length;mi=m-i;nj=n-j;k=mi-1){start=isWordStart(pos2,subject,subject_lw);if(start){pos=pos2}}}i=-1;sameCase=0;while(++i1&&n>1)){return emptyAcronymResult}count=0;pos=0;sameCase=0;i=-1;j=-1;while(++j0){basePos=subject.lastIndexOf(PathSeparator,basePos-1);if(basePos===-1){return fullPathScore}}basePos++;end++;basePathScore=doScore(subject.slice(basePos,end),subject_lw.slice(basePos,end),prepQuery);alpha=0.5*tau_depth/(tau_depth+countDir(subject,end+1));return alpha*basePathScore+(1-alpha)*fullPathScore*scoreSize(0,file_coeff*(end-basePos))};exports.countDir=countDir=function(path,end){var count,i;if(end<1){return 0}count=0;i=-1;while(++i=0;i--){var last=parts[i];if(last==='.'){parts.splice(i,1)}else if(last==='..'){parts.splice(i,1);up++}else if(up){parts.splice(i,1);up--}}if(allowAboveRoot){for(;up--;up){parts.unshift('..')}}return parts}var splitPathRe=/^(\/?|)([\s\S]*?)((?:\.{1,2}|[^\/]+?|)(\.[^.\/]*|))(?:[\/]*)$/;var splitPath=function(filename){return splitPathRe.exec(filename).slice(1)};exports.resolve=function(){var resolvedPath='',resolvedAbsolute=false;for(var i=arguments.length-1;i>=-1&&!resolvedAbsolute;i--){var path=(i>=0)?arguments[i]:process.cwd();if(typeof path!=='string'){throw new TypeError('Arguments to path.resolve must be strings');}else if(!path){continue}resolvedPath=path+'/'+resolvedPath;resolvedAbsolute=path.charAt(0)==='/'}resolvedPath=normalizeArray(filter(resolvedPath.split('/'),function(p){return!!p}),!resolvedAbsolute).join('/');return((resolvedAbsolute?'/':'')+resolvedPath)||'.'};exports.normalize=function(path){var isAbsolute=exports.isAbsolute(path),trailingSlash=substr(path,-1)==='/';path=normalizeArray(filter(path.split('/'),function(p){return!!p}),!isAbsolute).join('/');if(!path&&!isAbsolute){path='.'}if(path&&trailingSlash){path+='/'}return(isAbsolute?'/':'')+path};exports.isAbsolute=function(path){return path.charAt(0)==='/'};exports.join=function(){var paths=Array.prototype.slice.call(arguments,0);return exports.normalize(filter(paths,function(p,index){if(typeof p!=='string'){throw new TypeError('Arguments to path.join must be strings');}return p}).join('/'))};exports.relative=function(from,to){from=exports.resolve(from).substr(1);to=exports.resolve(to).substr(1);function trim(arr){var start=0;for(;start=0;end--){if(arr[end]!=='')break}if(start>end)return[];return arr.slice(start,end-start+1)}var fromParts=trim(from.split('/'));var toParts=trim(to.split('/'));var length=Math.min(fromParts.length,toParts.length);var samePartsLength=length;for(var i=0;i1){for(var i=1;i Date: Thu, 7 Jan 2016 11:47:06 +0100 Subject: Revert "Store SQL/view timings in milliseconds" This reverts commit 7549102bb727daecc51da84af39956b32fc41537. Apparently I was wrong about ActiveSupport::Notifications::Event#duration returning the duration in seconds, instead it returns it in milliseconds already. --- lib/gitlab/metrics/subscribers/action_view.rb | 8 ++------ lib/gitlab/metrics/subscribers/active_record.rb | 6 +----- spec/lib/gitlab/metrics/subscribers/action_view_spec.rb | 4 ++-- spec/lib/gitlab/metrics/subscribers/active_record_spec.rb | 2 +- 4 files changed, 6 insertions(+), 14 deletions(-) diff --git a/lib/gitlab/metrics/subscribers/action_view.rb b/lib/gitlab/metrics/subscribers/action_view.rb index 84d9e383625..7c0105d543a 100644 --- a/lib/gitlab/metrics/subscribers/action_view.rb +++ b/lib/gitlab/metrics/subscribers/action_view.rb @@ -19,7 +19,7 @@ module Gitlab values = values_for(event) tags = tags_for(event) - current_transaction.increment(:view_duration, duration(event)) + current_transaction.increment(:view_duration, event.duration) current_transaction.add_metric(SERIES, values, tags) end @@ -28,7 +28,7 @@ module Gitlab end def values_for(event) - { duration: duration(event) } + { duration: event.duration } end def tags_for(event) @@ -48,10 +48,6 @@ module Gitlab def current_transaction Transaction.current end - - def duration(event) - event.duration * 1000.0 - end end end end diff --git a/lib/gitlab/metrics/subscribers/active_record.rb b/lib/gitlab/metrics/subscribers/active_record.rb index 6fa73e7a3be..8008b3bc895 100644 --- a/lib/gitlab/metrics/subscribers/active_record.rb +++ b/lib/gitlab/metrics/subscribers/active_record.rb @@ -8,7 +8,7 @@ module Gitlab def sql(event) return unless current_transaction - current_transaction.increment(:sql_duration, duration(event)) + current_transaction.increment(:sql_duration, event.duration) end private @@ -16,10 +16,6 @@ module Gitlab def current_transaction Transaction.current end - - def duration(event) - event.duration * 1000.0 - end end end end diff --git a/spec/lib/gitlab/metrics/subscribers/action_view_spec.rb b/spec/lib/gitlab/metrics/subscribers/action_view_spec.rb index 0a4cc5e929b..05e4fbbeb51 100644 --- a/spec/lib/gitlab/metrics/subscribers/action_view_spec.rb +++ b/spec/lib/gitlab/metrics/subscribers/action_view_spec.rb @@ -21,7 +21,7 @@ describe Gitlab::Metrics::Subscribers::ActionView do describe '#render_template' do it 'tracks rendering of a template' do - values = { duration: 2100 } + values = { duration: 2.1 } tags = { view: 'app/views/x.html.haml', file: 'app/views/x.html.haml', @@ -29,7 +29,7 @@ describe Gitlab::Metrics::Subscribers::ActionView do } expect(transaction).to receive(:increment). - with(:view_duration, 2100) + with(:view_duration, 2.1) expect(transaction).to receive(:add_metric). with(described_class::SERIES, values, tags) diff --git a/spec/lib/gitlab/metrics/subscribers/active_record_spec.rb b/spec/lib/gitlab/metrics/subscribers/active_record_spec.rb index ca86142a2f4..7bc070a4d09 100644 --- a/spec/lib/gitlab/metrics/subscribers/active_record_spec.rb +++ b/spec/lib/gitlab/metrics/subscribers/active_record_spec.rb @@ -26,7 +26,7 @@ describe Gitlab::Metrics::Subscribers::ActiveRecord do and_return(transaction) expect(transaction).to receive(:increment). - with(:sql_duration, 200) + with(:sql_duration, 0.2) subscriber.sql(event) end -- cgit v1.2.1 From b38eabdaf69c4da19f39c26b7626e9ce4b51158b Mon Sep 17 00:00:00 2001 From: Douwe Maan Date: Thu, 7 Jan 2016 12:10:35 +0100 Subject: Fix changelog --- CHANGELOG | 1 - 1 file changed, 1 deletion(-) diff --git a/CHANGELOG b/CHANGELOG index ed839b8fc82..de8d2c43424 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -8,7 +8,6 @@ v 8.4.0 (unreleased) - Add API support for looking up a user by username (Stan Hu) - Add project permissions to all project API endpoints (Stan Hu) - Link to milestone in "Milestone changed" system note - - Expose Git's version in the admin area - Only allow group/project members to mention `@all` - Expose Git's version in the admin area (Trey Davis) - Add "Frequently used" category to emoji picker -- cgit v1.2.1 From 539b41929bddf0e82d986f9e823208dd92707a21 Mon Sep 17 00:00:00 2001 From: Douwe Maan Date: Thu, 7 Jan 2016 12:26:05 +0100 Subject: Milestone reference is a Markdown link --- app/models/milestone.rb | 6 +++++- spec/fixtures/markdown.md.erb | 1 - spec/lib/banzai/filter/milestone_reference_filter_spec.rb | 4 +++- 3 files changed, 8 insertions(+), 3 deletions(-) diff --git a/app/models/milestone.rb b/app/models/milestone.rb index eaa2db2e247..550d14d4c39 100644 --- a/app/models/milestone.rb +++ b/app/models/milestone.rb @@ -71,8 +71,12 @@ class Milestone < ActiveRecord::Base end def to_reference(from_project = nil) + escaped_title = self.title.gsub("]", "\\]") + h = Gitlab::Application.routes.url_helpers - h.namespace_project_milestone_url(self.project.namespace, self.project, self) + url = h.namespace_project_milestone_url(self.project.namespace, self.project, self) + + "[#{escaped_title}](#{url})" end def reference_link_text(from_project = nil) diff --git a/spec/fixtures/markdown.md.erb b/spec/fixtures/markdown.md.erb index 302b750aee5..0620096d689 100644 --- a/spec/fixtures/markdown.md.erb +++ b/spec/fixtures/markdown.md.erb @@ -219,7 +219,6 @@ References should be parseable even inside _<%= merge_request.to_reference %>_ e - Milestone: <%= milestone.to_reference %> - Milestone in another project: <%= xmilestone.to_reference(project) %> - Ignored in code: `<%= milestone.to_reference %>` -- Ignored in links: [Link to <%= milestone.to_reference %>](#milestone-link) - Link to milestone by URL: [Milestone](<%= urls.namespace_project_milestone_url(milestone.project.namespace, milestone.project, milestone) %>) ### Task Lists diff --git a/spec/lib/banzai/filter/milestone_reference_filter_spec.rb b/spec/lib/banzai/filter/milestone_reference_filter_spec.rb index 86b71210100..ebf3d7489b5 100644 --- a/spec/lib/banzai/filter/milestone_reference_filter_spec.rb +++ b/spec/lib/banzai/filter/milestone_reference_filter_spec.rb @@ -18,7 +18,9 @@ describe Banzai::Filter::MilestoneReferenceFilter, lib: true do end context 'internal reference' do - let(:reference) { milestone.to_reference } + # Convert the Markdown link to only the URL, since these tests aren't run through the regular Markdown pipeline. + # Milestone reference behavior in the full Markdown pipeline is tested elsewhere. + let(:reference) { milestone.to_reference.gsub(/\[([^\]]+)\]\(([^)]+)\)/, '\2') } it 'links to a valid reference' do doc = reference_filter("See #{reference}") -- cgit v1.2.1 From 364b07cff0183956ea11962b94c70448767351d3 Mon Sep 17 00:00:00 2001 From: Yorick Peterse Date: Thu, 7 Jan 2016 12:44:15 +0100 Subject: Removed UUIDs from metrics transactions While useful for finding out what methods/views belong to a transaction this might result in too much data being stored in InfluxDB. --- lib/gitlab/metrics/transaction.rb | 4 +--- spec/lib/gitlab/metrics/transaction_spec.rb | 4 ++-- 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/lib/gitlab/metrics/transaction.rb b/lib/gitlab/metrics/transaction.rb index 68b86de0655..306656d30fe 100644 --- a/lib/gitlab/metrics/transaction.rb +++ b/lib/gitlab/metrics/transaction.rb @@ -4,7 +4,7 @@ module Gitlab class Transaction THREAD_KEY = :_gitlab_metrics_transaction - attr_reader :uuid, :tags + attr_reader :tags def self.current Thread.current[THREAD_KEY] @@ -12,7 +12,6 @@ module Gitlab def initialize @metrics = [] - @uuid = SecureRandom.uuid @started_at = nil @finished_at = nil @@ -38,7 +37,6 @@ module Gitlab end def add_metric(series, values, tags = {}) - tags = tags.merge(transaction_id: @uuid) prefix = sidekiq? ? 'sidekiq_' : 'rails_' @metrics << Metric.new("#{prefix}#{series}", values, tags) diff --git a/spec/lib/gitlab/metrics/transaction_spec.rb b/spec/lib/gitlab/metrics/transaction_spec.rb index b9b94947afa..0c98b8f0127 100644 --- a/spec/lib/gitlab/metrics/transaction_spec.rb +++ b/spec/lib/gitlab/metrics/transaction_spec.rb @@ -30,9 +30,9 @@ describe Gitlab::Metrics::Transaction do end describe '#add_metric' do - it 'adds a metric tagged with the transaction UUID' do + it 'adds a metric to the transaction' do expect(Gitlab::Metrics::Metric).to receive(:new). - with('rails_foo', { number: 10 }, { transaction_id: transaction.uuid }) + with('rails_foo', { number: 10 }, {}) transaction.add_metric('foo', number: 10) end -- cgit v1.2.1 From 41b8a238ce4bd7f091d46fb9b89b7456fde17ddf Mon Sep 17 00:00:00 2001 From: Jacob Vosmaer Date: Thu, 7 Jan 2016 12:56:18 +0100 Subject: Merge branch 'master' of github.com:gitlabhq/gitlabhq --- CHANGELOG | 1 + Gemfile | 2 +- Gemfile.lock | 2 +- app/assets/javascripts/application.js.coffee | 1 + app/assets/javascripts/dispatcher.js.coffee | 4 +- app/assets/javascripts/project_find_file.js.coffee | 125 +++++++++++++++++++++ .../javascripts/shortcuts_find_file.js.coffee | 19 ++++ app/assets/javascripts/shortcuts_tree.coffee | 4 + app/assets/stylesheets/pages/tree.scss | 8 ++ app/controllers/projects/find_file_controller.rb | 26 +++++ app/controllers/projects/refs_controller.rb | 2 + app/models/repository.rb | 5 + app/views/help/_shortcuts.html.haml | 26 +++++ app/views/layouts/nav/_project.html.haml | 3 +- app/views/projects/_find_file_link.html.haml | 3 + app/views/projects/find_file/show.html.haml | 27 +++++ app/views/projects/tree/show.html.haml | 8 +- config/routes.rb | 18 +++ doc/workflow/shortcuts.png | Bin 78736 -> 48782 bytes features/project/find_file.feature | 42 +++++++ features/steps/project/project_find_file.rb | 73 ++++++++++++ features/steps/shared/paths.rb | 4 + .../projects/find_file_controller_spec.rb | 66 +++++++++++ spec/routing/project_routing_spec.rb | 12 ++ vendor/assets/javascripts/fuzzaldrin-plus.min.js | 1 + 25 files changed, 473 insertions(+), 9 deletions(-) create mode 100644 app/assets/javascripts/project_find_file.js.coffee create mode 100644 app/assets/javascripts/shortcuts_find_file.js.coffee create mode 100644 app/assets/javascripts/shortcuts_tree.coffee create mode 100644 app/controllers/projects/find_file_controller.rb create mode 100644 app/views/projects/_find_file_link.html.haml create mode 100644 app/views/projects/find_file/show.html.haml create mode 100644 features/project/find_file.feature create mode 100644 features/steps/project/project_find_file.rb create mode 100644 spec/controllers/projects/find_file_controller_spec.rb create mode 100644 vendor/assets/javascripts/fuzzaldrin-plus.min.js diff --git a/CHANGELOG b/CHANGELOG index e7f1d2b67da..22fb91baaf0 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -106,6 +106,7 @@ v 8.3.0 - Fix online editor should not remove newlines at the end of the file - Expose Git's version in the admin area - Show "New Merge Request" buttons on canonical repos when you have a fork (Josh Frye) + - Add file finder feature in tree view v 8.2.3 - Fix application settings cache not expiring after changes (Stan Hu) diff --git a/Gemfile b/Gemfile index 6145745b6f3..6b0bc241494 100644 --- a/Gemfile +++ b/Gemfile @@ -49,7 +49,7 @@ gem "browser", '~> 1.0.0' # Extracting information from a git repository # Provide access to Gitlab::Git library -gem "gitlab_git", '~> 7.2.20' +gem "gitlab_git", '~> 7.2.22' # LDAP Auth # GitLab fork with several improvements to original library. For full list of changes diff --git a/Gemfile.lock b/Gemfile.lock index 2b42f325503..a1168ed3b7a 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -887,7 +887,7 @@ DEPENDENCIES github-markup (~> 1.3.1) gitlab-flowdock-git-hook (~> 1.0.1) gitlab_emoji (~> 0.2.0) - gitlab_git (~> 7.2.20) + gitlab_git (~> 7.2.22) gitlab_meta (= 7.0) gitlab_omniauth-ldap (~> 1.2.1) gollum-lib (~> 4.1.0) diff --git a/app/assets/javascripts/application.js.coffee b/app/assets/javascripts/application.js.coffee index b9b095e004a..c095e5ae2b1 100644 --- a/app/assets/javascripts/application.js.coffee +++ b/app/assets/javascripts/application.js.coffee @@ -40,6 +40,7 @@ #= require shortcuts_network #= require jquery.nicescroll.min #= require_tree . +#= require fuzzaldrin-plus.min window.slugify = (text) -> text.replace(/[^-a-zA-Z0-9]+/g, '_').toLowerCase() diff --git a/app/assets/javascripts/dispatcher.js.coffee b/app/assets/javascripts/dispatcher.js.coffee index 69e061ce6e9..58d6b9d4060 100644 --- a/app/assets/javascripts/dispatcher.js.coffee +++ b/app/assets/javascripts/dispatcher.js.coffee @@ -87,7 +87,9 @@ class Dispatcher new GroupAvatar() when 'projects:tree:show' new TreeView() - shortcut_handler = new ShortcutsNavigation() + shortcut_handler = new ShortcutsTree() + when 'projects:find_file:show' + shortcut_handler = true when 'projects:blob:show' new LineHighlighter() shortcut_handler = new ShortcutsNavigation() diff --git a/app/assets/javascripts/project_find_file.js.coffee b/app/assets/javascripts/project_find_file.js.coffee new file mode 100644 index 00000000000..0dd32352c34 --- /dev/null +++ b/app/assets/javascripts/project_find_file.js.coffee @@ -0,0 +1,125 @@ +class @ProjectFindFile + constructor: (@element, @options)-> + @filePaths = {} + @inputElement = @element.find(".file-finder-input") + + # init event + @initEvent() + + # focus text input box + @inputElement.focus() + + # load file list + @load(@options.url) + + # init event + initEvent: -> + @inputElement.off "keyup" + @inputElement.on "keyup", (event) => + target = $(event.target) + value = target.val() + oldValue = target.data("oldValue") ? "" + + if value != oldValue + target.data("oldValue", value) + @findFile() + @element.find("tr.tree-item").eq(0).addClass("selected").focus() + + @element.find(".tree-content-holder .tree-table").on "click", (event) -> + if (event.target.nodeName != "A") + path = @element.find(".tree-item-file-name a", this).attr("href") + location.href = path if path + + # find file + findFile: -> + searchText = @inputElement.val() + result = if searchText.length > 0 then fuzzaldrinPlus.filter(@filePaths, searchText) else @filePaths + @renderList result, searchText + + # files pathes load + load: (url) -> + $.ajax + url: url + method: "get" + dataType: "json" + success: (data) => + @element.find(".loading").hide() + @filePaths = data + @findFile() + @element.find(".files-slider tr.tree-item").eq(0).addClass("selected").focus() + + # render result + renderList: (filePaths, searchText) -> + @element.find(".tree-table > tbody").empty() + + for filePath, i in filePaths + break if i == 20 + + if searchText + matches = fuzzaldrinPlus.match(filePath, searchText) + + blobItemUrl = "#{@options.blobUrlTemplate}/#{filePath}" + + html = @makeHtml filePath, matches, blobItemUrl + @element.find(".tree-table > tbody").append(html) + + # highlight text(awefwbwgtc -> awefwbwgtc ) + highlighter = (element, text, matches) -> + lastIndex = 0 + highlightText = "" + matchedChars = [] + + for matchIndex in matches + unmatched = text.substring(lastIndex, matchIndex) + + if unmatched + element.append(matchedChars.join("").bold()) if matchedChars.length + matchedChars = [] + element.append(document.createTextNode(unmatched)) + + matchedChars.push(text[matchIndex]) + lastIndex = matchIndex + 1 + + element.append(matchedChars.join("").bold()) if matchedChars.length + element.append(document.createTextNode(text.substring(lastIndex))) + + # make tbody row html + makeHtml: (filePath, matches, blobItemUrl) -> + $tr = $("") + if matches + $tr.find("a").replaceWith(highlighter($tr.find("a"), filePath, matches).attr("href", blobItemUrl)) + else + $tr.find("a").attr("href", blobItemUrl).text(filePath) + + return $tr + + selectRow: (type) -> + rows = @element.find(".files-slider tr.tree-item") + selectedRow = @element.find(".files-slider tr.tree-item.selected") + + if rows && rows.length > 0 + if selectedRow && selectedRow.length > 0 + if type == "UP" + next = selectedRow.prev() + else if type == "DOWN" + next = selectedRow.next() + + if next.length > 0 + selectedRow.removeClass "selected" + selectedRow = next + else + selectedRow = rows.eq(0) + selectedRow.addClass("selected").focus() + + selectRowUp: => + @selectRow "UP" + + selectRowDown: => + @selectRow "DOWN" + + goToTree: => + location.href = @options.treeUrl + + goToBlob: => + path = @element.find(".tree-item.selected .tree-item-file-name a").attr("href") + location.href = path if path diff --git a/app/assets/javascripts/shortcuts_find_file.js.coffee b/app/assets/javascripts/shortcuts_find_file.js.coffee new file mode 100644 index 00000000000..311e80bae19 --- /dev/null +++ b/app/assets/javascripts/shortcuts_find_file.js.coffee @@ -0,0 +1,19 @@ +#= require shortcuts_navigation + +class @ShortcutsFindFile extends ShortcutsNavigation + constructor: (@projectFindFile) -> + super() + _oldStopCallback = Mousetrap.stopCallback + # override to fire shortcuts action when focus in textbox + Mousetrap.stopCallback = (event, element, combo) => + if element == @projectFindFile.inputElement[0] and (combo == 'up' or combo == 'down' or combo == 'esc' or combo == 'enter') + # when press up/down key in textbox, cusor prevent to move to home/end + event.preventDefault() + return false + + return _oldStopCallback(event, element, combo) + + Mousetrap.bind('up', @projectFindFile.selectRowUp) + Mousetrap.bind('down', @projectFindFile.selectRowDown) + Mousetrap.bind('esc', @projectFindFile.goToTree) + Mousetrap.bind('enter', @projectFindFile.goToBlob) diff --git a/app/assets/javascripts/shortcuts_tree.coffee b/app/assets/javascripts/shortcuts_tree.coffee new file mode 100644 index 00000000000..ba0839c9fc0 --- /dev/null +++ b/app/assets/javascripts/shortcuts_tree.coffee @@ -0,0 +1,4 @@ +class @ShortcutsTree extends ShortcutsNavigation + constructor: -> + super() + Mousetrap.bind('t', -> ShortcutsTree.findAndFollowLink('.shortcuts-find-file')) diff --git a/app/assets/stylesheets/pages/tree.scss b/app/assets/stylesheets/pages/tree.scss index d4ab6967ccd..97505edeabf 100644 --- a/app/assets/stylesheets/pages/tree.scss +++ b/app/assets/stylesheets/pages/tree.scss @@ -1,5 +1,13 @@ .tree-holder { + .file-finder { + width: 50%; + .file-finder-input { + width: 95%; + display: inline-block; + } + } + .tree-table { margin-bottom: 0; diff --git a/app/controllers/projects/find_file_controller.rb b/app/controllers/projects/find_file_controller.rb new file mode 100644 index 00000000000..54a0c447aee --- /dev/null +++ b/app/controllers/projects/find_file_controller.rb @@ -0,0 +1,26 @@ +# Controller for viewing a repository's file structure +class Projects::FindFileController < Projects::ApplicationController + include ExtractsPath + include ActionView::Helpers::SanitizeHelper + include TreeHelper + + before_action :require_non_empty_project + before_action :assign_ref_vars + before_action :authorize_download_code! + + def show + return render_404 unless @repository.commit(@ref) + + respond_to do |format| + format.html + end + end + + def list + file_paths = @repo.ls_files(@ref) + + respond_to do |format| + format.json { render json: file_paths } + end + end +end diff --git a/app/controllers/projects/refs_controller.rb b/app/controllers/projects/refs_controller.rb index c4e18c17077..a8f091819ca 100644 --- a/app/controllers/projects/refs_controller.rb +++ b/app/controllers/projects/refs_controller.rb @@ -20,6 +20,8 @@ class Projects::RefsController < Projects::ApplicationController namespace_project_network_path(@project.namespace, @project, @id, @options) when "graphs" namespace_project_graph_path(@project.namespace, @project, @id) + when "find_file" + namespace_project_find_file_path(@project.namespace, @project, @id) when "graphs_commits" commits_namespace_project_graph_path(@project.namespace, @project, @id) else diff --git a/app/models/repository.rb b/app/models/repository.rb index 6ecd2d2f27e..9deb08d93b8 100644 --- a/app/models/repository.rb +++ b/app/models/repository.rb @@ -681,6 +681,11 @@ class Repository end end + def ls_files(ref) + actual_ref = ref || root_ref + raw_repository.ls_files(actual_ref) + end + private def cache diff --git a/app/views/help/_shortcuts.html.haml b/app/views/help/_shortcuts.html.haml index e8e331dd109..9ee6f07b26b 100644 --- a/app/views/help/_shortcuts.html.haml +++ b/app/views/help/_shortcuts.html.haml @@ -40,6 +40,32 @@ %td.shortcut .key enter %td Open Selection + %tr + %td.shortcut + .key t + %td Go to finding file + %tbody + %tr + %th + %th Finding Project File + %tr + %td.shortcut + .key + %i.fa.fa-arrow-up + %td Move selection up + %tr + %td.shortcut + .key + %i.fa.fa-arrow-down + %td Move selection down + %tr + %td.shortcut + .key enter + %td Open Selection + %tr + %td.shortcut + .key esc + %td Go back .col-lg-4 %table.shortcut-mappings diff --git a/app/views/layouts/nav/_project.html.haml b/app/views/layouts/nav/_project.html.haml index d3eaf0f3209..270ccfd387f 100644 --- a/app/views/layouts/nav/_project.html.haml +++ b/app/views/layouts/nav/_project.html.haml @@ -25,7 +25,7 @@ %span Activity - if project_nav_tab? :files - = nav_link(controller: %w(tree blob blame edit_tree new_tree)) do + = nav_link(controller: %w(tree blob blame edit_tree new_tree find_file)) do = link_to project_files_path(@project), title: 'Files', class: 'shortcuts-tree' do = icon('files-o fw') %span @@ -117,4 +117,3 @@ %li.hidden = link_to namespace_project_network_path(@project.namespace, @project, current_ref), title: 'Network', class: 'shortcuts-network' do Network - diff --git a/app/views/projects/_find_file_link.html.haml b/app/views/projects/_find_file_link.html.haml new file mode 100644 index 00000000000..08e2fc48be7 --- /dev/null +++ b/app/views/projects/_find_file_link.html.haml @@ -0,0 +1,3 @@ += link_to namespace_project_find_file_path(@project.namespace, @project, @ref), class: 'btn btn-grouped shortcuts-find-file', rel: 'nofollow' do + = icon('search') + %span Find File diff --git a/app/views/projects/find_file/show.html.haml b/app/views/projects/find_file/show.html.haml new file mode 100644 index 00000000000..2930209fb56 --- /dev/null +++ b/app/views/projects/find_file/show.html.haml @@ -0,0 +1,27 @@ +- page_title "Find File", @ref +- header_title project_title(@project, "Files", project_files_path(@project)) + +.file-finder-holder.tree-holder.clearfix + .gray-content-block.top-block + .tree-ref-holder + = render 'shared/ref_switcher', destination: 'find_file', path: @path + %ul.breadcrumb.repo-breadcrumb + %li + = link_to namespace_project_tree_path(@project.namespace, @project, @ref) do + = @project.path + %li.file-finder + %input#file_find.form-control.file-finder-input{type: "text", placeholder: 'Find by path'} + + %div.tree-content-holder + .table-holder + %table.table.files-slider{class: "table_#{@hex_path} tree-table table-striped" } + %tbody + = spinner nil, true + +:coffeescript + projectFindFile = new ProjectFindFile($(".file-finder-holder"), { + url: "#{escape_javascript(namespace_project_files_path(@project.namespace, @project, @ref, @options.merge(format: :json)))}" + treeUrl: "#{escape_javascript(namespace_project_tree_path(@project.namespace, @project, @ref))}" + blobUrlTemplate: "#{escape_javascript(namespace_project_blob_path(@project.namespace, @project, @id || @commit.id))}" + }) + new ShortcutsFindFile(projectFindFile) diff --git a/app/views/projects/tree/show.html.haml b/app/views/projects/tree/show.html.haml index ec14bd7f65a..c57570afa09 100644 --- a/app/views/projects/tree/show.html.haml +++ b/app/views/projects/tree/show.html.haml @@ -3,12 +3,12 @@ = content_for :meta_tags do - if current_user = auto_discovery_link_tag(:atom, namespace_project_commits_url(@project.namespace, @project, @ref, format: :atom, private_token: current_user.private_token), title: "#{@project.name}:#{@ref} commits") - = render 'projects/last_push' -- if can? current_user, :download_code, @project - .tree-download-holder - = render 'projects/repositories/download_archive', ref: @ref, btn_class: 'btn-group pull-right hidden-xs hidden-sm', split_button: true +.pull-right + = render 'projects/find_file_link' + - if can? current_user, :download_code, @project + = render 'projects/repositories/download_archive', ref: @ref, btn_class: 'hidden-xs hidden-sm btn-grouped', split_button: true #tree-holder.tree-holder.clearfix .gray-content-block.top-block diff --git a/config/routes.rb b/config/routes.rb index 3e7d9f78710..5b69d06eb76 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -440,6 +440,24 @@ Rails.application.routes.draw do ) end + scope do + get( + '/find_file/*id', + to: 'find_file#show', + constraints: { id: /.+/, format: /html/ }, + as: :find_file + ) + end + + scope do + get( + '/files/*id', + to: 'find_file#list', + constraints: { id: /(?:[^.]|\.(?!json$))+/, format: /json/ }, + as: :files + ) + end + scope do post( '/create_dir/*id', diff --git a/doc/workflow/shortcuts.png b/doc/workflow/shortcuts.png index 68756ed1f98..e5914aa8e67 100644 Binary files a/doc/workflow/shortcuts.png and b/doc/workflow/shortcuts.png differ diff --git a/features/project/find_file.feature b/features/project/find_file.feature new file mode 100644 index 00000000000..ae8fa245923 --- /dev/null +++ b/features/project/find_file.feature @@ -0,0 +1,42 @@ +@dashboard +Feature: Project Find File + Background: + Given I sign in as a user + And I own a project + And I visit my project's files page + + @javascript + Scenario: Navigate to find file by shortcut + Given I press "t" + Then I should see "find file" page + + Scenario: Navigate to find file + Given I click Find File button + Then I should see "find file" page + + @javascript + Scenario: I search file + Given I visit project find file page + And I fill in file find with "change" + Then I should not see ".gitignore" in files + And I should not see ".gitmodules" in files + And I should see "CHANGELOG" in files + And I should not see "VERSION" in files + + @javascript + Scenario: I search file that not exist + Given I visit project find file page + And I fill in file find with "asdfghjklqwertyuizxcvbnm" + Then I should not see ".gitignore" in files + And I should not see ".gitmodules" in files + And I should not see "CHANGELOG" in files + And I should not see "VERSION" in files + + @javascript + Scenario: I search file that partially matches + Given I visit project find file page + And I fill in file find with "git" + Then I should see ".gitignore" in files + And I should see ".gitmodules" in files + And I should not see "CHANGELOG" in files + And I should not see "VERSION" in files diff --git a/features/steps/project/project_find_file.rb b/features/steps/project/project_find_file.rb new file mode 100644 index 00000000000..8c1d09d6cc6 --- /dev/null +++ b/features/steps/project/project_find_file.rb @@ -0,0 +1,73 @@ +class Spinach::Features::ProjectFindFile < Spinach::FeatureSteps + include SharedAuthentication + include SharedPaths + include SharedProject + include SharedProjectTab + + step 'I press "t"' do + find('body').native.send_key('t') + end + + step 'I click Find File button' do + click_link 'Find File' + end + + step 'I should see "find file" page' do + ensure_active_main_tab('Files') + expect(page).to have_selector('.file-finder-holder', count: 1) + end + + step 'I fill in Find by path with "git"' do + ensure_active_main_tab('Files') + expect(page).to have_selector('.file-finder-holder', count: 1) + end + + step 'I fill in file find with "git"' do + find_file "git" + end + + step 'I fill in file find with "change"' do + find_file "change" + end + + step 'I fill in file find with "asdfghjklqwertyuizxcvbnm"' do + find_file "asdfghjklqwertyuizxcvbnm" + end + + step 'I should see "VERSION" in files' do + expect(page).to have_content("VERSION") + end + + step 'I should not see "VERSION" in files' do + expect(page).not_to have_content("VERSION") + end + + step 'I should see "CHANGELOG" in files' do + expect(page).to have_content("CHANGELOG") + end + + step 'I should not see "CHANGELOG" in files' do + expect(page).not_to have_content("CHANGELOG") + end + + step 'I should see ".gitmodules" in files' do + expect(page).to have_content(".gitmodules") + end + + step 'I should not see ".gitmodules" in files' do + expect(page).not_to have_content(".gitmodules") + end + + step 'I should see ".gitignore" in files' do + expect(page).to have_content(".gitignore") + end + + step 'I should not see ".gitignore" in files' do + expect(page).not_to have_content(".gitignore") + end + + + def find_file(text) + fill_in 'file_find', with: text + end +end diff --git a/features/steps/shared/paths.rb b/features/steps/shared/paths.rb index b33bd332655..4264c9c6f1a 100644 --- a/features/steps/shared/paths.rb +++ b/features/steps/shared/paths.rb @@ -259,6 +259,10 @@ module SharedPaths visit namespace_project_deploy_keys_path(@project.namespace, @project) end + step 'I visit project find file page' do + visit namespace_project_find_file_path(@project.namespace, @project, root_ref) + end + # ---------------------------------------- # "Shop" Project # ---------------------------------------- diff --git a/spec/controllers/projects/find_file_controller_spec.rb b/spec/controllers/projects/find_file_controller_spec.rb new file mode 100644 index 00000000000..038dfeb8466 --- /dev/null +++ b/spec/controllers/projects/find_file_controller_spec.rb @@ -0,0 +1,66 @@ +require 'spec_helper' + +describe Projects::FindFileController do + let(:project) { create(:project) } + let(:user) { create(:user) } + + before do + sign_in(user) + + project.team << [user, :master] + controller.instance_variable_set(:@project, project) + end + + describe "GET #show" do + # Make sure any errors accessing the tree in our views bubble up to this spec + render_views + + before do + get(:show, + namespace_id: project.namespace.to_param, + project_id: project.to_param, + id: id) + end + + context "valid branch" do + let(:id) { 'master' } + it { is_expected.to respond_with(:success) } + end + + context "invalid branch" do + let(:id) { 'invalid-branch' } + it { is_expected.to respond_with(:not_found) } + end + end + + describe "GET #list" do + def go(format: 'json') + get :list, + namespace_id: project.namespace.to_param, + project_id: project.to_param, + id: id, + format: format + end + + context "valid branch" do + let(:id) { 'master' } + it 'returns an array of file path list' do + go + + json = JSON.parse(response.body) + is_expected.to respond_with(:success) + expect(json).not_to eq(nil) + expect(json.length).to be >= 0 + end + end + + context "invalid branch" do + let(:id) { 'invalid-branch' } + + it 'responds with status 404' do + go + is_expected.to respond_with(:not_found) + end + end + end +end diff --git a/spec/routing/project_routing_spec.rb b/spec/routing/project_routing_spec.rb index 82f62a8709c..2a70c190337 100644 --- a/spec/routing/project_routing_spec.rb +++ b/spec/routing/project_routing_spec.rb @@ -434,6 +434,18 @@ describe Projects::TreeController, 'routing' do end end +# project_find_file GET /:namespace_id/:project_id/find_file/*id(.:format) projects/find_file#show {:id=>/.+/, :namespace_id=>/[a-zA-Z.0-9_\-]+/, :project_id=>/[a-zA-Z.0-9_\-]+(?/html/} +# project_files GET /:namespace_id/:project_id/files/*id(.:format) projects/find_file#list {:id=>/(?:[^.]|\.(?!json$))+/, :namespace_id=>/[a-zA-Z.0-9_\-]+/, :project_id=>/[a-zA-Z.0-9_\-]+(?/json/} +describe Projects::FindFileController, 'routing' do + it 'to #show' do + expect(get('/gitlab/gitlabhq/find_file/master')).to route_to('projects/find_file#show', namespace_id: 'gitlab', project_id: 'gitlabhq', id: 'master') + end + + it 'to #list' do + expect(get('/gitlab/gitlabhq/files/master.json')).to route_to('projects/find_file#list', namespace_id: 'gitlab', project_id: 'gitlabhq', id: 'master', format: 'json') + end +end + describe Projects::BlobController, 'routing' do it 'to #edit' do expect(get('/gitlab/gitlabhq/edit/master/app/models/project.rb')).to( diff --git a/vendor/assets/javascripts/fuzzaldrin-plus.min.js b/vendor/assets/javascripts/fuzzaldrin-plus.min.js new file mode 100644 index 00000000000..3f25c2d8373 --- /dev/null +++ b/vendor/assets/javascripts/fuzzaldrin-plus.min.js @@ -0,0 +1 @@ +(function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o0?maxInners:candidates.length;bAllowErrors=!!allowErrors;bKey=key!=null;prepQuery=scorer.prepQuery(query);if(!legacy){for(i=0,len=candidates.length;i0){scoredCandidates.push({candidate:candidate,score:score});if(!--spotLeft){break}}}}else{queryHasSlashes=prepQuery.depth>0;coreQuery=prepQuery.core;for(j=0,len1=candidates.length;j0){scoredCandidates.push({candidate:candidate,score:score})}}}scoredCandidates.sort(sortCandidates);candidates=scoredCandidates.map(pluckCandidates);if(maxResults!=null){candidates=candidates.slice(0,maxResults)}return candidates}}).call(this)},{"./legacy":4,"./scorer":6,"path":7}],2:[function(require,module,exports){(function(){var PathSeparator,filter,legacy_scorer,matcher,prepQueryCache,scorer;scorer=require('./scorer');legacy_scorer=require('./legacy');filter=require('./filter');matcher=require('./matcher');PathSeparator=require('path').sep;prepQueryCache=null;module.exports={filter:function(candidates,query,options){if(!((query!=null?query.length:void 0)&&(candidates!=null?candidates.length:void 0))){return[]}return filter(candidates,query,options)},prepQuery:function(query){return scorer.prepQuery(query)},score:function(string,query,prepQuery,arg){var allowErrors,coreQuery,legacy,queryHasSlashes,ref,score;ref=arg!=null?arg:{},allowErrors=ref.allowErrors,legacy=ref.legacy;if(!((string!=null?string.length:void 0)&&(query!=null?query.length:void 0))){return 0}if(prepQuery==null){prepQuery=prepQueryCache&&prepQueryCache.query===query?prepQueryCache:(prepQueryCache=scorer.prepQuery(query))}if(!legacy){score=scorer.score(string,query,prepQuery,!!allowErrors)}else{queryHasSlashes=prepQuery.depth>0;coreQuery=prepQuery.core;score=legacy_scorer.score(string,coreQuery,queryHasSlashes);if(!queryHasSlashes){score=legacy_scorer.basenameScore(string,coreQuery,score)}}return score},match:function(string,query,prepQuery,arg){var allowErrors,baseMatches,i,matches,query_lw,ref,results,string_lw;allowErrors=(arg!=null?arg:{}).allowErrors;if(!string){return[]}if(!query){return[]}if(string===query){return(function(){results=[];for(var i=0,ref=string.length;0<=ref?iref;0<=ref?i++:i--){results.push(i)}return results}).apply(this)}if(prepQuery==null){prepQuery=prepQueryCache&&prepQueryCache.query===query?prepQueryCache:(prepQueryCache=scorer.prepQuery(query))}if(!(allowErrors||scorer.isMatch(string,prepQuery.core_lw,prepQuery.core_up))){return[]}string_lw=string.toLowerCase();query_lw=prepQuery.query_lw;matches=matcher.match(string,string_lw,prepQuery);if(matches.length===0){return matches}if(string.indexOf(PathSeparator)>-1){baseMatches=matcher.basenameMatch(string,string_lw,prepQuery);matches=matcher.mergeMatches(matches,baseMatches)}return matches}}}).call(this)},{"./filter":1,"./legacy":4,"./matcher":5,"./scorer":6,"path":7}],3:[function(require,module,exports){fuzzaldrinPlus=require('./fuzzaldrin')},{"./fuzzaldrin":2}],4:[function(require,module,exports){(function(){var PathSeparator,queryIsLastPathSegment;PathSeparator=require('path').sep;exports.basenameScore=function(string,query,score){var base,depth,index,lastCharacter,segmentCount,slashCount;index=string.length-1;while(string[index]===PathSeparator){index--}slashCount=0;lastCharacter=index;base=null;while(index>=0){if(string[index]===PathSeparator){slashCount++;if(base==null){base=string.substring(index+1,lastCharacter+1)}}else if(index===0){if(lastCharacterref;stringOffset<=ref?i++:i--){results.push(i)}return results}).apply(this)}queryLength=query.length;stringLength=string.length;indexInQuery=0;indexInString=0;matches=[];while(indexInQuery0){basePos=subject.lastIndexOf(PathSeparator,basePos-1);if(basePos===-1){return[]}}basePos++;end++;return exports.match(subject.slice(basePos,end),subject_lw.slice(basePos,end),prepQuery,basePos)};exports.mergeMatches=function(a,b){var ai,bj,i,j,m,n,out;m=a.length;n=b.length;if(n===0){return a.slice()}if(m===0){return b.slice()}i=-1;j=0;bj=b[j];out=[];while(++i0?csc_diag:scorer.scoreConsecutives(subject,subject_lw,query,query_lw,i,j,start);align=score_diag+scorer.scoreCharacter(i,j,start,acro_score,csc_score)}score_up=score_row[j];csc_diag=csc_row[j];if(score>score_up){move=LEFT}else{score=score_up;move=UP}if(align>score){score=align;move=DIAGONAL}else{csc_score=0}score_row[j]=score;csc_row[j]=csc_score;trace[++pos]=score>0?move:STOP}}i=m-1;j=n-1;pos=i*n+j;backtrack=true;matches=[];while(backtrack&&i>=0&&j>=0){switch(trace[pos]){case UP:i--;pos-=n;break;case LEFT:j--;pos--;break;case DIAGONAL:matches.push(i+offset);j--;i--;pos-=n+1;break;default:backtrack=false}}matches.reverse();return matches}}).call(this)},{"./scorer":6,"path":7}],6:[function(require,module,exports){(function(){var AcronymResult,PathSeparator,Query,basenameScore,coreChars,countDir,doScore,emptyAcronymResult,file_coeff,isMatch,isSeparator,isWordEnd,isWordStart,miss_coeff,opt_char_re,pos_bonus,scoreAcronyms,scoreCharacter,scoreConsecutives,scoreExact,scoreExactMatch,scorePattern,scorePosition,scoreSize,tau_depth,tau_size,truncatedUpperCase,wm;PathSeparator=require('path').sep;wm=150;pos_bonus=20;tau_depth=13;tau_size=85;file_coeff=1.2;miss_coeff=0.75;opt_char_re=/[ _\-:\/\\]/g;exports.coreChars=coreChars=function(query){return query.replace(opt_char_re,'')};exports.score=function(string,query,prepQuery,allowErrors){var score,string_lw;if(prepQuery==null){prepQuery=new Query(query)}if(allowErrors==null){allowErrors=false}if(!(allowErrors||isMatch(string,prepQuery.core_lw,prepQuery.core_up))){return 0}string_lw=string.toLowerCase();score=doScore(string,string_lw,prepQuery);return Math.ceil(basenameScore(string,string_lw,prepQuery,score))};Query=(function(){function Query(query){if(!(query!=null?query.length:void 0)){return null}this.query=query;this.query_lw=query.toLowerCase();this.core=coreChars(query);this.core_lw=this.core.toLowerCase();this.core_up=truncatedUpperCase(this.core);this.depth=countDir(query,query.length)}return Query})();exports.prepQuery=function(query){return new Query(query)};exports.isMatch=isMatch=function(subject,query_lw,query_up){var i,j,m,n,qj_lw,qj_up,si;m=subject.length;n=query_lw.length;if(!m||!n||n>m){return false}i=-1;j=-1;while(++j-1){return scoreExactMatch(subject,subject_lw,query,query_lw,pos,n,m)}score_row=new Array(n);csc_row=new Array(n);sz=scoreSize(n,m);miss_budget=Math.ceil(miss_coeff*n)+5;miss_left=miss_budget;j=-1;while(++j-1){i--}mm=subject_lw.lastIndexOf(query_lw[n-1],m);if(mm>i){m=mm+1}while(++iscore){score=score_up}csc_score=0;if(query_lw[j]===si_lw){start=isWordStart(i,subject,subject_lw);csc_score=csc_diag>0?csc_diag:scoreConsecutives(subject,subject_lw,query,query_lw,i,j,start);align=score_diag+scoreCharacter(i,j,start,acro_score,csc_score);if(align>score){score=align;miss_left=miss_budget}else{if(record_miss&&--miss_left<=0){return score_row[n-1]*sz}record_miss=false}}score_diag=score_up;csc_diag=csc_row[j];csc_row[j]=csc_score;score_row[j]=score}}return score*sz};exports.isWordStart=isWordStart=function(pos,subject,subject_lw){var curr_s,prev_s;if(pos===0){return true}curr_s=subject[pos];prev_s=subject[pos-1];return isSeparator(curr_s)||isSeparator(prev_s)||(curr_s!==subject_lw[pos]&&prev_s===subject_lw[pos-1])};exports.isWordEnd=isWordEnd=function(pos,subject,subject_lw,len){var curr_s,next_s;if(pos===len-1){return true}curr_s=subject[pos];next_s=subject[pos+1];return isSeparator(curr_s)||isSeparator(next_s)||(curr_s===subject_lw[pos]&&next_s!==subject_lw[pos+1])};isSeparator=function(c){return c===' '||c==='.'||c==='-'||c==='_'||c==='/'||c==='\\'};scorePosition=function(pos){var sc;if(poscsc_score?acro_score:csc_score)+10)}return posBonus+wm*csc_score};exports.scoreConsecutives=scoreConsecutives=function(subject,subject_lw,query,query_lw,i,j,start){var k,m,mi,n,nj,sameCase,startPos,sz;m=subject.length;n=query.length;mi=m-i;nj=n-j;k=mi-1){start=isWordStart(pos2,subject,subject_lw);if(start){pos=pos2}}}i=-1;sameCase=0;while(++i1&&n>1)){return emptyAcronymResult}count=0;pos=0;sameCase=0;i=-1;j=-1;while(++j0){basePos=subject.lastIndexOf(PathSeparator,basePos-1);if(basePos===-1){return fullPathScore}}basePos++;end++;basePathScore=doScore(subject.slice(basePos,end),subject_lw.slice(basePos,end),prepQuery);alpha=0.5*tau_depth/(tau_depth+countDir(subject,end+1));return alpha*basePathScore+(1-alpha)*fullPathScore*scoreSize(0,file_coeff*(end-basePos))};exports.countDir=countDir=function(path,end){var count,i;if(end<1){return 0}count=0;i=-1;while(++i=0;i--){var last=parts[i];if(last==='.'){parts.splice(i,1)}else if(last==='..'){parts.splice(i,1);up++}else if(up){parts.splice(i,1);up--}}if(allowAboveRoot){for(;up--;up){parts.unshift('..')}}return parts}var splitPathRe=/^(\/?|)([\s\S]*?)((?:\.{1,2}|[^\/]+?|)(\.[^.\/]*|))(?:[\/]*)$/;var splitPath=function(filename){return splitPathRe.exec(filename).slice(1)};exports.resolve=function(){var resolvedPath='',resolvedAbsolute=false;for(var i=arguments.length-1;i>=-1&&!resolvedAbsolute;i--){var path=(i>=0)?arguments[i]:process.cwd();if(typeof path!=='string'){throw new TypeError('Arguments to path.resolve must be strings');}else if(!path){continue}resolvedPath=path+'/'+resolvedPath;resolvedAbsolute=path.charAt(0)==='/'}resolvedPath=normalizeArray(filter(resolvedPath.split('/'),function(p){return!!p}),!resolvedAbsolute).join('/');return((resolvedAbsolute?'/':'')+resolvedPath)||'.'};exports.normalize=function(path){var isAbsolute=exports.isAbsolute(path),trailingSlash=substr(path,-1)==='/';path=normalizeArray(filter(path.split('/'),function(p){return!!p}),!isAbsolute).join('/');if(!path&&!isAbsolute){path='.'}if(path&&trailingSlash){path+='/'}return(isAbsolute?'/':'')+path};exports.isAbsolute=function(path){return path.charAt(0)==='/'};exports.join=function(){var paths=Array.prototype.slice.call(arguments,0);return exports.normalize(filter(paths,function(p,index){if(typeof p!=='string'){throw new TypeError('Arguments to path.join must be strings');}return p}).join('/'))};exports.relative=function(from,to){from=exports.resolve(from).substr(1);to=exports.resolve(to).substr(1);function trim(arr){var start=0;for(;start=0;end--){if(arr[end]!=='')break}if(start>end)return[];return arr.slice(start,end-start+1)}var fromParts=trim(from.split('/'));var toParts=trim(to.split('/'));var length=Math.min(fromParts.length,toParts.length);var samePartsLength=length;for(var i=0;i1){for(var i=1;i Date: Thu, 7 Jan 2016 13:04:09 +0100 Subject: Credit koreamic for creating Find File --- CHANGELOG | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG b/CHANGELOG index 22fb91baaf0..32308becba0 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -21,6 +21,7 @@ v 8.4.0 (unreleased) - Update version check images to use SVG - Validate README format before displaying - Enable Microsoft Azure OAuth2 support (Janis Meybohm) + - Add file finder feature in tree view (koreamic) v 8.3.3 (unreleased) - Get "Merge when build succeeds" to work when commits were pushed to MR target branch while builds were running @@ -106,7 +107,6 @@ v 8.3.0 - Fix online editor should not remove newlines at the end of the file - Expose Git's version in the admin area - Show "New Merge Request" buttons on canonical repos when you have a fork (Josh Frye) - - Add file finder feature in tree view v 8.2.3 - Fix application settings cache not expiring after changes (Stan Hu) -- cgit v1.2.1 From 7b10cb6f0f5758c17dd950587982ff400d7aa971 Mon Sep 17 00:00:00 2001 From: Yorick Peterse Date: Thu, 7 Jan 2016 13:05:00 +0100 Subject: Store request methods/URIs as values Since filtering by these values is very rare (they're mostly just displayed as-is) we don't need to waste any index space by saving them as tags. By storing them as values we also greatly reduce the number of series in InfluxDB. --- lib/gitlab/metrics/rack_middleware.rb | 4 ++-- lib/gitlab/metrics/transaction.rb | 6 +++++- spec/lib/gitlab/metrics/rack_middleware_spec.rb | 6 +++--- spec/lib/gitlab/metrics/transaction_spec.rb | 11 +++++++++++ 4 files changed, 21 insertions(+), 6 deletions(-) diff --git a/lib/gitlab/metrics/rack_middleware.rb b/lib/gitlab/metrics/rack_middleware.rb index 5c0587c4c51..e7a2f26d48b 100644 --- a/lib/gitlab/metrics/rack_middleware.rb +++ b/lib/gitlab/metrics/rack_middleware.rb @@ -32,8 +32,8 @@ module Gitlab def transaction_from_env(env) trans = Transaction.new - trans.add_tag(:request_method, env['REQUEST_METHOD']) - trans.add_tag(:request_uri, env['REQUEST_URI']) + trans.set(:request_uri, env['REQUEST_URI']) + trans.set(:request_method, env['REQUEST_METHOD']) trans end diff --git a/lib/gitlab/metrics/transaction.rb b/lib/gitlab/metrics/transaction.rb index 306656d30fe..73131cc6ef2 100644 --- a/lib/gitlab/metrics/transaction.rb +++ b/lib/gitlab/metrics/transaction.rb @@ -4,7 +4,7 @@ module Gitlab class Transaction THREAD_KEY = :_gitlab_metrics_transaction - attr_reader :tags + attr_reader :tags, :values def self.current Thread.current[THREAD_KEY] @@ -46,6 +46,10 @@ module Gitlab @values[name] += value end + def set(name, value) + @values[name] = value + end + def add_tag(key, value) @tags[key] = value end diff --git a/spec/lib/gitlab/metrics/rack_middleware_spec.rb b/spec/lib/gitlab/metrics/rack_middleware_spec.rb index a143fe4cfcd..4e6dfc73df2 100644 --- a/spec/lib/gitlab/metrics/rack_middleware_spec.rb +++ b/spec/lib/gitlab/metrics/rack_middleware_spec.rb @@ -40,9 +40,9 @@ describe Gitlab::Metrics::RackMiddleware do expect(transaction).to be_an_instance_of(Gitlab::Metrics::Transaction) end - it 'tags the transaction with the request method and URI' do - expect(transaction.tags[:request_method]).to eq('GET') - expect(transaction.tags[:request_uri]).to eq('/foo') + it 'stores the request method and URI in the transaction as values' do + expect(transaction.values[:request_method]).to eq('GET') + expect(transaction.values[:request_uri]).to eq('/foo') end end diff --git a/spec/lib/gitlab/metrics/transaction_spec.rb b/spec/lib/gitlab/metrics/transaction_spec.rb index 0c98b8f0127..3a27f897735 100644 --- a/spec/lib/gitlab/metrics/transaction_spec.rb +++ b/spec/lib/gitlab/metrics/transaction_spec.rb @@ -50,6 +50,17 @@ describe Gitlab::Metrics::Transaction do end end + describe '#set' do + it 'sets a value' do + transaction.set(:number, 10) + + expect(transaction).to receive(:add_metric). + with('transactions', { duration: 0.0, number: 10 }, {}) + + transaction.track_self + end + end + describe '#add_tag' do it 'adds a tag' do transaction.add_tag(:foo, 'bar') -- cgit v1.2.1 From 1886d727f738895bb552151d59d4024f405522e2 Mon Sep 17 00:00:00 2001 From: Douwe Maan Date: Thu, 7 Jan 2016 13:37:14 +0100 Subject: Add API project upload endpoint --- app/assets/javascripts/dropzone_input.js.coffee | 14 ++----------- app/services/projects/download_service.rb | 7 ++++++- app/services/projects/upload_service.rb | 7 ++++++- doc/api/projects.md | 28 +++++++++++++++++++++++++ lib/api/projects.rb | 12 ++++++++++- lib/gitlab/email/receiver.rb | 7 ++----- lib/gitlab/fogbugz_import/importer.rb | 4 +--- spec/requests/api/projects_spec.rb | 14 +++++++++++++ 8 files changed, 70 insertions(+), 23 deletions(-) diff --git a/app/assets/javascripts/dropzone_input.js.coffee b/app/assets/javascripts/dropzone_input.js.coffee index 30a35a04339..c714c0fa939 100644 --- a/app/assets/javascripts/dropzone_input.js.coffee +++ b/app/assets/javascripts/dropzone_input.js.coffee @@ -66,7 +66,7 @@ class @DropzoneInput success: (header, response) -> child = $(dropzone[0]).children("textarea") - $(child).val $(child).val() + formatLink(response.link) + "\n" + $(child).val $(child).val() + response.link.markdown + "\n" return error: (temp, errorMessage) -> @@ -99,11 +99,6 @@ class @DropzoneInput child = $(dropzone[0]).children("textarea") - formatLink = (link) -> - text = "[#{link.alt}](#{link.url})" - text = "!#{text}" if link.is_image - text - handlePaste = (event) -> pasteEvent = event.originalEvent if pasteEvent.clipboardData and pasteEvent.clipboardData.items @@ -162,7 +157,7 @@ class @DropzoneInput closeAlertMessage() success: (e, textStatus, response) -> - insertToTextArea(filename, formatLink(response.responseJSON.link)) + insertToTextArea(filename, response.responseJSON.link.markdown) error: (response) -> showError(response.responseJSON.message) @@ -202,8 +197,3 @@ class @DropzoneInput e.preventDefault() $(@).closest('.gfm-form').find('.div-dropzone').click() return - - formatLink: (link) -> - text = "[#{link.alt}](#{link.url})" - text = "!#{text}" if link.is_image - text diff --git a/app/services/projects/download_service.rb b/app/services/projects/download_service.rb index 99f22293d0d..b846a59ed94 100644 --- a/app/services/projects/download_service.rb +++ b/app/services/projects/download_service.rb @@ -18,10 +18,15 @@ module Projects filename = uploader.image? ? uploader.file.basename : uploader.file.filename + escaped_filename = filename.gsub("]", "\\]") + markdown = "[#{escaped_filename}](#{uploader.secure_url})" + markdown.prepend("!") if uploader.image? + { 'alt' => filename, 'url' => uploader.secure_url, - 'is_image' => uploader.image? + 'is_image' => uploader.image?, + 'markdown' => markdown } end diff --git a/app/services/projects/upload_service.rb b/app/services/projects/upload_service.rb index 279550d6f4a..36ccf1cda12 100644 --- a/app/services/projects/upload_service.rb +++ b/app/services/projects/upload_service.rb @@ -12,10 +12,15 @@ module Projects filename = uploader.image? ? uploader.file.basename : uploader.file.filename + escaped_filename = filename.gsub("]", "\\]") + markdown = "[#{escaped_filename}](#{uploader.secure_url})" + markdown.prepend("!") if uploader.image? + { alt: filename, url: uploader.secure_url, - is_image: uploader.image? + is_image: uploader.image?, + markdown: markdown } end diff --git a/doc/api/projects.md b/doc/api/projects.md index 0ca81ffd49e..37d74216c1b 100644 --- a/doc/api/projects.md +++ b/doc/api/projects.md @@ -482,6 +482,34 @@ Parameters: - `id` (required) - The ID of a project +## Uploads + +### Upload a file + +Uploads a file to the specified project to be used in an issue or merge request description, or a comment. + +``` +POST /projects/:id/uploads +``` + +Parameters: + +- `id` (required) - The ID of the project +- `file` (required) - The file to be uploaded + +```json +{ + "alt": "dk", + "url": "/uploads/66dbcd21ec5d24ed6ea225176098d52b/dk.png", + "is_image": true, + "markdown": "![dk](/uploads/66dbcd21ec5d24ed6ea225176098d52b/dk.png)" +} +``` + +**Note**: The returned `url` is relative to the project path. +In Markdown contexts, the link is automatically expanded when the format in `markdown` is used. + + ## Team members ### List project team members diff --git a/lib/api/projects.rb b/lib/api/projects.rb index 0781236cf6d..8b1390e3289 100644 --- a/lib/api/projects.rb +++ b/lib/api/projects.rb @@ -269,7 +269,7 @@ module API # Remove a forked_from relationship # # Parameters: - # id: (required) - The ID of the project being marked as a fork + # id: (required) - The ID of the project being marked as a fork # Example Request: # DELETE /projects/:id/fork delete ":id/fork" do @@ -278,6 +278,16 @@ module API user_project.forked_project_link.destroy end end + + # Upload a file + # + # Parameters: + # id: (required) - The ID of the project + # file: (required) - The file to be uploaded + post ":id/uploads" do + ::Projects::UploadService.new(user_project, params[:file]).execute + end + # search for projects current_user has access to # # Parameters: diff --git a/lib/gitlab/email/receiver.rb b/lib/gitlab/email/receiver.rb index 2b252b32887..2ca21af5bc8 100644 --- a/lib/gitlab/email/receiver.rb +++ b/lib/gitlab/email/receiver.rb @@ -74,7 +74,7 @@ module Gitlab def sent_notification return nil unless reply_key - + SentNotification.for(reply_key) end @@ -82,10 +82,7 @@ module Gitlab attachments = Email::AttachmentUploader.new(message).execute(sent_notification.project) attachments.each do |link| - text = "[#{link[:alt]}](#{link[:url]})" - text.prepend("!") if link[:is_image] - - reply << "\n\n#{text}" + reply << "\n\n#{link[:markdown]}" end reply diff --git a/lib/gitlab/fogbugz_import/importer.rb b/lib/gitlab/fogbugz_import/importer.rb index 403ebeec474..d5f755f90e5 100644 --- a/lib/gitlab/fogbugz_import/importer.rb +++ b/lib/gitlab/fogbugz_import/importer.rb @@ -232,9 +232,7 @@ module Gitlab return nil if res.nil? - text = "[#{res['alt']}](#{res['url']})" - text = "!#{text}" if res['is_image'] - text + text = res['markdown'] end def build_attachment_url(rel_url) diff --git a/spec/requests/api/projects_spec.rb b/spec/requests/api/projects_spec.rb index ab2530859ea..6f4c336b66c 100644 --- a/spec/requests/api/projects_spec.rb +++ b/spec/requests/api/projects_spec.rb @@ -353,6 +353,20 @@ describe API::API, api: true do end end + describe "POST /projects/:id/uploads" do + before { project } + + it "uploads the file and returns its info" do + post api("/projects/#{project.id}/uploads", user), file: fixture_file_upload(Rails.root + "spec/fixtures/dk.png", "image/png") + + expect(response.status).to be(201) + expect(json_response['alt']).to eq("dk") + expect(json_response['url']).to start_with("/uploads/") + expect(json_response['url']).to end_with("/dk.png") + expect(json_response['is_image']).to eq(true) + end + end + describe 'GET /projects/:id' do before { project } before { project_member } -- cgit v1.2.1 From 706d7eb0b7a1d54604a11e1202e44069c6acccee Mon Sep 17 00:00:00 2001 From: Douwe Maan Date: Thu, 7 Jan 2016 13:37:59 +0100 Subject: Satisfy Rubocp --- lib/gitlab/fogbugz_import/importer.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/gitlab/fogbugz_import/importer.rb b/lib/gitlab/fogbugz_import/importer.rb index d5f755f90e5..0e6bee732f1 100644 --- a/lib/gitlab/fogbugz_import/importer.rb +++ b/lib/gitlab/fogbugz_import/importer.rb @@ -232,7 +232,7 @@ module Gitlab return nil if res.nil? - text = res['markdown'] + res['markdown'] end def build_attachment_url(rel_url) -- cgit v1.2.1 From 892d5dbb87614156bb9ad7ce8aa817fdb6b9c79b Mon Sep 17 00:00:00 2001 From: Douwe Maan Date: Thu, 7 Jan 2016 14:10:23 +0100 Subject: Update Gemfile.lock --- Gemfile.lock | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/Gemfile.lock b/Gemfile.lock index a1168ed3b7a..3c7cb6cf439 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -443,6 +443,10 @@ GEM omniauth (1.2.2) hashie (>= 1.2, < 4) rack (~> 1.0) + omniauth-azure-oauth2 (0.0.6) + jwt (~> 1.0) + omniauth (~> 1.0) + omniauth-oauth2 (~> 1.1) omniauth-bitbucket (0.0.2) multi_json (~> 1.7) omniauth (~> 1.1) @@ -488,10 +492,6 @@ GEM activesupport nokogiri (>= 1.4.4) omniauth (~> 1.0) - omniauth-azure-oauth2 (0.0.6) - jwt (~> 1.0) - omniauth (~> 1.0) - omniauth-oauth2 (~> 1.1) opennebula (4.14.2) json nokogiri @@ -920,6 +920,7 @@ DEPENDENCIES oauth2 (~> 1.0.0) octokit (~> 3.7.0) omniauth (~> 1.2.2) + omniauth-azure-oauth2 omniauth-bitbucket (~> 0.0.2) omniauth-cas3 (~> 1.1.2) omniauth-facebook (~> 3.0.0) @@ -931,7 +932,6 @@ DEPENDENCIES omniauth-shibboleth (~> 1.2.0) omniauth-twitter (~> 1.2.0) omniauth_crowd - omniauth-azure-oauth2 org-ruby (~> 0.9.12) paranoia (~> 2.0) pg (~> 0.18.2) -- cgit v1.2.1 From 9a250ad6d85678d7f9197a55c69cb724c81008e0 Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Wed, 6 Jan 2016 11:27:23 +0100 Subject: Filter commits by search parameter Signed-off-by: Dmitriy Zaporozhets --- app/controllers/projects/commits_controller.rb | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/app/controllers/projects/commits_controller.rb b/app/controllers/projects/commits_controller.rb index 04a88990bf4..66e27524a23 100644 --- a/app/controllers/projects/commits_controller.rb +++ b/app/controllers/projects/commits_controller.rb @@ -8,10 +8,16 @@ class Projects::CommitsController < Projects::ApplicationController before_action :authorize_download_code! def show - @repo = @project.repository @limit, @offset = (params[:limit] || 40).to_i, (params[:offset] || 0).to_i + search = params[:search] + + @commits = + if search.present? + @repository.find_commits_by_message(search).compact + else + @repository.commits(@ref, @path, @limit, @offset) + end - @commits = @repo.commits(@ref, @path, @limit, @offset) @note_counts = project.notes.where(commit_id: @commits.map(&:id)). group(:commit_id).count -- cgit v1.2.1 From 5e93f912c3d77e8e22ff563d1701e89b36ddf733 Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Wed, 6 Jan 2016 11:40:03 +0100 Subject: Add search field to commits page Signed-off-by: Dmitriy Zaporozhets --- app/assets/stylesheets/pages/commits.scss | 10 +++------- app/views/projects/commits/show.html.haml | 18 ++++++++++++------ 2 files changed, 15 insertions(+), 13 deletions(-) diff --git a/app/assets/stylesheets/pages/commits.scss b/app/assets/stylesheets/pages/commits.scss index 879bd287470..800df95cff3 100644 --- a/app/assets/stylesheets/pages/commits.scss +++ b/app/assets/stylesheets/pages/commits.scss @@ -28,10 +28,6 @@ } } -.commits-feed-holder { - float: right; -} - li.commit { list-style: none; @@ -126,14 +122,14 @@ li.commit { .divergence-graph { padding: 12px 12px 0 0; float: right; - + .graph-side { position: relative; width: 80px; height: 22px; padding: 5px 0 13px; float: left; - + .bar { position: absolute; height: 4px; @@ -149,7 +145,7 @@ li.commit { left: 0; border-radius: 0 3px 3px 0; } - + .count { padding-top: 6px; padding-bottom: 0px; diff --git a/app/views/projects/commits/show.html.haml b/app/views/projects/commits/show.html.haml index 2dd99cc8215..0d652a832f5 100644 --- a/app/views/projects/commits/show.html.haml +++ b/app/views/projects/commits/show.html.haml @@ -10,15 +10,21 @@ .tree-ref-holder = render 'shared/ref_switcher', destination: 'commits' - .commits-feed-holder.hidden-xs.hidden-sm + .pull-right.hidden-xs.hidden-sm - if create_mr_button?(@repository.root_ref, @ref) - = link_to create_mr_path(@repository.root_ref, @ref), class: 'btn btn-success' do - = icon('plus') - Create Merge Request + .pull-left.prepend-left-10 + = link_to create_mr_path(@repository.root_ref, @ref), class: 'btn btn-success' do + = icon('plus') + Create Merge Request + + .pull-left.prepend-left-10 + = form_tag(namespace_project_commits_path(@project.namespace, @project, @ref), method: :get, class: 'pull-left commits-search-form') do + = search_field_tag :search, params[:search], { placeholder: 'Filter by commit message', class: 'form-control search-text-input', spellcheck: false } - if current_user && current_user.private_token - = link_to namespace_project_commits_path(@project.namespace, @project, @ref, {format: :atom, private_token: current_user.private_token}), title: "Commits Feed", class: 'prepend-left-10 btn' do - = icon("rss") + .pull-left.prepend-left-10 + = link_to namespace_project_commits_path(@project.namespace, @project, @ref, {format: :atom, private_token: current_user.private_token}), title: "Commits Feed", class: 'btn' do + = icon("rss") %ul.breadcrumb.repo-breadcrumb -- cgit v1.2.1 From d1a40e06cc34a83f196345635e5b5ed16685ab62 Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Wed, 6 Jan 2016 12:58:15 +0100 Subject: Add ajax filtering for commits list Also handle commits list with Pager class to prevent code duplication Signed-off-by: Dmitriy Zaporozhets --- app/assets/javascripts/commits.js.coffee | 67 +++++++++++++------------------ app/views/projects/commits/show.html.haml | 10 ++--- 2 files changed, 31 insertions(+), 46 deletions(-) diff --git a/app/assets/javascripts/commits.js.coffee b/app/assets/javascripts/commits.js.coffee index c183e78e513..2d33e0f6ebe 100644 --- a/app/assets/javascripts/commits.js.coffee +++ b/app/assets/javascripts/commits.js.coffee @@ -1,15 +1,5 @@ class @CommitsList - @data = - ref: null - limit: 0 - offset: 0 - @disable = false - - @showProgress: -> - $('.loading').show() - - @hideProgress: -> - $('.loading').hide() + @timer = null @init: (ref, limit) -> $("body").on "click", ".day-commits-table li.commit", (event) -> @@ -18,38 +8,35 @@ class @CommitsList e.stopPropagation() return false - @data.ref = ref - @data.limit = limit - @data.offset = limit + Pager.init limit, true + + @content = $("#commits-list") + @searchField = $("#commits-search") + @initSearch() - this.initLoadMore() - this.showProgress() + @initSearch: -> + @timer = null + @searchField.keyup => + clearTimeout(@timer) + @timer = setTimeout(@filterResults, 500) + + @filterResults: => + form = $(".commits-search-form") + search = @searchField.val() + commitsUrl = form.attr("action") + '?' + form.serialize() + @setOpacitiy("0.5") - @getOld: -> - this.showProgress() $.ajax type: "GET" - url: location.href - data: @data - complete: this.hideProgress - success: (data) -> - CommitsList.append(data.count, data.html) + url: form.attr("action") + data: form.serialize() + complete: => + @setOpacitiy("1.0") + success: (data) => + @content.html(data.html) + # Change url so if user reload a page - search results are saved + history.replaceState {page: commitsUrl}, document.title, commitsUrl dataType: "json" - @append: (count, html) -> - $("#commits-list").append(html) - if count > 0 - @data.offset += count - else - @disable = true - - @initLoadMore: -> - $(document).unbind('scroll') - $(document).endlessScroll - bottomPixels: 400 - fireDelay: 1000 - fireOnce: true - ceaseFire: => - @disable - callback: => - this.getOld() + @setOpacitiy: (opacity) -> + @content.css("opacity", opacity) diff --git a/app/views/projects/commits/show.html.haml b/app/views/projects/commits/show.html.haml index 0d652a832f5..5e59afcd783 100644 --- a/app/views/projects/commits/show.html.haml +++ b/app/views/projects/commits/show.html.haml @@ -19,7 +19,7 @@ .pull-left.prepend-left-10 = form_tag(namespace_project_commits_path(@project.namespace, @project, @ref), method: :get, class: 'pull-left commits-search-form') do - = search_field_tag :search, params[:search], { placeholder: 'Filter by commit message', class: 'form-control search-text-input', spellcheck: false } + = search_field_tag :search, params[:search], { placeholder: 'Filter by commit message', id: 'commits-search', class: 'form-control search-text-input', spellcheck: false } - if current_user && current_user.private_token .pull-left.prepend-left-10 @@ -31,11 +31,9 @@ = commits_breadcrumbs %div{id: dom_id(@project)} - #commits-list= render "commits", project: @project + #commits-list.content_list= render "commits", project: @project .clear = spinner -- if @commits.count == @limit - :javascript - CommitsList.init("#{@ref}", #{@limit}); - +:javascript + CommitsList.init("#{@ref}", #{@limit}); -- cgit v1.2.1 From 0456855911448bca5996428283e0c3e9b2d27c3b Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Wed, 6 Jan 2016 17:12:25 +0100 Subject: Add CHANGELOG item and tests Signed-off-by: Dmitriy Zaporozhets --- CHANGELOG | 1 + features/project/commits/commits.feature | 5 +++++ features/steps/project/commits/commits.rb | 9 +++++++++ 3 files changed, 15 insertions(+) diff --git a/CHANGELOG b/CHANGELOG index 94a776a35eb..879d057fff0 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -23,6 +23,7 @@ v 8.4.0 (unreleased) - Validate README format before displaying - Enable Microsoft Azure OAuth2 support (Janis Meybohm) - Add file finder feature in tree view (koreamic) + - Ajax filter by message for commits page v 8.3.3 (unreleased) - Get "Merge when build succeeds" to work when commits were pushed to MR target branch while builds were running diff --git a/features/project/commits/commits.feature b/features/project/commits/commits.feature index 5bb2d0e976b..01c10721312 100644 --- a/features/project/commits/commits.feature +++ b/features/project/commits/commits.feature @@ -55,3 +55,8 @@ Feature: Project Commits Scenario: I browse a commit with an image Given I visit a commit with an image that changed Then The diff links to both the previous and current image + + @javascript + Scenario: I filter commits by message + When I search "submodules" commits + Then I should see only "submodules" commits diff --git a/features/steps/project/commits/commits.rb b/features/steps/project/commits/commits.rb index a3141fe3be1..daf6cdaaac8 100644 --- a/features/steps/project/commits/commits.rb +++ b/features/steps/project/commits/commits.rb @@ -124,4 +124,13 @@ class Spinach::Features::ProjectCommits < Spinach::FeatureSteps expect(page).to have_content "build: pending" expect(page).to have_content "1 build" end + + step 'I search "submodules" commits' do + fill_in 'commits-search', with: 'submodules' + end + + step 'I should see only "submodules" commits' do + expect(page).to have_content "More submodules" + expect(page).not_to have_content "Change some files" + end end -- cgit v1.2.1 From b2b4e9a7eb925bec2a09e44940cab31199f1de5c Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Thu, 7 Jan 2016 12:38:35 +0100 Subject: Prevent loading first 20 commits twice Signed-off-by: Dmitriy Zaporozhets --- app/assets/javascripts/commits.js.coffee | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/app/assets/javascripts/commits.js.coffee b/app/assets/javascripts/commits.js.coffee index 2d33e0f6ebe..bddcf83d4dd 100644 --- a/app/assets/javascripts/commits.js.coffee +++ b/app/assets/javascripts/commits.js.coffee @@ -8,7 +8,7 @@ class @CommitsList e.stopPropagation() return false - Pager.init limit, true + Pager.init limit, false @content = $("#commits-list") @searchField = $("#commits-search") @@ -24,14 +24,14 @@ class @CommitsList form = $(".commits-search-form") search = @searchField.val() commitsUrl = form.attr("action") + '?' + form.serialize() - @setOpacitiy("0.5") + @setOpacitiy(0.5) $.ajax type: "GET" url: form.attr("action") data: form.serialize() complete: => - @setOpacitiy("1.0") + @setOpacitiy(1.0) success: (data) => @content.html(data.html) # Change url so if user reload a page - search results are saved -- cgit v1.2.1 From 4443a5f3c76015f7bf083248b6910d01839cfc88 Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Thu, 7 Jan 2016 13:00:47 +0100 Subject: Add support for ref and path to commits filtering Signed-off-by: Dmitriy Zaporozhets --- app/controllers/projects/commits_controller.rb | 2 +- app/models/repository.rb | 21 ++++++++++++--------- app/views/projects/commits/show.html.haml | 2 +- 3 files changed, 14 insertions(+), 11 deletions(-) diff --git a/app/controllers/projects/commits_controller.rb b/app/controllers/projects/commits_controller.rb index 66e27524a23..bf5b54c8cb7 100644 --- a/app/controllers/projects/commits_controller.rb +++ b/app/controllers/projects/commits_controller.rb @@ -13,7 +13,7 @@ class Projects::CommitsController < Projects::ApplicationController @commits = if search.present? - @repository.find_commits_by_message(search).compact + @repository.find_commits_by_message(search, @ref, @path, @limit, @offset).compact else @repository.commits(@ref, @path, @limit, @offset) end diff --git a/app/models/repository.rb b/app/models/repository.rb index 9deb08d93b8..d9ff71c01ed 100644 --- a/app/models/repository.rb +++ b/app/models/repository.rb @@ -92,9 +92,12 @@ class Repository commits end - def find_commits_by_message(query) + def find_commits_by_message(query, ref = nil, path = nil, limit = 1000, offset = 0) + ref ||= root_ref + # Limited to 1000 commits for now, could be parameterized? - args = %W(#{Gitlab.config.git.bin_path} log --pretty=%H --max-count 1000 --grep=#{query}) + args = %W(#{Gitlab.config.git.bin_path} log #{ref} --pretty=%H --skip #{offset} --max-count #{limit} --grep=#{query}) + args = args.concat(%W(-- #{path})) if path.present? git_log_results = Gitlab::Popen.popen(args, path_to_repo).first.lines.map(&:chomp) commits = git_log_results.map { |c| commit(c) } @@ -175,7 +178,7 @@ class Repository def size cache.fetch(:size) { raw_repository.size } end - + def diverging_commit_counts(branch) root_ref_hash = raw_repository.rev_parse_target(root_ref).oid cache.fetch(:"diverging_commit_counts_#{branch.name}") do @@ -183,7 +186,7 @@ class Repository # than SHA-1 hashes number_commits_behind = commits_between(branch.target, root_ref_hash).size number_commits_ahead = commits_between(root_ref_hash, branch.target).size - + { behind: number_commits_behind, ahead: number_commits_ahead } end end @@ -192,7 +195,7 @@ class Repository %i(size branch_names tag_names commit_count readme version contribution_guide changelog license) end - + def branch_cache_keys branches.map do |branch| :"diverging_commit_counts_#{branch.name}" @@ -205,7 +208,7 @@ class Repository send(key) end end - + branches.each do |branch| unless cache.exist?(:"diverging_commit_counts_#{branch.name}") send(:diverging_commit_counts, branch) @@ -227,10 +230,10 @@ class Repository cache_keys.each do |key| cache.expire(key) end - + expire_branch_cache end - + def expire_branch_cache branches.each do |branch| cache.expire(:"diverging_commit_counts_#{branch.name}") @@ -242,7 +245,7 @@ class Repository cache.expire(key) send(key) end - + branches.each do |branch| cache.expire(:"diverging_commit_counts_#{branch.name}") diverging_commit_counts(branch) diff --git a/app/views/projects/commits/show.html.haml b/app/views/projects/commits/show.html.haml index 5e59afcd783..8f6625fef8a 100644 --- a/app/views/projects/commits/show.html.haml +++ b/app/views/projects/commits/show.html.haml @@ -18,7 +18,7 @@ Create Merge Request .pull-left.prepend-left-10 - = form_tag(namespace_project_commits_path(@project.namespace, @project, @ref), method: :get, class: 'pull-left commits-search-form') do + = form_tag(namespace_project_commits_path(@project.namespace, @project, @id), method: :get, class: 'pull-left commits-search-form') do = search_field_tag :search, params[:search], { placeholder: 'Filter by commit message', id: 'commits-search', class: 'form-control search-text-input', spellcheck: false } - if current_user && current_user.private_token -- cgit v1.2.1 From 44dc9aa69e19d90564fdb279f9e8d51b5caf2cae Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Thu, 7 Jan 2016 13:04:25 +0100 Subject: Fix typo in js method and some repeating css Signed-off-by: Dmitriy Zaporozhets --- app/assets/javascripts/commits.js.coffee | 6 +++--- app/assets/stylesheets/framework/blocks.scss | 9 +++++++++ app/views/projects/commits/show.html.haml | 8 ++++---- 3 files changed, 16 insertions(+), 7 deletions(-) diff --git a/app/assets/javascripts/commits.js.coffee b/app/assets/javascripts/commits.js.coffee index bddcf83d4dd..c337038e446 100644 --- a/app/assets/javascripts/commits.js.coffee +++ b/app/assets/javascripts/commits.js.coffee @@ -24,19 +24,19 @@ class @CommitsList form = $(".commits-search-form") search = @searchField.val() commitsUrl = form.attr("action") + '?' + form.serialize() - @setOpacitiy(0.5) + @setOpacity(0.5) $.ajax type: "GET" url: form.attr("action") data: form.serialize() complete: => - @setOpacitiy(1.0) + @setOpacity(1.0) success: (data) => @content.html(data.html) # Change url so if user reload a page - search results are saved history.replaceState {page: commitsUrl}, document.title, commitsUrl dataType: "json" - @setOpacitiy: (opacity) -> + @setOpacity: (opacity) -> @content.css("opacity", opacity) diff --git a/app/assets/stylesheets/framework/blocks.scss b/app/assets/stylesheets/framework/blocks.scss index 206d39cc9b3..fa0e70847f3 100644 --- a/app/assets/stylesheets/framework/blocks.scss +++ b/app/assets/stylesheets/framework/blocks.scss @@ -72,6 +72,15 @@ > p:last-child { margin-bottom: 0; } + + .block-controls { + float: right; + + .control { + float: left; + margin-left: 10px; + } + } } .cover-block { diff --git a/app/views/projects/commits/show.html.haml b/app/views/projects/commits/show.html.haml index 8f6625fef8a..034057da42e 100644 --- a/app/views/projects/commits/show.html.haml +++ b/app/views/projects/commits/show.html.haml @@ -10,19 +10,19 @@ .tree-ref-holder = render 'shared/ref_switcher', destination: 'commits' - .pull-right.hidden-xs.hidden-sm + .block-controls.hidden-xs.hidden-sm - if create_mr_button?(@repository.root_ref, @ref) - .pull-left.prepend-left-10 + .control = link_to create_mr_path(@repository.root_ref, @ref), class: 'btn btn-success' do = icon('plus') Create Merge Request - .pull-left.prepend-left-10 + .control = form_tag(namespace_project_commits_path(@project.namespace, @project, @id), method: :get, class: 'pull-left commits-search-form') do = search_field_tag :search, params[:search], { placeholder: 'Filter by commit message', id: 'commits-search', class: 'form-control search-text-input', spellcheck: false } - if current_user && current_user.private_token - .pull-left.prepend-left-10 + .control = link_to namespace_project_commits_path(@project.namespace, @project, @ref, {format: :atom, private_token: current_user.private_token}), title: "Commits Feed", class: 'btn' do = icon("rss") -- cgit v1.2.1 From c7fc84f5162f58d1f643beaf88196a3333c75980 Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Thu, 7 Jan 2016 15:15:21 +0100 Subject: Use fadeTo instead of css Signed-off-by: Dmitriy Zaporozhets --- app/assets/javascripts/commits.js.coffee | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/app/assets/javascripts/commits.js.coffee b/app/assets/javascripts/commits.js.coffee index c337038e446..ffd3627b1b0 100644 --- a/app/assets/javascripts/commits.js.coffee +++ b/app/assets/javascripts/commits.js.coffee @@ -24,19 +24,16 @@ class @CommitsList form = $(".commits-search-form") search = @searchField.val() commitsUrl = form.attr("action") + '?' + form.serialize() - @setOpacity(0.5) + @content.fadeTo('fast', 0.5) $.ajax type: "GET" url: form.attr("action") data: form.serialize() complete: => - @setOpacity(1.0) + @content.fadeTo('fast', 1.0) success: (data) => @content.html(data.html) # Change url so if user reload a page - search results are saved history.replaceState {page: commitsUrl}, document.title, commitsUrl dataType: "json" - - @setOpacity: (opacity) -> - @content.css("opacity", opacity) -- cgit v1.2.1 From 8386edafd13c8cca1c6ed45abbbc554351300e9d Mon Sep 17 00:00:00 2001 From: Stan Hu Date: Thu, 7 Jan 2016 06:28:24 -0800 Subject: Accept 2xx status codes for successful Web hook triggers Closes https://github.com/gitlabhq/gitlabhq/issues/9956 --- CHANGELOG | 1 + app/models/hooks/web_hook.rb | 2 +- spec/models/hooks/web_hook_spec.rb | 12 ++++++++++++ 3 files changed, 14 insertions(+), 1 deletion(-) diff --git a/CHANGELOG b/CHANGELOG index 94a776a35eb..a849d5efbf0 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.4.0 (unreleased) + - Accept 2xx status codes for successful Web hook triggers (Stan Hu) - Fix missing date of month in network graph when commits span a month (Stan Hu) - Expire view caches when application settings change (e.g. Gravatar disabled) (Stan Hu) - Don't notify users twice if they are both project watchers and subscribers (Stan Hu) diff --git a/app/models/hooks/web_hook.rb b/app/models/hooks/web_hook.rb index 40eb0e20b4b..b12a45e922a 100644 --- a/app/models/hooks/web_hook.rb +++ b/app/models/hooks/web_hook.rb @@ -60,7 +60,7 @@ class WebHook < ActiveRecord::Base basic_auth: auth) end - [response.code == 200, ActionView::Base.full_sanitizer.sanitize(response.to_s)] + [(response.code >= 200 && response.code < 300), ActionView::Base.full_sanitizer.sanitize(response.to_s)] rescue SocketError, OpenSSL::SSL::SSLError, Errno::ECONNRESET, Errno::ECONNREFUSED, Net::OpenTimeout => e logger.error("WebHook Error => #{e}") [false, e.to_s] diff --git a/spec/models/hooks/web_hook_spec.rb b/spec/models/hooks/web_hook_spec.rb index 2d90b0793cc..7070aa4ac62 100644 --- a/spec/models/hooks/web_hook_spec.rb +++ b/spec/models/hooks/web_hook_spec.rb @@ -77,5 +77,17 @@ describe ProjectHook, models: true do expect(@project_hook.execute(@data, 'push_hooks')).to eq([false, 'SSL error']) end + + it "handles 200 status code" do + WebMock.stub_request(:post, @project_hook.url).to_return(status: 200, body: "Success") + + expect(@project_hook.execute(@data, 'push_hooks')).to eq([true, 'Success']) + end + + it "handles 2xx status codes" do + WebMock.stub_request(:post, @project_hook.url).to_return(status: 201, body: "Success") + + expect(@project_hook.execute(@data, 'push_hooks')).to eq([true, 'Success']) + end end end -- cgit v1.2.1 From 1e927d39b4bf6d1177dee0dd4a6c60bf270db3f2 Mon Sep 17 00:00:00 2001 From: Douwe Maan Date: Thu, 7 Jan 2016 15:51:12 +0100 Subject: Update spec --- Gemfile.lock | 10 +++++----- spec/lib/gitlab/email/receiver_spec.rb | 11 +++++++---- 2 files changed, 12 insertions(+), 9 deletions(-) diff --git a/Gemfile.lock b/Gemfile.lock index a1168ed3b7a..3c7cb6cf439 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -443,6 +443,10 @@ GEM omniauth (1.2.2) hashie (>= 1.2, < 4) rack (~> 1.0) + omniauth-azure-oauth2 (0.0.6) + jwt (~> 1.0) + omniauth (~> 1.0) + omniauth-oauth2 (~> 1.1) omniauth-bitbucket (0.0.2) multi_json (~> 1.7) omniauth (~> 1.1) @@ -488,10 +492,6 @@ GEM activesupport nokogiri (>= 1.4.4) omniauth (~> 1.0) - omniauth-azure-oauth2 (0.0.6) - jwt (~> 1.0) - omniauth (~> 1.0) - omniauth-oauth2 (~> 1.1) opennebula (4.14.2) json nokogiri @@ -920,6 +920,7 @@ DEPENDENCIES oauth2 (~> 1.0.0) octokit (~> 3.7.0) omniauth (~> 1.2.2) + omniauth-azure-oauth2 omniauth-bitbucket (~> 0.0.2) omniauth-cas3 (~> 1.1.2) omniauth-facebook (~> 3.0.0) @@ -931,7 +932,6 @@ DEPENDENCIES omniauth-shibboleth (~> 1.2.0) omniauth-twitter (~> 1.2.0) omniauth_crowd - omniauth-azure-oauth2 org-ruby (~> 0.9.12) paranoia (~> 2.0) pg (~> 0.18.2) diff --git a/spec/lib/gitlab/email/receiver_spec.rb b/spec/lib/gitlab/email/receiver_spec.rb index b535413bbd4..abe179cd4af 100644 --- a/spec/lib/gitlab/email/receiver_spec.rb +++ b/spec/lib/gitlab/email/receiver_spec.rb @@ -42,7 +42,7 @@ describe Gitlab::Email::Receiver, lib: true do context "when the email was auto generated" do let!(:reply_key) { '636ca428858779856c226bb145ef4fad' } let!(:email_raw) { fixture_file("emails/auto_reply.eml") } - + it "raises an AutoGeneratedEmailError" do expect { receiver.execute }.to raise_error(Gitlab::Email::Receiver::AutoGeneratedEmailError) end @@ -90,7 +90,7 @@ describe Gitlab::Email::Receiver, lib: true do context "when the reply is blank" do let!(:email_raw) { fixture_file("emails/no_content_reply.eml") } - + it "raises an EmptyEmailError" do expect { receiver.execute }.to raise_error(Gitlab::Email::Receiver::EmptyEmailError) end @@ -107,13 +107,16 @@ describe Gitlab::Email::Receiver, lib: true do end context "when everything is fine" do + let(:markdown) { "![image](uploads/image.png)" } + before do allow_any_instance_of(Gitlab::Email::AttachmentUploader).to receive(:execute).and_return( [ { url: "uploads/image.png", is_image: true, - alt: "image" + alt: "image", + markdown: markdown } ] ) @@ -132,7 +135,7 @@ describe Gitlab::Email::Receiver, lib: true do note = noteable.notes.last - expect(note.note).to include("![image](uploads/image.png)") + expect(note.note).to include(markdown) end end end -- cgit v1.2.1 From c3865bda0257506e3e9ba8352913eb288f0e3e34 Mon Sep 17 00:00:00 2001 From: Douwe Maan Date: Thu, 7 Jan 2016 14:04:01 +0100 Subject: Properly set task-list class on single item task lists --- CHANGELOG | 1 + lib/banzai/filter/task_list_filter.rb | 13 +++++++++---- 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index 22fb91baaf0..c034344e7f9 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -21,6 +21,7 @@ v 8.4.0 (unreleased) - Update version check images to use SVG - Validate README format before displaying - Enable Microsoft Azure OAuth2 support (Janis Meybohm) + - Properly set task-list class on single item task lists v 8.3.3 (unreleased) - Get "Merge when build succeeds" to work when commits were pushed to MR target branch while builds were running diff --git a/lib/banzai/filter/task_list_filter.rb b/lib/banzai/filter/task_list_filter.rb index bdf7c2ebdfc..d0ce13003a5 100644 --- a/lib/banzai/filter/task_list_filter.rb +++ b/lib/banzai/filter/task_list_filter.rb @@ -12,13 +12,18 @@ module Banzai # # See https://github.com/github/task_list/pull/60 class TaskListFilter < TaskList::Filter - def add_css_class(node, *new_class_names) + def add_css_class_with_fix(node, *new_class_names) if new_class_names.include?('task-list') - super if node.children.any? { |c| c['class'] == 'task-list-item' } - else - super + # Don't add class to all lists + return + elsif new_class_names.include?('task-list-item') + add_css_class_without_fix(node.parent, 'task-list') end + + add_css_class_without_fix(node, *new_class_names) end + + alias_method_chain :add_css_class, :fix end end end -- cgit v1.2.1 From 8f6ca700553bdb88fa924dba21f5cb00a3c515f1 Mon Sep 17 00:00:00 2001 From: Jacob Schatz Date: Thu, 7 Jan 2016 12:27:01 -0500 Subject: fixes ajax issue with issue spec --- Gemfile.lock | 12 ++++++------ spec/javascripts/issue_spec.js.coffee | 32 ++++++++++++++++---------------- 2 files changed, 22 insertions(+), 22 deletions(-) diff --git a/Gemfile.lock b/Gemfile.lock index a1168ed3b7a..f5391ef9e48 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -443,6 +443,10 @@ GEM omniauth (1.2.2) hashie (>= 1.2, < 4) rack (~> 1.0) + omniauth-azure-oauth2 (0.0.6) + jwt (~> 1.0) + omniauth (~> 1.0) + omniauth-oauth2 (~> 1.1) omniauth-bitbucket (0.0.2) multi_json (~> 1.7) omniauth (~> 1.1) @@ -488,10 +492,6 @@ GEM activesupport nokogiri (>= 1.4.4) omniauth (~> 1.0) - omniauth-azure-oauth2 (0.0.6) - jwt (~> 1.0) - omniauth (~> 1.0) - omniauth-oauth2 (~> 1.1) opennebula (4.14.2) json nokogiri @@ -920,6 +920,7 @@ DEPENDENCIES oauth2 (~> 1.0.0) octokit (~> 3.7.0) omniauth (~> 1.2.2) + omniauth-azure-oauth2 omniauth-bitbucket (~> 0.0.2) omniauth-cas3 (~> 1.1.2) omniauth-facebook (~> 3.0.0) @@ -931,7 +932,6 @@ DEPENDENCIES omniauth-shibboleth (~> 1.2.0) omniauth-twitter (~> 1.2.0) omniauth_crowd - omniauth-azure-oauth2 org-ruby (~> 0.9.12) paranoia (~> 2.0) pg (~> 0.18.2) @@ -999,4 +999,4 @@ DEPENDENCIES wikicloth (= 0.8.1) BUNDLED WITH - 1.10.6 + 1.11.2 diff --git a/spec/javascripts/issue_spec.js.coffee b/spec/javascripts/issue_spec.js.coffee index 7e67c778861..b85fadcbe82 100644 --- a/spec/javascripts/issue_spec.js.coffee +++ b/spec/javascripts/issue_spec.js.coffee @@ -26,10 +26,10 @@ describe 'reopen/close issue', -> fixture.load('issues_show.html') @issue = new Issue() it 'closes an issue', -> - $.ajax = (obj) -> - expect(obj.type).toBe('PUT') - expect(obj.url).toBe('http://gitlab.com/issues/6/close') - obj.success saved: true + spyOn(jQuery, 'ajax').and.callFake (req) -> + expect(req.type).toBe('PUT') + expect(req.url).toBe('http://gitlab.com/issues/6/close') + req.success saved: true $btnClose = $('a.btn-close') $btnReopen = $('a.btn-reopen') @@ -46,10 +46,10 @@ describe 'reopen/close issue', -> it 'fails to closes an issue with success:false', -> - $.ajax = (obj) -> - expect(obj.type).toBe('PUT') - expect(obj.url).toBe('http://goesnowhere.nothing/whereami') - obj.success saved: false + spyOn(jQuery, 'ajax').and.callFake (req) -> + expect(req.type).toBe('PUT') + expect(req.url).toBe('http://goesnowhere.nothing/whereami') + req.success saved: false $btnClose = $('a.btn-close') $btnReopen = $('a.btn-reopen') @@ -69,10 +69,10 @@ describe 'reopen/close issue', -> it 'fails to closes an issue with HTTP error', -> - $.ajax = (obj) -> - expect(obj.type).toBe('PUT') - expect(obj.url).toBe('http://goesnowhere.nothing/whereami') - obj.error() + spyOn(jQuery, 'ajax').and.callFake (req) -> + expect(req.type).toBe('PUT') + expect(req.url).toBe('http://goesnowhere.nothing/whereami') + req.error() $btnClose = $('a.btn-close') $btnReopen = $('a.btn-reopen') @@ -91,10 +91,10 @@ describe 'reopen/close issue', -> expect($('div.flash-alert').text()).toBe('Unable to update this issue at this time.') it 'reopens an issue', -> - $.ajax = (obj) -> - expect(obj.type).toBe('PUT') - expect(obj.url).toBe('http://gitlab.com/issues/6/reopen') - obj.success saved: true + spyOn(jQuery, 'ajax').and.callFake (req) -> + expect(req.type).toBe('PUT') + expect(req.url).toBe('http://gitlab.com/issues/6/reopen') + req.success saved: true $btnClose = $('a.btn-close') $btnReopen = $('a.btn-reopen') -- cgit v1.2.1 From df18441e09e99d79d228c58d63bb9247c516163b Mon Sep 17 00:00:00 2001 From: Jacob Schatz Date: Thu, 7 Jan 2016 12:59:45 -0500 Subject: changes titles --- Gemfile.lock | 12 ++++++------ app/helpers/sorting_helper.rb | 4 ++-- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/Gemfile.lock b/Gemfile.lock index a1168ed3b7a..f5391ef9e48 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -443,6 +443,10 @@ GEM omniauth (1.2.2) hashie (>= 1.2, < 4) rack (~> 1.0) + omniauth-azure-oauth2 (0.0.6) + jwt (~> 1.0) + omniauth (~> 1.0) + omniauth-oauth2 (~> 1.1) omniauth-bitbucket (0.0.2) multi_json (~> 1.7) omniauth (~> 1.1) @@ -488,10 +492,6 @@ GEM activesupport nokogiri (>= 1.4.4) omniauth (~> 1.0) - omniauth-azure-oauth2 (0.0.6) - jwt (~> 1.0) - omniauth (~> 1.0) - omniauth-oauth2 (~> 1.1) opennebula (4.14.2) json nokogiri @@ -920,6 +920,7 @@ DEPENDENCIES oauth2 (~> 1.0.0) octokit (~> 3.7.0) omniauth (~> 1.2.2) + omniauth-azure-oauth2 omniauth-bitbucket (~> 0.0.2) omniauth-cas3 (~> 1.1.2) omniauth-facebook (~> 3.0.0) @@ -931,7 +932,6 @@ DEPENDENCIES omniauth-shibboleth (~> 1.2.0) omniauth-twitter (~> 1.2.0) omniauth_crowd - omniauth-azure-oauth2 org-ruby (~> 0.9.12) paranoia (~> 2.0) pg (~> 0.18.2) @@ -999,4 +999,4 @@ DEPENDENCIES wikicloth (= 0.8.1) BUNDLED WITH - 1.10.6 + 1.11.2 diff --git a/app/helpers/sorting_helper.rb b/app/helpers/sorting_helper.rb index bb12d43f397..99d7df64a83 100644 --- a/app/helpers/sorting_helper.rb +++ b/app/helpers/sorting_helper.rb @@ -19,7 +19,7 @@ module SortingHelper end def sort_title_recently_updated - 'Recently updated' + 'Last updated' end def sort_title_oldest_created @@ -27,7 +27,7 @@ module SortingHelper end def sort_title_recently_created - 'Recently created' + 'Last created' end def sort_title_milestone_soon -- cgit v1.2.1 From ad8366ed84b9c32c24c0ffe1c0a071f726cb119f Mon Sep 17 00:00:00 2001 From: Jacob Schatz Date: Thu, 7 Jan 2016 13:23:17 -0500 Subject: css change to height to make gray container fit --- Gemfile.lock | 12 ++++++------ app/assets/stylesheets/pages/events.scss | 1 + app/assets/stylesheets/pages/projects.scss | 1 + 3 files changed, 8 insertions(+), 6 deletions(-) diff --git a/Gemfile.lock b/Gemfile.lock index a1168ed3b7a..f5391ef9e48 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -443,6 +443,10 @@ GEM omniauth (1.2.2) hashie (>= 1.2, < 4) rack (~> 1.0) + omniauth-azure-oauth2 (0.0.6) + jwt (~> 1.0) + omniauth (~> 1.0) + omniauth-oauth2 (~> 1.1) omniauth-bitbucket (0.0.2) multi_json (~> 1.7) omniauth (~> 1.1) @@ -488,10 +492,6 @@ GEM activesupport nokogiri (>= 1.4.4) omniauth (~> 1.0) - omniauth-azure-oauth2 (0.0.6) - jwt (~> 1.0) - omniauth (~> 1.0) - omniauth-oauth2 (~> 1.1) opennebula (4.14.2) json nokogiri @@ -920,6 +920,7 @@ DEPENDENCIES oauth2 (~> 1.0.0) octokit (~> 3.7.0) omniauth (~> 1.2.2) + omniauth-azure-oauth2 omniauth-bitbucket (~> 0.0.2) omniauth-cas3 (~> 1.1.2) omniauth-facebook (~> 3.0.0) @@ -931,7 +932,6 @@ DEPENDENCIES omniauth-shibboleth (~> 1.2.0) omniauth-twitter (~> 1.2.0) omniauth_crowd - omniauth-azure-oauth2 org-ruby (~> 0.9.12) paranoia (~> 2.0) pg (~> 0.18.2) @@ -999,4 +999,4 @@ DEPENDENCIES wikicloth (= 0.8.1) BUNDLED WITH - 1.10.6 + 1.11.2 diff --git a/app/assets/stylesheets/pages/events.scss b/app/assets/stylesheets/pages/events.scss index 282aaf2219b..984b4b91216 100644 --- a/app/assets/stylesheets/pages/events.scss +++ b/app/assets/stylesheets/pages/events.scss @@ -138,6 +138,7 @@ */ .event-last-push { overflow: auto; + width: 100%; .event-last-push-text { @include str-truncated(100%); padding: 5px 0; diff --git a/app/assets/stylesheets/pages/projects.scss b/app/assets/stylesheets/pages/projects.scss index be6ef43e49c..0133a0d6822 100644 --- a/app/assets/stylesheets/pages/projects.scss +++ b/app/assets/stylesheets/pages/projects.scss @@ -415,6 +415,7 @@ ul.nav.nav-projects-tabs { border-bottom: 1px solid #EEE; margin: 0 -16px; padding: 0 $gl-padding; + height: 57px; ul.left-top-menu { display: inline-block; -- cgit v1.2.1 From 69209612e1793fcebcdb784074056d7a02b0f6f7 Mon Sep 17 00:00:00 2001 From: Stan Hu Date: Tue, 22 Dec 2015 12:15:06 -0800 Subject: Suppress e-mails on failed builds if allow_failure is set Every time I push to GitLab, I get > 2 emails saying a spec failed when I don't care about benchmarks and other specs that have `allow_failure` set to `true`. --- CHANGELOG | 1 + .../project_services/builds_email_service.rb | 6 +++++- lib/gitlab/build_data_builder.rb | 1 + spec/lib/gitlab/build_data_builder_spec.rb | 1 + .../project_services/builds_email_service_spec.rb | 23 ++++++++++++++++++++++ 5 files changed, 31 insertions(+), 1 deletion(-) create mode 100644 spec/models/project_services/builds_email_service_spec.rb diff --git a/CHANGELOG b/CHANGELOG index 879d057fff0..a6726eb1ec2 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -27,6 +27,7 @@ v 8.4.0 (unreleased) v 8.3.3 (unreleased) - Get "Merge when build succeeds" to work when commits were pushed to MR target branch while builds were running + - Suppress e-mails on failed builds if allow_failure is set (Stan Hu) - Fix project transfer e-mail sending incorrect paths in e-mail notification (Stan Hu) - Enable "Add key" button when user fills in a proper key (Stan Hu) diff --git a/app/models/project_services/builds_email_service.rb b/app/models/project_services/builds_email_service.rb index 92c9b13c9b9..f6313255cbb 100644 --- a/app/models/project_services/builds_email_service.rb +++ b/app/models/project_services/builds_email_service.rb @@ -73,12 +73,16 @@ class BuildsEmailService < Service when 'success' !notify_only_broken_builds? when 'failed' - true + !allow_failure?(data) else false end end + def allow_failure?(data) + data[:build_allow_failure] == true + end + def all_recipients(data) all_recipients = recipients.split(',') diff --git a/lib/gitlab/build_data_builder.rb b/lib/gitlab/build_data_builder.rb index 86bfa0a4378..34e949130da 100644 --- a/lib/gitlab/build_data_builder.rb +++ b/lib/gitlab/build_data_builder.rb @@ -23,6 +23,7 @@ module Gitlab build_started_at: build.started_at, build_finished_at: build.finished_at, build_duration: build.duration, + build_allow_failure: build.allow_failure, # TODO: do we still need it? project_id: project.id, diff --git a/spec/lib/gitlab/build_data_builder_spec.rb b/spec/lib/gitlab/build_data_builder_spec.rb index 839b30f1ff4..38be9448794 100644 --- a/spec/lib/gitlab/build_data_builder_spec.rb +++ b/spec/lib/gitlab/build_data_builder_spec.rb @@ -14,6 +14,7 @@ describe 'Gitlab::BuildDataBuilder' do it { expect(data[:tag]).to eq(build.tag) } it { expect(data[:build_id]).to eq(build.id) } it { expect(data[:build_status]).to eq(build.status) } + it { expect(data[:build_allow_failure]).to eq(false) } it { expect(data[:project_id]).to eq(build.project.id) } it { expect(data[:project_name]).to eq(build.project.name_with_namespace) } end diff --git a/spec/models/project_services/builds_email_service_spec.rb b/spec/models/project_services/builds_email_service_spec.rb new file mode 100644 index 00000000000..905379a64e3 --- /dev/null +++ b/spec/models/project_services/builds_email_service_spec.rb @@ -0,0 +1,23 @@ +require 'spec_helper' + +describe BuildsEmailService do + let(:build) { create(:ci_build) } + let(:data) { Gitlab::BuildDataBuilder.build(build) } + let(:service) { BuildsEmailService.new } + + describe :execute do + it "sends email" do + service.recipients = 'test@gitlab.com' + data[:build_status] = 'failed' + expect(BuildEmailWorker).to receive(:perform_async) + service.execute(data) + end + + it "does not sends email with failed build and allowed_failure on" do + data[:build_status] = 'failed' + data[:build_allow_failure] = true + expect(BuildEmailWorker).not_to receive(:perform_async) + service.execute(data) + end + end +end -- cgit v1.2.1 From 60aedb46d9e6d6c084ddfdc62805b7b1031fbea5 Mon Sep 17 00:00:00 2001 From: Jacob Schatz Date: Thu, 7 Jan 2016 15:18:07 -0500 Subject: adds reference to the bottom of sidebar --- app/assets/stylesheets/pages/issuable.scss | 10 +++++++++- app/views/shared/issuable/_sidebar.html.haml | 19 ++++++++++--------- 2 files changed, 19 insertions(+), 10 deletions(-) diff --git a/app/assets/stylesheets/pages/issuable.scss b/app/assets/stylesheets/pages/issuable.scss index 9da273a0b6b..81925283f11 100644 --- a/app/assets/stylesheets/pages/issuable.scss +++ b/app/assets/stylesheets/pages/issuable.scss @@ -94,8 +94,16 @@ } .cross-project-reference { - font-weight: bold; color: $gl-link-color; + + span { + white-space: nowrap; + width: 80%; + overflow: hidden; + position: relative; + display: inline-block; + text-overflow: ellipsis; + } button { float: right; diff --git a/app/views/shared/issuable/_sidebar.html.haml b/app/views/shared/issuable/_sidebar.html.haml index 79c5cc7f40a..78c52938bd9 100644 --- a/app/views/shared/issuable/_sidebar.html.haml +++ b/app/views/shared/issuable/_sidebar.html.haml @@ -54,14 +54,6 @@ = f.collection_select :label_ids, issuable.project.labels.all, :id, :name, { selected: issuable.label_ids }, multiple: true, class: 'select2 js-select2', data: { placeholder: "Select labels" } - .block - .title - Cross-project reference - .cross-project-reference - %span#cross-project-reference - = cross_project_reference(@project, issuable) - = clipboard_button(clipboard_target: 'span#cross-project-reference') - = render "shared/issuable/participants", participants: issuable.participants(current_user) - if current_user @@ -77,7 +69,16 @@ You're not receiving notifications from this thread. .subscribed{class: ( 'hidden' unless subscribed )} You're receiving notifications because you're subscribed to this thread. + - project_ref = cross_project_reference(@project, issuable) + .block + .title + .cross-project-reference + %span#cross-project-reference + References: + %a{href: '#', title:project_ref} + = project_ref + = clipboard_button(clipboard_target: 'span#cross-project-reference') :javascript new Subscription("#{toggle_subscription_path(issuable)}"); - new IssuableContext(); + new IssuableContext(); \ No newline at end of file -- cgit v1.2.1 From a652c563663a0f5ed101fd5f9bcb14dfe111a9eb Mon Sep 17 00:00:00 2001 From: Jacob Schatz Date: Thu, 7 Jan 2016 15:25:38 -0500 Subject: adds 85% width for text --- app/assets/stylesheets/pages/issuable.scss | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/assets/stylesheets/pages/issuable.scss b/app/assets/stylesheets/pages/issuable.scss index 81925283f11..d4b44004f4f 100644 --- a/app/assets/stylesheets/pages/issuable.scss +++ b/app/assets/stylesheets/pages/issuable.scss @@ -98,7 +98,7 @@ span { white-space: nowrap; - width: 80%; + width: 85%; overflow: hidden; position: relative; display: inline-block; -- cgit v1.2.1 From 65308a9c15cd371986999d38eb6f359d8f601687 Mon Sep 17 00:00:00 2001 From: Robert Speicher Date: Thu, 7 Jan 2016 15:23:29 -0500 Subject: Add spec for single-item task lists --- spec/lib/banzai/filter/task_list_filter_spec.rb | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/spec/lib/banzai/filter/task_list_filter_spec.rb b/spec/lib/banzai/filter/task_list_filter_spec.rb index f2e3a44478d..569cbc885c7 100644 --- a/spec/lib/banzai/filter/task_list_filter_spec.rb +++ b/spec/lib/banzai/filter/task_list_filter_spec.rb @@ -7,4 +7,10 @@ describe Banzai::Filter::TaskListFilter, lib: true do exp = act = %(
  • Item
) expect(filter(act).to_html).to eq exp end + + it 'applies `task-list` to single-item task lists' do + act = filter('
  • [ ] Task 1
') + + expect(act.to_html).to start_with '
    ' + end end -- cgit v1.2.1 From 59305715e9d3569f47d7c2accc2106022c0a6960 Mon Sep 17 00:00:00 2001 From: Robert Speicher Date: Wed, 6 Jan 2016 16:35:17 -0500 Subject: Remove stamp gem Closes #5908 --- Gemfile | 4 ---- Gemfile.lock | 2 -- app/helpers/application_helper.rb | 2 +- app/models/global_milestone.rb | 4 ++-- app/models/milestone.rb | 4 ++-- app/views/admin/groups/show.html.haml | 2 +- app/views/admin/projects/show.html.haml | 2 +- app/views/admin/users/_profile.html.haml | 2 +- app/views/admin/users/show.html.haml | 8 ++++---- app/views/profiles/keys/_key_details.html.haml | 2 +- app/views/projects/commits/_commits.html.haml | 2 +- app/views/users/show.html.haml | 2 +- 12 files changed, 15 insertions(+), 21 deletions(-) diff --git a/Gemfile b/Gemfile index 6b0bc241494..aa912867dda 100644 --- a/Gemfile +++ b/Gemfile @@ -67,10 +67,6 @@ gem 'grape', '~> 0.13.0' gem 'grape-entity', '~> 0.4.2' gem 'rack-cors', '~> 0.4.0', require: 'rack/cors' -# Format dates and times -# based on human-friendly examples -gem "stamp", '~> 0.6.0' - # Pagination gem "kaminari", "~> 0.16.3" diff --git a/Gemfile.lock b/Gemfile.lock index f5391ef9e48..96bf2bd1a2e 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -734,7 +734,6 @@ GEM actionpack (>= 3.0) activesupport (>= 3.0) sprockets (>= 2.8, < 4.0) - stamp (0.6.0) state_machines (0.4.0) state_machines-activemodel (0.3.0) activemodel (~> 4.1) @@ -978,7 +977,6 @@ DEPENDENCIES spring-commands-spinach (~> 1.0.0) spring-commands-teaspoon (~> 0.0.2) sprockets (~> 2.12.3) - stamp (~> 0.6.0) state_machines-activerecord (~> 0.3.0) task_list (~> 1.0.2) teaspoon (~> 1.0.0) diff --git a/app/helpers/application_helper.rb b/app/helpers/application_helper.rb index f7f7a1a02d3..ea0cc3be4b1 100644 --- a/app/helpers/application_helper.rb +++ b/app/helpers/application_helper.rb @@ -206,7 +206,7 @@ module ApplicationHelper element = content_tag :time, time.to_s, class: "#{html_class} js-timeago js-timeago-pending", datetime: time.getutc.iso8601, - title: time.in_time_zone.stamp('Aug 21, 2011 9:23pm'), + title: time.in_time_zone.strftime('%b %-d, %Y %-I:%m%P'), # Aug 1, 2011 9:23pm data: { toggle: 'tooltip', placement: placement, container: 'body' } unless skip_js diff --git a/app/models/global_milestone.rb b/app/models/global_milestone.rb index af1d7562ebe..4fa5825a5f3 100644 --- a/app/models/global_milestone.rb +++ b/app/models/global_milestone.rb @@ -121,9 +121,9 @@ class GlobalMilestone def expires_at if due_date if due_date.past? - "expired at #{due_date.stamp("Aug 21, 2011")}" + "expired at #{due_date.strftime('%b %-d, %Y')}" else - "expires at #{due_date.stamp("Aug 21, 2011")}" + "expires at #{due_date.strftime('%b %-d, %Y')}" end end end diff --git a/app/models/milestone.rb b/app/models/milestone.rb index 550d14d4c39..5f920132da9 100644 --- a/app/models/milestone.rb +++ b/app/models/milestone.rb @@ -112,9 +112,9 @@ class Milestone < ActiveRecord::Base def expires_at if due_date if due_date.past? - "expired at #{due_date.stamp("Aug 21, 2011")}" + "expired at #{due_date.strftime('%b %-d, %Y')}" else - "expires at #{due_date.stamp("Aug 21, 2011")}" + "expires at #{due_date.strftime('%b %-d, %Y')}" end end end diff --git a/app/views/admin/groups/show.html.haml b/app/views/admin/groups/show.html.haml index 296497a4cd4..ef57f51d811 100644 --- a/app/views/admin/groups/show.html.haml +++ b/app/views/admin/groups/show.html.haml @@ -30,7 +30,7 @@ %li %span.light Created on: %strong - = @group.created_at.stamp("March 1, 1999") + = @group.created_at.strftime('%B %-d, %Y') .panel.panel-default .panel-heading diff --git a/app/views/admin/projects/show.html.haml b/app/views/admin/projects/show.html.haml index 5260eadf95b..9c3e6ce3214 100644 --- a/app/views/admin/projects/show.html.haml +++ b/app/views/admin/projects/show.html.haml @@ -38,7 +38,7 @@ %li %span.light Created on: %strong - = @project.created_at.stamp("March 1, 1999") + = @project.created_at.strftime('%B %-d, %Y') %li %span.light http: diff --git a/app/views/admin/users/_profile.html.haml b/app/views/admin/users/_profile.html.haml index 7d11edc79e2..26f01c0df04 100644 --- a/app/views/admin/users/_profile.html.haml +++ b/app/views/admin/users/_profile.html.haml @@ -4,7 +4,7 @@ %ul.well-list %li %span.light Member since - %strong= user.created_at.stamp("Aug 21, 2011") + %strong= user.created_at.strftime('%b %-d, %Y') - unless user.public_email.blank? %li %span.light E-mail: diff --git a/app/views/admin/users/show.html.haml b/app/views/admin/users/show.html.haml index 0848504b7a6..5d8601c4668 100644 --- a/app/views/admin/users/show.html.haml +++ b/app/views/admin/users/show.html.haml @@ -58,12 +58,12 @@ %li %span.light Member since: %strong - = @user.created_at.stamp("Nov 12, 2031") + = @user.created_at.strftime('%b %-d, %Y') - if @user.confirmed_at %li %span.light Confirmed at: %strong - = @user.confirmed_at.stamp("Nov 12, 2031") + = @user.confirmed_at.strftime('%b %-d, %Y') - else %li %span.light Confirmed: @@ -74,7 +74,7 @@ %span.light Current sign-in at: %strong - if @user.current_sign_in_at - = @user.current_sign_in_at.stamp("Nov 12, 2031") + = @user.current_sign_in_at.strftime('%b %-d, %Y') - else never @@ -82,7 +82,7 @@ %span.light Last sign-in at: %strong - if @user.last_sign_in_at - = @user.last_sign_in_at.stamp("Nov 12, 2031") + = @user.last_sign_in_at.strftime('%b %-d, %Y') - else never diff --git a/app/views/profiles/keys/_key_details.html.haml b/app/views/profiles/keys/_key_details.html.haml index 0ca8bd95157..35624908e82 100644 --- a/app/views/profiles/keys/_key_details.html.haml +++ b/app/views/profiles/keys/_key_details.html.haml @@ -10,7 +10,7 @@ %strong= @key.title %li %span.light Created on: - %strong= @key.created_at.stamp("Aug 21, 2011") + %strong= @key.created_at.strftime('%b %-d, %Y') .col-md-8 %p diff --git a/app/views/projects/commits/_commits.html.haml b/app/views/projects/commits/_commits.html.haml index 0cd9ce1f371..6c631228002 100644 --- a/app/views/projects/commits/_commits.html.haml +++ b/app/views/projects/commits/_commits.html.haml @@ -6,7 +6,7 @@ .col-md-2.hidden-xs.hidden-sm %h5.commits-row-date %i.fa.fa-calendar - %span= day.stamp("28 Aug, 2010") + %span= day.strftime('%d %b, %Y') .light = pluralize(commits.count, 'commit') .col-md-10.col-sm-12 diff --git a/app/views/users/show.html.haml b/app/views/users/show.html.haml index 0bca8177e14..814ba146602 100644 --- a/app/views/users/show.html.haml +++ b/app/views/users/show.html.haml @@ -21,7 +21,7 @@ %span #{@user.bio}. %span - Member since #{@user.created_at.stamp("Aug 21, 2011")} + Member since #{@user.created_at.strftime('%b %d, %Y')} .cover-desc - unless @user.public_email.blank? -- cgit v1.2.1 From f7fdcb95daf235455effa96d00eb082c147ac49e Mon Sep 17 00:00:00 2001 From: Drew Blessing Date: Thu, 7 Jan 2016 15:07:13 -0600 Subject: Do not call API if there is no API URL --- CHANGELOG | 1 + app/models/project_services/jira_service.rb | 3 +++ 2 files changed, 4 insertions(+) diff --git a/CHANGELOG b/CHANGELOG index dfee55d963b..2d760c2f53b 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -28,6 +28,7 @@ v 8.4.0 (unreleased) - Ajax filter by message for commits page v 8.3.3 (unreleased) + - Preserve CE behavior with JIRA integration by only calling API if URL is set - Get "Merge when build succeeds" to work when commits were pushed to MR target branch while builds were running - Fix project transfer e-mail sending incorrect paths in e-mail notification (Stan Hu) - Enable "Add key" button when user fills in a proper key (Stan Hu) diff --git a/app/models/project_services/jira_service.rb b/app/models/project_services/jira_service.rb index a1b77c61576..b6c01c32d9a 100644 --- a/app/models/project_services/jira_service.rb +++ b/app/models/project_services/jira_service.rb @@ -121,6 +121,7 @@ class JiraService < IssueTrackerService end def test_settings + return unless api_url.present? result = JiraService.get( jira_api_test_url, headers: { @@ -218,6 +219,7 @@ class JiraService < IssueTrackerService end def send_message(url, message) + return unless api_url.present? result = JiraService.post( url, body: message, @@ -243,6 +245,7 @@ class JiraService < IssueTrackerService end def existing_comment?(issue_name, new_comment) + return unless api_url.present? result = JiraService.get( comment_url(issue_name), headers: { -- cgit v1.2.1 From fa36749bcee7fa2eb72c9f2a6a28aab1b7274097 Mon Sep 17 00:00:00 2001 From: Robert Speicher Date: Wed, 6 Jan 2016 17:27:56 -0500 Subject: Add two custom Date/Time conversion formats --- app/helpers/application_helper.rb | 2 +- app/models/global_milestone.rb | 4 ++-- app/models/milestone.rb | 4 ++-- app/views/admin/groups/show.html.haml | 2 +- app/views/admin/projects/show.html.haml | 2 +- app/views/admin/users/_profile.html.haml | 2 +- app/views/admin/users/show.html.haml | 8 ++++---- app/views/profiles/keys/_key_details.html.haml | 2 +- app/views/users/show.html.haml | 2 +- config/initializers/date_time_formats.rb | 9 +++++++++ spec/helpers/application_helper_spec.rb | 8 ++++---- 11 files changed, 27 insertions(+), 18 deletions(-) create mode 100644 config/initializers/date_time_formats.rb diff --git a/app/helpers/application_helper.rb b/app/helpers/application_helper.rb index ea0cc3be4b1..2b9bad9c9ea 100644 --- a/app/helpers/application_helper.rb +++ b/app/helpers/application_helper.rb @@ -206,7 +206,7 @@ module ApplicationHelper element = content_tag :time, time.to_s, class: "#{html_class} js-timeago js-timeago-pending", datetime: time.getutc.iso8601, - title: time.in_time_zone.strftime('%b %-d, %Y %-I:%m%P'), # Aug 1, 2011 9:23pm + title: time.in_time_zone.to_s(:medium), data: { toggle: 'tooltip', placement: placement, container: 'body' } unless skip_js diff --git a/app/models/global_milestone.rb b/app/models/global_milestone.rb index 4fa5825a5f3..7ee276255a0 100644 --- a/app/models/global_milestone.rb +++ b/app/models/global_milestone.rb @@ -121,9 +121,9 @@ class GlobalMilestone def expires_at if due_date if due_date.past? - "expired at #{due_date.strftime('%b %-d, %Y')}" + "expired on #{due_date.to_s(:medium)}" else - "expires at #{due_date.strftime('%b %-d, %Y')}" + "expires on #{due_date.to_s(:medium)}" end end end diff --git a/app/models/milestone.rb b/app/models/milestone.rb index 5f920132da9..c9a0ad8b9b6 100644 --- a/app/models/milestone.rb +++ b/app/models/milestone.rb @@ -112,9 +112,9 @@ class Milestone < ActiveRecord::Base def expires_at if due_date if due_date.past? - "expired at #{due_date.strftime('%b %-d, %Y')}" + "expired on #{due_date.to_s(:medium)}" else - "expires at #{due_date.strftime('%b %-d, %Y')}" + "expires on #{due_date.to_s(:medium)}" end end end diff --git a/app/views/admin/groups/show.html.haml b/app/views/admin/groups/show.html.haml index ef57f51d811..f7fd156b84a 100644 --- a/app/views/admin/groups/show.html.haml +++ b/app/views/admin/groups/show.html.haml @@ -30,7 +30,7 @@ %li %span.light Created on: %strong - = @group.created_at.strftime('%B %-d, %Y') + = @group.created_at.to_s(:medium) .panel.panel-default .panel-heading diff --git a/app/views/admin/projects/show.html.haml b/app/views/admin/projects/show.html.haml index 9c3e6ce3214..0c986af4a95 100644 --- a/app/views/admin/projects/show.html.haml +++ b/app/views/admin/projects/show.html.haml @@ -38,7 +38,7 @@ %li %span.light Created on: %strong - = @project.created_at.strftime('%B %-d, %Y') + = @project.created_at.to_s(:medium) %li %span.light http: diff --git a/app/views/admin/users/_profile.html.haml b/app/views/admin/users/_profile.html.haml index 26f01c0df04..6bc217f84cc 100644 --- a/app/views/admin/users/_profile.html.haml +++ b/app/views/admin/users/_profile.html.haml @@ -4,7 +4,7 @@ %ul.well-list %li %span.light Member since - %strong= user.created_at.strftime('%b %-d, %Y') + %strong= user.created_at.to_s(:medium) - unless user.public_email.blank? %li %span.light E-mail: diff --git a/app/views/admin/users/show.html.haml b/app/views/admin/users/show.html.haml index 5d8601c4668..2c2450d4117 100644 --- a/app/views/admin/users/show.html.haml +++ b/app/views/admin/users/show.html.haml @@ -58,12 +58,12 @@ %li %span.light Member since: %strong - = @user.created_at.strftime('%b %-d, %Y') + = @user.created_at.to_s(:medium) - if @user.confirmed_at %li %span.light Confirmed at: %strong - = @user.confirmed_at.strftime('%b %-d, %Y') + = @user.confirmed_at.to_s(:medium) - else %li %span.light Confirmed: @@ -74,7 +74,7 @@ %span.light Current sign-in at: %strong - if @user.current_sign_in_at - = @user.current_sign_in_at.strftime('%b %-d, %Y') + = @user.current_sign_in_at.to_s(:medium) - else never @@ -82,7 +82,7 @@ %span.light Last sign-in at: %strong - if @user.last_sign_in_at - = @user.last_sign_in_at.strftime('%b %-d, %Y') + = @user.last_sign_in_at.to_s(:medium) - else never diff --git a/app/views/profiles/keys/_key_details.html.haml b/app/views/profiles/keys/_key_details.html.haml index 35624908e82..3bd1f1af162 100644 --- a/app/views/profiles/keys/_key_details.html.haml +++ b/app/views/profiles/keys/_key_details.html.haml @@ -10,7 +10,7 @@ %strong= @key.title %li %span.light Created on: - %strong= @key.created_at.strftime('%b %-d, %Y') + %strong= @key.created_at.to_s(:medium) .col-md-8 %p diff --git a/app/views/users/show.html.haml b/app/views/users/show.html.haml index 814ba146602..ce17fc7bca1 100644 --- a/app/views/users/show.html.haml +++ b/app/views/users/show.html.haml @@ -21,7 +21,7 @@ %span #{@user.bio}. %span - Member since #{@user.created_at.strftime('%b %d, %Y')} + Member since #{@user.created_at.to_s(:medium)} .cover-desc - unless @user.public_email.blank? diff --git a/config/initializers/date_time_formats.rb b/config/initializers/date_time_formats.rb new file mode 100644 index 00000000000..57568203cab --- /dev/null +++ b/config/initializers/date_time_formats.rb @@ -0,0 +1,9 @@ +# :short - 10 Nov +# :medium - Nov 10, 2007 +# :long - November 10, 2007 +Date::DATE_FORMATS[:medium] = '%b %-d, %Y' + +# :short - 18 Jan 06:10 +# :medium - Jan 18, 2007 6:10am +# :long - January 18, 2007 06:10 +Time::DATE_FORMATS[:medium] = '%b %-d, %Y %-I:%M%P' diff --git a/spec/helpers/application_helper_spec.rb b/spec/helpers/application_helper_spec.rb index 68527c3a4f8..efc850eb705 100644 --- a/spec/helpers/application_helper_spec.rb +++ b/spec/helpers/application_helper_spec.rb @@ -240,7 +240,7 @@ describe ApplicationHelper do describe 'time_ago_with_tooltip' do def element(*arguments) Time.zone = 'UTC' - time = Time.zone.parse('2015-07-02 08:00') + time = Time.zone.parse('2015-07-02 08:23') element = helper.time_ago_with_tooltip(time, *arguments) Nokogiri::HTML::DocumentFragment.parse(element).first_element_child @@ -251,15 +251,15 @@ describe ApplicationHelper do end it 'includes the date string' do - expect(element.text).to eq '2015-07-02 08:00:00 UTC' + expect(element.text).to eq '2015-07-02 08:23:00 UTC' end it 'has a datetime attribute' do - expect(element.attr('datetime')).to eq '2015-07-02T08:00:00Z' + expect(element.attr('datetime')).to eq '2015-07-02T08:23:00Z' end it 'has a formatted title attribute' do - expect(element.attr('title')).to eq 'Jul 02, 2015 8:00am' + expect(element.attr('title')).to eq 'Jul 2, 2015 8:23am' end it 'includes a default js-timeago class' do -- cgit v1.2.1 From 63444936559cffba174a69c01d2425fb6b5e61cf Mon Sep 17 00:00:00 2001 From: Robert Speicher Date: Thu, 7 Jan 2016 16:45:56 -0500 Subject: Use `to_s(:iso8601)` where appropriate --- app/helpers/issues_helper.rb | 2 +- app/views/dashboard/issues.atom.builder | 2 +- app/views/dashboard/projects/index.atom.builder | 2 +- app/views/groups/issues.atom.builder | 2 +- app/views/groups/show.atom.builder | 2 +- app/views/notify/repository_push_email.html.haml | 2 +- app/views/notify/repository_push_email.text.haml | 2 +- app/views/projects/commits/show.atom.builder | 4 ++-- app/views/projects/issues/index.atom.builder | 2 +- app/views/projects/show.atom.builder | 2 +- app/views/users/show.atom.builder | 2 +- 11 files changed, 12 insertions(+), 12 deletions(-) diff --git a/app/helpers/issues_helper.rb b/app/helpers/issues_helper.rb index c12456a187f..acc0e867e8e 100644 --- a/app/helpers/issues_helper.rb +++ b/app/helpers/issues_helper.rb @@ -80,7 +80,7 @@ module IssuesHelper xml.link href: namespace_project_issue_url(issue.project.namespace, issue.project, issue) xml.title truncate(issue.title, length: 80) - xml.updated issue.created_at.strftime("%Y-%m-%dT%H:%M:%SZ") + xml.updated issue.created_at.to_s(:iso8601) xml.media :thumbnail, width: "40", height: "40", url: image_url(avatar_icon(issue.author_email)) xml.author do |author| xml.name issue.author_name diff --git a/app/views/dashboard/issues.atom.builder b/app/views/dashboard/issues.atom.builder index 07bda1c77f8..4aa27036618 100644 --- a/app/views/dashboard/issues.atom.builder +++ b/app/views/dashboard/issues.atom.builder @@ -4,7 +4,7 @@ xml.feed "xmlns" => "http://www.w3.org/2005/Atom", "xmlns:media" => "http://sear xml.link href: issues_dashboard_url(format: :atom, private_token: current_user.try(:private_token)), rel: "self", type: "application/atom+xml" xml.link href: issues_dashboard_url, rel: "alternate", type: "text/html" xml.id issues_dashboard_url - xml.updated @issues.first.created_at.strftime("%Y-%m-%dT%H:%M:%SZ") if @issues.any? + xml.updated @issues.first.created_at.to_s(:iso8601) if @issues.any? @issues.each do |issue| issue_to_atom(xml, issue) diff --git a/app/views/dashboard/projects/index.atom.builder b/app/views/dashboard/projects/index.atom.builder index c8c219f4cca..2b6ef3230fb 100644 --- a/app/views/dashboard/projects/index.atom.builder +++ b/app/views/dashboard/projects/index.atom.builder @@ -4,7 +4,7 @@ xml.feed "xmlns" => "http://www.w3.org/2005/Atom", "xmlns:media" => "http://sear xml.link href: dashboard_projects_url(format: :atom, private_token: current_user.try(:private_token)), rel: "self", type: "application/atom+xml" xml.link href: dashboard_projects_url, rel: "alternate", type: "text/html" xml.id dashboard_projects_url - xml.updated @events.latest_update_time.strftime("%Y-%m-%dT%H:%M:%SZ") if @events.any? + xml.updated @events.latest_update_time.to_s(:iso8601) if @events.any? @events.each do |event| event_to_atom(xml, event) diff --git a/app/views/groups/issues.atom.builder b/app/views/groups/issues.atom.builder index 66fe7e25871..fc58a99854e 100644 --- a/app/views/groups/issues.atom.builder +++ b/app/views/groups/issues.atom.builder @@ -4,7 +4,7 @@ xml.feed "xmlns" => "http://www.w3.org/2005/Atom", "xmlns:media" => "http://sear xml.link href: issues_dashboard_url(format: :atom, private_token: @user.private_token), rel: "self", type: "application/atom+xml" xml.link href: issues_dashboard_url, rel: "alternate", type: "text/html" xml.id issues_dashboard_url - xml.updated @issues.first.created_at.strftime("%Y-%m-%dT%H:%M:%SZ") if @issues.any? + xml.updated @issues.first.created_at.to_s(:iso8601) if @issues.any? @issues.each do |issue| issue_to_atom(xml, issue) diff --git a/app/views/groups/show.atom.builder b/app/views/groups/show.atom.builder index 7ea574434c3..3dbdd08a15e 100644 --- a/app/views/groups/show.atom.builder +++ b/app/views/groups/show.atom.builder @@ -4,7 +4,7 @@ xml.feed "xmlns" => "http://www.w3.org/2005/Atom", "xmlns:media" => "http://sear xml.link href: group_url(@group, format: :atom, private_token: current_user.try(:private_token)), rel: "self", type: "application/atom+xml" xml.link href: group_url(@group), rel: "alternate", type: "text/html" xml.id group_url(@group) - xml.updated @events.latest_update_time.strftime("%Y-%m-%dT%H:%M:%SZ") if @events.any? + xml.updated @events.latest_update_time.to_s(:iso8601) if @events.any? @events.each do |event| event_to_atom(xml, event) diff --git a/app/views/notify/repository_push_email.html.haml b/app/views/notify/repository_push_email.html.haml index 4361f67a74d..3dd2595f1ad 100644 --- a/app/views/notify/repository_push_email.html.haml +++ b/app/views/notify/repository_push_email.html.haml @@ -17,7 +17,7 @@ %strong #{link_to(commit.short_id, namespace_project_commit_url(@message.project_namespace, @message.project, commit))} %div %span by #{commit.author_name} - %i at #{commit.committed_date.strftime("%Y-%m-%dT%H:%M:%SZ")} + %i at #{commit.committed_date.to_s(:iso8601)} %pre.commit-message = commit.safe_message diff --git a/app/views/notify/repository_push_email.text.haml b/app/views/notify/repository_push_email.text.haml index aa0e263b6df..53869e36b28 100644 --- a/app/views/notify/repository_push_email.text.haml +++ b/app/views/notify/repository_push_email.text.haml @@ -8,7 +8,7 @@ \ = @message.reverse_compare? ? "Deleted commits:" : "Commits:" - @message.commits.each do |commit| - #{commit.short_id} by #{commit.author_name} at #{commit.committed_date.strftime("%Y-%m-%dT%H:%M:%SZ")} + #{commit.short_id} by #{commit.author_name} at #{commit.committed_date.to_s(:iso8601)} #{commit.safe_message} \- - - - - \ diff --git a/app/views/projects/commits/show.atom.builder b/app/views/projects/commits/show.atom.builder index 7ffa7317196..43f10b51c20 100644 --- a/app/views/projects/commits/show.atom.builder +++ b/app/views/projects/commits/show.atom.builder @@ -4,14 +4,14 @@ xml.feed "xmlns" => "http://www.w3.org/2005/Atom", "xmlns:media" => "http://sear xml.link href: namespace_project_commits_url(@project.namespace, @project, @ref, format: :atom, private_token: current_user.try(:private_token)), rel: "self", type: "application/atom+xml" xml.link href: namespace_project_commits_url(@project.namespace, @project, @ref), rel: "alternate", type: "text/html" xml.id namespace_project_commits_url(@project.namespace, @project, @ref) - xml.updated @commits.first.committed_date.strftime("%Y-%m-%dT%H:%M:%SZ") if @commits.any? + xml.updated @commits.first.committed_date.to_s(:iso8601) if @commits.any? @commits.each do |commit| xml.entry do xml.id namespace_project_commit_url(@project.namespace, @project, id: commit.id) xml.link href: namespace_project_commit_url(@project.namespace, @project, id: commit.id) xml.title truncate(commit.title, length: 80) - xml.updated commit.committed_date.strftime("%Y-%m-%dT%H:%M:%SZ") + xml.updated commit.committed_date.to_s(:iso8601) xml.media :thumbnail, width: "40", height: "40", url: image_url(avatar_icon(commit.author_email)) xml.author do |author| xml.name commit.author_name diff --git a/app/views/projects/issues/index.atom.builder b/app/views/projects/issues/index.atom.builder index dc8e477185b..cfaafe379aa 100644 --- a/app/views/projects/issues/index.atom.builder +++ b/app/views/projects/issues/index.atom.builder @@ -4,7 +4,7 @@ xml.feed "xmlns" => "http://www.w3.org/2005/Atom", "xmlns:media" => "http://sear xml.link href: namespace_project_issues_url(@project.namespace, @project, format: :atom, private_token: current_user.try(:private_token)), rel: "self", type: "application/atom+xml" xml.link href: namespace_project_issues_url(@project.namespace, @project), rel: "alternate", type: "text/html" xml.id namespace_project_issues_url(@project.namespace, @project) - xml.updated @issues.first.created_at.strftime("%Y-%m-%dT%H:%M:%SZ") if @issues.any? + xml.updated @issues.first.created_at.to_s(:iso8601) if @issues.any? @issues.each do |issue| issue_to_atom(xml, issue) diff --git a/app/views/projects/show.atom.builder b/app/views/projects/show.atom.builder index 15c49767556..cff1ab1a6c9 100644 --- a/app/views/projects/show.atom.builder +++ b/app/views/projects/show.atom.builder @@ -4,7 +4,7 @@ xml.feed "xmlns" => "http://www.w3.org/2005/Atom", "xmlns:media" => "http://sear xml.link href: namespace_project_url(@project.namespace, @project, format: :atom, private_token: current_user.try(:private_token)), rel: "self", type: "application/atom+xml" xml.link href: namespace_project_url(@project.namespace, @project), rel: "alternate", type: "text/html" xml.id namespace_project_url(@project.namespace, @project) - xml.updated @events.latest_update_time.strftime("%Y-%m-%dT%H:%M:%SZ") if @events.any? + xml.updated @events.latest_update_time.to_s(:iso8601) if @events.any? @events.each do |event| event_to_atom(xml, event) diff --git a/app/views/users/show.atom.builder b/app/views/users/show.atom.builder index 2fe5b7fac83..758dfc72abf 100644 --- a/app/views/users/show.atom.builder +++ b/app/views/users/show.atom.builder @@ -4,7 +4,7 @@ xml.feed "xmlns" => "http://www.w3.org/2005/Atom", "xmlns:media" => "http://sear xml.link href: user_url(@user, :atom), rel: "self", type: "application/atom+xml" xml.link href: user_url(@user), rel: "alternate", type: "text/html" xml.id user_url(@user) - xml.updated @events.latest_update_time.strftime("%Y-%m-%dT%H:%M:%SZ") if @events.any? + xml.updated @events.latest_update_time.to_s(:iso8601) if @events.any? @events.each do |event| event_to_atom(xml, event) -- cgit v1.2.1 From 4408dc0bd18dc1cddda8b413dbf57143290f5d73 Mon Sep 17 00:00:00 2001 From: Robert Speicher Date: Thu, 7 Jan 2016 17:00:13 -0500 Subject: Use `xmlschema` where even more appropriate! --- app/helpers/issues_helper.rb | 2 +- app/views/dashboard/issues.atom.builder | 2 +- app/views/dashboard/projects/index.atom.builder | 2 +- app/views/groups/issues.atom.builder | 2 +- app/views/groups/show.atom.builder | 2 +- app/views/projects/commits/show.atom.builder | 4 ++-- app/views/projects/issues/index.atom.builder | 2 +- app/views/projects/show.atom.builder | 2 +- app/views/users/show.atom.builder | 2 +- 9 files changed, 10 insertions(+), 10 deletions(-) diff --git a/app/helpers/issues_helper.rb b/app/helpers/issues_helper.rb index acc0e867e8e..a7080ddfefb 100644 --- a/app/helpers/issues_helper.rb +++ b/app/helpers/issues_helper.rb @@ -80,7 +80,7 @@ module IssuesHelper xml.link href: namespace_project_issue_url(issue.project.namespace, issue.project, issue) xml.title truncate(issue.title, length: 80) - xml.updated issue.created_at.to_s(:iso8601) + xml.updated issue.created_at.xmlschema xml.media :thumbnail, width: "40", height: "40", url: image_url(avatar_icon(issue.author_email)) xml.author do |author| xml.name issue.author_name diff --git a/app/views/dashboard/issues.atom.builder b/app/views/dashboard/issues.atom.builder index 4aa27036618..0d7b1b30dc3 100644 --- a/app/views/dashboard/issues.atom.builder +++ b/app/views/dashboard/issues.atom.builder @@ -4,7 +4,7 @@ xml.feed "xmlns" => "http://www.w3.org/2005/Atom", "xmlns:media" => "http://sear xml.link href: issues_dashboard_url(format: :atom, private_token: current_user.try(:private_token)), rel: "self", type: "application/atom+xml" xml.link href: issues_dashboard_url, rel: "alternate", type: "text/html" xml.id issues_dashboard_url - xml.updated @issues.first.created_at.to_s(:iso8601) if @issues.any? + xml.updated @issues.first.created_at.xmlschema if @issues.any? @issues.each do |issue| issue_to_atom(xml, issue) diff --git a/app/views/dashboard/projects/index.atom.builder b/app/views/dashboard/projects/index.atom.builder index 2b6ef3230fb..2e2712c5146 100644 --- a/app/views/dashboard/projects/index.atom.builder +++ b/app/views/dashboard/projects/index.atom.builder @@ -4,7 +4,7 @@ xml.feed "xmlns" => "http://www.w3.org/2005/Atom", "xmlns:media" => "http://sear xml.link href: dashboard_projects_url(format: :atom, private_token: current_user.try(:private_token)), rel: "self", type: "application/atom+xml" xml.link href: dashboard_projects_url, rel: "alternate", type: "text/html" xml.id dashboard_projects_url - xml.updated @events.latest_update_time.to_s(:iso8601) if @events.any? + xml.updated @events.latest_update_time.xmlschema if @events.any? @events.each do |event| event_to_atom(xml, event) diff --git a/app/views/groups/issues.atom.builder b/app/views/groups/issues.atom.builder index fc58a99854e..486d1d8587a 100644 --- a/app/views/groups/issues.atom.builder +++ b/app/views/groups/issues.atom.builder @@ -4,7 +4,7 @@ xml.feed "xmlns" => "http://www.w3.org/2005/Atom", "xmlns:media" => "http://sear xml.link href: issues_dashboard_url(format: :atom, private_token: @user.private_token), rel: "self", type: "application/atom+xml" xml.link href: issues_dashboard_url, rel: "alternate", type: "text/html" xml.id issues_dashboard_url - xml.updated @issues.first.created_at.to_s(:iso8601) if @issues.any? + xml.updated @issues.first.created_at.xmlschema if @issues.any? @issues.each do |issue| issue_to_atom(xml, issue) diff --git a/app/views/groups/show.atom.builder b/app/views/groups/show.atom.builder index 3dbdd08a15e..5cc0f5e1d2e 100644 --- a/app/views/groups/show.atom.builder +++ b/app/views/groups/show.atom.builder @@ -4,7 +4,7 @@ xml.feed "xmlns" => "http://www.w3.org/2005/Atom", "xmlns:media" => "http://sear xml.link href: group_url(@group, format: :atom, private_token: current_user.try(:private_token)), rel: "self", type: "application/atom+xml" xml.link href: group_url(@group), rel: "alternate", type: "text/html" xml.id group_url(@group) - xml.updated @events.latest_update_time.to_s(:iso8601) if @events.any? + xml.updated @events.latest_update_time.xmlschema if @events.any? @events.each do |event| event_to_atom(xml, event) diff --git a/app/views/projects/commits/show.atom.builder b/app/views/projects/commits/show.atom.builder index 43f10b51c20..e310fafd82c 100644 --- a/app/views/projects/commits/show.atom.builder +++ b/app/views/projects/commits/show.atom.builder @@ -4,14 +4,14 @@ xml.feed "xmlns" => "http://www.w3.org/2005/Atom", "xmlns:media" => "http://sear xml.link href: namespace_project_commits_url(@project.namespace, @project, @ref, format: :atom, private_token: current_user.try(:private_token)), rel: "self", type: "application/atom+xml" xml.link href: namespace_project_commits_url(@project.namespace, @project, @ref), rel: "alternate", type: "text/html" xml.id namespace_project_commits_url(@project.namespace, @project, @ref) - xml.updated @commits.first.committed_date.to_s(:iso8601) if @commits.any? + xml.updated @commits.first.committed_date.xmlschema if @commits.any? @commits.each do |commit| xml.entry do xml.id namespace_project_commit_url(@project.namespace, @project, id: commit.id) xml.link href: namespace_project_commit_url(@project.namespace, @project, id: commit.id) xml.title truncate(commit.title, length: 80) - xml.updated commit.committed_date.to_s(:iso8601) + xml.updated commit.committed_date.xmlschema xml.media :thumbnail, width: "40", height: "40", url: image_url(avatar_icon(commit.author_email)) xml.author do |author| xml.name commit.author_name diff --git a/app/views/projects/issues/index.atom.builder b/app/views/projects/issues/index.atom.builder index cfaafe379aa..ee8a9414657 100644 --- a/app/views/projects/issues/index.atom.builder +++ b/app/views/projects/issues/index.atom.builder @@ -4,7 +4,7 @@ xml.feed "xmlns" => "http://www.w3.org/2005/Atom", "xmlns:media" => "http://sear xml.link href: namespace_project_issues_url(@project.namespace, @project, format: :atom, private_token: current_user.try(:private_token)), rel: "self", type: "application/atom+xml" xml.link href: namespace_project_issues_url(@project.namespace, @project), rel: "alternate", type: "text/html" xml.id namespace_project_issues_url(@project.namespace, @project) - xml.updated @issues.first.created_at.to_s(:iso8601) if @issues.any? + xml.updated @issues.first.created_at.xmlschema if @issues.any? @issues.each do |issue| issue_to_atom(xml, issue) diff --git a/app/views/projects/show.atom.builder b/app/views/projects/show.atom.builder index cff1ab1a6c9..d6762219108 100644 --- a/app/views/projects/show.atom.builder +++ b/app/views/projects/show.atom.builder @@ -4,7 +4,7 @@ xml.feed "xmlns" => "http://www.w3.org/2005/Atom", "xmlns:media" => "http://sear xml.link href: namespace_project_url(@project.namespace, @project, format: :atom, private_token: current_user.try(:private_token)), rel: "self", type: "application/atom+xml" xml.link href: namespace_project_url(@project.namespace, @project), rel: "alternate", type: "text/html" xml.id namespace_project_url(@project.namespace, @project) - xml.updated @events.latest_update_time.to_s(:iso8601) if @events.any? + xml.updated @events.latest_update_time.xmlschema if @events.any? @events.each do |event| event_to_atom(xml, event) diff --git a/app/views/users/show.atom.builder b/app/views/users/show.atom.builder index 758dfc72abf..114d1e7a379 100644 --- a/app/views/users/show.atom.builder +++ b/app/views/users/show.atom.builder @@ -4,7 +4,7 @@ xml.feed "xmlns" => "http://www.w3.org/2005/Atom", "xmlns:media" => "http://sear xml.link href: user_url(@user, :atom), rel: "self", type: "application/atom+xml" xml.link href: user_url(@user), rel: "alternate", type: "text/html" xml.id user_url(@user) - xml.updated @events.latest_update_time.to_s(:iso8601) if @events.any? + xml.updated @events.latest_update_time.xmlschema if @events.any? @events.each do |event| event_to_atom(xml, event) -- cgit v1.2.1 From 09dbe3752c8e93818111a551021274f100183a82 Mon Sep 17 00:00:00 2001 From: Robert Speicher Date: Thu, 7 Jan 2016 20:23:13 -0500 Subject: Fix feature step --- features/steps/group/milestones.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/features/steps/group/milestones.rb b/features/steps/group/milestones.rb index 6e57b16ccb6..2363ad797fa 100644 --- a/features/steps/group/milestones.rb +++ b/features/steps/group/milestones.rb @@ -28,7 +28,7 @@ class Spinach::Features::GroupMilestones < Spinach::FeatureSteps end step 'I should see group milestone with descriptions and expiry date' do - expect(page).to have_content('expires at Aug 20, 2114') + expect(page).to have_content('expires on Aug 20, 2114') end step 'I should see group milestone with all issues and MRs assigned to that milestone' do -- cgit v1.2.1 From 3c58b89b0e2c50075da3418b39c5b989e8d4318a Mon Sep 17 00:00:00 2001 From: Stan Hu Date: Thu, 7 Jan 2016 18:33:41 -0800 Subject: Give credit to user who created find file feature [ci skip] --- CHANGELOG | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG b/CHANGELOG index dfee55d963b..d1500ab7d3a 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -24,7 +24,7 @@ v 8.4.0 (unreleased) - Validate README format before displaying - Enable Microsoft Azure OAuth2 support (Janis Meybohm) - Properly set task-list class on single item task lists - - Add file finder feature in tree view (koreamic) + - Add file finder feature in tree view (Kyungchul Shin) - Ajax filter by message for commits page v 8.3.3 (unreleased) -- cgit v1.2.1 From 423d2d621a3b244bc64b40e84cd7e6043cc1525f Mon Sep 17 00:00:00 2001 From: Stan Hu Date: Fri, 8 Jan 2016 00:32:04 -0800 Subject: Fix duplicated branch creation/deletion events when using Web UI When deleting a branch, this is what was happening: 1. DeleteBranchService calls EventCreateService and creates an event. 2. The call to repository.rm_branch triggers the GitHooksService. 3. This, in turn, calls GitPushService and then calls EventCreateService again. 5145706c now makes it no longer necessary for DeleteBranchService and CreateBranchService to create an event. Closes #4304 --- CHANGELOG | 1 + app/services/create_branch_service.rb | 1 - app/services/delete_branch_service.rb | 1 - 3 files changed, 1 insertion(+), 2 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index dfee55d963b..f7032f52bc0 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -28,6 +28,7 @@ v 8.4.0 (unreleased) - Ajax filter by message for commits page v 8.3.3 (unreleased) + - Fix duplicated branch creation/deletion events when using Web UI (Stan Hu) - Get "Merge when build succeeds" to work when commits were pushed to MR target branch while builds were running - Fix project transfer e-mail sending incorrect paths in e-mail notification (Stan Hu) - Enable "Add key" button when user fills in a proper key (Stan Hu) diff --git a/app/services/create_branch_service.rb b/app/services/create_branch_service.rb index f139872c728..c0e08a151f2 100644 --- a/app/services/create_branch_service.rb +++ b/app/services/create_branch_service.rb @@ -31,7 +31,6 @@ class CreateBranchService < BaseService if new_branch push_data = build_push_data(project, current_user, new_branch) - EventCreateService.new.push(project, current_user, push_data) project.execute_hooks(push_data.dup, :push_hooks) project.execute_services(push_data.dup, :push_hooks) diff --git a/app/services/delete_branch_service.rb b/app/services/delete_branch_service.rb index 22bf9dd935e..004b3ce7286 100644 --- a/app/services/delete_branch_service.rb +++ b/app/services/delete_branch_service.rb @@ -27,7 +27,6 @@ class DeleteBranchService < BaseService if repository.rm_branch(current_user, branch_name) push_data = build_push_data(branch) - EventCreateService.new.push(project, current_user, push_data) project.execute_hooks(push_data.dup, :push_hooks) project.execute_services(push_data.dup, :push_hooks) -- cgit v1.2.1 From 4c90ed52fe6ff7b1155088c46460c411e121feb3 Mon Sep 17 00:00:00 2001 From: Robert Schilling Date: Fri, 8 Jan 2016 10:10:04 +0100 Subject: Delete tag via API --- CHANGELOG | 1 + doc/api/tags.md | 20 ++++++++++++++++++++ lib/api/tags.rb | 21 +++++++++++++++++++++ spec/requests/api/tags_spec.rb | 21 +++++++++++++++++++++ 4 files changed, 63 insertions(+) diff --git a/CHANGELOG b/CHANGELOG index d1500ab7d3a..c60fd2f2ca8 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -26,6 +26,7 @@ v 8.4.0 (unreleased) - Properly set task-list class on single item task lists - Add file finder feature in tree view (Kyungchul Shin) - Ajax filter by message for commits page + - API: Add support for deleting a tag via the API (Robert Schilling) v 8.3.3 (unreleased) - Get "Merge when build succeeds" to work when commits were pushed to MR target branch while builds were running diff --git a/doc/api/tags.md b/doc/api/tags.md index 085d387e824..17d12e9cc62 100644 --- a/doc/api/tags.md +++ b/doc/api/tags.md @@ -83,6 +83,26 @@ it will contain the annotation. It returns 200 if the operation succeed. In case of an error, 405 with an explaining error message is returned. +## Delete a tag + +Deletes a tag of a repository with given name. On success, this API method +returns 200 with the name of the deleted tag. If the tag does not exist, the +API returns 404. + +``` +DELETE /projects/:id/repository/tags/:tag_name +``` + +Parameters: + +- `id` (required) - The ID of a project +- `tag_name` (required) - The name of a tag + +```json +{ + "tag_name": "v4.3.0" +} +``` ## Create a new release diff --git a/lib/api/tags.rb b/lib/api/tags.rb index 47621f443e6..2d8a9e51bb9 100644 --- a/lib/api/tags.rb +++ b/lib/api/tags.rb @@ -40,6 +40,27 @@ module API end end + # Delete tag + # + # Parameters: + # id (required) - The ID of a project + # tag_name (required) - The name of the tag + # Example Request: + # DELETE /projects/:id/repository/tags/:tag + delete ":id/repository/tags/:tag_name", requirements: { tag_name: /.*/ } do + authorize_push_project + result = DeleteTagService.new(user_project, current_user). + execute(params[:tag_name]) + + if result[:status] == :success + { + tag_name: params[:tag_name] + } + else + render_api_error!(result[:message], result[:return_code]) + end + end + # Add release notes to tag # # Parameters: diff --git a/spec/requests/api/tags_spec.rb b/spec/requests/api/tags_spec.rb index 17f2643fd45..f966e38cd3e 100644 --- a/spec/requests/api/tags_spec.rb +++ b/spec/requests/api/tags_spec.rb @@ -65,6 +65,27 @@ describe API::API, api: true do end end + describe 'DELETE /projects/:id/repository/tags/:tag_name' do + let(:tag_name) { project.repository.tag_names.sort.reverse.first } + + before do + allow_any_instance_of(Repository).to receive(:rm_tag).and_return(true) + end + + context 'delete tag' do + it 'should delete an existing tag' do + delete api("/projects/#{project.id}/repository/tags/#{tag_name}", user) + expect(response.status).to eq(200) + expect(json_response['tag_name']).to eq(tag_name) + end + + it 'should raise 404 if the tag does not exist' do + delete api("/projects/#{project.id}/repository/tags/foobar", user) + expect(response.status).to eq(404) + end + end + end + context 'annotated tag' do it 'should create a new annotated tag' do # Identity must be set in .gitconfig to create annotated tag. -- cgit v1.2.1 From c3c0dda3f585f6f6064491a8838725df3c6c88c6 Mon Sep 17 00:00:00 2001 From: Robert Schilling Date: Fri, 8 Jan 2016 10:19:22 +0100 Subject: Blacklist 'new' --- app/validators/namespace_validator.rb | 1 + 1 file changed, 1 insertion(+) diff --git a/app/validators/namespace_validator.rb b/app/validators/namespace_validator.rb index 10e35ce665a..7a35958cc5f 100644 --- a/app/validators/namespace_validator.rb +++ b/app/validators/namespace_validator.rb @@ -17,6 +17,7 @@ class NamespaceValidator < ActiveModel::EachValidator hooks issues merge_requests + new notes profile projects -- cgit v1.2.1 From b059fa55092620d07762aacde76e0b9aaf65566b Mon Sep 17 00:00:00 2001 From: Achilleas Pipinellis Date: Fri, 8 Jan 2016 10:40:45 +0100 Subject: Clean up integration README [ci skip] --- doc/integration/README.md | 29 +++++++++++++++++++++-------- 1 file changed, 21 insertions(+), 8 deletions(-) diff --git a/doc/integration/README.md b/doc/integration/README.md index 2a9f76533b7..5edac746c7b 100644 --- a/doc/integration/README.md +++ b/doc/integration/README.md @@ -1,6 +1,7 @@ # GitLab Integration -GitLab integrates with multiple third-party services to allow external issue trackers and external authentication. +GitLab integrates with multiple third-party services to allow external issue +trackers and external authentication. See the documentation below for details on how to configure these services. @@ -15,13 +16,25 @@ See the documentation below for details on how to configure these services. - [Gmail actions buttons](gmail_action_buttons_for_gitlab.md) Adds GitLab actions to messages - [reCAPTCHA](recaptcha.md) Configure GitLab to use Google reCAPTCHA for new users -GitLab Enterprise Edition contains [advanced JIRA support](http://doc.gitlab.com/ee/integration/jira.html) and [advanced Jenkins support](http://doc.gitlab.com/ee/integration/jenkins.html). +GitLab Enterprise Edition contains [advanced Jenkins support][jenkins]. ## Project services -Integration with services such as Campfire, Flowdock, Gemnasium, HipChat, Pivotal Tracker, and Slack are available in the form of a Project Service. -You can find these within GitLab in the Services page under Project Settings if you are at least a master on the project. -Project Services are a bit like plugins in that they allow a lot of freedom in adding functionality to GitLab, for example there is also a service that can send an email every time someone pushes new commits. -Because GitLab is open source we can ship with the code and tests for all plugins. -This allows the community to keep the plugins up to date so that they always work in newer GitLab versions. -For an overview of what projects services are available without logging in please see the [project_services directory](https://gitlab.com/gitlab-org/gitlab-ce/tree/master/app/models/project_services). +Integration with services such as Campfire, Flowdock, Gemnasium, HipChat, +Pivotal Tracker, and Slack are available in the form of a [Project Service][]. +You can find these within GitLab in the Services page under Project Settings if +you are at least a master on the project. +Project Services are a bit like plugins in that they allow a lot of freedom in +adding functionality to GitLab. For example there is also a service that can +send an email every time someone pushes new commits. + +Because GitLab is open source we can ship with the code and tests for all +plugins. This allows the community to keep the plugins up to date so that they +always work in newer GitLab versions. + +For an overview of what projects services are available without logging in, +please see the [project_services directory][projects-code]. + +[jenkins]: http://doc.gitlab.com/ee/integration/jenkins.html +[Project Service]: ../project_services/project_services.md +[projects-code]: https://gitlab.com/gitlab-org/gitlab-ce/tree/master/app/models/project_services -- cgit v1.2.1 From 629becde2faaa4042a21415b2fbfc9fb6da80e33 Mon Sep 17 00:00:00 2001 From: Achilleas Pipinellis Date: Fri, 8 Jan 2016 12:43:33 +0100 Subject: Split external issue tracker document [ci skip] --- doc/integration/external-issue-tracker.md | 48 ++++++++------------- doc/integration/redmine_configuration.png | Bin 118752 -> 0 bytes doc/integration/redmine_service_template.png | Bin 198077 -> 0 bytes doc/project_services/img/redmine_configuration.png | Bin 0 -> 21061 bytes .../img/services_templates_redmine_example.png | Bin 0 -> 17351 bytes doc/project_services/project_services.md | 9 +++- doc/project_services/redmine.md | 21 +++++++++ doc/project_services/services_templates.md | 25 +++++++++++ 8 files changed, 71 insertions(+), 32 deletions(-) delete mode 100644 doc/integration/redmine_configuration.png delete mode 100644 doc/integration/redmine_service_template.png create mode 100644 doc/project_services/img/redmine_configuration.png create mode 100644 doc/project_services/img/services_templates_redmine_example.png create mode 100644 doc/project_services/redmine.md create mode 100644 doc/project_services/services_templates.md diff --git a/doc/integration/external-issue-tracker.md b/doc/integration/external-issue-tracker.md index 3e660cfba1e..3543a67dd49 100644 --- a/doc/integration/external-issue-tracker.md +++ b/doc/integration/external-issue-tracker.md @@ -1,44 +1,30 @@ # External issue tracker -GitLab has a great issue tracker but you can also use an external issue tracker such as Jira, Bugzilla or Redmine. You can configure issue trackers per GitLab project. For instance, if you configure Jira it allows you to do the following: +GitLab has a great issue tracker but you can also use an external one such as +Jira or Redmine. Issue trackers are configurable per GitLab project and allow +you to do the following: -- the 'Issues' link on the GitLab project pages takes you to the appropriate Jira issue index; -- clicking 'New issue' on the project dashboard creates a new Jira issue; -- To reference Jira issue PROJECT-1234 in comments, use syntax PROJECT-1234. Commit messages get turned into HTML links to the corresponding Jira issue. - -![Jira screenshot](jira-integration-points.png) - -GitLab Enterprise Edition contains [advanced JIRA support](http://doc.gitlab.com/ee/integration/jira.html). +- the **Issues** link on the GitLab project pages takes you to the appropriate + issue index of the external tracker +- clicking **New issue** on the project dashboard creates a new issue on the + external tracker ## Configuration -### Project Service +The configuration is done via a project's **Services**. -You can enable an external issue tracker per project. As an example, we will configure `Redmine` for project named gitlab-ci. - -Fill in the required details on the page: +### Project Service -![redmine configuration](redmine_configuration.png) +To enable an external issue tracker you must configure the appropriate **Service**. +Visit the links below for details: -* `description` A name for the issue tracker (to differentiate between instances, for example). -* `project_url` The URL to the project in Redmine which is being linked to this GitLab project. -* `issues_url` The URL to the issue in Redmine project that is linked to this GitLab project. Note that the `issues_url` requires `:id` in the url. This id is used by GitLab as a placeholder to replace the issue number. -* `new_issue_url` This is the URL to create a new issue in Redmine for the project linked to this GitLab project. +- [Redmine](../project_services/redmine.md) +- [Jira](jira.md) ### Service Template -It is necessary to configure the external issue tracker per project, because project specific details are needed for the integration with GitLab. -The admin can add a service template that sets a default for each project. This makes it much easier to configure individual projects. - -In GitLab Admin section, navigate to `Service Templates` and choose the service template you want to create: - -![redmine service template](redmine_service_template.png) - -After the template is created, the template details will be pre-filled on the project service page. - -NOTE: For each project, you will still need to configure the issue tracking URLs by replacing `:issues_tracker_id` in the above screenshot -with the ID used by your external issue tracker. Prior to GitLab v7.8, this ID was configured in the project settings, and GitLab would automatically -update the URL configured in `gitlab.yml`. This behavior is now depecated, and all issue tracker URLs must be configured directly -within the project's Services settings. +To save you the hassle from configuring each project's service individually, +GitLab provides the ability to set Service Templates which can then be +overridden in each project's settings. -Support to add your commits to the Jira ticket automatically is [available in GitLab EE](http://doc.gitlab.com/ee/integration/jira.html). +Read more on [Services Templates](../project_services/services_templates.md). diff --git a/doc/integration/redmine_configuration.png b/doc/integration/redmine_configuration.png deleted file mode 100644 index 6b145363229..00000000000 Binary files a/doc/integration/redmine_configuration.png and /dev/null differ diff --git a/doc/integration/redmine_service_template.png b/doc/integration/redmine_service_template.png deleted file mode 100644 index 1159eb5b964..00000000000 Binary files a/doc/integration/redmine_service_template.png and /dev/null differ diff --git a/doc/project_services/img/redmine_configuration.png b/doc/project_services/img/redmine_configuration.png new file mode 100644 index 00000000000..d14e526ad33 Binary files /dev/null and b/doc/project_services/img/redmine_configuration.png differ diff --git a/doc/project_services/img/services_templates_redmine_example.png b/doc/project_services/img/services_templates_redmine_example.png new file mode 100644 index 00000000000..384d057fc8e Binary files /dev/null and b/doc/project_services/img/services_templates_redmine_example.png differ diff --git a/doc/project_services/project_services.md b/doc/project_services/project_services.md index 2d3e899383f..e3403127723 100644 --- a/doc/project_services/project_services.md +++ b/doc/project_services/project_services.md @@ -26,5 +26,12 @@ further configuration instructions and details. Contributions are welcome. | JetBrains TeamCity CI | A continuous integration and build server | | PivotalTracker | Project Management Software (Source Commits Endpoint) | | Pushover | Pushover makes it easy to get real-time notifications on your Android device, iPhone, iPad, and Desktop | -| Redmine | Redmine issue tracker | +| [Redmine](redmine.md) | Redmine issue tracker | | Slack | A team communication tool for the 21st century | + +## Services Templates + +Services templates is a way to set some predefined values in the Service of +your liking which will then be pre-filled on each project's Service. + +Read more about [Services Templates in this document](services_templates.md). diff --git a/doc/project_services/redmine.md b/doc/project_services/redmine.md new file mode 100644 index 00000000000..b9830ea7c38 --- /dev/null +++ b/doc/project_services/redmine.md @@ -0,0 +1,21 @@ +# Redmine Service + +Go to your project's **Settings > Services > Redmine** and fill in the required +details as described in the table below. + +| Field | Description | +| ----- | ----------- | +| `description` | A name for the issue tracker (to differentiate between instances, for example) | +| `project_url` | The URL to the project in Redmine which is being linked to this GitLab project | +| `issues_url` | The URL to the issue in Redmine project that is linked to this GitLab project. Note that the `issues_url` requires `:id` in the URL. This ID is used by GitLab as a placeholder to replace the issue number. | +| `new_issue_url` | This is the URL to create a new issue in Redmine for the project linked to this GitLab project | + +Once you have configured and enabled Redmine: + +- the **Issues** link on the GitLab project pages takes you to the appropriate + Redmine issue index +- clicking **New issue** on the project dashboard creates a new Redmine issue + +As an example, below is a configuration for a project named gitlab-ci. + +![Redmine configuration](img/redmine_configuration.png) diff --git a/doc/project_services/services_templates.md b/doc/project_services/services_templates.md new file mode 100644 index 00000000000..be6d13b6d2b --- /dev/null +++ b/doc/project_services/services_templates.md @@ -0,0 +1,25 @@ +# Services Templates + +A GitLab administrator can add a service template that sets a default for each +project. This makes it much easier to configure individual projects. + +After the template is created, the template details will be pre-filled on a +project's Service page. + +## Enable a Service template + +In GitLab's Admin area, navigate to **Service Templates** and choose the +service template you wish to create. + +For example, in the image below you can see Redmine. + +![Redmine service template](img/services_templates_redmine_example.png) + +--- + +**NOTE:** For each project, you will still need to configure the issue tracking +URLs by replacing `:issues_tracker_id` in the above screenshot with the ID used +by your external issue tracker. Prior to GitLab v7.8, this ID was configured in +the project settings, and GitLab would automatically update the URL configured +in `gitlab.yml`. This behavior is now deprecated and all issue tracker URLs +must be configured directly within the project's **Services** settings. -- cgit v1.2.1 From 1d48b180bc43acd078b2c7a172c338a66d5f2b4f Mon Sep 17 00:00:00 2001 From: Achilleas Pipinellis Date: Fri, 8 Jan 2016 13:19:40 +0100 Subject: Clean up the JIRA integration document [ci skip] - new images where needed - move images to a separate img directory - use table for the service fields - link to new documents --- doc/integration/img/jira_issue_reference.png | Bin 0 -> 39942 bytes doc/integration/img/jira_merge_request_close.png | Bin 0 -> 111150 bytes doc/integration/img/jira_project_name.png | Bin 0 -> 60598 bytes doc/integration/img/jira_service.png | Bin 0 -> 59082 bytes doc/integration/img/jira_service_close_issue.png | Bin 0 -> 88433 bytes doc/integration/img/jira_service_page.png | Bin 0 -> 35496 bytes doc/integration/img/jira_workflow_screenshot.png | Bin 0 -> 121534 bytes doc/integration/jira.md | 134 ++++++++++++++--------- doc/integration/jira_issue_reference.png | Bin 39942 -> 0 bytes doc/integration/jira_project_name.png | Bin 60598 -> 0 bytes doc/integration/jira_service.png | Bin 59082 -> 0 bytes doc/integration/jira_service_close_issue.png | Bin 88433 -> 0 bytes doc/integration/jira_service_page.png | Bin 162449 -> 0 bytes doc/integration/jira_workflow_screenshot.png | Bin 121534 -> 0 bytes 14 files changed, 82 insertions(+), 52 deletions(-) create mode 100644 doc/integration/img/jira_issue_reference.png create mode 100644 doc/integration/img/jira_merge_request_close.png create mode 100644 doc/integration/img/jira_project_name.png create mode 100644 doc/integration/img/jira_service.png create mode 100644 doc/integration/img/jira_service_close_issue.png create mode 100644 doc/integration/img/jira_service_page.png create mode 100644 doc/integration/img/jira_workflow_screenshot.png delete mode 100644 doc/integration/jira_issue_reference.png delete mode 100644 doc/integration/jira_project_name.png delete mode 100644 doc/integration/jira_service.png delete mode 100644 doc/integration/jira_service_close_issue.png delete mode 100644 doc/integration/jira_service_page.png delete mode 100644 doc/integration/jira_workflow_screenshot.png diff --git a/doc/integration/img/jira_issue_reference.png b/doc/integration/img/jira_issue_reference.png new file mode 100644 index 00000000000..15739a22dc7 Binary files /dev/null and b/doc/integration/img/jira_issue_reference.png differ diff --git a/doc/integration/img/jira_merge_request_close.png b/doc/integration/img/jira_merge_request_close.png new file mode 100644 index 00000000000..1e78daf105f Binary files /dev/null and b/doc/integration/img/jira_merge_request_close.png differ diff --git a/doc/integration/img/jira_project_name.png b/doc/integration/img/jira_project_name.png new file mode 100644 index 00000000000..5986fdb63fb Binary files /dev/null and b/doc/integration/img/jira_project_name.png differ diff --git a/doc/integration/img/jira_service.png b/doc/integration/img/jira_service.png new file mode 100644 index 00000000000..1f6628c4371 Binary files /dev/null and b/doc/integration/img/jira_service.png differ diff --git a/doc/integration/img/jira_service_close_issue.png b/doc/integration/img/jira_service_close_issue.png new file mode 100644 index 00000000000..67dfc6144c4 Binary files /dev/null and b/doc/integration/img/jira_service_close_issue.png differ diff --git a/doc/integration/img/jira_service_page.png b/doc/integration/img/jira_service_page.png new file mode 100644 index 00000000000..2b37eda3520 Binary files /dev/null and b/doc/integration/img/jira_service_page.png differ diff --git a/doc/integration/img/jira_workflow_screenshot.png b/doc/integration/img/jira_workflow_screenshot.png new file mode 100644 index 00000000000..8635a32eb68 Binary files /dev/null and b/doc/integration/img/jira_workflow_screenshot.png differ diff --git a/doc/integration/jira.md b/doc/integration/jira.md index 624601d0fac..abe3ba70d6d 100644 --- a/doc/integration/jira.md +++ b/doc/integration/jira.md @@ -1,14 +1,15 @@ # GitLab Jira integration -GitLab can be configured to interact with Jira. -Configuration happens via username and password. -Connecting to a Jira server via CAS is not possible. +GitLab can be configured to interact with Jira. Configuration happens via +username and password. Connecting to a Jira server via CAS is not possible. -Each project can be configured to connect to a different Jira instance, configuration is explained [here](#configuration). -If you have one Jira instance you can pre-fill the settings page with a default template. To configure the template [see external issue tracker document](external-issue-tracker.md#service-template)). - -Once the project is connected to Jira, you can reference and close the issues in Jira directly from GitLab. +Each project can be configured to connect to a different Jira instance, see the +[configuration](#configuration) section. If you have one Jira instance you can +pre-fill the settings page with a default template. To configure the template +see the [Services Templates][services-templates] document. +Once the project is connected to Jira, you can reference and close the issues +in Jira directly from GitLab. ## Table of Contents @@ -18,8 +19,11 @@ Once the project is connected to Jira, you can reference and close the issues in ### Referencing Jira Issues -When GitLab project has Jira issue tracker configured and enabled, mentioning Jira issue in GitLab will automatically add a comment in Jira issue with the link back to GitLab. This means that in comments in merge requests and commits referencing an issue, eg. `PROJECT-7`, will add a comment in Jira issue in the format: - +When GitLab project has Jira issue tracker configured and enabled, mentioning +Jira issue in GitLab will automatically add a comment in Jira issue with the +link back to GitLab. This means that in comments in merge requests and commits +referencing an issue, eg. `PROJECT-7`, will add a comment in Jira issue in the +format: ``` USER mentioned this issue in LINK_TO_THE_MENTION @@ -29,85 +33,111 @@ When GitLab project has Jira issue tracker configured and enabled, mentioning Ji * `LINK_TO_THE_MENTION` Link to the origin of mention with a name of the entity where Jira issue was mentioned. Can be commit or merge request. +![example of mentioning or closing the Jira issue](img/jira_issue_reference.png) -![example of mentioning or closing the Jira issue](jira_issue_reference.png) - +--- ### Closing Jira Issues -Jira issues can be closed directly from GitLab by using trigger words, eg. `Resolves PROJECT-1`, `Closes PROJECT-1` or `Fixes PROJECT-1`, in commits and merge requests. -When a commit which contains the trigger word in the commit message is pushed, GitLab will add a comment in the mentioned Jira issue. +Jira issues can be closed directly from GitLab by using trigger words, eg. +`Resolves PROJECT-1`, `Closes PROJECT-1` or `Fixes PROJECT-1`, in commits and +merge requests. When a commit which contains the trigger word in the commit +message is pushed, GitLab will add a comment in the mentioned Jira issue. -For example, for project named PROJECT in Jira, we implemented a new feature and created a merge request in GitLab. +For example, for project named `PROJECT` in Jira, we implemented a new feature +and created a merge request in GitLab. -This feature was requested in Jira issue PROJECT-7. Merge request in GitLab contains the improvement and in merge request description we say that this merge request `Closes PROJECT-7` issue. +This feature was requested in Jira issue `PROJECT-7`. Merge request in GitLab +contains the improvement and in merge request description we say that this +merge request `Closes PROJECT-7` issue. -Once this merge request is merged, Jira issue will be automatically closed with a link to the commit that resolved the issue. +Once this merge request is merged, the Jira issue will be automatically closed +with a link to the commit that resolved the issue. -![A Git commit that causes the Jira issue to be closed](merge_request_close_jira.png) +![A Git commit that causes the Jira issue to be closed](img/jira_merge_request_close.png) +--- -![The GitLab integration user leaves a comment on Jira](jira_service_close_issue.png) +![The GitLab integration user leaves a comment on Jira](img/jira_service_close_issue.png) +--- ## Configuration ### Configuring JIRA -We need to create a user in JIRA which will have access to all projects that need to integrate with GitLab. -Login to your JIRA instance as admin and under Administration go to User Management and create a new user. -As an example, we'll create a user named `gitlab` and add it to `jira-developers` group. +We need to create a user in JIRA which will have access to all projects that +need to integrate with GitLab. Login to your JIRA instance as admin and under +Administration go to User Management and create a new user. + +As an example, we'll create a user named `gitlab` and add it to `jira-developers` +group. **It is important that the user `gitlab` has write-access to projects in JIRA** ### Configuring GitLab -### GitLab 7.8 EE and up with JIRA v6.x +JIRA configuration in GitLab is done via a project's **Services**. -To enable JIRA integration in a project, navigate to the project Settings page and go to Services. Here you will find JIRA. +#### GitLab 7.8 and up with JIRA v6.x -Fill in the required details on the page: +To enable JIRA integration in a project, navigate to the project's +**Settings > Services > JIRA**. -![Jira service page](jira_service_page.png) +Fill in the required details on the page as described in the table below. -* `description` A name for the issue tracker (to differentiate between instances, for instance). -* `project url` The URL to the JIRA project which is being linked to this GitLab project. -* `issues url` The URL to the JIRA project issues overview for the project that is linked to this GitLab project. -* `new issue url` This is the URL to create a new issue in JIRA for the project linked to this GitLab project. -* `api url` The base URL of the JIRA API. It may be omitted, in which case GitLab will automatically use API version `2` based on the `project url`, i.e. `https://jira.example.com/rest/api/2`. -* `username` The username of the user created in [configuring JIRA step](#configuring-jira). -* `password` The password of the user created in [configuring JIRA step](#configuring-jira). -* `Jira issue transition` This is the id of a transition that moves issues to a closed state. You can find this number under [JIRA workflow administration, see screenshot](jira_workflow_screenshot.png). By default, this id is `2`. (In the example image, this is `2` as well) +| Field | Description | +| ----- | ----------- | +| `description` | A name for the issue tracker (to differentiate between instances, for instance). | +| `project url` | The URL to the JIRA project which is being linked to this GitLab project. | +| `issues url` | The URL to the JIRA project issues overview for the project that is linked to this GitLab project. | +| `new issue url` | This is the URL to create a new issue in JIRA for the project linked to this GitLab project. | +| `api url` | The base URL of the JIRA API. It may be omitted, in which case GitLab will automatically use API version `2` based on the `project url`, i.e. `https://jira.example.com/rest/api/2`. | +| `username` | The username of the user created in [configuring JIRA step](#configuring-jira). | +| `password` |The password of the user created in [configuring JIRA step](#configuring-jira). | +| `Jira issue transition` | This is the ID of a transition that moves issues to a closed state. You can find this number under JIRA workflow administration ([see screenshot](img/jira_workflow_screenshot.png)). By default, this ID is `2` (in the example image, this is `2` as well) | -After saving the configuration, your GitLab project will be able to interact with the linked JIRA project. +After saving the configuration, your GitLab project will be able to interact +with the linked JIRA project. +![Jira service page](img/jira_service_page.png) -### GitLab 6.x-7.7 with JIRA v6.x +--- -**Note: GitLab 7.8 and up contain various integration improvements. We strongly recommend upgrading.** +#### GitLab 6.x-7.7 with JIRA v6.x +_**Note:** GitLab versions 7.8 and up contain various integration improvements. +We strongly recommend upgrading._ -In `gitlab.yml` enable [JIRA issue tracker section by uncommenting the lines](https://gitlab.com/subscribers/gitlab-ee/blob/6-8-stable-ee/config/gitlab.yml.example#L111-115). -This will make sure that all issues within GitLab are pointing to the JIRA issue tracker. +In `gitlab.yml` enable the JIRA issue tracker section by +[uncommenting these lines][jira-gitlab-yml]. This will make sure that all +issues within GitLab are pointing to the JIRA issue tracker. -We can also enable JIRA service that will allow us to interact with JIRA issues. +After you set this, you will be able to close issues in JIRA by a commit in +GitLab. -For example, we can close issues in JIRA by a commit in GitLab. +Go to your project's **Settings** page and fill in the project name for the +JIRA project: -Go to project settings page and fill in the project name for the JIRA project: +![Set the JIRA project name in GitLab to 'NEW'](img/jira_project_name.png) -![Set the JIRA project name in GitLab to 'NEW'](jira_project_name.png) +--- -Next, go to the services page and find JIRA. +You can also enable the JIRA service that will allow you to interact with JIRA +issues. Go to the **Settings > Services > JIRA** and: -![Jira services page](jira_service.png) - -1. Tick the active check box to enable the service. -1. Supply the url to JIRA server, for example http://jira.sample -1. Supply the username of a user we created under `Configuring JIRA` section, for example `gitlab` +1. Tick the active check box to enable the service +1. Supply the URL to JIRA server, for example http://jira.example.com +1. Supply the username of a user we created under `Configuring JIRA` section, + for example `gitlab` 1. Supply the password of the user -1. Optional: supply the JIRA api version, default is version -1. Optional: supply the JIRA issue transition ID (issue transition to closed). This is dependant on JIRA settings, default is 2 -1. Save +1. Optional: supply the JIRA API version, default is version `2` +1. Optional: supply the JIRA issue transition ID (issue transition to closed). + This is dependent on JIRA settings, default is `2` +1. Hit save + + +![Jira services page](img/jira_service.png) -Now we should be able to interact with JIRA issues. +[services-templates]: ../project_services/services_templates.md +[jira-gitlab-yml]: https://gitlab.com/subscribers/gitlab-ee/blob/6-8-stable-ee/config/gitlab.yml.example#L111-115 diff --git a/doc/integration/jira_issue_reference.png b/doc/integration/jira_issue_reference.png deleted file mode 100644 index 15739a22dc7..00000000000 Binary files a/doc/integration/jira_issue_reference.png and /dev/null differ diff --git a/doc/integration/jira_project_name.png b/doc/integration/jira_project_name.png deleted file mode 100644 index 5986fdb63fb..00000000000 Binary files a/doc/integration/jira_project_name.png and /dev/null differ diff --git a/doc/integration/jira_service.png b/doc/integration/jira_service.png deleted file mode 100644 index 1f6628c4371..00000000000 Binary files a/doc/integration/jira_service.png and /dev/null differ diff --git a/doc/integration/jira_service_close_issue.png b/doc/integration/jira_service_close_issue.png deleted file mode 100644 index 67dfc6144c4..00000000000 Binary files a/doc/integration/jira_service_close_issue.png and /dev/null differ diff --git a/doc/integration/jira_service_page.png b/doc/integration/jira_service_page.png deleted file mode 100644 index 69ec44e826f..00000000000 Binary files a/doc/integration/jira_service_page.png and /dev/null differ diff --git a/doc/integration/jira_workflow_screenshot.png b/doc/integration/jira_workflow_screenshot.png deleted file mode 100644 index 8635a32eb68..00000000000 Binary files a/doc/integration/jira_workflow_screenshot.png and /dev/null differ -- cgit v1.2.1 From fc7b14a534ed63af787b63b22fee9cd267cae5b0 Mon Sep 17 00:00:00 2001 From: Achilleas Pipinellis Date: Fri, 8 Jan 2016 13:21:40 +0100 Subject: Remove reference to EE from JIRA service model --- app/models/project_services/jira_service.rb | 5 ----- 1 file changed, 5 deletions(-) diff --git a/app/models/project_services/jira_service.rb b/app/models/project_services/jira_service.rb index a1b77c61576..9f9b44f099b 100644 --- a/app/models/project_services/jira_service.rb +++ b/app/models/project_services/jira_service.rb @@ -44,11 +44,6 @@ class JiraService < IssueTrackerService 'allow a user to easily navigate to the Jira issue tracker. See the '\ '[integration doc](http://doc.gitlab.com/ce/integration/external-issue-tracker.html) '\ 'for details.' - - line2 = 'Support for referencing commits and automatic closing of Jira issues directly '\ - 'from GitLab is [available in GitLab EE.](http://doc.gitlab.com/ee/integration/jira.html)' - - [line1, line2].join("\n\n") end def title -- cgit v1.2.1 From 8d7a968d6dbc70d31953bac5262c86c4ca9dc7d9 Mon Sep 17 00:00:00 2001 From: Yorick Peterse Date: Fri, 8 Jan 2016 14:31:39 +0100 Subject: Handle missing DBs in connect_to_db? This ensures CurrentSettings#connect_to_db? returns "false" in the event of a database not existing, instead of raising an error. --- lib/gitlab/current_settings.rb | 3 +++ 1 file changed, 3 insertions(+) diff --git a/lib/gitlab/current_settings.rb b/lib/gitlab/current_settings.rb index 7a86c09158e..7f938780ab1 100644 --- a/lib/gitlab/current_settings.rb +++ b/lib/gitlab/current_settings.rb @@ -41,6 +41,9 @@ module Gitlab use_db && ActiveRecord::Base.connection.active? && !ActiveRecord::Migrator.needs_migration? && ActiveRecord::Base.connection.table_exists?('application_settings') + + rescue ActiveRecord::NoDatabaseError + false end end end -- cgit v1.2.1 From d09f1a4443696cdd7187ba855da26e57905ef422 Mon Sep 17 00:00:00 2001 From: Achilleas Pipinellis Date: Fri, 8 Jan 2016 15:22:42 +0100 Subject: Remove useless assignment to variable --- app/models/project_services/jira_service.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/models/project_services/jira_service.rb b/app/models/project_services/jira_service.rb index 9f9b44f099b..8a43a021819 100644 --- a/app/models/project_services/jira_service.rb +++ b/app/models/project_services/jira_service.rb @@ -40,7 +40,7 @@ class JiraService < IssueTrackerService end def help - line1 = 'Setting `project_url`, `issues_url` and `new_issue_url` will '\ + 'Setting `project_url`, `issues_url` and `new_issue_url` will '\ 'allow a user to easily navigate to the Jira issue tracker. See the '\ '[integration doc](http://doc.gitlab.com/ce/integration/external-issue-tracker.html) '\ 'for details.' -- cgit v1.2.1 From 65c474997d18b4978dcca3bafeb2e6c6552227c9 Mon Sep 17 00:00:00 2001 From: Achilleas Pipinellis Date: Fri, 8 Jan 2016 15:57:47 +0100 Subject: Add JIRA 7 to the supported versions [ci skip] --- doc/integration/jira.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/doc/integration/jira.md b/doc/integration/jira.md index abe3ba70d6d..de574d53410 100644 --- a/doc/integration/jira.md +++ b/doc/integration/jira.md @@ -81,6 +81,12 @@ JIRA configuration in GitLab is done via a project's **Services**. #### GitLab 7.8 and up with JIRA v6.x +See next section. + +#### GitLab 7.8 and up + +_The currently supported JIRA versions are v6.x and v7.x._ + To enable JIRA integration in a project, navigate to the project's **Settings > Services > JIRA**. -- cgit v1.2.1 From cb22e5f942ef77cfaf4c92cefef93e1ec510a55c Mon Sep 17 00:00:00 2001 From: Yorick Peterse Date: Wed, 6 Jan 2016 11:43:21 +0100 Subject: Load autocomplete data when loading an issue page This ensures the dropdown is fully available the moment a user starts typing out a username, issue ID, etc. While this won't speed up loading the autocomplete data itself it should at least make it less annoying for the user. --- app/assets/javascripts/gfm_auto_complete.js.coffee | 25 +++++++++++----------- 1 file changed, 12 insertions(+), 13 deletions(-) diff --git a/app/assets/javascripts/gfm_auto_complete.js.coffee b/app/assets/javascripts/gfm_auto_complete.js.coffee index 7967892f856..fa90fb65f42 100644 --- a/app/assets/javascripts/gfm_auto_complete.js.coffee +++ b/app/assets/javascripts/gfm_auto_complete.js.coffee @@ -34,7 +34,7 @@ GitLab.GfmAutoComplete = searchKey: 'search' callbacks: beforeSave: (members) -> - $.map members, (m) -> + $.map members, (m) -> title = m.name title += " (#{m.count})" if m.count @@ -50,7 +50,7 @@ GitLab.GfmAutoComplete = insertTpl: '${atwho-at}${id}' callbacks: beforeSave: (issues) -> - $.map issues, (i) -> + $.map issues, (i) -> id: i.iid title: sanitize(i.title) search: "#{i.iid} #{i.title}" @@ -63,18 +63,17 @@ GitLab.GfmAutoComplete = insertTpl: '${atwho-at}${id}' callbacks: beforeSave: (merges) -> - $.map merges, (m) -> + $.map merges, (m) -> id: m.iid title: sanitize(m.title) search: "#{m.iid} #{m.title}" - input.one 'focus', => - $.getJSON(@dataSource).done (data) -> - # load members - input.atwho 'load', '@', data.members - # load issues - input.atwho 'load', 'issues', data.issues - # load merge requests - input.atwho 'load', 'mergerequests', data.mergerequests - # load emojis - input.atwho 'load', ':', data.emojis + $.getJSON(@dataSource).done (data) -> + # load members + input.atwho 'load', '@', data.members + # load issues + input.atwho 'load', 'issues', data.issues + # load merge requests + input.atwho 'load', 'mergerequests', data.mergerequests + # load emojis + input.atwho 'load', ':', data.emojis -- cgit v1.2.1 From 0614793b38db4711053cbcb4fa80d9c8cc492eec Mon Sep 17 00:00:00 2001 From: Douwe Maan Date: Fri, 8 Jan 2016 17:38:53 +0100 Subject: DRY up upload and download services --- app/services/projects/download_service.rb | 13 +------------ app/services/projects/upload_service.rb | 13 +------------ app/uploaders/file_uploader.rb | 15 +++++++++++++++ lib/gitlab/fogbugz_import/importer.rb | 2 +- spec/services/projects/download_service_spec.rb | 24 ++++++++++++------------ 5 files changed, 30 insertions(+), 37 deletions(-) diff --git a/app/services/projects/download_service.rb b/app/services/projects/download_service.rb index b846a59ed94..6386f57fb0d 100644 --- a/app/services/projects/download_service.rb +++ b/app/services/projects/download_service.rb @@ -16,18 +16,7 @@ module Projects uploader.download!(@url) uploader.store! - filename = uploader.image? ? uploader.file.basename : uploader.file.filename - - escaped_filename = filename.gsub("]", "\\]") - markdown = "[#{escaped_filename}](#{uploader.secure_url})" - markdown.prepend("!") if uploader.image? - - { - 'alt' => filename, - 'url' => uploader.secure_url, - 'is_image' => uploader.image?, - 'markdown' => markdown - } + uploader.to_h end private diff --git a/app/services/projects/upload_service.rb b/app/services/projects/upload_service.rb index 36ccf1cda12..012e82a7704 100644 --- a/app/services/projects/upload_service.rb +++ b/app/services/projects/upload_service.rb @@ -10,18 +10,7 @@ module Projects uploader = FileUploader.new(@project) uploader.store!(@file) - filename = uploader.image? ? uploader.file.basename : uploader.file.filename - - escaped_filename = filename.gsub("]", "\\]") - markdown = "[#{escaped_filename}](#{uploader.secure_url})" - markdown.prepend("!") if uploader.image? - - { - alt: filename, - url: uploader.secure_url, - is_image: uploader.image?, - markdown: markdown - } + uploader.to_h end private diff --git a/app/uploaders/file_uploader.rb b/app/uploaders/file_uploader.rb index ac920119a85..86d24469e05 100644 --- a/app/uploaders/file_uploader.rb +++ b/app/uploaders/file_uploader.rb @@ -30,4 +30,19 @@ class FileUploader < CarrierWave::Uploader::Base def secure_url File.join("/uploads", @secret, file.filename) end + + def to_h + filename = image? ? self.file.basename : self.file.filename + escaped_filename = filename.gsub("]", "\\]") + + markdown = "[#{escaped_filename}](#{self.secure_url})" + markdown.prepend("!") if image? + + { + alt: filename, + url: self.secure_url, + is_image: image?, + markdown: markdown + } + end end diff --git a/lib/gitlab/fogbugz_import/importer.rb b/lib/gitlab/fogbugz_import/importer.rb index 0e6bee732f1..db580b5e578 100644 --- a/lib/gitlab/fogbugz_import/importer.rb +++ b/lib/gitlab/fogbugz_import/importer.rb @@ -232,7 +232,7 @@ module Gitlab return nil if res.nil? - res['markdown'] + res[:markdown] end def build_attachment_url(rel_url) diff --git a/spec/services/projects/download_service_spec.rb b/spec/services/projects/download_service_spec.rb index 5ceed5af9a5..f252e2c5902 100644 --- a/spec/services/projects/download_service_spec.rb +++ b/spec/services/projects/download_service_spec.rb @@ -33,12 +33,12 @@ describe Projects::DownloadService, services: true do @link_to_file = download_file(@project, url) end - it { expect(@link_to_file).to have_key('alt') } - it { expect(@link_to_file).to have_key('url') } - it { expect(@link_to_file).to have_key('is_image') } - it { expect(@link_to_file['is_image']).to be true } - it { expect(@link_to_file['url']).to match('rails_sample.jpg') } - it { expect(@link_to_file['alt']).to eq('rails_sample') } + it { expect(@link_to_file).to have_key(:alt) } + it { expect(@link_to_file).to have_key(:url) } + it { expect(@link_to_file).to have_key(:is_image) } + it { expect(@link_to_file[:is_image]).to be true } + it { expect(@link_to_file[:url]).to match('rails_sample.jpg') } + it { expect(@link_to_file[:alt]).to eq('rails_sample') } end context 'a txt file' do @@ -47,12 +47,12 @@ describe Projects::DownloadService, services: true do @link_to_file = download_file(@project, url) end - it { expect(@link_to_file).to have_key('alt') } - it { expect(@link_to_file).to have_key('url') } - it { expect(@link_to_file).to have_key('is_image') } - it { expect(@link_to_file['is_image']).to be false } - it { expect(@link_to_file['url']).to match('doc_sample.txt') } - it { expect(@link_to_file['alt']).to eq('doc_sample.txt') } + it { expect(@link_to_file).to have_key(:alt) } + it { expect(@link_to_file).to have_key(:url) } + it { expect(@link_to_file).to have_key(:is_image) } + it { expect(@link_to_file[:is_image]).to be false } + it { expect(@link_to_file[:url]).to match('doc_sample.txt') } + it { expect(@link_to_file[:alt]).to eq('doc_sample.txt') } end end end -- cgit v1.2.1 From 463905929ef9d85bcd6f5b430fd2bdb25311c17c Mon Sep 17 00:00:00 2001 From: Jacob Schatz Date: Fri, 8 Jan 2016 12:48:11 -0500 Subject: fixes new branch button positioning, when visible and not visible container --- app/assets/stylesheets/pages/projects.scss | 7 ++++++- app/views/events/_event_last_push.html.haml | 2 +- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/app/assets/stylesheets/pages/projects.scss b/app/assets/stylesheets/pages/projects.scss index 0133a0d6822..d32509b7d49 100644 --- a/app/assets/stylesheets/pages/projects.scss +++ b/app/assets/stylesheets/pages/projects.scss @@ -411,11 +411,15 @@ ul.nav.nav-projects-tabs { } } +.last-push-widget { + margin-top: -1px; +} + .top-area { border-bottom: 1px solid #EEE; margin: 0 -16px; padding: 0 $gl-padding; - height: 57px; + height: 42px; ul.left-top-menu { display: inline-block; @@ -522,6 +526,7 @@ pre.light-well { .projects-search-form { margin: -$gl-padding; padding: $gl-padding; + padding-bottom: 0; margin-bottom: 0px; input { diff --git a/app/views/events/_event_last_push.html.haml b/app/views/events/_event_last_push.html.haml index ffc37ad6178..abea86b026a 100644 --- a/app/views/events/_event_last_push.html.haml +++ b/app/views/events/_event_last_push.html.haml @@ -1,5 +1,5 @@ - if show_last_push_widget?(event) - .gray-content-block.clear-block + .gray-content-block.clear-block.last-push-widget .event-last-push .event-last-push-text %span You pushed to -- cgit v1.2.1 From b284ba24c2ea0ee62be83756cf55c2b40b5ca38c Mon Sep 17 00:00:00 2001 From: Jacob Schatz Date: Fri, 8 Jan 2016 13:08:57 -0500 Subject: changes verb `references` to noun `reference`. --- app/views/shared/issuable/_sidebar.html.haml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/views/shared/issuable/_sidebar.html.haml b/app/views/shared/issuable/_sidebar.html.haml index 78c52938bd9..2299112bec7 100644 --- a/app/views/shared/issuable/_sidebar.html.haml +++ b/app/views/shared/issuable/_sidebar.html.haml @@ -74,7 +74,7 @@ .title .cross-project-reference %span#cross-project-reference - References: + Reference: %a{href: '#', title:project_ref} = project_ref = clipboard_button(clipboard_target: 'span#cross-project-reference') -- cgit v1.2.1 From 99eb6470878724452191b35c143275b49ae9f87d Mon Sep 17 00:00:00 2001 From: Robert Speicher Date: Fri, 8 Jan 2016 15:46:55 -0500 Subject: Add a CHANGELOG entry for The Most Important Feature of All Time(TM) Also, Open Graph data, if you're into that kind of thing. [ci skip] --- CHANGELOG | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGELOG b/CHANGELOG index 10092243e4e..921dac01264 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.4.0 (unreleased) + - The default GitLab logo now acts as a loading indicator - Accept 2xx status codes for successful Web hook triggers (Stan Hu) - Fix missing date of month in network graph when commits span a month (Stan Hu) - Expire view caches when application settings change (e.g. Gravatar disabled) (Stan Hu) @@ -21,6 +22,7 @@ v 8.4.0 (unreleased) - Add system hook messages for project rename and transfer (Steve Norman) - Fix version check image in Safari - Show 'All' tab by default in the builds page + - Add Open Graph and Twitter Card data to all pages - Fix API project lookups when querying with a namespace with dots (Stan Hu) - Update version check images to use SVG - Validate README format before displaying -- cgit v1.2.1 From d5c8f1fdde7dd9c0467f7743694ffdecd15fdf94 Mon Sep 17 00:00:00 2001 From: Stan Hu Date: Fri, 8 Jan 2016 15:47:25 -0800 Subject: Fix caching issue where build status was not updating in project dashboard Closes #3268 --- CHANGELOG | 1 + app/views/shared/projects/_project.html.haml | 13 ++++++++----- 2 files changed, 9 insertions(+), 5 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index 921dac01264..f87b1cc8016 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.4.0 (unreleased) - The default GitLab logo now acts as a loading indicator + - Fix caching issue where build status was not updating in project dashboard (Stan Hu) - Accept 2xx status codes for successful Web hook triggers (Stan Hu) - Fix missing date of month in network graph when commits span a month (Stan Hu) - Expire view caches when application settings change (e.g. Gravatar disabled) (Stan Hu) diff --git a/app/views/shared/projects/_project.html.haml b/app/views/shared/projects/_project.html.haml index 86249851a82..5db8056b77c 100644 --- a/app/views/shared/projects/_project.html.haml +++ b/app/views/shared/projects/_project.html.haml @@ -4,8 +4,12 @@ - skip_namespace = false unless local_assigns[:skip_namespace] == true - css_class = '' unless local_assigns[:css_class] - css_class += " no-description" unless project.description.present? +- ci_commit = project.ci_commit(project.commit.sha) if ci && !project.empty_repo? && project.commit +- cache_key = [project.namespace, project, controller.controller_name, controller.action_name, current_application_settings, 'v2.2'] +- cache_key.push(ci_commit.status) if ci_commit + %li.project-row{ class: css_class } - = cache [project.namespace, project, controller.controller_name, controller.action_name, current_application_settings, 'v2.2'] do + = cache(cache_key) do = link_to project_path(project), class: dom_class(project) do - if avatar .dash-project-avatar @@ -19,10 +23,9 @@ = project.name .project-controls - - if ci && !project.empty_repo? && project.commit - - if ci_commit = project.ci_commit(project.commit.sha) - = render_ci_status(ci_commit) -   + - if ci_commit + = render_ci_status(ci_commit) +   - if stars %span %i.fa.fa-star -- cgit v1.2.1 From 89ca4f04f6d46fdc9eee2907669b63f220be3f20 Mon Sep 17 00:00:00 2001 From: Robert Speicher Date: Fri, 8 Jan 2016 23:33:08 -0500 Subject: Refactor ZenMode - No longer depends on the "hidden checkbox". - No longer depends on manually storing/restoring the scroll position. Instead, we take advantage of jquery.scrollTo. - Event-based. - Simplifies the state-based styling. --- app/assets/javascripts/zen_mode.js.coffee | 104 ++++++++++++++++----------- app/assets/stylesheets/framework/zen.scss | 99 ++++++++++--------------- app/views/projects/_zen.html.haml | 9 ++- spec/javascripts/fixtures/zen_mode.html.haml | 9 ++- spec/javascripts/zen_mode_spec.js.coffee | 26 +++---- 5 files changed, 119 insertions(+), 128 deletions(-) diff --git a/app/assets/javascripts/zen_mode.js.coffee b/app/assets/javascripts/zen_mode.js.coffee index a1462cf3cae..e1c5446eaac 100644 --- a/app/assets/javascripts/zen_mode.js.coffee +++ b/app/assets/javascripts/zen_mode.js.coffee @@ -1,56 +1,80 @@ +# Zen Mode (full screen) textarea +# +#= provides zen_mode:enter +#= provides zen_mode:leave +# +#= require jquery.scrollTo #= require dropzone #= require mousetrap #= require mousetrap/pause - +# +# ### Events +# +# `zen_mode:enter` +# +# Fired when the "Edit in fullscreen" link is clicked. +# +# **Synchronicity** Sync +# **Bubbles** Yes +# **Cancelable** No +# **Target** a.js-zen-enter +# +# `zen_mode:leave` +# +# Fired when the "Leave Fullscreen" link is clicked. +# +# **Synchronicity** Sync +# **Bubbles** Yes +# **Cancelable** No +# **Target** a.js-zen-leave +# class @ZenMode constructor: -> - @active_zen_area = null - @active_checkbox = null - @scroll_position = 0 - - $(window).scroll => - if not @active_checkbox - @scroll_position = window.pageYOffset + @active_backdrop = null + @active_textarea = null - $('body').on 'click', '.zen-enter-link', (e) => + $(document).on 'click', '.js-zen-enter', (e) -> e.preventDefault() - $(e.currentTarget).closest('.zennable').find('.zen-toggle-comment').prop('checked', true).change() + $(e.currentTarget).trigger('zen_mode:enter') - $('body').on 'click', '.zen-leave-link', (e) => + $(document).on 'click', '.js-zen-leave', (e) -> e.preventDefault() - $(e.currentTarget).closest('.zennable').find('.zen-toggle-comment').prop('checked', false).change() - - $('body').on 'change', '.zen-toggle-comment', (e) => - checkbox = e.currentTarget - if checkbox.checked - # Disable other keyboard shortcuts in ZEN mode - Mousetrap.pause() - @updateActiveZenArea(checkbox) - else - @exitZenMode() - - $(document).on 'keydown', (e) => - if e.keyCode is 27 # Esc - @exitZenMode() + $(e.currentTarget).trigger('zen_mode:leave') + + $(document).on 'zen_mode:enter', (e) => + @enter(e.target.parentNode) + $(document).on 'zen_mode:leave', (e) => + @exit() + + $(document).on 'keydown', (e) -> + if e.keyCode == 27 # Esc e.preventDefault() + $(document).trigger('zen_mode:leave') + + enter: (backdrop) -> + Mousetrap.pause() + + @active_backdrop = $(backdrop) + @active_backdrop.addClass('fullscreen') + + @active_textarea = @active_backdrop.find('textarea') - updateActiveZenArea: (checkbox) => - @active_checkbox = $(checkbox) - @active_checkbox.prop('checked', true) - @active_zen_area = @active_checkbox.parent().find('textarea') # Prevent a user-resized textarea from persisting to fullscreen - @active_zen_area.removeAttr('style') - @active_zen_area.focus() + @active_textarea.removeAttr('style') + @active_textarea.focus() - exitZenMode: => - if @active_zen_area isnt null + exit: -> + if @active_textarea Mousetrap.unpause() - @active_checkbox.prop('checked', false) - @active_zen_area = null - @active_checkbox = null - @restoreScroll(@scroll_position) - # Enable dropzone when leaving ZEN mode + + @active_textarea.closest('.zen-backdrop').removeClass('fullscreen') + + @scrollTo(@active_textarea) + + @active_textarea = null + @active_backdrop = null + Dropzone.forElement('.div-dropzone').enable() - restoreScroll: (y) -> - window.scrollTo(window.pageXOffset, y) + scrollTo: (zen_area) -> + $.scrollTo(zen_area, 0, offset: -150) diff --git a/app/assets/stylesheets/framework/zen.scss b/app/assets/stylesheets/framework/zen.scss index 32e2c020e06..002bd7e8ca5 100644 --- a/app/assets/stylesheets/framework/zen.scss +++ b/app/assets/stylesheets/framework/zen.scss @@ -1,9 +1,5 @@ .zennable { - .zen-toggle-comment { - display: none; - } - - .zen-enter-link { + a.js-zen-enter { color: $gl-gray; position: absolute; top: 0px; @@ -11,7 +7,7 @@ line-height: 40px; } - .zen-leave-link { + a.js-zen-leave { display: none; color: $gl-text-color; position: absolute; @@ -25,62 +21,41 @@ } } - // Hide the Enter link when we're in Zen mode - input:checked ~ .zen-backdrop .zen-enter-link { - display: none; - } - - // Show the Leave link when we're in Zen mode - input:checked ~ .zen-backdrop .zen-leave-link { - display: block; - position: absolute; - top: 0; - } - - input:checked ~ .zen-backdrop { - background-color: white; - position: fixed; - top: 0; - bottom: 0; - left: 0; - right: 0; - z-index: 1031; - - textarea { - border: none; - box-shadow: none; - border-radius: 0; - color: #000; - font-size: 20px; - line-height: 26px; - padding: 30px; - display: block; - outline: none; - resize: none; - height: 100vh; - max-width: 900px; - margin: 0 auto; + .zen-backdrop { + &.fullscreen { + background-color: white; + position: fixed; + top: 0; + bottom: 0; + left: 0; + right: 0; + z-index: 1031; + + textarea { + border: none; + box-shadow: none; + border-radius: 0; + color: #000; + font-size: 20px; + line-height: 26px; + padding: 30px; + display: block; + outline: none; + resize: none; + height: 100vh; + max-width: 900px; + margin: 0 auto; + } + + a.js-zen-enter { + display: none; + } + + a.js-zen-leave { + display: block; + position: absolute; + top: 0; + } } } - - // Make the color of the placeholder text in the Zenned-out textarea darker, - // so it becomes visible - - input:checked ~ .zen-backdrop textarea::-webkit-input-placeholder { - color: #A8A8A8; - } - - input:checked ~ .zen-backdrop textarea:-moz-placeholder { - color: #A8A8A8; - opacity: 1; - } - - input:checked ~ .zen-backdrop textarea::-moz-placeholder { - color: #A8A8A8; - opacity: 1; - } - - input:checked ~ .zen-backdrop textarea:-ms-input-placeholder { - color: #A8A8A8; - } } diff --git a/app/views/projects/_zen.html.haml b/app/views/projects/_zen.html.haml index 7e6301abde8..d5829568275 100644 --- a/app/views/projects/_zen.html.haml +++ b/app/views/projects/_zen.html.haml @@ -1,13 +1,12 @@ .zennable - %input#zen-toggle-comment.zen-toggle-comment(tabindex="-1" type="checkbox") .zen-backdrop - classes << ' js-gfm-input markdown-area' - if defined?(f) && f - = f.text_area attr, class: classes, placeholder: '' + = f.text_area attr, class: classes - else - = text_area_tag attr, nil, class: classes, placeholder: '' - %a.zen-enter-link(tabindex="-1" href="#") + = text_area_tag attr, nil, class: classes + %a.js-zen-enter(tabindex="-1" href="#") = icon('expand') Edit in fullscreen - %a.zen-leave-link(href="#") + %a.js-zen-leave(tabindex="-1" href="#") = icon('compress') diff --git a/spec/javascripts/fixtures/zen_mode.html.haml b/spec/javascripts/fixtures/zen_mode.html.haml index e867e4de2b9..1701652c61e 100644 --- a/spec/javascripts/fixtures/zen_mode.html.haml +++ b/spec/javascripts/fixtures/zen_mode.html.haml @@ -1,9 +1,8 @@ .zennable - %input#zen-toggle-comment.zen-toggle-comment{ tabindex: '-1', type: 'checkbox' } .zen-backdrop - %textarea#note_note.js-gfm-input.markdown-area{placeholder: 'Leave a comment'} - %a.zen-enter-link{tabindex: '-1'} + %textarea#note_note.js-gfm-input.markdown-area + %a.js-zen-enter(tabindex="-1" href="#") %i.fa.fa-expand - Edit in fullscreen - %a.zen-leave-link + Edit in fullscreen + %a.js-zen-leave(tabindex="-1" href="#") %i.fa.fa-compress diff --git a/spec/javascripts/zen_mode_spec.js.coffee b/spec/javascripts/zen_mode_spec.js.coffee index 4cb3836755f..b790fce01ed 100644 --- a/spec/javascripts/zen_mode_spec.js.coffee +++ b/spec/javascripts/zen_mode_spec.js.coffee @@ -15,14 +15,6 @@ describe 'ZenMode', -> # Set this manually because we can't actually scroll the window @zen.scroll_position = 456 - # Ohmmmmmmm - enterZen = -> - $('.zen-toggle-comment').prop('checked', true).trigger('change') - - # Wh- what was that?! - exitZen = -> - $('.zen-toggle-comment').prop('checked', false).trigger('change') - describe 'on enter', -> it 'pauses Mousetrap', -> spyOn(Mousetrap, 'pause') @@ -35,16 +27,14 @@ describe 'ZenMode', -> expect('textarea').not.toHaveAttr('style') describe 'in use', -> - beforeEach -> - enterZen() + beforeEach -> enterZen() it 'exits on Escape', -> - $(document).trigger(jQuery.Event('keydown', {keyCode: 27})) - expect($('.zen-toggle-comment').prop('checked')).toBe(false) + escapeKeydown() + expect($('.zen-backdrop')).not.toHaveClass('fullscreen') describe 'on exit', -> - beforeEach -> - enterZen() + beforeEach -> enterZen() it 'unpauses Mousetrap', -> spyOn(Mousetrap, 'unpause') @@ -52,6 +42,10 @@ describe 'ZenMode', -> expect(Mousetrap.unpause).toHaveBeenCalled() it 'restores the scroll position', -> - spyOn(@zen, 'restoreScroll') + spyOn(@zen, 'scrollTo') exitZen() - expect(@zen.restoreScroll).toHaveBeenCalledWith(456) + expect(@zen.scrollTo).toHaveBeenCalled() + +enterZen = -> $('a.js-zen-enter').click() # Ohmmmmmmm +exitZen = -> $('a.js-zen-leave').click() +escapeKeydown = -> $('textarea').trigger($.Event('keydown', {keyCode: 27})) -- cgit v1.2.1 From 11b4c0d3cf80c216147a4508a05a45d90fa58e2d Mon Sep 17 00:00:00 2001 From: Achilleas Pipinellis Date: Sat, 9 Jan 2016 11:03:10 +0100 Subject: Clean up document on adding users to a project [ci skip] --- doc/workflow/add-user/add-user.md | 90 ++++++++++++++++++--- doc/workflow/add-user/images/add-members.png | Bin 2361 -> 0 bytes doc/workflow/add-user/images/members.png | Bin 8295 -> 0 bytes doc/workflow/add-user/images/new-member.png | Bin 12038 -> 0 bytes doc/workflow/add-user/images/select-project.png | Bin 4042 -> 0 bytes .../img/add_new_user_to_project_settings.png | Bin 0 -> 22822 bytes .../add-user/img/add_user_email_accept.png | Bin 0 -> 10833 bytes doc/workflow/add-user/img/add_user_email_ready.png | Bin 0 -> 16177 bytes .../add-user/img/add_user_email_search.png | Bin 0 -> 15889 bytes .../add-user/img/add_user_give_permissions.png | Bin 0 -> 22089 bytes ...dd_user_import_members_from_another_project.png | Bin 0 -> 18897 bytes .../add-user/img/add_user_imported_members.png | Bin 0 -> 23897 bytes .../add-user/img/add_user_list_members.png | Bin 0 -> 15732 bytes .../add-user/img/add_user_members_menu.png | Bin 0 -> 8295 bytes .../add-user/img/add_user_search_people.png | Bin 0 -> 13518 bytes 15 files changed, 77 insertions(+), 13 deletions(-) delete mode 100644 doc/workflow/add-user/images/add-members.png delete mode 100644 doc/workflow/add-user/images/members.png delete mode 100644 doc/workflow/add-user/images/new-member.png delete mode 100644 doc/workflow/add-user/images/select-project.png create mode 100644 doc/workflow/add-user/img/add_new_user_to_project_settings.png create mode 100644 doc/workflow/add-user/img/add_user_email_accept.png create mode 100644 doc/workflow/add-user/img/add_user_email_ready.png create mode 100644 doc/workflow/add-user/img/add_user_email_search.png create mode 100644 doc/workflow/add-user/img/add_user_give_permissions.png create mode 100644 doc/workflow/add-user/img/add_user_import_members_from_another_project.png create mode 100644 doc/workflow/add-user/img/add_user_imported_members.png create mode 100644 doc/workflow/add-user/img/add_user_list_members.png create mode 100644 doc/workflow/add-user/img/add_user_members_menu.png create mode 100644 doc/workflow/add-user/img/add_user_search_people.png diff --git a/doc/workflow/add-user/add-user.md b/doc/workflow/add-user/add-user.md index 8c9b4f72631..fffa0aba57f 100644 --- a/doc/workflow/add-user/add-user.md +++ b/doc/workflow/add-user/add-user.md @@ -1,25 +1,89 @@ # Project users -You can manage the groups and users and their access levels in all of your projects. You can also personalize the access level you give each user, per project. +You can manage the groups and users and their access levels in all of your +projects. You can also personalize the access level you give each user, +per-project. -Here's how to add or import users to your projects. - -You should have 'master' or 'owner' permissions to add or import a new user +You should have `master` or `owner` permissions to add or import a new user to your project. -To add or import a user, go to your project and click on "Members" on the left side of your screen: +The first step to add or import a user, go to your project and click on +**Members** on the left side of your screen. + +![Members](img/add_user_members_menu.png) + +--- + +## Add a user + +Right next to **People**, start typing the name or username of the user you +want to add. + +![Search for people](img/add_user_search_people.png) + +--- + +Select the user and the [permission level](../../permissions/permissions.md) +that you'd like to give the user. Note that you can select more than one user. + +![Give user permissions](img/add_user_give_permissions.png) + +--- + +Once done, hit **Add users to project** and they will be immediately added to +your project with the permissions you gave them above. + +![List members](img/add_user_list_members.png) + +--- + +From there on, you can either remove an existing user or change their access +level to the project. + +## Import users from another project + +You can import another project's users in your own project by hitting the +**Import members** button on the upper right corner of the **Members** menu. + +In the dropdown menu, you can see only the projects you are Master on. + +![Import members from another project](img/add_user_import_members_from_another_project.png) + +--- + +Select the one you want and hit **Import project members**. A flash message +notifying you that the import was successful will appear, and the new members +are now in the project's members list. Notice that the permissions that they +had on the project you imported from are retained. + +![Members list of new members](img/add_user_imported_members.png) + +--- + +## Invite people using their e-mail address + +If a user you want to give access to doesn't have an account on your GitLab +instance, you can invite them just by typing their e-mail address in the +user search field. + +![Invite user by mail](img/add_user_email_search.png) + +--- -![Members](images/members.png) +As you can imagine, you can mix inviting multiple people and adding existing +GitLab users to the project. -Select "Add members" or "Import members" on the right side of your screen: +![Invite user by mail ready to submit](img/add_user_email_ready.png) -![Add or Import](images/add-members.png) +--- -If you are adding a user, select the user and the [permission level](doc/permissions/permissions.md) that you'd like to -give the user: +Once done, hit **Add users to project** and watch that there is a new member +with the e-mail address we used above. From there on, you can resend the +invitation, change their access level or even delete them. -![Add or Import](images/new-member.png) +![Invite user members list](img/add_user_email_accept.png) -If you are importing a user, follow the steps to select the project where you'd like to import the user from: +--- -![Add or Import](images/select-project.png) +Once the user accepts the invitation, they will be prompted to create a new +GitLab account using the same e-mail address the invitation was sent to. diff --git a/doc/workflow/add-user/images/add-members.png b/doc/workflow/add-user/images/add-members.png deleted file mode 100644 index 2805c5764a5..00000000000 Binary files a/doc/workflow/add-user/images/add-members.png and /dev/null differ diff --git a/doc/workflow/add-user/images/members.png b/doc/workflow/add-user/images/members.png deleted file mode 100644 index f1797b95f67..00000000000 Binary files a/doc/workflow/add-user/images/members.png and /dev/null differ diff --git a/doc/workflow/add-user/images/new-member.png b/doc/workflow/add-user/images/new-member.png deleted file mode 100644 index d500daea56e..00000000000 Binary files a/doc/workflow/add-user/images/new-member.png and /dev/null differ diff --git a/doc/workflow/add-user/images/select-project.png b/doc/workflow/add-user/images/select-project.png deleted file mode 100644 index dd3844edff8..00000000000 Binary files a/doc/workflow/add-user/images/select-project.png and /dev/null differ diff --git a/doc/workflow/add-user/img/add_new_user_to_project_settings.png b/doc/workflow/add-user/img/add_new_user_to_project_settings.png new file mode 100644 index 00000000000..3da18cdae53 Binary files /dev/null and b/doc/workflow/add-user/img/add_new_user_to_project_settings.png differ diff --git a/doc/workflow/add-user/img/add_user_email_accept.png b/doc/workflow/add-user/img/add_user_email_accept.png new file mode 100644 index 00000000000..910affc9659 Binary files /dev/null and b/doc/workflow/add-user/img/add_user_email_accept.png differ diff --git a/doc/workflow/add-user/img/add_user_email_ready.png b/doc/workflow/add-user/img/add_user_email_ready.png new file mode 100644 index 00000000000..5f02ce89b3e Binary files /dev/null and b/doc/workflow/add-user/img/add_user_email_ready.png differ diff --git a/doc/workflow/add-user/img/add_user_email_search.png b/doc/workflow/add-user/img/add_user_email_search.png new file mode 100644 index 00000000000..140979fbe13 Binary files /dev/null and b/doc/workflow/add-user/img/add_user_email_search.png differ diff --git a/doc/workflow/add-user/img/add_user_give_permissions.png b/doc/workflow/add-user/img/add_user_give_permissions.png new file mode 100644 index 00000000000..8ef9156c8d5 Binary files /dev/null and b/doc/workflow/add-user/img/add_user_give_permissions.png differ diff --git a/doc/workflow/add-user/img/add_user_import_members_from_another_project.png b/doc/workflow/add-user/img/add_user_import_members_from_another_project.png new file mode 100644 index 00000000000..5770d5cf0c4 Binary files /dev/null and b/doc/workflow/add-user/img/add_user_import_members_from_another_project.png differ diff --git a/doc/workflow/add-user/img/add_user_imported_members.png b/doc/workflow/add-user/img/add_user_imported_members.png new file mode 100644 index 00000000000..dea4b3f40ad Binary files /dev/null and b/doc/workflow/add-user/img/add_user_imported_members.png differ diff --git a/doc/workflow/add-user/img/add_user_list_members.png b/doc/workflow/add-user/img/add_user_list_members.png new file mode 100644 index 00000000000..7daa6ca7d9e Binary files /dev/null and b/doc/workflow/add-user/img/add_user_list_members.png differ diff --git a/doc/workflow/add-user/img/add_user_members_menu.png b/doc/workflow/add-user/img/add_user_members_menu.png new file mode 100644 index 00000000000..f1797b95f67 Binary files /dev/null and b/doc/workflow/add-user/img/add_user_members_menu.png differ diff --git a/doc/workflow/add-user/img/add_user_search_people.png b/doc/workflow/add-user/img/add_user_search_people.png new file mode 100644 index 00000000000..5ac10ce80d4 Binary files /dev/null and b/doc/workflow/add-user/img/add_user_search_people.png differ -- cgit v1.2.1 From c7aeca993ee472eed919db00f237cf9f9351207c Mon Sep 17 00:00:00 2001 From: Robert Speicher Date: Sat, 9 Jan 2016 16:05:53 -0500 Subject: Use WOFF versions of SourceSansPro See https://gitlab.com/gitlab-org/gitlab-ce/issues/6023 --- app/assets/fonts/OFL.txt | 7 ++++--- app/assets/fonts/SourceSansPro-Black.ttf | Bin 289364 -> 0 bytes app/assets/fonts/SourceSansPro-Black.ttf.woff | Bin 0 -> 113800 bytes app/assets/fonts/SourceSansPro-BlackIt.ttf | Bin 103404 -> 0 bytes app/assets/fonts/SourceSansPro-BlackIt.ttf.woff | Bin 0 -> 49704 bytes app/assets/fonts/SourceSansPro-BlackItalic.ttf | Bin 116360 -> 0 bytes app/assets/fonts/SourceSansPro-Bold.ttf | Bin 291424 -> 0 bytes app/assets/fonts/SourceSansPro-Bold.ttf.woff | Bin 0 -> 117872 bytes app/assets/fonts/SourceSansPro-BoldIt.ttf | Bin 103608 -> 0 bytes app/assets/fonts/SourceSansPro-BoldIt.ttf.woff | Bin 0 -> 50608 bytes app/assets/fonts/SourceSansPro-BoldItalic.ttf | Bin 116192 -> 0 bytes app/assets/fonts/SourceSansPro-ExtraLight.ttf | Bin 291652 -> 0 bytes app/assets/fonts/SourceSansPro-ExtraLight.ttf.woff | Bin 0 -> 114336 bytes app/assets/fonts/SourceSansPro-ExtraLightIt.ttf | Bin 104768 -> 0 bytes app/assets/fonts/SourceSansPro-ExtraLightIt.ttf.woff | Bin 0 -> 49684 bytes app/assets/fonts/SourceSansPro-ExtraLightItalic.ttf | Bin 117140 -> 0 bytes app/assets/fonts/SourceSansPro-It.ttf | Bin 104236 -> 0 bytes app/assets/fonts/SourceSansPro-It.ttf.woff | Bin 0 -> 51012 bytes app/assets/fonts/SourceSansPro-Italic.ttf | Bin 117328 -> 0 bytes app/assets/fonts/SourceSansPro-Light.ttf | Bin 293220 -> 0 bytes app/assets/fonts/SourceSansPro-Light.ttf.woff | Bin 0 -> 118284 bytes app/assets/fonts/SourceSansPro-LightIt.ttf | Bin 104616 -> 0 bytes app/assets/fonts/SourceSansPro-LightIt.ttf.woff | Bin 0 -> 50992 bytes app/assets/fonts/SourceSansPro-LightItalic.ttf | Bin 116960 -> 0 bytes app/assets/fonts/SourceSansPro-Regular.ttf | Bin 293956 -> 0 bytes app/assets/fonts/SourceSansPro-Regular.ttf.woff | Bin 0 -> 119064 bytes app/assets/fonts/SourceSansPro-Semibold.ttf | Bin 292404 -> 0 bytes app/assets/fonts/SourceSansPro-Semibold.ttf.woff | Bin 0 -> 118412 bytes app/assets/fonts/SourceSansPro-SemiboldIt.ttf | Bin 104020 -> 0 bytes app/assets/fonts/SourceSansPro-SemiboldIt.ttf.woff | Bin 0 -> 50924 bytes app/assets/fonts/SourceSansPro-SemiboldItalic.ttf | Bin 116424 -> 0 bytes app/assets/stylesheets/framework/fonts.scss | 8 ++++---- 32 files changed, 8 insertions(+), 7 deletions(-) delete mode 100644 app/assets/fonts/SourceSansPro-Black.ttf create mode 100755 app/assets/fonts/SourceSansPro-Black.ttf.woff delete mode 100644 app/assets/fonts/SourceSansPro-BlackIt.ttf create mode 100755 app/assets/fonts/SourceSansPro-BlackIt.ttf.woff delete mode 100755 app/assets/fonts/SourceSansPro-BlackItalic.ttf delete mode 100644 app/assets/fonts/SourceSansPro-Bold.ttf create mode 100755 app/assets/fonts/SourceSansPro-Bold.ttf.woff delete mode 100644 app/assets/fonts/SourceSansPro-BoldIt.ttf create mode 100755 app/assets/fonts/SourceSansPro-BoldIt.ttf.woff delete mode 100755 app/assets/fonts/SourceSansPro-BoldItalic.ttf delete mode 100644 app/assets/fonts/SourceSansPro-ExtraLight.ttf create mode 100755 app/assets/fonts/SourceSansPro-ExtraLight.ttf.woff delete mode 100644 app/assets/fonts/SourceSansPro-ExtraLightIt.ttf create mode 100755 app/assets/fonts/SourceSansPro-ExtraLightIt.ttf.woff delete mode 100755 app/assets/fonts/SourceSansPro-ExtraLightItalic.ttf delete mode 100644 app/assets/fonts/SourceSansPro-It.ttf create mode 100755 app/assets/fonts/SourceSansPro-It.ttf.woff delete mode 100755 app/assets/fonts/SourceSansPro-Italic.ttf delete mode 100644 app/assets/fonts/SourceSansPro-Light.ttf create mode 100755 app/assets/fonts/SourceSansPro-Light.ttf.woff delete mode 100644 app/assets/fonts/SourceSansPro-LightIt.ttf create mode 100755 app/assets/fonts/SourceSansPro-LightIt.ttf.woff delete mode 100755 app/assets/fonts/SourceSansPro-LightItalic.ttf delete mode 100644 app/assets/fonts/SourceSansPro-Regular.ttf create mode 100755 app/assets/fonts/SourceSansPro-Regular.ttf.woff delete mode 100644 app/assets/fonts/SourceSansPro-Semibold.ttf create mode 100755 app/assets/fonts/SourceSansPro-Semibold.ttf.woff delete mode 100644 app/assets/fonts/SourceSansPro-SemiboldIt.ttf create mode 100755 app/assets/fonts/SourceSansPro-SemiboldIt.ttf.woff delete mode 100755 app/assets/fonts/SourceSansPro-SemiboldItalic.ttf diff --git a/app/assets/fonts/OFL.txt b/app/assets/fonts/OFL.txt index a9b845ed1d4..df187637e18 100755 --- a/app/assets/fonts/OFL.txt +++ b/app/assets/fonts/OFL.txt @@ -1,7 +1,8 @@ -Copyright 2010, 2012 Adobe Systems Incorporated (http://www.adobe.com/), with Reserved Font Name 'Source'. All Rights Reserved. Source is a trademark of Adobe Systems Incorporated in the United States and/or other countries. +Copyright 2010, 2012, 2014 Adobe Systems Incorporated (http://www.adobe.com/), with Reserved Font Name 'Source'. All Rights Reserved. Source is a trademark of Adobe Systems Incorporated in the United States and/or other countries. + This Font Software is licensed under the SIL Open Font License, Version 1.1. -This license is copied below, and is also available with a FAQ at: -http://scripts.sil.org/OFL + +This license is copied below, and is also available with a FAQ at: http://scripts.sil.org/OFL ----------------------------------------------------------- diff --git a/app/assets/fonts/SourceSansPro-Black.ttf b/app/assets/fonts/SourceSansPro-Black.ttf deleted file mode 100644 index 9c9b5cb7f03..00000000000 Binary files a/app/assets/fonts/SourceSansPro-Black.ttf and /dev/null differ diff --git a/app/assets/fonts/SourceSansPro-Black.ttf.woff b/app/assets/fonts/SourceSansPro-Black.ttf.woff new file mode 100755 index 00000000000..b7e86200927 Binary files /dev/null and b/app/assets/fonts/SourceSansPro-Black.ttf.woff differ diff --git a/app/assets/fonts/SourceSansPro-BlackIt.ttf b/app/assets/fonts/SourceSansPro-BlackIt.ttf deleted file mode 100644 index 294ce5abe8f..00000000000 Binary files a/app/assets/fonts/SourceSansPro-BlackIt.ttf and /dev/null differ diff --git a/app/assets/fonts/SourceSansPro-BlackIt.ttf.woff b/app/assets/fonts/SourceSansPro-BlackIt.ttf.woff new file mode 100755 index 00000000000..c3314b1ef06 Binary files /dev/null and b/app/assets/fonts/SourceSansPro-BlackIt.ttf.woff differ diff --git a/app/assets/fonts/SourceSansPro-BlackItalic.ttf b/app/assets/fonts/SourceSansPro-BlackItalic.ttf deleted file mode 100755 index c719243c0d6..00000000000 Binary files a/app/assets/fonts/SourceSansPro-BlackItalic.ttf and /dev/null differ diff --git a/app/assets/fonts/SourceSansPro-Bold.ttf b/app/assets/fonts/SourceSansPro-Bold.ttf deleted file mode 100644 index 5d65c93242f..00000000000 Binary files a/app/assets/fonts/SourceSansPro-Bold.ttf and /dev/null differ diff --git a/app/assets/fonts/SourceSansPro-Bold.ttf.woff b/app/assets/fonts/SourceSansPro-Bold.ttf.woff new file mode 100755 index 00000000000..d1d40f840f8 Binary files /dev/null and b/app/assets/fonts/SourceSansPro-Bold.ttf.woff differ diff --git a/app/assets/fonts/SourceSansPro-BoldIt.ttf b/app/assets/fonts/SourceSansPro-BoldIt.ttf deleted file mode 100644 index 3decd130070..00000000000 Binary files a/app/assets/fonts/SourceSansPro-BoldIt.ttf and /dev/null differ diff --git a/app/assets/fonts/SourceSansPro-BoldIt.ttf.woff b/app/assets/fonts/SourceSansPro-BoldIt.ttf.woff new file mode 100755 index 00000000000..ef6ff514d3a Binary files /dev/null and b/app/assets/fonts/SourceSansPro-BoldIt.ttf.woff differ diff --git a/app/assets/fonts/SourceSansPro-BoldItalic.ttf b/app/assets/fonts/SourceSansPro-BoldItalic.ttf deleted file mode 100755 index d20dd0c5eca..00000000000 Binary files a/app/assets/fonts/SourceSansPro-BoldItalic.ttf and /dev/null differ diff --git a/app/assets/fonts/SourceSansPro-ExtraLight.ttf b/app/assets/fonts/SourceSansPro-ExtraLight.ttf deleted file mode 100644 index 253eafa3783..00000000000 Binary files a/app/assets/fonts/SourceSansPro-ExtraLight.ttf and /dev/null differ diff --git a/app/assets/fonts/SourceSansPro-ExtraLight.ttf.woff b/app/assets/fonts/SourceSansPro-ExtraLight.ttf.woff new file mode 100755 index 00000000000..1e6c94d9eb3 Binary files /dev/null and b/app/assets/fonts/SourceSansPro-ExtraLight.ttf.woff differ diff --git a/app/assets/fonts/SourceSansPro-ExtraLightIt.ttf b/app/assets/fonts/SourceSansPro-ExtraLightIt.ttf deleted file mode 100644 index 00d7e9a7aa8..00000000000 Binary files a/app/assets/fonts/SourceSansPro-ExtraLightIt.ttf and /dev/null differ diff --git a/app/assets/fonts/SourceSansPro-ExtraLightIt.ttf.woff b/app/assets/fonts/SourceSansPro-ExtraLightIt.ttf.woff new file mode 100755 index 00000000000..7a408b1ec73 Binary files /dev/null and b/app/assets/fonts/SourceSansPro-ExtraLightIt.ttf.woff differ diff --git a/app/assets/fonts/SourceSansPro-ExtraLightItalic.ttf b/app/assets/fonts/SourceSansPro-ExtraLightItalic.ttf deleted file mode 100755 index 2c34f3b8dc4..00000000000 Binary files a/app/assets/fonts/SourceSansPro-ExtraLightItalic.ttf and /dev/null differ diff --git a/app/assets/fonts/SourceSansPro-It.ttf b/app/assets/fonts/SourceSansPro-It.ttf deleted file mode 100644 index f7af5377595..00000000000 Binary files a/app/assets/fonts/SourceSansPro-It.ttf and /dev/null differ diff --git a/app/assets/fonts/SourceSansPro-It.ttf.woff b/app/assets/fonts/SourceSansPro-It.ttf.woff new file mode 100755 index 00000000000..4d54bc95718 Binary files /dev/null and b/app/assets/fonts/SourceSansPro-It.ttf.woff differ diff --git a/app/assets/fonts/SourceSansPro-Italic.ttf b/app/assets/fonts/SourceSansPro-Italic.ttf deleted file mode 100755 index e5a1a86e631..00000000000 Binary files a/app/assets/fonts/SourceSansPro-Italic.ttf and /dev/null differ diff --git a/app/assets/fonts/SourceSansPro-Light.ttf b/app/assets/fonts/SourceSansPro-Light.ttf deleted file mode 100644 index 83a0a336661..00000000000 Binary files a/app/assets/fonts/SourceSansPro-Light.ttf and /dev/null differ diff --git a/app/assets/fonts/SourceSansPro-Light.ttf.woff b/app/assets/fonts/SourceSansPro-Light.ttf.woff new file mode 100755 index 00000000000..1706d57d3c5 Binary files /dev/null and b/app/assets/fonts/SourceSansPro-Light.ttf.woff differ diff --git a/app/assets/fonts/SourceSansPro-LightIt.ttf b/app/assets/fonts/SourceSansPro-LightIt.ttf deleted file mode 100644 index f18827985ef..00000000000 Binary files a/app/assets/fonts/SourceSansPro-LightIt.ttf and /dev/null differ diff --git a/app/assets/fonts/SourceSansPro-LightIt.ttf.woff b/app/assets/fonts/SourceSansPro-LightIt.ttf.woff new file mode 100755 index 00000000000..87378d6c609 Binary files /dev/null and b/app/assets/fonts/SourceSansPro-LightIt.ttf.woff differ diff --git a/app/assets/fonts/SourceSansPro-LightItalic.ttf b/app/assets/fonts/SourceSansPro-LightItalic.ttf deleted file mode 100755 index 88a6778d24f..00000000000 Binary files a/app/assets/fonts/SourceSansPro-LightItalic.ttf and /dev/null differ diff --git a/app/assets/fonts/SourceSansPro-Regular.ttf b/app/assets/fonts/SourceSansPro-Regular.ttf deleted file mode 100644 index 44486cdc670..00000000000 Binary files a/app/assets/fonts/SourceSansPro-Regular.ttf and /dev/null differ diff --git a/app/assets/fonts/SourceSansPro-Regular.ttf.woff b/app/assets/fonts/SourceSansPro-Regular.ttf.woff new file mode 100755 index 00000000000..460ab12a638 Binary files /dev/null and b/app/assets/fonts/SourceSansPro-Regular.ttf.woff differ diff --git a/app/assets/fonts/SourceSansPro-Semibold.ttf b/app/assets/fonts/SourceSansPro-Semibold.ttf deleted file mode 100644 index 86b00c067e0..00000000000 Binary files a/app/assets/fonts/SourceSansPro-Semibold.ttf and /dev/null differ diff --git a/app/assets/fonts/SourceSansPro-Semibold.ttf.woff b/app/assets/fonts/SourceSansPro-Semibold.ttf.woff new file mode 100755 index 00000000000..43379631b2d Binary files /dev/null and b/app/assets/fonts/SourceSansPro-Semibold.ttf.woff differ diff --git a/app/assets/fonts/SourceSansPro-SemiboldIt.ttf b/app/assets/fonts/SourceSansPro-SemiboldIt.ttf deleted file mode 100644 index 13d66a1fc45..00000000000 Binary files a/app/assets/fonts/SourceSansPro-SemiboldIt.ttf and /dev/null differ diff --git a/app/assets/fonts/SourceSansPro-SemiboldIt.ttf.woff b/app/assets/fonts/SourceSansPro-SemiboldIt.ttf.woff new file mode 100755 index 00000000000..232c2048ae7 Binary files /dev/null and b/app/assets/fonts/SourceSansPro-SemiboldIt.ttf.woff differ diff --git a/app/assets/fonts/SourceSansPro-SemiboldItalic.ttf b/app/assets/fonts/SourceSansPro-SemiboldItalic.ttf deleted file mode 100755 index 2c5ad3008c3..00000000000 Binary files a/app/assets/fonts/SourceSansPro-SemiboldItalic.ttf and /dev/null differ diff --git a/app/assets/stylesheets/framework/fonts.scss b/app/assets/stylesheets/framework/fonts.scss index e214567eca1..20988f7b430 100644 --- a/app/assets/stylesheets/framework/fonts.scss +++ b/app/assets/stylesheets/framework/fonts.scss @@ -3,23 +3,23 @@ font-family: 'Source Sans Pro'; font-style: normal; font-weight: 300; - src: local('Source Sans Pro Light'), local('SourceSansPro-Light'), font-url('SourceSansPro-Light.ttf'); + src: local('Source Sans Pro Light'), local('SourceSansPro-Light'), font-url('SourceSansPro-Light.ttf.woff'); } @font-face { font-family: 'Source Sans Pro'; font-style: normal; font-weight: 400; - src: local('Source Sans Pro'), local('SourceSansPro-Regular'), font-url('SourceSansPro-Regular.ttf'); + src: local('Source Sans Pro'), local('SourceSansPro-Regular'), font-url('SourceSansPro-Regular.ttf.woff'); } @font-face { font-family: 'Source Sans Pro'; font-style: normal; font-weight: 600; - src: local('Source Sans Pro Semibold'), local('SourceSansPro-Semibold'), font-url('SourceSansPro-Semibold.ttf'); + src: local('Source Sans Pro Semibold'), local('SourceSansPro-Semibold'), font-url('SourceSansPro-Semibold.ttf.woff'); } @font-face { font-family: 'Source Sans Pro'; font-style: normal; font-weight: 700; - src: local('Source Sans Pro Bold'), local('SourceSansPro-Bold'), font-url('SourceSansPro-Bold.ttf'); + src: local('Source Sans Pro Bold'), local('SourceSansPro-Bold'), font-url('SourceSansPro-Bold.ttf.woff'); } -- cgit v1.2.1 From a8b444953bf618977e797090209d7222b0efc834 Mon Sep 17 00:00:00 2001 From: Stan Hu Date: Sat, 9 Jan 2016 17:07:52 -0800 Subject: Add CHANGELOG entry for reply-by-email fix [ci skip] --- CHANGELOG | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG b/CHANGELOG index 921dac01264..e12be8b7b65 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -37,6 +37,7 @@ v 8.3.3 (unreleased) - Suppress e-mails on failed builds if allow_failure is set (Stan Hu) - Fix project transfer e-mail sending incorrect paths in e-mail notification (Stan Hu) - Enable "Add key" button when user fills in a proper key (Stan Hu) + - Fix error in processing reply-by-email messages (Jason Lee) v 8.3.2 - Change single user API endpoint to return more detailed data (Michael Potthoff) -- cgit v1.2.1 From 5f6b093445ff0165fe4da228034db57b3395d983 Mon Sep 17 00:00:00 2001 From: Stan Hu Date: Sat, 9 Jan 2016 21:20:25 -0800 Subject: Disable "Already Blocked" button in admin abuse report page --- app/views/admin/abuse_reports/_abuse_report.html.haml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/views/admin/abuse_reports/_abuse_report.html.haml b/app/views/admin/abuse_reports/_abuse_report.html.haml index 853a780c576..2ab01704b77 100644 --- a/app/views/admin/abuse_reports/_abuse_report.html.haml +++ b/app/views/admin/abuse_reports/_abuse_report.html.haml @@ -26,6 +26,6 @@ - if user && !user.blocked? = link_to 'Block user', block_admin_user_path(user), data: {confirm: 'USER WILL BE BLOCKED! Are you sure?'}, method: :put, class: "btn btn-xs" - else - .btn.btn-xs + .btn.btn-xs.disabled Already Blocked = link_to 'Remove report', [:admin, abuse_report], remote: true, method: :delete, class: "btn btn-xs btn-close js-remove-tr" -- cgit v1.2.1 From e6dbbafd0ad372514fc509af36540936803720b8 Mon Sep 17 00:00:00 2001 From: Luke Waite Date: Sat, 9 Jan 2016 19:02:34 -0500 Subject: Update docs for shared runner default settings Fixes #5993 --- doc/ci/runners/README.md | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/doc/ci/runners/README.md b/doc/ci/runners/README.md index 68dcfe23ffb..295d953db11 100644 --- a/doc/ci/runners/README.md +++ b/doc/ci/runners/README.md @@ -62,8 +62,9 @@ Now simply register the runner as any runner: sudo gitlab-runner register ``` -Note that you will have to enable `Allows shared runners` for each project -that you want to make use of a shared runner. This is by default `off`. +Shared runners are enabled by default as of GitLab 8.2, but can be disabled with the +`DISABLE SHARED RUNNERS` button. Previous versions of GitLab defaulted shared runners to +disabled. ## Registering a Specific Runner -- cgit v1.2.1 From 9061b55c178d23acde535f4f729b4ed293853233 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Steffen=20K=C3=B6hler?= Date: Fri, 8 Jan 2016 17:54:48 +0100 Subject: Fix typo in build page of projects The column containing links to the builds is named Runner but actually contains the Build ID. [ci skip] --- app/views/projects/builds/index.html.haml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/views/projects/builds/index.html.haml b/app/views/projects/builds/index.html.haml index 1a26908ab11..3fa21faf970 100644 --- a/app/views/projects/builds/index.html.haml +++ b/app/views/projects/builds/index.html.haml @@ -40,7 +40,7 @@ %thead %tr %th Status - %th Runner + %th Build ID %th Commit %th Ref %th Stage -- cgit v1.2.1 From 70cba8e9a833b6a5ae4d916ce50c394868de8116 Mon Sep 17 00:00:00 2001 From: Robert Speicher Date: Sun, 10 Jan 2016 19:59:40 -0500 Subject: Remove outdated gitlab-git-http-server reference from Install doc [ci skip] --- doc/install/installation.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/doc/install/installation.md b/doc/install/installation.md index 81edd8da2b8..dd59733cf4d 100644 --- a/doc/install/installation.md +++ b/doc/install/installation.md @@ -552,6 +552,6 @@ Apart from the always supported markdown style there are other rich text files t If you see this message when attempting to clone a repository hosted by GitLab, this is likely due to an outdated Nginx or Apache configuration, or a missing or -misconfigured `gitlab-git-http-server` instance. Double-check that you've -[installed Go](#3-go), [installed gitlab-git-http-server](#install-gitlab-git-http-server), +misconfigured gitlab-workhorse instance. Double-check that you've +[installed Go](#3-go), [installed gitlab-workhorse](#install-gitlab-workhorse), and correctly [configured Nginx](#site-configuration). -- cgit v1.2.1 From 4b4fdf58c7f358fb06bed6dae166b758465850d0 Mon Sep 17 00:00:00 2001 From: Stan Hu Date: Mon, 4 Jan 2016 23:18:23 -0800 Subject: Fix Error 500 when visiting build page of project with nil runners_token Properly ensure that the token exists and add defensively check for a non-nil value. Closes #4294 --- CHANGELOG | 1 + app/models/ci/build.rb | 2 +- app/models/project.rb | 10 ++++++---- spec/models/ci/build_spec.rb | 22 ++++++++++++++++++++++ 4 files changed, 30 insertions(+), 5 deletions(-) create mode 100644 spec/models/ci/build_spec.rb diff --git a/CHANGELOG b/CHANGELOG index f7c278823ee..a7d352b53aa 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -4,6 +4,7 @@ v 8.4.0 (unreleased) - The default GitLab logo now acts as a loading indicator - Accept 2xx status codes for successful Web hook triggers (Stan Hu) - Fix missing date of month in network graph when commits span a month (Stan Hu) + - Fix Error 500 when visiting build page of project with nil runners_token (Stan Hu) - Expire view caches when application settings change (e.g. Gravatar disabled) (Stan Hu) - Don't notify users twice if they are both project watchers and subscribers (Stan Hu) - Implement new UI for group page diff --git a/app/models/ci/build.rb b/app/models/ci/build.rb index 30f79fd3bfa..a4779d06de8 100644 --- a/app/models/ci/build.rb +++ b/app/models/ci/build.rb @@ -206,7 +206,7 @@ module Ci def trace trace = raw_trace - if project && trace.present? + if project && trace.present? && project.runners_token.present? trace.gsub(project.runners_token, 'xxxxxx') else trace diff --git a/app/models/project.rb b/app/models/project.rb index 7626c698816..0d7341e1384 100644 --- a/app/models/project.rb +++ b/app/models/project.rb @@ -50,6 +50,7 @@ class Project < ActiveRecord::Base include Sortable include AfterCommitQueue include CaseSensitivity + include TokenAuthenticatable extend Gitlab::ConfigHelper @@ -193,10 +194,7 @@ class Project < ActiveRecord::Base if: ->(project) { project.avatar.present? && project.avatar_changed? } validates :avatar, file_size: { maximum: 200.kilobytes.to_i } - before_validation :set_runners_token_token - def set_runners_token_token - self.runners_token = SecureRandom.hex(15) if self.runners_token.blank? - end + add_authentication_token_field :runners_token mount_uploader :avatar, AvatarUploader @@ -900,4 +898,8 @@ class Project < ActiveRecord::Base return true unless forked? Gitlab::VisibilityLevel.allowed_fork_levels(forked_from_project.visibility_level).include?(level.to_i) end + + def runners_token + ensure_runners_token! + end end diff --git a/spec/models/ci/build_spec.rb b/spec/models/ci/build_spec.rb new file mode 100644 index 00000000000..36d10636ae9 --- /dev/null +++ b/spec/models/ci/build_spec.rb @@ -0,0 +1,22 @@ +require 'spec_helper' + +describe Ci::Build, models: true do + let(:build) { create(:ci_build) } + let(:test_trace) { 'This is a test' } + + describe '#trace' do + it 'obfuscates project runners token' do + allow(build).to receive(:raw_trace).and_return("Test: #{build.project.runners_token}") + + expect(build.trace).to eq("Test: xxxxxx") + end + + it 'empty project runners token' do + allow(build).to receive(:raw_trace).and_return(test_trace) + # runners_token can't normally be set to nil + allow(build.project).to receive(:runners_token).and_return(nil) + + expect(build.trace).to eq(test_trace) + end + end +end -- cgit v1.2.1 From b7aa13a0cfdcd2ebd5f0dab2bc5cad222f9f379b Mon Sep 17 00:00:00 2001 From: Stan Hu Date: Fri, 8 Jan 2016 08:00:45 -0800 Subject: Before project save ensure that a runners_token exists --- CHANGELOG | 2 +- app/models/project.rb | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/CHANGELOG b/CHANGELOG index a7d352b53aa..04bcbf9dad2 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -4,7 +4,6 @@ v 8.4.0 (unreleased) - The default GitLab logo now acts as a loading indicator - Accept 2xx status codes for successful Web hook triggers (Stan Hu) - Fix missing date of month in network graph when commits span a month (Stan Hu) - - Fix Error 500 when visiting build page of project with nil runners_token (Stan Hu) - Expire view caches when application settings change (e.g. Gravatar disabled) (Stan Hu) - Don't notify users twice if they are both project watchers and subscribers (Stan Hu) - Implement new UI for group page @@ -40,6 +39,7 @@ v 8.3.3 (unreleased) - Fix project transfer e-mail sending incorrect paths in e-mail notification (Stan Hu) - Enable "Add key" button when user fills in a proper key (Stan Hu) - Fix error in processing reply-by-email messages (Jason Lee) + - Fix Error 500 when visiting build page of project with nil runners_token (Stan Hu) v 8.3.2 - Change single user API endpoint to return more detailed data (Michael Potthoff) diff --git a/app/models/project.rb b/app/models/project.rb index 0d7341e1384..31990485f7d 100644 --- a/app/models/project.rb +++ b/app/models/project.rb @@ -195,6 +195,7 @@ class Project < ActiveRecord::Base validates :avatar, file_size: { maximum: 200.kilobytes.to_i } add_authentication_token_field :runners_token + before_save :ensure_runners_token mount_uploader :avatar, AvatarUploader -- cgit v1.2.1 From a789dcaeb3958cf7b2f74d394b646f34297ff3a1 Mon Sep 17 00:00:00 2001 From: Jason Lee Date: Mon, 11 Jan 2016 11:01:15 +0800 Subject: use JavaScript instead of CoffeeScript in Views, the reason #9819 --- app/views/projects/_home_panel.html.haml | 4 ++-- app/views/projects/find_file/show.html.haml | 12 ++++++------ app/views/votes/_votes_block.html.haml | 30 +++++++++++++++-------------- 3 files changed, 24 insertions(+), 22 deletions(-) diff --git a/app/views/projects/_home_panel.html.haml b/app/views/projects/_home_panel.html.haml index 0f61e623396..53eec76129b 100644 --- a/app/views/projects/_home_panel.html.haml +++ b/app/views/projects/_home_panel.html.haml @@ -52,5 +52,5 @@ = render 'projects/buttons/notifications' -:coffeescript - new Star() \ No newline at end of file +:javascript + new Star(); diff --git a/app/views/projects/find_file/show.html.haml b/app/views/projects/find_file/show.html.haml index 2930209fb56..40a2a61d8a1 100644 --- a/app/views/projects/find_file/show.html.haml +++ b/app/views/projects/find_file/show.html.haml @@ -18,10 +18,10 @@ %tbody = spinner nil, true -:coffeescript - projectFindFile = new ProjectFindFile($(".file-finder-holder"), { - url: "#{escape_javascript(namespace_project_files_path(@project.namespace, @project, @ref, @options.merge(format: :json)))}" - treeUrl: "#{escape_javascript(namespace_project_tree_path(@project.namespace, @project, @ref))}" +:javascript + var projectFindFile = new ProjectFindFile($(".file-finder-holder"), { + url: "#{escape_javascript(namespace_project_files_path(@project.namespace, @project, @ref, @options.merge(format: :json)))}", + treeUrl: "#{escape_javascript(namespace_project_tree_path(@project.namespace, @project, @ref))}", blobUrlTemplate: "#{escape_javascript(namespace_project_blob_path(@project.namespace, @project, @id || @commit.id))}" - }) - new ShortcutsFindFile(projectFindFile) + }); + new ShortcutsFindFile(projectFindFile); diff --git a/app/views/votes/_votes_block.html.haml b/app/views/votes/_votes_block.html.haml index ce0a0113403..b1f8645eea0 100644 --- a/app/views/votes/_votes_block.html.haml +++ b/app/views/votes/_votes_block.html.haml @@ -20,27 +20,29 @@ = emoji_icon(emoji["name"], emoji["unicode"], emoji["aliases"]) - if current_user - :coffeescript - post_emoji_url = "#{award_toggle_namespace_project_notes_path(@project.namespace, @project)}" - noteable_type = "#{votable.class.name.underscore}" - noteable_id = "#{votable.id}" - aliases = #{AwardEmoji.aliases.to_json} + :javascript + var post_emoji_url = "#{award_toggle_namespace_project_notes_path(@project.namespace, @project)}"; + var noteable_type = "#{votable.class.name.underscore}"; + var noteable_id = "#{votable.id}"; + var aliases = #{AwardEmoji.aliases.to_json}; window.awards_handler = new AwardsHandler( post_emoji_url, noteable_type, noteable_id, aliases - ) + ); - $(".awards").on "click", ".emoji-menu-content li", (e) -> - emoji = $(this).find(".emoji-icon").data("emoji") - awards_handler.addAward(emoji) + $(".awards").on("click", ".emoji-menu-content li", function(e) { + var emoji = $(this).find(".emoji-icon").data("emoji"); + awards_handler.addAward(emoji); + }); - $(".awards").on "click", ".award", (e) -> - emoji = $(this).find(".icon").data("emoji") - awards_handler.addAward(emoji) + $(".awards").on("click", ".award", function(e) { + var emoji = $(this).find(".icon").data("emoji"); + awards_handler.addAward(emoji); + }); - $(".award").tooltip() + $(".award").tooltip(); - $(".emoji-menu-content").niceScroll({cursorwidth: "7px", autohidemode: false}) + $(".emoji-menu-content").niceScroll({cursorwidth: "7px", autohidemode: false}); -- cgit v1.2.1 From e304a76eb6f15310dc53f560e12db0eae7816856 Mon Sep 17 00:00:00 2001 From: iqualisoni Date: Mon, 11 Jan 2016 01:02:27 -0200 Subject: Issue #5817 wording of the web hooks updated on issue and merge events --- app/views/projects/hooks/index.html.haml | 4 ++-- app/views/shared/_service_settings.html.haml | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/app/views/projects/hooks/index.html.haml b/app/views/projects/hooks/index.html.haml index b18d9197d0b..a0511819c9f 100644 --- a/app/views/projects/hooks/index.html.haml +++ b/app/views/projects/hooks/index.html.haml @@ -47,14 +47,14 @@ = f.label :issues_events, class: 'list-label' do %strong Issues events %p.light - This url will be triggered when an issue is created + This url will be triggered when an issue is created/updated/merged %div = f.check_box :merge_requests_events, class: 'pull-left' .prepend-left-20 = f.label :merge_requests_events, class: 'list-label' do %strong Merge Request events %p.light - This url will be triggered when a merge request is created + This url will be triggered when a merge request is created/updated/merged %div = f.check_box :build_events, class: 'pull-left' .prepend-left-20 diff --git a/app/views/shared/_service_settings.html.haml b/app/views/shared/_service_settings.html.haml index 28d6f421fea..5a60ff5a5da 100644 --- a/app/views/shared/_service_settings.html.haml +++ b/app/views/shared/_service_settings.html.haml @@ -50,7 +50,7 @@ = form.label :issues_events, class: 'list-label' do %strong Issues events %p.light - This url will be triggered when an issue is created + This url will be triggered when an issue is created/updated/merged - if @service.supported_events.include?("merge_request") %div = form.check_box :merge_requests_events, class: 'pull-left' @@ -58,7 +58,7 @@ = form.label :merge_requests_events, class: 'list-label' do %strong Merge Request events %p.light - This url will be triggered when a merge request is created + This url will be triggered when a merge request is created/updated/merged - if @service.supported_events.include?("build") %div = form.check_box :build_events, class: 'pull-left' -- cgit v1.2.1 From 8aac39d8362442823cc3eb96fcfcacc9abf54257 Mon Sep 17 00:00:00 2001 From: Stan Hu Date: Sun, 10 Jan 2016 00:49:14 -0800 Subject: Add pencil icon to edit group settings Move icons to upper-right corner of group page Closes #6038 --- app/views/groups/show.html.haml | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/app/views/groups/show.html.haml b/app/views/groups/show.html.haml index a607d860d7d..5511d8272ab 100644 --- a/app/views/groups/show.html.haml +++ b/app/views/groups/show.html.haml @@ -6,6 +6,11 @@ = auto_discovery_link_tag(:atom, group_url(@group, format: :atom, private_token: current_user.private_token), title: "#{@group.name} activity") .cover-block + .cover-controls + - if @group && can?(current_user, :admin_group, @group) + = link_to icon('pencil'), edit_group_path(@group), class: 'btn' + = link_to icon('rss'), group_path(@group, { format: :atom, private_token: current_user.private_token }), title: "Feed", class: 'btn rss-btn' + .avatar-holder = link_to group_icon(@group), target: '_blank' do = image_tag group_icon(@group), class: "avatar group-avatar s90" @@ -34,9 +39,6 @@ .gray-content-block.activity-filter-block - if current_user = render "events/event_last_push", event: @last_push - .pull-right - = link_to group_path(@group, { format: :atom, private_token: current_user.private_token }), title: "Feed", class: 'btn rss-btn' do - %i.fa.fa-rss = render 'shared/event_filter' -- cgit v1.2.1 From 1587d57197fa1d04128223af29c2385a2137628f Mon Sep 17 00:00:00 2001 From: Stan Hu Date: Sun, 10 Jan 2016 20:46:57 -0800 Subject: Check for current user --- app/views/groups/show.html.haml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/app/views/groups/show.html.haml b/app/views/groups/show.html.haml index 5511d8272ab..48a544fc834 100644 --- a/app/views/groups/show.html.haml +++ b/app/views/groups/show.html.haml @@ -9,7 +9,8 @@ .cover-controls - if @group && can?(current_user, :admin_group, @group) = link_to icon('pencil'), edit_group_path(@group), class: 'btn' - = link_to icon('rss'), group_path(@group, { format: :atom, private_token: current_user.private_token }), title: "Feed", class: 'btn rss-btn' + - if current_user + = link_to icon('rss'), group_path(@group, { format: :atom, private_token: current_user.private_token }), title: "Feed", class: 'btn rss-btn' .avatar-holder = link_to group_icon(@group), target: '_blank' do -- cgit v1.2.1 From 569f5701ee410b3f6da7e005e7277d1add467d44 Mon Sep 17 00:00:00 2001 From: Yorick Peterse Date: Mon, 11 Jan 2016 11:06:00 +0100 Subject: Only load autocomplete data when actually needed Previously this would result in autocomplete data being loaded for every page (e.g. the page showing all Git branches of a project). --- app/assets/javascripts/gfm_auto_complete.js.coffee | 19 ++++++++++--------- app/views/layouts/_init_auto_complete.html.haml | 8 +++++--- 2 files changed, 15 insertions(+), 12 deletions(-) diff --git a/app/assets/javascripts/gfm_auto_complete.js.coffee b/app/assets/javascripts/gfm_auto_complete.js.coffee index fa90fb65f42..4718bcf7a1e 100644 --- a/app/assets/javascripts/gfm_auto_complete.js.coffee +++ b/app/assets/javascripts/gfm_auto_complete.js.coffee @@ -68,12 +68,13 @@ GitLab.GfmAutoComplete = title: sanitize(m.title) search: "#{m.iid} #{m.title}" - $.getJSON(@dataSource).done (data) -> - # load members - input.atwho 'load', '@', data.members - # load issues - input.atwho 'load', 'issues', data.issues - # load merge requests - input.atwho 'load', 'mergerequests', data.mergerequests - # load emojis - input.atwho 'load', ':', data.emojis + if @dataSource + $.getJSON(@dataSource).done (data) -> + # load members + input.atwho 'load', '@', data.members + # load issues + input.atwho 'load', 'issues', data.issues + # load merge requests + input.atwho 'load', 'mergerequests', data.mergerequests + # load emojis + input.atwho 'load', ':', data.emojis diff --git a/app/views/layouts/_init_auto_complete.html.haml b/app/views/layouts/_init_auto_complete.html.haml index 035fe0056d3..96b38485425 100644 --- a/app/views/layouts/_init_auto_complete.html.haml +++ b/app/views/layouts/_init_auto_complete.html.haml @@ -1,4 +1,6 @@ - project = @target_project || @project -:javascript - GitLab.GfmAutoComplete.dataSource = "#{autocomplete_sources_namespace_project_path(project.namespace, project, type: @noteable.class, type_id: params[:id])}" - GitLab.GfmAutoComplete.setup(); + +- if @noteable + :javascript + GitLab.GfmAutoComplete.dataSource = "#{autocomplete_sources_namespace_project_path(project.namespace, project, type: @noteable.class, type_id: params[:id])}" + GitLab.GfmAutoComplete.setup(); -- cgit v1.2.1