From a3f645ef51ec12ce93934b4ddb11313613d8c451 Mon Sep 17 00:00:00 2001 From: skv Date: Sun, 19 Jan 2014 22:55:59 +0400 Subject: [PATCH 01/39] Remove deprecated finders --- Gemfile | 1 - Gemfile.lock | 1 - app/controllers/admin/groups_controller.rb | 2 +- app/controllers/admin/projects_controller.rb | 2 +- app/controllers/admin/users_controller.rb | 2 +- app/controllers/dashboard_controller.rb | 2 +- app/controllers/groups_controller.rb | 2 +- app/controllers/profiles/groups_controller.rb | 2 +- app/controllers/projects/issues_controller.rb | 4 ++-- .../projects/merge_requests_controller.rb | 2 +- .../projects/milestones_controller.rb | 2 +- .../projects/team_members_controller.rb | 8 ++++---- app/controllers/search_controller.rb | 4 ++-- app/controllers/snippets_controller.rb | 2 +- app/controllers/users_controller.rb | 2 +- app/controllers/users_groups_controller.rb | 2 +- app/helpers/application_helper.rb | 2 +- app/mailers/emails/issues.rb | 2 +- app/mailers/emails/merge_requests.rb | 2 +- app/models/note.rb | 4 ++-- app/models/project.rb | 6 +++--- app/models/project_team.rb | 8 ++++---- app/models/user.rb | 4 ++-- app/services/notification_service.rb | 4 ++-- app/services/projects/create_service.rb | 2 +- app/services/search/global_service.rb | 2 +- db/fixtures/development/04_project.rb | 2 +- ...130506095501_remove_project_id_from_key.rb | 2 +- features/steps/admin/admin_groups.rb | 2 +- features/steps/dashboard/dashboard.rb | 4 ++-- .../dashboard_with_archived_projects.rb | 2 +- features/steps/group/group.rb | 2 +- features/steps/profile/profile_ssh_keys.rb | 2 +- features/steps/project/project_archived.rb | 6 +++--- .../steps/project/project_browse_branches.rb | 2 +- features/steps/project/project_fork.rb | 4 ++-- .../project/project_forked_merge_requests.rb | 8 ++++---- features/steps/project/project_graph.rb | 2 +- .../steps/project/project_issue_tracker.rb | 2 +- features/steps/project/project_issues.rb | 16 +++++++-------- features/steps/project/project_labels.rb | 2 +- .../steps/project/project_markdown_render.rb | 2 +- .../steps/project/project_merge_requests.rb | 6 +++--- features/steps/project/project_milestones.rb | 10 +++++----- .../steps/project/project_network_graph.rb | 2 +- features/steps/project/project_snippets.rb | 4 ++-- .../steps/project/project_team_management.rb | 20 +++++++++---------- features/steps/project/redirects.rb | 6 +++--- features/steps/public/projects_feature.rb | 16 +++++++-------- features/steps/shared/paths.rb | 10 +++++----- features/steps/shared/project.rb | 8 ++++---- features/steps/snippets/discover_snippets.rb | 2 +- features/steps/snippets/snippets.rb | 2 +- features/steps/snippets/user_snippets.rb | 2 +- lib/api/deploy_keys.rb | 4 ++-- lib/api/entities.rb | 8 ++++---- lib/api/groups.rb | 6 +++--- lib/api/helpers.rb | 4 ++-- lib/api/merge_requests.rb | 2 +- lib/api/projects.rb | 4 ++-- lib/api/repositories.rb | 4 ++-- lib/api/users.rb | 2 +- lib/gitlab/auth.rb | 2 +- lib/gitlab/identifier.rb | 6 +++--- lib/gitlab/ldap/user.rb | 4 ++-- lib/tasks/gitlab/bulk_add_permission.rake | 2 +- lib/tasks/gitlab/enable_namespaces.rake | 4 ++-- lib/tasks/gitlab/import.rake | 2 +- spec/lib/gitlab/ldap/ldap_user_auth_spec.rb | 10 +++++----- spec/requests/api/users_spec.rb | 2 +- spec/workers/post_receive_spec.rb | 2 +- 71 files changed, 145 insertions(+), 147 deletions(-) diff --git a/Gemfile b/Gemfile index b9ef6b1f46..3a10e7f2a3 100644 --- a/Gemfile +++ b/Gemfile @@ -14,7 +14,6 @@ gem "protected_attributes" gem 'rails-observers' gem 'actionpack-page_caching' gem 'actionpack-action_caching' -gem 'activerecord-deprecated_finders' # Supported DBs gem "mysql2", group: :mysql diff --git a/Gemfile.lock b/Gemfile.lock index 80d98a5088..cb55d58ed4 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -549,7 +549,6 @@ PLATFORMS DEPENDENCIES actionpack-action_caching actionpack-page_caching - activerecord-deprecated_finders acts-as-taggable-on annotate (~> 2.6.0.beta2) asciidoctor diff --git a/app/controllers/admin/groups_controller.rb b/app/controllers/admin/groups_controller.rb index 89b395786b..4bb3cf07da 100644 --- a/app/controllers/admin/groups_controller.rb +++ b/app/controllers/admin/groups_controller.rb @@ -52,6 +52,6 @@ class Admin::GroupsController < Admin::ApplicationController private def group - @group = Group.find_by_path(params[:id]) + @group = Group.find_by(path: params[:id]) end end diff --git a/app/controllers/admin/projects_controller.rb b/app/controllers/admin/projects_controller.rb index ea20595047..13a7bdcf34 100644 --- a/app/controllers/admin/projects_controller.rb +++ b/app/controllers/admin/projects_controller.rb @@ -5,7 +5,7 @@ class Admin::ProjectsController < Admin::ApplicationController def index owner_id = params[:owner_id] - user = User.find_by_id(owner_id) + user = User.find_by(id: owner_id) @projects = user ? user.owned_projects : Project.all @projects = @projects.where("visibility_level IN (?)", params[:visibility_levels]) if params[:visibility_levels].present? diff --git a/app/controllers/admin/users_controller.rb b/app/controllers/admin/users_controller.rb index 2f98162713..bdbb9a354b 100644 --- a/app/controllers/admin/users_controller.rb +++ b/app/controllers/admin/users_controller.rb @@ -100,6 +100,6 @@ class Admin::UsersController < Admin::ApplicationController protected def user - @user ||= User.find_by_username!(params[:id]) + @user ||= User.find_by!(username: params[:id]) end end diff --git a/app/controllers/dashboard_controller.rb b/app/controllers/dashboard_controller.rb index d4a4ea80bc..656eda9dec 100644 --- a/app/controllers/dashboard_controller.rb +++ b/app/controllers/dashboard_controller.rb @@ -41,7 +41,7 @@ class DashboardController < ApplicationController current_user.authorized_projects end - @projects = @projects.where(namespace_id: Group.find_by_name(params[:group])) if params[:group].present? + @projects = @projects.where(namespace_id: Group.find_by(name: params[:group])) if params[:group].present? @projects = @projects.where(visibility_level: params[:visibility_level]) if params[:visibility_level].present? @projects = @projects.includes(:namespace) @projects = @projects.tagged_with(params[:label]) if params[:label].present? diff --git a/app/controllers/groups_controller.rb b/app/controllers/groups_controller.rb index 6a407503ec..7b418ec98f 100644 --- a/app/controllers/groups_controller.rb +++ b/app/controllers/groups_controller.rb @@ -87,7 +87,7 @@ class GroupsController < ApplicationController protected def group - @group ||= Group.find_by_path(params[:id]) + @group ||= Group.find_by(path: params[:id]) end def projects diff --git a/app/controllers/profiles/groups_controller.rb b/app/controllers/profiles/groups_controller.rb index 378ff6bcf3..bdd991bec0 100644 --- a/app/controllers/profiles/groups_controller.rb +++ b/app/controllers/profiles/groups_controller.rb @@ -19,6 +19,6 @@ class Profiles::GroupsController < ApplicationController private def group - @group ||= Group.find_by_path(params[:id]) + @group ||= Group.find_by(path: params[:id]) end end diff --git a/app/controllers/projects/issues_controller.rb b/app/controllers/projects/issues_controller.rb index 770fccaa11..58ead666d8 100644 --- a/app/controllers/projects/issues_controller.rb +++ b/app/controllers/projects/issues_controller.rb @@ -97,7 +97,7 @@ class Projects::IssuesController < Projects::ApplicationController def issue @issue ||= begin - @project.issues.find_by_iid!(params[:id]) + @project.issues.find_by!(iid: params[:id]) rescue ActiveRecord::RecordNotFound redirect_old end @@ -128,7 +128,7 @@ class Projects::IssuesController < Projects::ApplicationController # To prevent 404 errors we provide a redirect to correct iids until 7.0 release # def redirect_old - issue = @project.issues.find_by_id(params[:id]) + issue = @project.issues.find_by(id: params[:id]) if issue redirect_to project_issue_path(@project, issue) diff --git a/app/controllers/projects/merge_requests_controller.rb b/app/controllers/projects/merge_requests_controller.rb index 40564c7f88..f8ead19ff1 100644 --- a/app/controllers/projects/merge_requests_controller.rb +++ b/app/controllers/projects/merge_requests_controller.rb @@ -169,7 +169,7 @@ class Projects::MergeRequestsController < Projects::ApplicationController end def merge_request - @merge_request ||= @project.merge_requests.find_by_iid!(params[:id]) + @merge_request ||= @project.merge_requests.find_by!(iid: params[:id]) end def closes_issues diff --git a/app/controllers/projects/milestones_controller.rb b/app/controllers/projects/milestones_controller.rb index ecb1fc1d56..aea92a19f3 100644 --- a/app/controllers/projects/milestones_controller.rb +++ b/app/controllers/projects/milestones_controller.rb @@ -76,7 +76,7 @@ class Projects::MilestonesController < Projects::ApplicationController protected def milestone - @milestone ||= @project.milestones.find_by_iid!(params[:id]) + @milestone ||= @project.milestones.find_by!(iid: params[:id]) end def authorize_admin_milestone! diff --git a/app/controllers/projects/team_members_controller.rb b/app/controllers/projects/team_members_controller.rb index 2c40b3c75f..44068878cd 100644 --- a/app/controllers/projects/team_members_controller.rb +++ b/app/controllers/projects/team_members_controller.rb @@ -26,7 +26,7 @@ class Projects::TeamMembersController < Projects::ApplicationController end def update - @user_project_relation = project.users_projects.find_by_user_id(member) + @user_project_relation = project.users_projects.find_by(user_id: member) @user_project_relation.update_attributes(params[:team_member]) unless @user_project_relation.valid? @@ -36,7 +36,7 @@ class Projects::TeamMembersController < Projects::ApplicationController end def destroy - @user_project_relation = project.users_projects.find_by_user_id(member) + @user_project_relation = project.users_projects.find_by(user_id: member) @user_project_relation.destroy respond_to do |format| @@ -46,7 +46,7 @@ class Projects::TeamMembersController < Projects::ApplicationController end def leave - project.users_projects.find_by_user_id(current_user).destroy + project.users_projects.find_by(user_id: current_user).destroy respond_to do |format| format.html { redirect_to :back } @@ -65,6 +65,6 @@ class Projects::TeamMembersController < Projects::ApplicationController protected def member - @member ||= User.find_by_username(params[:id]) + @member ||= User.find_by(username: params[:id]) end end diff --git a/app/controllers/search_controller.rb b/app/controllers/search_controller.rb index e853c22800..d98a44ed3f 100644 --- a/app/controllers/search_controller.rb +++ b/app/controllers/search_controller.rb @@ -1,7 +1,7 @@ class SearchController < ApplicationController def show - @project = Project.find_by_id(params[:project_id]) if params[:project_id].present? - @group = Group.find_by_id(params[:group_id]) if params[:group_id].present? + @project = Project.find_by(id: params[:project_id]) if params[:project_id].present? + @group = Group.find_by(id: params[:group_id]) if params[:group_id].present? if @project return access_denied! unless can?(current_user, :download_code, @project) diff --git a/app/controllers/snippets_controller.rb b/app/controllers/snippets_controller.rb index b91f68aab5..e54a968326 100644 --- a/app/controllers/snippets_controller.rb +++ b/app/controllers/snippets_controller.rb @@ -18,7 +18,7 @@ class SnippetsController < ApplicationController end def user_index - @user = User.find_by_username(params[:username]) + @user = User.find_by(username: params[:username]) @snippets = @user.snippets.fresh.non_expired if @user == current_user diff --git a/app/controllers/users_controller.rb b/app/controllers/users_controller.rb index ddc7630f89..6a5ce62909 100644 --- a/app/controllers/users_controller.rb +++ b/app/controllers/users_controller.rb @@ -2,7 +2,7 @@ class UsersController < ApplicationController layout 'navless' def show - @user = User.find_by_username!(params[:username]) + @user = User.find_by!(username: params[:username]) @projects = @user.authorized_projects.where(id: current_user.authorized_projects.pluck(:id)).includes(:namespace) @events = @user.recent_events.where(project_id: @projects.map(&:id)).limit(20) diff --git a/app/controllers/users_groups_controller.rb b/app/controllers/users_groups_controller.rb index 749da1e141..bc5db44552 100644 --- a/app/controllers/users_groups_controller.rb +++ b/app/controllers/users_groups_controller.rb @@ -30,7 +30,7 @@ class UsersGroupsController < ApplicationController protected def group - @group ||= Group.find_by_path(params[:group_id]) + @group ||= Group.find_by(path: params[:group_id]) end def authorize_admin_group! diff --git a/app/helpers/application_helper.rb b/app/helpers/application_helper.rb index 0db43fa180..e60cba2bb2 100644 --- a/app/helpers/application_helper.rb +++ b/app/helpers/application_helper.rb @@ -50,7 +50,7 @@ module ApplicationHelper end def avatar_icon(user_email = '', size = nil) - user = User.find_by_email(user_email) + user = User.find_by(email: user_email) if user && user.avatar.present? user.avatar.url else diff --git a/app/mailers/emails/issues.rb b/app/mailers/emails/issues.rb index 5abdf99529..b2b4b83d6c 100644 --- a/app/mailers/emails/issues.rb +++ b/app/mailers/emails/issues.rb @@ -8,7 +8,7 @@ module Emails def reassigned_issue_email(recipient_id, issue_id, previous_assignee_id) @issue = Issue.find(issue_id) - @previous_assignee = User.find_by_id(previous_assignee_id) if previous_assignee_id + @previous_assignee = User.find_by(id: previous_assignee_id) if previous_assignee_id @project = @issue.project mail(to: recipient(recipient_id), subject: subject("Changed issue ##{@issue.iid}", @issue.title)) end diff --git a/app/mailers/emails/merge_requests.rb b/app/mailers/emails/merge_requests.rb index 25b8bf755e..e60887d525 100644 --- a/app/mailers/emails/merge_requests.rb +++ b/app/mailers/emails/merge_requests.rb @@ -8,7 +8,7 @@ module Emails def reassigned_merge_request_email(recipient_id, merge_request_id, previous_assignee_id) @merge_request = MergeRequest.find(merge_request_id) - @previous_assignee = User.find_by_id(previous_assignee_id) if previous_assignee_id + @previous_assignee = User.find_by(id: previous_assignee_id) if previous_assignee_id @project = @merge_request.project mail(to: recipient(recipient_id), subject: subject("Changed merge request ##{@merge_request.iid}", @merge_request.title)) end diff --git a/app/models/note.rb b/app/models/note.rb index 67755f4414..f4c0be3307 100644 --- a/app/models/note.rb +++ b/app/models/note.rb @@ -123,8 +123,8 @@ class Note < ActiveRecord::Base def commit_author @commit_author ||= - project.users.find_by_email(noteable.author_email) || - project.users.find_by_name(noteable.author_name) + project.users.find_by(email: noteable.author_email) || + project.users.find_by(name: noteable.author_name) rescue nil end diff --git a/app/models/project.rb b/app/models/project.rb index f322b5a2e2..8450b91680 100644 --- a/app/models/project.rb +++ b/app/models/project.rb @@ -141,10 +141,10 @@ class Project < ActiveRecord::Base def find_with_namespace(id) if id.include?("/") id = id.split("/") - namespace = Namespace.find_by_path(id.first) + namespace = Namespace.find_by(path: id.first) return nil unless namespace - where(namespace_id: namespace.id).find_by_path(id.second) + where(namespace_id: namespace.id).find_by(path: id.second) else where(path: id, namespace_id: nil).last end @@ -288,7 +288,7 @@ class Project < ActiveRecord::Base # Get Team Member record by user id def team_member_by_id(user_id) - users_projects.find_by_user_id(user_id) + users_projects.find_by(user_id: user_id) end def name_with_namespace diff --git a/app/models/project_team.rb b/app/models/project_team.rb index 5630f280ae..eca13e5606 100644 --- a/app/models/project_team.rb +++ b/app/models/project_team.rb @@ -22,22 +22,22 @@ class ProjectTeam end def find(user_id) - user = project.users.find_by_id(user_id) + user = project.users.find_by(id: user_id) if group - user ||= group.users.find_by_id(user_id) + user ||= group.users.find_by(id: user_id) end user end def find_tm(user_id) - tm = project.users_projects.find_by_user_id(user_id) + tm = project.users_projects.find_by(user_id: user_id) # If user is not in project members # we should check for group membership if group && !tm - tm = group.users_groups.find_by_user_id(user_id) + tm = group.users_groups.find_by(user_id: user_id) end tm diff --git a/app/models/user.rb b/app/models/user.rb index f2cd554f9c..fd2bf34e0c 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -238,7 +238,7 @@ class User < ActiveRecord::Base def namespace_uniq namespace_name = self.username - if Namespace.find_by_path(namespace_name) + if Namespace.find_by(path: namespace_name) self.errors.add :username, "already exist" end end @@ -382,7 +382,7 @@ class User < ActiveRecord::Base end def created_by - User.find_by_id(created_by_id) if created_by_id + User.find_by(id: created_by_id) if created_by_id end def sanitize_attrs diff --git a/app/services/notification_service.rb b/app/services/notification_service.rb index ebbb556b63..7c02777e91 100644 --- a/app/services/notification_service.rb +++ b/app/services/notification_service.rb @@ -195,10 +195,10 @@ class NotificationService users.reject do |user| next user.notification.disabled? unless project - tm = project.users_projects.find_by_user_id(user.id) + tm = project.users_projects.find_by(user_id: user.id) if !tm && project.group - tm = project.group.users_groups.find_by_user_id(user.id) + tm = project.group.users_groups.find_by(user_id: user.id) end # reject users who globally disabled notification and has no membership diff --git a/app/services/projects/create_service.rb b/app/services/projects/create_service.rb index 033be8f9ed..ba131d8ffb 100644 --- a/app/services/projects/create_service.rb +++ b/app/services/projects/create_service.rb @@ -73,7 +73,7 @@ module Projects end def allowed_namespace?(user, namespace_id) - namespace = Namespace.find_by_id(namespace_id) + namespace = Namespace.find_by(id: namespace_id) current_user.can?(:manage_namespace, namespace) end end diff --git a/app/services/search/global_service.rb b/app/services/search/global_service.rb index c5ca332236..c113040157 100644 --- a/app/services/search/global_service.rb +++ b/app/services/search/global_service.rb @@ -15,7 +15,7 @@ module Search authorized_projects_ids += current_user.authorized_projects.pluck(:id) if current_user authorized_projects_ids += Project.public_or_internal_only(current_user).pluck(:id) - group = Group.find_by_id(params[:group_id]) if params[:group_id].present? + group = Group.find_by(id: params[:group_id]) if params[:group_id].present? projects = Project.where(id: authorized_projects_ids) projects = projects.where(namespace_id: group.id) if group projects = projects.search(query) diff --git a/db/fixtures/development/04_project.rb b/db/fixtures/development/04_project.rb index 6fdb163c27..990575306c 100644 --- a/db/fixtures/development/04_project.rb +++ b/db/fixtures/development/04_project.rb @@ -19,7 +19,7 @@ project_urls = [ project_urls.each_with_index do |url, i| group_path, project_path = url.split('/')[-2..-1] - group = Group.find_by_path(group_path) + group = Group.find_by(path: group_path) unless group group = Group.new( diff --git a/db/migrate/20130506095501_remove_project_id_from_key.rb b/db/migrate/20130506095501_remove_project_id_from_key.rb index 4214fd45d1..6b794cfb5c 100644 --- a/db/migrate/20130506095501_remove_project_id_from_key.rb +++ b/db/migrate/20130506095501_remove_project_id_from_key.rb @@ -4,7 +4,7 @@ class RemoveProjectIdFromKey < ActiveRecord::Migration Key.where('project_id IS NOT NULL').update_all(type: 'DeployKey') DeployKey.all.each do |key| - project = Project.find_by_id(key.project_id) + project = Project.find_by(id: key.project_id) if project project.deploy_keys << key print '.' diff --git a/features/steps/admin/admin_groups.rb b/features/steps/admin/admin_groups.rb index b4591f227e..013fa6da8b 100644 --- a/features/steps/admin/admin_groups.rb +++ b/features/steps/admin/admin_groups.rb @@ -40,7 +40,7 @@ class AdminGroups < Spinach::FeatureSteps end When 'I select user "John" from user list as "Reporter"' do - user = User.find_by_name("John") + user = User.find_by(name: "John") select2(user.id, from: "#user_ids", multiple: true) within "#new_team_member" do select "Reporter", from: "group_access" diff --git a/features/steps/dashboard/dashboard.rb b/features/steps/dashboard/dashboard.rb index bde32128b9..3526006c94 100644 --- a/features/steps/dashboard/dashboard.rb +++ b/features/steps/dashboard/dashboard.rb @@ -43,7 +43,7 @@ class Dashboard < Spinach::FeatureSteps end And 'user with name "John Doe" left project "Shop"' do - user = User.find_by_name "John Doe" + user = User.find_by(name: "John Doe") Event.create( project: project, author_id: user.id, @@ -85,6 +85,6 @@ class Dashboard < Spinach::FeatureSteps end def project - @project ||= Project.find_by_name "Shop" + @project ||= Project.find_by(name: "Shop") end end diff --git a/features/steps/dashboard/dashboard_with_archived_projects.rb b/features/steps/dashboard/dashboard_with_archived_projects.rb index 700f4b426c..1bc69555b5 100644 --- a/features/steps/dashboard/dashboard_with_archived_projects.rb +++ b/features/steps/dashboard/dashboard_with_archived_projects.rb @@ -4,7 +4,7 @@ class DashboardWithArchivedProjects < Spinach::FeatureSteps include SharedProject When 'project "Forum" is archived' do - project = Project.find_by_name "Forum" + project = Project.find_by(name: "Forum") project.update_attribute(:archived, true) end diff --git a/features/steps/group/group.rb b/features/steps/group/group.rb index bcadf21c23..15d7c46c69 100644 --- a/features/steps/group/group.rb +++ b/features/steps/group/group.rb @@ -39,7 +39,7 @@ class Groups < Spinach::FeatureSteps end And 'I select user "John" from list with role "Reporter"' do - user = User.find_by_name("John") + user = User.find_by(name: "John") within ".users-group-form" do select2(user.id, from: "#user_ids", multiple: true) select "Reporter", from: "group_access" diff --git a/features/steps/profile/profile_ssh_keys.rb b/features/steps/profile/profile_ssh_keys.rb index 65bfc505d8..65ca824bb5 100644 --- a/features/steps/profile/profile_ssh_keys.rb +++ b/features/steps/profile/profile_ssh_keys.rb @@ -18,7 +18,7 @@ class ProfileSshKeys < Spinach::FeatureSteps end Then 'I should see new ssh key "Laptop"' do - key = Key.find_by_title("Laptop") + key = Key.find_by(title: "Laptop") page.should have_content(key.title) page.should have_content(key.key) current_path.should == profile_key_path(key) diff --git a/features/steps/project/project_archived.rb b/features/steps/project/project_archived.rb index 149d293cd0..dfbe762c43 100644 --- a/features/steps/project/project_archived.rb +++ b/features/steps/project/project_archived.rb @@ -4,17 +4,17 @@ class ProjectArchived < Spinach::FeatureSteps include SharedPaths When 'project "Forum" is archived' do - project = Project.find_by_name "Forum" + project = Project.find_by(name: "Forum") project.update_attribute(:archived, true) end When 'project "Shop" is archived' do - project = Project.find_by_name "Shop" + project = Project.find_by(name: "Shop") project.update_attribute(:archived, true) end When 'I visit project "Forum" page' do - project = Project.find_by_name "Forum" + project = Project.find_by(name: "Forum") visit project_path(project) end diff --git a/features/steps/project/project_browse_branches.rb b/features/steps/project/project_browse_branches.rb index e77825411f..ef29cc67a4 100644 --- a/features/steps/project/project_browse_branches.rb +++ b/features/steps/project/project_browse_branches.rb @@ -29,7 +29,7 @@ class ProjectBrowseBranches < Spinach::FeatureSteps end And 'project "Shop" has protected branches' do - project = Project.find_by_name("Shop") + project = Project.find_by(name: "Shop") project.protected_branches.create(name: "stable") end end diff --git a/features/steps/project/project_fork.rb b/features/steps/project/project_fork.rb index 858c7d11b3..128687ca28 100644 --- a/features/steps/project/project_fork.rb +++ b/features/steps/project/project_fork.rb @@ -11,7 +11,7 @@ class ForkProject < Spinach::FeatureSteps end step 'I am a member of project "Shop"' do - @project = Project.find_by_name "Shop" + @project = Project.find_by(name: "Shop") @project ||= create(:project_with_code, name: "Shop", group: create(:group)) @project.team << [@user, :reporter] end @@ -19,7 +19,7 @@ class ForkProject < Spinach::FeatureSteps step 'I should see the forked project page' do page.should have_content "Project was successfully forked." current_path.should include current_user.namespace.path - @forked_project = Project.find_by_namespace_id(current_user.namespace.path) + @forked_project = Project.find_by(namespace_id: current_user.namespace.path) end step 'I already have a project named "Shop" in my namespace' do diff --git a/features/steps/project/project_forked_merge_requests.rb b/features/steps/project/project_forked_merge_requests.rb index d34aeac30b..a8198532ae 100644 --- a/features/steps/project/project_forked_merge_requests.rb +++ b/features/steps/project/project_forked_merge_requests.rb @@ -6,7 +6,7 @@ class ProjectForkedMergeRequests < Spinach::FeatureSteps include Select2Helper step 'I am a member of project "Shop"' do - @project = Project.find_by_name "Shop" + @project = Project.find_by(name: "Shop") @project ||= create(:project_with_code, name: "Shop") @project.team << [@user, :reporter] end @@ -14,7 +14,7 @@ class ProjectForkedMergeRequests < Spinach::FeatureSteps step 'I have a project forked off of "Shop" called "Forked Shop"' do @forking_user = @user forked_project_link = build(:forked_project_link) - @forked_project = Project.find_by_name "Forked Shop" + @forked_project = Project.find_by(name: "Forked Shop") @forked_project ||= create(:source_project_with_code, name: "Forked Shop", forked_project_link: forked_project_link, creator_id: @forking_user.id , namespace: @forking_user.namespace) forked_project_link.forked_from_project = @project @@ -114,7 +114,7 @@ class ProjectForkedMergeRequests < Spinach::FeatureSteps end step 'project "Forked Shop" has push event' do - @forked_project = Project.find_by_name("Forked Shop") + @forked_project = Project.find_by(name: "Forked Shop") data = { before: "0000000000000000000000000000000000000000", @@ -172,7 +172,7 @@ class ProjectForkedMergeRequests < Spinach::FeatureSteps end def project - @project ||= Project.find_by_name!("Shop") + @project ||= Project.find_by!(name: "Shop") end # Verify a link is generated against the correct project diff --git a/features/steps/project/project_graph.rb b/features/steps/project/project_graph.rb index 50942b3cbb..89fe5fdead 100644 --- a/features/steps/project/project_graph.rb +++ b/features/steps/project/project_graph.rb @@ -7,7 +7,7 @@ class ProjectGraph < Spinach::FeatureSteps end When 'I visit project "Shop" graph page' do - project = Project.find_by_name("Shop") + project = Project.find_by(name: "Shop") visit project_graph_path(project, "master") end end diff --git a/features/steps/project/project_issue_tracker.rb b/features/steps/project/project_issue_tracker.rb index a05d7a0bc3..fe41a900a9 100644 --- a/features/steps/project/project_issue_tracker.rb +++ b/features/steps/project/project_issue_tracker.rb @@ -4,7 +4,7 @@ class ProjectIssueTracker < Spinach::FeatureSteps include SharedPaths step 'project "Shop" has issues enabled' do - @project = Project.find_by_name "Shop" + @project = Project.find_by(name: "Shop") @project ||= create(:project_with_code, name: "Shop", namespace: @user.namespace) @project.issues_enabled = true end diff --git a/features/steps/project/project_issues.rb b/features/steps/project/project_issues.rb index 801fff78a5..4a503dfaf4 100644 --- a/features/steps/project/project_issues.rb +++ b/features/steps/project/project_issues.rb @@ -54,7 +54,7 @@ class ProjectIssues < Spinach::FeatureSteps end Then 'I should see issue "500 error on profile"' do - issue = Issue.find_by_title("500 error on profile") + issue = Issue.find_by(title: "500 error on profile") page.should have_content issue.title page.should have_content issue.author_name page.should have_content issue.project.name @@ -81,14 +81,14 @@ class ProjectIssues < Spinach::FeatureSteps end Given 'project "Shop" has milestone "v2.2"' do - project = Project.find_by_name("Shop") + project = Project.find_by(name: "Shop") milestone = create(:milestone, title: "v2.2", project: project) 3.times { create(:issue, project: project, milestone: milestone) } end And 'project "Shop" has milestone "v3.0"' do - project = Project.find_by_name("Shop") + project = Project.find_by(name: "Shop") milestone = create(:milestone, title: "v3.0", project: project) 3.times { create(:issue, project: project, milestone: milestone) } @@ -104,20 +104,20 @@ class ProjectIssues < Spinach::FeatureSteps end When 'I select first assignee from "Shop" project' do - project = Project.find_by_name "Shop" + project = Project.find_by(name: "Shop") first_assignee = project.users.first select first_assignee.name, from: "assignee_id" end Then 'I should see first assignee from "Shop" as selected assignee' do issues_assignee_selector = "#issue_assignee_id_chzn > a" - project = Project.find_by_name "Shop" + project = Project.find_by(name: "Shop") assignee_name = project.users.first.name page.find(issues_assignee_selector).should have_content(assignee_name) end And 'project "Shop" have "Release 0.4" open issue' do - project = Project.find_by_name("Shop") + project = Project.find_by(name: "Shop") create(:issue, title: "Release 0.4", project: project, @@ -125,7 +125,7 @@ class ProjectIssues < Spinach::FeatureSteps end And 'project "Shop" have "Tweet control" open issue' do - project = Project.find_by_name("Shop") + project = Project.find_by(name: "Shop") create(:issue, title: "Tweet control", project: project, @@ -133,7 +133,7 @@ class ProjectIssues < Spinach::FeatureSteps end And 'project "Shop" have "Release 0.3" closed issue' do - project = Project.find_by_name("Shop") + project = Project.find_by(name: "Shop") create(:closed_issue, title: "Release 0.3", project: project, diff --git a/features/steps/project/project_labels.rb b/features/steps/project/project_labels.rb index 915190f3da..0907cdb526 100644 --- a/features/steps/project/project_labels.rb +++ b/features/steps/project/project_labels.rb @@ -16,7 +16,7 @@ class ProjectLabels < Spinach::FeatureSteps end And 'project "Shop" have issues tags: "bug", "feature"' do - project = Project.find_by_name("Shop") + project = Project.find_by(name: "Shop") ['bug', 'feature'].each do |label| create(:issue, project: project, label_list: label) end diff --git a/features/steps/project/project_markdown_render.rb b/features/steps/project/project_markdown_render.rb index da044e46eb..3c5c3e09da 100644 --- a/features/steps/project/project_markdown_render.rb +++ b/features/steps/project/project_markdown_render.rb @@ -3,7 +3,7 @@ class Spinach::Features::ProjectMarkdownRender < Spinach::FeatureSteps include SharedPaths And 'I own project "Delta"' do - @project = Project.find_by_name "Delta" + @project = Project.find_by(name: "Delta") @project ||= create(:project_with_code, name: "Delta", namespace: @user.namespace) @project.team << [@user, :master] end diff --git a/features/steps/project/project_merge_requests.rb b/features/steps/project/project_merge_requests.rb index 8ef952cf3d..b771c8d139 100644 --- a/features/steps/project/project_merge_requests.rb +++ b/features/steps/project/project_merge_requests.rb @@ -27,7 +27,7 @@ class ProjectMergeRequests < Spinach::FeatureSteps end step 'I should see closed merge request "Bug NS-04"' do - merge_request = MergeRequest.find_by_title!("Bug NS-04") + merge_request = MergeRequest.find_by!(title: "Bug NS-04") merge_request.closed?.should be_true page.should have_content "Closed by" end @@ -180,11 +180,11 @@ class ProjectMergeRequests < Spinach::FeatureSteps end def project - @project ||= Project.find_by_name!("Shop") + @project ||= Project.find_by!(name: "Shop") end def merge_request - @merge_request ||= MergeRequest.find_by_title!("Bug NS-05") + @merge_request ||= MergeRequest.find_by!(title: "Bug NS-05") end def init_diff_note diff --git a/features/steps/project/project_milestones.rb b/features/steps/project/project_milestones.rb index c4d0d176f3..85962221c0 100644 --- a/features/steps/project/project_milestones.rb +++ b/features/steps/project/project_milestones.rb @@ -4,7 +4,7 @@ class ProjectMilestones < Spinach::FeatureSteps include SharedPaths Then 'I should see milestone "v2.2"' do - milestone = @project.milestones.find_by_title("v2.2") + milestone = @project.milestones.find_by(title: "v2.2") page.should have_content(milestone.title[0..10]) page.should have_content(milestone.expires_at) page.should have_content("Browse Issues") @@ -24,22 +24,22 @@ class ProjectMilestones < Spinach::FeatureSteps end Then 'I should see milestone "v2.3"' do - milestone = @project.milestones.find_by_title("v2.3") + milestone = @project.milestones.find_by(title: "v2.3") page.should have_content(milestone.title[0..10]) page.should have_content(milestone.expires_at) page.should have_content("Browse Issues") end And 'project "Shop" has milestone "v2.2"' do - project = Project.find_by_name("Shop") + project = Project.find_by(name: "Shop") milestone = create(:milestone, title: "v2.2", project: project) 3.times { create(:issue, project: project, milestone: milestone) } end Given 'the milestone has open and closed issues' do - project = Project.find_by_name("Shop") - milestone = project.milestones.find_by_title('v2.2') + project = Project.find_by(name: "Shop") + milestone = project.milestones.find_by(title: 'v2.2') # 3 Open issues created above; create one closed issue create(:closed_issue, project: project, milestone: milestone) diff --git a/features/steps/project/project_network_graph.rb b/features/steps/project/project_network_graph.rb index bc228e6e68..c7d9ece6fe 100644 --- a/features/steps/project/project_network_graph.rb +++ b/features/steps/project/project_network_graph.rb @@ -10,7 +10,7 @@ class ProjectNetworkGraph < Spinach::FeatureSteps # Stub Graph max_size to speed up test (10 commits vs. 650) Network::Graph.stub(max_count: 10) - project = Project.find_by_name("Shop") + project = Project.find_by(name: "Shop") visit project_network_path(project, "master") end diff --git a/features/steps/project/project_snippets.rb b/features/steps/project/project_snippets.rb index 82ff895970..c3a76bea26 100644 --- a/features/steps/project/project_snippets.rb +++ b/features/steps/project/project_snippets.rb @@ -90,10 +90,10 @@ class ProjectSnippets < Spinach::FeatureSteps end def project - @project ||= Project.find_by_name!("Shop") + @project ||= Project.find_by!(name: "Shop") end def project_snippet - @project_snippet ||= ProjectSnippet.find_by_title!("Snippet One") + @project_snippet ||= ProjectSnippet.find_by!(title: "Snippet one") end end diff --git a/features/steps/project/project_team_management.rb b/features/steps/project/project_team_management.rb index efebba1be2..cde06cadda 100644 --- a/features/steps/project/project_team_management.rb +++ b/features/steps/project/project_team_management.rb @@ -10,7 +10,7 @@ class ProjectTeamManagement < Spinach::FeatureSteps end And 'I should see "Sam" in team list' do - user = User.find_by_name("Sam") + user = User.find_by(name: "Sam") page.should have_content(user.name) page.should have_content(user.username) end @@ -20,7 +20,7 @@ class ProjectTeamManagement < Spinach::FeatureSteps end And 'I select "Mike" as "Reporter"' do - user = User.find_by_name("Mike") + user = User.find_by(name: "Mike") select2(user.id, from: "#user_ids", multiple: true) within "#new_team_member" do @@ -42,7 +42,7 @@ class ProjectTeamManagement < Spinach::FeatureSteps end And 'I change "Sam" role to "Reporter"' do - user = User.find_by_name("Sam") + user = User.find_by(name: "Sam") within "#user_#{user.id}" do select "Reporter", from: "team_member_project_access" end @@ -59,7 +59,7 @@ class ProjectTeamManagement < Spinach::FeatureSteps end And 'I should not see "Sam" in team list' do - user = User.find_by_name("Sam") + user = User.find_by(name: "Sam") page.should_not have_content(user.name) page.should_not have_content(user.username) end @@ -73,8 +73,8 @@ class ProjectTeamManagement < Spinach::FeatureSteps end And '"Sam" is "Shop" developer' do - user = User.find_by_name("Sam") - project = Project.find_by_name("Shop") + user = User.find_by(name: "Sam") + project = Project.find_by(name: "Shop") project.team << [user, :developer] end @@ -84,8 +84,8 @@ class ProjectTeamManagement < Spinach::FeatureSteps end And '"Mike" is "Website" reporter' do - user = User.find_by_name("Mike") - project = Project.find_by_name("Website") + user = User.find_by(name: "Mike") + project = Project.find_by(name: "Website") project.team << [user, :reporter] end @@ -94,13 +94,13 @@ class ProjectTeamManagement < Spinach::FeatureSteps end When 'I submit "Website" project for import team' do - project = Project.find_by_name("Website") + project = Project.find_by(name: "Website") select project.name_with_namespace, from: 'source_project_id' click_button 'Import' end step 'I click cancel link for "Sam"' do - within "#user_#{User.find_by_name('Sam').id}" do + within "#user_#{User.find_by(name: 'Sam').id}" do click_link('Remove user from team') end end diff --git a/features/steps/project/redirects.rb b/features/steps/project/redirects.rb index 4ac5307570..896f7180f9 100644 --- a/features/steps/project/redirects.rb +++ b/features/steps/project/redirects.rb @@ -12,7 +12,7 @@ class Spinach::Features::ProjectRedirects < Spinach::FeatureSteps end step 'I visit project "Community" page' do - project = Project.find_by_name('Community') + project = Project.find_by(name: 'Community') visit project_path(project) end @@ -23,12 +23,12 @@ class Spinach::Features::ProjectRedirects < Spinach::FeatureSteps end step 'I visit project "Enterprise" page' do - project = Project.find_by_name('Enterprise') + project = Project.find_by(name: 'Enterprise') visit project_path(project) end step 'I visit project "CommunityDoesNotExist" page' do - project = Project.find_by_name('Community') + project = Project.find_by(name: 'Community') visit project_path(project) + 'DoesNotExist' end end diff --git a/features/steps/public/projects_feature.rb b/features/steps/public/projects_feature.rb index 47e52f47d0..49db9b316b 100644 --- a/features/steps/public/projects_feature.rb +++ b/features/steps/public/projects_feature.rb @@ -33,12 +33,12 @@ class Spinach::Features::PublicProjectsFeature < Spinach::FeatureSteps end step 'I visit empty project page' do - project = Project.find_by_name('Empty Public Project') + project = Project.find_by(name: 'Empty Public Project') visit project_path(project) end step 'I visit project "Community" page' do - project = Project.find_by_name('Community') + project = Project.find_by(name: 'Community') visit project_path(project) end @@ -47,14 +47,14 @@ class Spinach::Features::PublicProjectsFeature < Spinach::FeatureSteps end step 'I should see empty public project details with http clone info' do - project = Project.find_by_name('Empty Public Project') + project = Project.find_by(name: 'Empty Public Project') page.all(:css, '.git-empty .clone').each do |element| element.text.should include(project.http_url_to_repo) end end step 'I should see empty public project details with ssh clone info' do - project = Project.find_by_name('Empty Public Project') + project = Project.find_by(name: 'Empty Public Project') page.all(:css, '.git-empty .clone').each do |element| element.text.should include(project.url_to_repo) end @@ -65,7 +65,7 @@ class Spinach::Features::PublicProjectsFeature < Spinach::FeatureSteps end step 'I visit project "Enterprise" page' do - project = Project.find_by_name('Enterprise') + project = Project.find_by(name: 'Enterprise') visit project_path(project) end @@ -88,7 +88,7 @@ class Spinach::Features::PublicProjectsFeature < Spinach::FeatureSteps end step 'I visit project "Internal" page' do - project = Project.find_by_name('Internal') + project = Project.find_by(name: 'Internal') visit project_path(project) end @@ -99,12 +99,12 @@ class Spinach::Features::PublicProjectsFeature < Spinach::FeatureSteps end step 'I should see an http link to the repository' do - project = Project.find_by_name 'Community' + project = Project.find_by(name: 'Community') page.should have_field('project_clone', with: project.http_url_to_repo) end step 'I should see an ssh link to the repository' do - project = Project.find_by_name 'Community' + project = Project.find_by(name: 'Community') page.should have_field('project_clone', with: project.url_to_repo) end end diff --git a/features/steps/shared/paths.rb b/features/steps/shared/paths.rb index 987cd3120c..d287121bb8 100644 --- a/features/steps/shared/paths.rb +++ b/features/steps/shared/paths.rb @@ -241,7 +241,7 @@ module SharedPaths end step 'I visit issue page "Release 0.4"' do - issue = Issue.find_by_title("Release 0.4") + issue = Issue.find_by(title: "Release 0.4") visit project_issue_path(issue.project, issue) end @@ -250,12 +250,12 @@ module SharedPaths end step 'I visit merge request page "Bug NS-04"' do - mr = MergeRequest.find_by_title("Bug NS-04") + mr = MergeRequest.find_by(title: "Bug NS-04") visit project_merge_request_path(mr.target_project, mr) end step 'I visit merge request page "Bug NS-05"' do - mr = MergeRequest.find_by_title("Bug NS-05") + mr = MergeRequest.find_by(title: "Bug NS-05") visit project_merge_request_path(mr.target_project, mr) end @@ -292,7 +292,7 @@ module SharedPaths end step 'I visit public page for "Community" project' do - visit public_project_path(Project.find_by_name("Community")) + visit public_project_path(Project.find_by(name: "Community")) end # ---------------------------------------- @@ -316,6 +316,6 @@ module SharedPaths end def project - project = Project.find_by_name!("Shop") + project = Project.find_by!(name: "Shop") end end diff --git a/features/steps/shared/project.rb b/features/steps/shared/project.rb index 3dc4932a09..00c289c232 100644 --- a/features/steps/shared/project.rb +++ b/features/steps/shared/project.rb @@ -9,20 +9,20 @@ module SharedProject # Create a specific project called "Shop" And 'I own project "Shop"' do - @project = Project.find_by_name "Shop" + @project = Project.find_by(name: "Shop") @project ||= create(:project_with_code, name: "Shop", namespace: @user.namespace) @project.team << [@user, :master] end # Create another specific project called "Forum" And 'I own project "Forum"' do - @project = Project.find_by_name "Forum" + @project = Project.find_by(name: "Forum") @project ||= create(:project_with_code, name: "Forum", namespace: @user.namespace, path: 'forum_project') @project.team << [@user, :master] end And 'project "Shop" has push event' do - @project = Project.find_by_name("Shop") + @project = Project.find_by(name: "Shop") data = { before: "0000000000000000000000000000000000000000", @@ -48,7 +48,7 @@ module SharedProject end Then 'I should see project "Shop" activity feed' do - project = Project.find_by_name("Shop") + project = Project.find_by(name: "Shop") page.should have_content "#{@user.name} pushed new branch new_design at #{project.name_with_namespace}" end diff --git a/features/steps/snippets/discover_snippets.rb b/features/steps/snippets/discover_snippets.rb index 3afe019adf..0933793700 100644 --- a/features/steps/snippets/discover_snippets.rb +++ b/features/steps/snippets/discover_snippets.rb @@ -12,6 +12,6 @@ class DiscoverSnippets < Spinach::FeatureSteps end def snippet - @snippet ||= PersonalSnippet.find_by_title!("Personal snippet one") + @snippet ||= PersonalSnippet.find_by!(title: "Personal snippet one") end end diff --git a/features/steps/snippets/snippets.rb b/features/steps/snippets/snippets.rb index 1aea01f6cd..fed54659eb 100644 --- a/features/steps/snippets/snippets.rb +++ b/features/steps/snippets/snippets.rb @@ -59,6 +59,6 @@ class SnippetsFeature < Spinach::FeatureSteps end def snippet - @snippet ||= PersonalSnippet.find_by_title!("Personal snippet one") + @snippet ||= PersonalSnippet.find_by!(title: "Personal snippet one") end end diff --git a/features/steps/snippets/user_snippets.rb b/features/steps/snippets/user_snippets.rb index 15d6da6db3..2d7ffc866e 100644 --- a/features/steps/snippets/user_snippets.rb +++ b/features/steps/snippets/user_snippets.rb @@ -36,6 +36,6 @@ class UserSnippets < Spinach::FeatureSteps end def snippet - @snippet ||= PersonalSnippet.find_by_title!("Personal snippet one") + @snippet ||= PersonalSnippet.find_by!(title: "Personal snippet one") end end diff --git a/lib/api/deploy_keys.rb b/lib/api/deploy_keys.rb index b599760899..7f5a125038 100644 --- a/lib/api/deploy_keys.rb +++ b/lib/api/deploy_keys.rb @@ -38,14 +38,14 @@ module API attrs[:key].strip! # check if key already exist in project - key = user_project.deploy_keys.find_by_key(attrs[:key]) + key = user_project.deploy_keys.find_by(key: attrs[:key]) if key present key, with: Entities::SSHKey return end # Check for available deploy keys in other projects - key = current_user.accessible_deploy_keys.find_by_key(attrs[:key]) + key = current_user.accessible_deploy_keys.find_by(key: attrs[:key]) if key user_project.deploy_keys << key present key, with: Entities::SSHKey diff --git a/lib/api/entities.rb b/lib/api/entities.rb index 8d2f38c4da..16df3446f4 100644 --- a/lib/api/entities.rb +++ b/lib/api/entities.rb @@ -48,19 +48,19 @@ module API class ProjectMember < UserBasic expose :project_access, as: :access_level do |user, options| - options[:project].users_projects.find_by_user_id(user.id).project_access + options[:project].users_projects.find_by(user_id: user.id).project_access end end class TeamMember < UserBasic expose :permission, as: :access_level do |user, options| - options[:user_team].user_team_user_relationships.find_by_user_id(user.id).permission + options[:user_team].user_team_user_relationships.find_by(user_id: user.id).permission end end class TeamProject < Project expose :greatest_access, as: :greatest_access_level do |project, options| - options[:user_team].user_team_project_relationships.find_by_project_id(project.id).greatest_access + options[:user_team].user_team_project_relationships.find_by(project_id: project.id).greatest_access end end @@ -74,7 +74,7 @@ module API class GroupMember < UserBasic expose :group_access, as: :access_level do |user, options| - options[:group].users_groups.find_by_user_id(user.id).group_access + options[:group].users_groups.find_by(user_id: user.id).group_access end end diff --git a/lib/api/groups.rb b/lib/api/groups.rb index 290b78d801..03f027706d 100644 --- a/lib/api/groups.rb +++ b/lib/api/groups.rb @@ -121,11 +121,11 @@ module API render_api_error!("Wrong access level", 422) end group = find_group(params[:id]) - if group.users_groups.find_by_user_id(params[:user_id]) + if group.users_groups.find_by(user_id: params[:user_id]) render_api_error!("Already exists", 409) end group.add_users([params[:user_id]], params[:access_level]) - member = group.users_groups.find_by_user_id(params[:user_id]) + member = group.users_groups.find_by(user_id: params[:user_id]) present member.user, with: Entities::GroupMember, group: group end @@ -139,7 +139,7 @@ module API # DELETE /groups/:id/members/:user_id delete ":id/members/:user_id" do group = find_group(params[:id]) - member = group.users_groups.find_by_user_id(params[:user_id]) + member = group.users_groups.find_by(user_id: params[:user_id]) if member.nil? render_api_error!("404 Not Found - user_id:#{params[:user_id]} not a member of group #{group.name}",404) else diff --git a/lib/api/helpers.rb b/lib/api/helpers.rb index b0f8d5a6da..f8c48e2f3b 100644 --- a/lib/api/helpers.rb +++ b/lib/api/helpers.rb @@ -7,7 +7,7 @@ module API def current_user private_token = (params[PRIVATE_TOKEN_PARAM] || env[PRIVATE_TOKEN_HEADER]).to_s - @current_user ||= User.find_by_authentication_token(private_token) + @current_user ||= User.find_by(authentication_token: private_token) identifier = sudo_identifier() # If the sudo is the current user do nothing @@ -47,7 +47,7 @@ module API end def find_project(id) - project = Project.find_by_id(id) || Project.find_with_namespace(id) + project = Project.find_by(id: id) || Project.find_with_namespace(id) if project && can?(current_user, :read_project, project) project diff --git a/lib/api/merge_requests.rb b/lib/api/merge_requests.rb index 3f4bec895b..cbaf22f265 100644 --- a/lib/api/merge_requests.rb +++ b/lib/api/merge_requests.rb @@ -81,7 +81,7 @@ module API merge_request.target_project = user_project else if target_matches_fork(target_project_id,user_project) - merge_request.target_project = Project.find_by_id(attrs[:target_project_id]) + merge_request.target_project = Project.find_by(id: attrs[:target_project_id]) else render_api_error!('(Bad Request) Specified target project that is not the source project, or the source fork of the project.', 400) end diff --git a/lib/api/projects.rb b/lib/api/projects.rb index a4c8f7fc87..888aa7e77d 100644 --- a/lib/api/projects.rb +++ b/lib/api/projects.rb @@ -266,7 +266,7 @@ module API authorize! :admin_project, user_project required_attributes! [:access_level] - team_member = user_project.users_projects.find_by_user_id(params[:user_id]) + team_member = user_project.users_projects.find_by(user_id: params[:user_id]) not_found!("User can not be found") if team_member.nil? if team_member.update_attributes(project_access: params[:access_level]) @@ -286,7 +286,7 @@ module API # DELETE /projects/:id/members/:user_id delete ":id/members/:user_id" do authorize! :admin_project, user_project - team_member = user_project.users_projects.find_by_user_id(params[:user_id]) + team_member = user_project.users_projects.find_by(user_id: params[:user_id]) unless team_member.nil? team_member.destroy else diff --git a/lib/api/repositories.rb b/lib/api/repositories.rb index af958f06c6..878929b803 100644 --- a/lib/api/repositories.rb +++ b/lib/api/repositories.rb @@ -51,7 +51,7 @@ module API @branch = user_project.repository.find_branch(params[:branch]) not_found! unless @branch - protected_branch = user_project.protected_branches.find_by_name(@branch.name) + protected_branch = user_project.protected_branches.find_by(name: @branch.name) user_project.protected_branches.create(name: @branch.name) unless protected_branch present @branch, with: Entities::RepoObject, project: user_project @@ -69,7 +69,7 @@ module API @branch = user_project.repository.find_branch(params[:branch]) not_found! unless @branch - protected_branch = user_project.protected_branches.find_by_name(@branch.name) + protected_branch = user_project.protected_branches.find_by(name: @branch.name) protected_branch.destroy if protected_branch present @branch, with: Entities::RepoObject, project: user_project diff --git a/lib/api/users.rb b/lib/api/users.rb index 475343a3ed..82290fe03b 100644 --- a/lib/api/users.rb +++ b/lib/api/users.rb @@ -117,7 +117,7 @@ module API # DELETE /users/:id delete ":id" do authenticated_as_admin! - user = User.find_by_id(params[:id]) + user = User.find_by(id: params[:id]) if user user.destroy diff --git a/lib/gitlab/auth.rb b/lib/gitlab/auth.rb index 0f19629747..955abc1bed 100644 --- a/lib/gitlab/auth.rb +++ b/lib/gitlab/auth.rb @@ -1,7 +1,7 @@ module Gitlab class Auth def find(login, password) - user = User.find_by_email(login) || User.find_by_username(login) + user = User.find_by(email: login) || User.find_by(username: login) if user.nil? || user.ldap_user? # Second chance - try LDAP authentication diff --git a/lib/gitlab/identifier.rb b/lib/gitlab/identifier.rb index a1ff248a77..6e4de197ee 100644 --- a/lib/gitlab/identifier.rb +++ b/lib/gitlab/identifier.rb @@ -6,17 +6,17 @@ module Gitlab if identifier.blank? # Local push from gitlab email = project.repository.commit(newrev).author_email rescue nil - User.find_by_email(email) if email + User.find_by(email: email) if email elsif identifier =~ /\Auser-\d+\Z/ # git push over http user_id = identifier.gsub("user-", "") - User.find_by_id(user_id) + User.find_by(id: user_id) elsif identifier =~ /\Akey-\d+\Z/ # git push over ssh key_id = identifier.gsub("key-", "") - Key.find_by_id(key_id).try(:user) + Key.find_by(id: key_id).try(:user) end end end diff --git a/lib/gitlab/ldap/user.rb b/lib/gitlab/ldap/user.rb index 59f0fa64a6..fd36dda7d2 100644 --- a/lib/gitlab/ldap/user.rb +++ b/lib/gitlab/ldap/user.rb @@ -44,13 +44,13 @@ module Gitlab end def find_user(email) - user = model.find_by_email(email) + user = model.find_by(email: email) # If no user found and allow_username_or_email_login is true # we look for user by extracting part of their email if !user && email && ldap_conf['allow_username_or_email_login'] uname = email.partition('@').first - user = model.find_by_username(uname) + user = model.find_by(username: uname) end user diff --git a/lib/tasks/gitlab/bulk_add_permission.rake b/lib/tasks/gitlab/bulk_add_permission.rake index c270232edb..612a9ba93a 100644 --- a/lib/tasks/gitlab/bulk_add_permission.rake +++ b/lib/tasks/gitlab/bulk_add_permission.rake @@ -15,7 +15,7 @@ namespace :gitlab do desc "GITLAB | Add a specific user to all projects (as a developer)" task :user_to_projects, [:email] => :environment do |t, args| - user = User.find_by_email args.email + user = User.find_by(email: args.email) project_ids = Project.pluck(:id) puts "Importing #{user.email} users into #{project_ids.size} projects" UsersProject.add_users_into_projects(project_ids, Array.wrap(user.id), UsersProject::DEVELOPER) diff --git a/lib/tasks/gitlab/enable_namespaces.rake b/lib/tasks/gitlab/enable_namespaces.rake index 927748c0fd..201f34ab54 100644 --- a/lib/tasks/gitlab/enable_namespaces.rake +++ b/lib/tasks/gitlab/enable_namespaces.rake @@ -43,13 +43,13 @@ namespace :gitlab do username.gsub!("+", ".") # return username if no matches - return username unless User.find_by_username(username) + return username unless User.find_by(username: username) # look for same username (1..10).each do |i| suffixed_username = "#{username}#{i}" - return suffixed_username unless User.find_by_username(suffixed_username) + return suffixed_username unless User.find_by(username: suffixed_username) end end diff --git a/lib/tasks/gitlab/import.rake b/lib/tasks/gitlab/import.rake index 83e941adcb..b7df6b13df 100644 --- a/lib/tasks/gitlab/import.rake +++ b/lib/tasks/gitlab/import.rake @@ -50,7 +50,7 @@ namespace :gitlab do # find group namespace if group_name - group = Group.find_by_path(group_name) + group = Group.find_by(path: group_name) # create group namespace if !group group = Group.new(:name => group_name) diff --git a/spec/lib/gitlab/ldap/ldap_user_auth_spec.rb b/spec/lib/gitlab/ldap/ldap_user_auth_spec.rb index b7d7bbaad2..a0e74c4963 100644 --- a/spec/lib/gitlab/ldap/ldap_user_auth_spec.rb +++ b/spec/lib/gitlab/ldap/ldap_user_auth_spec.rb @@ -25,7 +25,7 @@ describe Gitlab::LDAP do it "should update credentials by email if missing uid" do user = double('User') User.stub find_by_extern_uid_and_provider: nil - User.stub find_by_email: user + User.stub(:find_by).with(hash_including(email: anything())) { user } user.should_receive :update_attributes gl_auth.find_or_create(@auth) end @@ -35,8 +35,8 @@ describe Gitlab::LDAP do value = Gitlab.config.ldap.allow_username_or_email_login Gitlab.config.ldap['allow_username_or_email_login'] = true User.stub find_by_extern_uid_and_provider: nil - User.stub find_by_email: nil - User.stub find_by_username: user + User.stub(:find_by).with(hash_including(email: anything())) { nil } + User.stub(:find_by).with(hash_including(username: anything())) { user } user.should_receive :update_attributes gl_auth.find_or_create(@auth) Gitlab.config.ldap['allow_username_or_email_login'] = value @@ -47,8 +47,8 @@ describe Gitlab::LDAP do value = Gitlab.config.ldap.allow_username_or_email_login Gitlab.config.ldap['allow_username_or_email_login'] = false User.stub find_by_extern_uid_and_provider: nil - User.stub find_by_email: nil - User.stub find_by_username: user + User.stub(:find_by).with(hash_including(email: anything())) { nil } + User.stub(:find_by).with(hash_including(username: anything())) { user } user.should_not_receive :update_attributes gl_auth.find_or_create(@auth) Gitlab.config.ldap['allow_username_or_email_login'] = value diff --git a/spec/requests/api/users_spec.rb b/spec/requests/api/users_spec.rb index 4ef78b8e5d..c4be510200 100644 --- a/spec/requests/api/users_spec.rb +++ b/spec/requests/api/users_spec.rb @@ -93,7 +93,7 @@ describe API::API do expect { post api("/users", admin), attr }.to change { User.count }.by(1) - user = User.find_by_username(attr[:username]) + user = User.find_by(username: attr[:username]) user.projects_limit.should == limit user.theme_id.should == Gitlab::Theme::MARS Gitlab.config.gitlab.unstub(:default_projects_limit) diff --git a/spec/workers/post_receive_spec.rb b/spec/workers/post_receive_spec.rb index 46e86dbe00..0850734f13 100644 --- a/spec/workers/post_receive_spec.rb +++ b/spec/workers/post_receive_spec.rb @@ -19,7 +19,7 @@ describe PostReceive do end it "does not run if the author is not in the project" do - Key.stub(find_by_id: nil) + Key.stub(:find_by).with(hash_including(id: anything())) { nil } project.should_not_receive(:execute_hooks) From c983e8eb3d9cac01090b8657735544f71f891576 Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Wed, 22 Jan 2014 14:22:47 +0200 Subject: [PATCH 02/39] Create separate table to store Merge request commits/diffs Signed-off-by: Dmitriy Zaporozhets --- ...140122112253_create_merge_request_diffs.rb | 12 +++ db/migrate/20140122114406_migrate_mr_diffs.rb | 11 +++ db/schema.rb | 83 ++++++++++--------- 3 files changed, 67 insertions(+), 39 deletions(-) create mode 100644 db/migrate/20140122112253_create_merge_request_diffs.rb create mode 100644 db/migrate/20140122114406_migrate_mr_diffs.rb diff --git a/db/migrate/20140122112253_create_merge_request_diffs.rb b/db/migrate/20140122112253_create_merge_request_diffs.rb new file mode 100644 index 0000000000..f016ef0f06 --- /dev/null +++ b/db/migrate/20140122112253_create_merge_request_diffs.rb @@ -0,0 +1,12 @@ +class CreateMergeRequestDiffs < ActiveRecord::Migration + def change + create_table :merge_request_diffs do |t| + t.string :state, null: false, default: 'valid' + t.text :st_commits, null: true, limit: 2147483647 + t.text :st_diffs, null: true, limit: 2147483647 + t.integer :merge_request_id, null: false + + t.timestamps + end + end +end diff --git a/db/migrate/20140122114406_migrate_mr_diffs.rb b/db/migrate/20140122114406_migrate_mr_diffs.rb new file mode 100644 index 0000000000..2cc5faaa85 --- /dev/null +++ b/db/migrate/20140122114406_migrate_mr_diffs.rb @@ -0,0 +1,11 @@ +class MigrateMrDiffs < ActiveRecord::Migration + def self.up + execute "INSERT INTO merge_request_diffs ( merge_request_id ) SELECT id FROM merge_requests" + execute "UPDATE merge_requests mr, merge_request_diffs md SET md.st_commits = mr.st_commits WHERE md.merge_request_id = mr.id" + execute "UPDATE merge_requests mr, merge_request_diffs md SET md.st_diffs = mr.st_diffs WHERE md.merge_request_id = mr.id" + end + + def self.down + MergeRequestDiff.delete_all + end +end diff --git a/db/schema.rb b/db/schema.rb index 73d0a92e1c..50170bf4a2 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: 20140116231608) do +ActiveRecord::Schema.define(version: 20140122114406) do create_table "broadcast_messages", force: true do |t| t.text "message", null: false @@ -66,8 +66,8 @@ ActiveRecord::Schema.define(version: 20140116231608) do t.integer "assignee_id" t.integer "author_id" t.integer "project_id" - t.datetime "created_at", null: false - t.datetime "updated_at", null: false + t.datetime "created_at" + t.datetime "updated_at" t.integer "position", default: 0 t.string "branch_name" t.text "description" @@ -85,8 +85,8 @@ ActiveRecord::Schema.define(version: 20140116231608) do create_table "keys", force: true do |t| t.integer "user_id" - t.datetime "created_at", null: false - t.datetime "updated_at", null: false + t.datetime "created_at" + t.datetime "updated_at" t.text "key" t.string "title" t.string "type" @@ -95,6 +95,15 @@ ActiveRecord::Schema.define(version: 20140116231608) do add_index "keys", ["user_id"], name: "index_keys_on_user_id", using: :btree + create_table "merge_request_diffs", force: true do |t| + t.string "state", default: "valid", null: false + t.text "st_commits", limit: 2147483647 + t.text "st_diffs", limit: 2147483647 + t.integer "merge_request_id", null: false + t.datetime "created_at" + t.datetime "updated_at" + end + create_table "merge_requests", force: true do |t| t.string "target_branch", null: false t.string "source_branch", null: false @@ -102,8 +111,8 @@ ActiveRecord::Schema.define(version: 20140116231608) do t.integer "author_id" t.integer "assignee_id" t.string "title" - t.datetime "created_at", null: false - t.datetime "updated_at", null: false + t.datetime "created_at" + t.datetime "updated_at" t.text "st_commits", limit: 2147483647 t.text "st_diffs", limit: 2147483647 t.integer "milestone_id" @@ -156,8 +165,8 @@ ActiveRecord::Schema.define(version: 20140116231608) do t.text "note" t.string "noteable_type" t.integer "author_id" - t.datetime "created_at", null: false - t.datetime "updated_at", null: false + t.datetime "created_at" + t.datetime "updated_at" t.integer "project_id" t.string "attachment" t.string "line_code" @@ -179,8 +188,8 @@ ActiveRecord::Schema.define(version: 20140116231608) do t.string "name" t.string "path" t.text "description" - t.datetime "created_at", null: false - t.datetime "updated_at", null: false + t.datetime "created_at" + t.datetime "updated_at" t.integer "creator_id" t.boolean "issues_enabled", default: true, null: false t.boolean "wall_enabled", default: true, null: false @@ -231,8 +240,8 @@ ActiveRecord::Schema.define(version: 20140116231608) do t.text "content", limit: 2147483647 t.integer "author_id", null: false t.integer "project_id" - t.datetime "created_at", null: false - t.datetime "updated_at", null: false + t.datetime "created_at" + t.datetime "updated_at" t.string "file_name" t.datetime "expires_at" t.boolean "private", default: true, null: false @@ -254,45 +263,42 @@ ActiveRecord::Schema.define(version: 20140116231608) do t.datetime "created_at" end - add_index "taggings", ["tag_id"], name: "index_taggings_on_tag_id", using: :btree - add_index "taggings", ["taggable_id", "taggable_type", "context"], name: "index_taggings_on_taggable_id_and_taggable_type_and_context", using: :btree - create_table "tags", force: true do |t| t.string "name" end create_table "users", force: true do |t| - t.string "email", default: "", null: false - t.string "encrypted_password", default: "", null: false + t.string "email", default: "", null: false + t.string "encrypted_password", limit: 128, default: "", null: false t.string "reset_password_token" t.datetime "reset_password_sent_at" t.datetime "remember_created_at" - t.integer "sign_in_count", default: 0 + t.integer "sign_in_count", default: 0 t.datetime "current_sign_in_at" t.datetime "last_sign_in_at" t.string "current_sign_in_ip" t.string "last_sign_in_ip" - t.datetime "created_at", null: false - t.datetime "updated_at", null: false + t.datetime "created_at" + t.datetime "updated_at" t.string "name" - t.boolean "admin", default: false, null: false - t.integer "projects_limit", default: 10 - t.string "skype", default: "", null: false - t.string "linkedin", default: "", null: false - t.string "twitter", default: "", null: false + t.boolean "admin", default: false, null: false + t.integer "projects_limit", default: 10 + t.string "skype", default: "", null: false + t.string "linkedin", default: "", null: false + t.string "twitter", default: "", null: false t.string "authentication_token" - t.integer "theme_id", default: 1, null: false + t.integer "theme_id", default: 1, null: false t.string "bio" - t.integer "failed_attempts", default: 0 + t.integer "failed_attempts", default: 0 t.datetime "locked_at" t.string "extern_uid" t.string "provider" t.string "username" - t.boolean "can_create_group", default: true, null: false - t.boolean "can_create_team", default: true, null: false + t.boolean "can_create_group", default: true, null: false + t.boolean "can_create_team", default: true, null: false t.string "state" - t.integer "color_scheme_id", default: 1, null: false - t.integer "notification_level", default: 1, null: false + t.integer "color_scheme_id", default: 1, null: false + t.integer "notification_level", default: 1, null: false t.datetime "password_expires_at" t.integer "created_by_id" t.string "avatar" @@ -300,15 +306,14 @@ ActiveRecord::Schema.define(version: 20140116231608) do t.datetime "confirmed_at" t.datetime "confirmation_sent_at" t.string "unconfirmed_email" - t.boolean "hide_no_ssh_key", default: false - t.string "website_url", default: "", null: false + t.boolean "hide_no_ssh_key", default: false + t.string "website_url", default: "", null: false end add_index "users", ["admin"], name: "index_users_on_admin", using: :btree add_index "users", ["authentication_token"], name: "index_users_on_authentication_token", unique: true, using: :btree add_index "users", ["confirmation_token"], name: "index_users_on_confirmation_token", unique: true, using: :btree add_index "users", ["email"], name: "index_users_on_email", unique: true, using: :btree - add_index "users", ["extern_uid", "provider"], name: "index_users_on_extern_uid_and_provider", unique: true, using: :btree add_index "users", ["name"], name: "index_users_on_name", using: :btree add_index "users", ["reset_password_token"], name: "index_users_on_reset_password_token", unique: true, using: :btree add_index "users", ["username"], name: "index_users_on_username", using: :btree @@ -327,8 +332,8 @@ ActiveRecord::Schema.define(version: 20140116231608) do create_table "users_projects", force: true do |t| t.integer "user_id", null: false t.integer "project_id", null: false - t.datetime "created_at", null: false - t.datetime "updated_at", null: false + t.datetime "created_at" + t.datetime "updated_at" t.integer "project_access", default: 0, null: false t.integer "notification_level", default: 3, null: false end @@ -340,8 +345,8 @@ ActiveRecord::Schema.define(version: 20140116231608) do create_table "web_hooks", force: true do |t| t.string "url" t.integer "project_id" - t.datetime "created_at", null: false - t.datetime "updated_at", null: false + t.datetime "created_at" + t.datetime "updated_at" t.string "type", default: "ProjectHook" t.integer "service_id" t.boolean "push_events", default: true, null: false From de724a7a34a501234000a539e9ba6ce16857ad5d Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Wed, 22 Jan 2014 15:17:41 +0200 Subject: [PATCH 03/39] Improve db schema for merge request diffs Signed-off-by: Dmitriy Zaporozhets --- .../20140122112253_create_merge_request_diffs.rb | 2 +- .../20140122122549_remove_m_rdiff_fields.rb | 13 +++++++++++++ db/schema.rb | 16 +++++++--------- 3 files changed, 21 insertions(+), 10 deletions(-) create mode 100644 db/migrate/20140122122549_remove_m_rdiff_fields.rb diff --git a/db/migrate/20140122112253_create_merge_request_diffs.rb b/db/migrate/20140122112253_create_merge_request_diffs.rb index f016ef0f06..ef592305a2 100644 --- a/db/migrate/20140122112253_create_merge_request_diffs.rb +++ b/db/migrate/20140122112253_create_merge_request_diffs.rb @@ -1,7 +1,7 @@ class CreateMergeRequestDiffs < ActiveRecord::Migration def change create_table :merge_request_diffs do |t| - t.string :state, null: false, default: 'valid' + t.string :state, null: false, default: 'collected' t.text :st_commits, null: true, limit: 2147483647 t.text :st_diffs, null: true, limit: 2147483647 t.integer :merge_request_id, null: false diff --git a/db/migrate/20140122122549_remove_m_rdiff_fields.rb b/db/migrate/20140122122549_remove_m_rdiff_fields.rb new file mode 100644 index 0000000000..c27e649e9a --- /dev/null +++ b/db/migrate/20140122122549_remove_m_rdiff_fields.rb @@ -0,0 +1,13 @@ +class RemoveMRdiffFields < ActiveRecord::Migration + def up + remove_column :merge_requests, :st_commits + remove_column :merge_requests, :st_diffs + end + + def down + add_column :merge_requests, :st_commits, :text, null: true, limit: 2147483647 + add_column :merge_requests, :st_diffs, :text, null: true, limit: 2147483647 + execute "UPDATE merge_requests mr, merge_request_diffs md SET mr.st_commits = md.st_commits WHERE md.merge_request_id = mr.id" + execute "UPDATE merge_requests mr, merge_request_diffs md SET mr.st_diffs = md.st_diffs WHERE md.merge_request_id = mr.id" + end +end diff --git a/db/schema.rb b/db/schema.rb index 50170bf4a2..75a44d9aa0 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: 20140122114406) do +ActiveRecord::Schema.define(version: 20140122122549) do create_table "broadcast_messages", force: true do |t| t.text "message", null: false @@ -96,29 +96,27 @@ ActiveRecord::Schema.define(version: 20140122114406) do add_index "keys", ["user_id"], name: "index_keys_on_user_id", using: :btree create_table "merge_request_diffs", force: true do |t| - t.string "state", default: "valid", null: false + t.string "state", default: "collected", null: false t.text "st_commits", limit: 2147483647 t.text "st_diffs", limit: 2147483647 - t.integer "merge_request_id", null: false + t.integer "merge_request_id", null: false t.datetime "created_at" t.datetime "updated_at" end create_table "merge_requests", force: true do |t| - t.string "target_branch", null: false - t.string "source_branch", null: false - t.integer "source_project_id", null: false + t.string "target_branch", null: false + t.string "source_branch", null: false + t.integer "source_project_id", null: false t.integer "author_id" t.integer "assignee_id" t.string "title" t.datetime "created_at" t.datetime "updated_at" - t.text "st_commits", limit: 2147483647 - t.text "st_diffs", limit: 2147483647 t.integer "milestone_id" t.string "state" t.string "merge_status" - t.integer "target_project_id", null: false + t.integer "target_project_id", null: false t.integer "iid" t.text "description" end From d9be420ee603fef634107c576b41715de18b5385 Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Wed, 22 Jan 2014 15:19:02 +0200 Subject: [PATCH 04/39] MergeRequestDiff model responsoible for storing commits/diff info Signed-off-by: Dmitriy Zaporozhets --- app/models/merge_request_diff.rb | 160 +++++++++++++++++++++++++++++++ 1 file changed, 160 insertions(+) create mode 100644 app/models/merge_request_diff.rb diff --git a/app/models/merge_request_diff.rb b/app/models/merge_request_diff.rb new file mode 100644 index 0000000000..d06b95daa6 --- /dev/null +++ b/app/models/merge_request_diff.rb @@ -0,0 +1,160 @@ +require Rails.root.join("app/models/commit") + +class MergeRequestDiff < ActiveRecord::Base + # Prevent store of diff + # if commits amount more then 200 + COMMITS_SAFE_SIZE = 200 + + attr_reader :commits, :diffs + + belongs_to :merge_request + + attr_accessible :state, :st_commits, :st_diffs + + delegate :target_branch, :source_branch, to: :merge_request, prefix: nil + + state_machine :state, initial: :empty do + state :collected + state :timeout + state :overflow_commits_safe_size + state :overflow_diff_files_limit + state :overflow_diff_lines_limit + end + + serialize :st_commits + serialize :st_diffs + + after_create :reload_content + + def reload_content + reload_commits + reload_diffs + end + + def diffs + @diffs ||= (load_diffs(st_diffs) || []) + end + + def commits + @commits ||= load_commits(st_commits || []) + end + + def last_commit + commits.first + end + + def last_commit_short_sha + @last_commit_short_sha ||= last_commit.sha[0..10] + end + + private + + def dump_commits(commits) + commits.map(&:to_hash) + end + + def load_commits(array) + array.map { |hash| Commit.new(Gitlab::Git::Commit.new(hash)) } + end + + def dump_diffs(diffs) + if diffs.respond_to?(:map) + diffs.map(&:to_hash) + end + end + + def load_diffs(raw) + if raw.respond_to?(:map) + raw.map { |hash| Gitlab::Git::Diff.new(hash) } + end + end + + # When Git::Diff is not able to get diff + # because of git timeout it return this value + def broken_diffs + [Gitlab::Git::Diff::BROKEN_DIFF] + end + + # Collect array of Git::Commit objects + # between target and source branches + def unmerged_commits + commits = if merge_request.for_fork? + Gitlab::Satellite::MergeAction.new(merge_request.author, merge_request).commits_between + else + repository.commits_between(target_branch, source_branch) + end + + if commits.present? + commits = Commit.decorate(commits). + sort_by(&:created_at). + reverse + end + + commits + end + + # Reload all commits related to current merge request from repo + # and save it as array of hashes in st_commits db field + def reload_commits + commit_objects = unmerged_commits + + if commit_objects.present? + self.st_commits = dump_commits(commit_objects) + end + + save + end + + # Reload diffs between branches related to current merge request from repo + # and save it as array of hashes in st_diffs db field + def reload_diffs + new_diffs = [] + + if commits.size.zero? + self.state = :empty + elsif commits.size > COMMITS_SAFE_SIZE + self.state = :overflow_commits_safe_size + else + new_diffs = unmerged_diffs + end + + if new_diffs.any? + if new_diffs.size > Commit::DIFF_HARD_LIMIT_FILES + self.state = :overflow_diff_files_limit + new_diffs = [] + end + + if new_diffs.sum { |diff| diff.diff.lines.count } > Commit::DIFF_HARD_LIMIT_LINES + self.state = :overflow_diff_lines_limit + new_diffs = [] + end + end + + new_diffs = dump_commits(new_diffs) if new_diffs.present? + + self.st_diffs = new_diffs + self.save + end + + # Collect array of Git::Diff objects + # between target and source branches + def unmerged_diffs + diffs = if merge_request.for_fork? + Gitlab::Satellite::MergeAction.new(merge_request.author, merge_request).diffs_between_satellite + else + Gitlab::Git::Diff.between(repository, source_branch, target_branch) + end + + if diffs == broken_diffs + self.state = :timeout + diffs = [] + end + + diffs ||= [] + diffs + end + + def repository + merge_request.target_project.repository + end +end From 79bfbe5918b414cc44fbb506f0b350c04f49c1e9 Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Wed, 22 Jan 2014 15:20:20 +0200 Subject: [PATCH 05/39] Remove commits/diff store login from MergeRequest model Signed-off-by: Dmitriy Zaporozhets --- app/models/merge_request.rb | 119 +----------------------- app/observers/merge_request_observer.rb | 1 + 2 files changed, 6 insertions(+), 114 deletions(-) diff --git a/app/models/merge_request.rb b/app/models/merge_request.rb index da7aebd944..01538cf8c1 100644 --- a/app/models/merge_request.rb +++ b/app/models/merge_request.rb @@ -30,6 +30,9 @@ class MergeRequest < ActiveRecord::Base belongs_to :target_project, foreign_key: :target_project_id, class_name: "Project" belongs_to :source_project, foreign_key: :source_project_id, class_name: "Project" + has_one :merge_request_diff, dependent: :destroy + + delegate :commits, :diffs, :last_commit, :last_commit_short_sha, to: :merge_request_diff, prefix: nil attr_accessible :title, :assignee_id, :source_project_id, :source_branch, :target_project_id, :target_branch, :milestone_id, :author_id_of_changes, :state_event, :description @@ -53,11 +56,8 @@ class MergeRequest < ActiveRecord::Base end state :opened - state :reopened - state :closed - state :merged end @@ -75,15 +75,10 @@ class MergeRequest < ActiveRecord::Base end state :unchecked - state :can_be_merged - state :cannot_be_merged end - serialize :st_commits - serialize :st_diffs - validates :source_project, presence: true, unless: :allow_broken validates :source_branch, presence: true validates :target_project, presence: true @@ -105,7 +100,7 @@ class MergeRequest < ActiveRecord::Base scope :closed, -> { with_states(:closed, :merged) } def validate_branches - if target_project==source_project && target_branch == source_branch + if target_project == source_project && target_branch == source_branch errors.add :branch_conflict, "You can not use same project/branch for source and target" end @@ -120,8 +115,7 @@ class MergeRequest < ActiveRecord::Base end def reload_code - self.reloaded_commits - self.reloaded_diffs + merge_request_diff.reload_content if opened? end def check_if_can_be_merged @@ -132,42 +126,6 @@ class MergeRequest < ActiveRecord::Base end end - def diffs - @diffs ||= (load_diffs(st_diffs) || []) - end - - def reloaded_diffs - if opened? && unmerged_diffs.any? - self.st_diffs = dump_diffs(unmerged_diffs) - self.save - end - end - - def broken_diffs? - diffs == broken_diffs - rescue - true - end - - def valid_diffs? - !broken_diffs? - end - - def unmerged_diffs - diffs = if for_fork? - Gitlab::Satellite::MergeAction.new(author, self).diffs_between_satellite - else - Gitlab::Git::Diff.between(target_project.repository, source_branch, target_branch) - end - - diffs ||= [] - diffs - end - - def last_commit - commits.first - end - def merge_event self.target_project.events.where(target_id: self.id, target_type: "MergeRequest", action: Event::MERGED).last end @@ -176,39 +134,6 @@ class MergeRequest < ActiveRecord::Base self.target_project.events.where(target_id: self.id, target_type: "MergeRequest", action: Event::CLOSED).last end - def commits - load_commits(st_commits || []) - end - - def probably_merged? - unmerged_commits.empty? && - commits.any? && opened? - end - - def reloaded_commits - if opened? && unmerged_commits.any? - self.st_commits = dump_commits(unmerged_commits) - save - - end - commits - end - - def unmerged_commits - if for_fork? - commits = Gitlab::Satellite::MergeAction.new(self.author, self).commits_between - else - commits = target_project.repository.commits_between(self.target_branch, self.source_branch) - end - - if commits.present? - commits = Commit.decorate(commits). - sort_by(&:created_at). - reverse - end - commits - end - def merge!(user_id) self.author_id_of_changes = user_id self.merge @@ -247,10 +172,6 @@ class MergeRequest < ActiveRecord::Base Gitlab::Satellite::MergeAction.new(current_user, self).format_patch end - def last_commit_short_sha - @last_commit_short_sha ||= last_commit.sha[0..10] - end - def for_fork? target_project != source_project end @@ -327,34 +248,4 @@ class MergeRequest < ActiveRecord::Base message << description.to_s message end - - private - - def dump_commits(commits) - commits.map(&:to_hash) - end - - def load_commits(array) - array.map { |hash| Commit.new(Gitlab::Git::Commit.new(hash)) } - end - - def dump_diffs(diffs) - if diffs == broken_diffs - broken_diffs - elsif diffs.respond_to?(:map) - diffs.map(&:to_hash) - end - end - - def load_diffs(raw) - if raw == broken_diffs - broken_diffs - elsif raw.respond_to?(:map) - raw.map { |hash| Gitlab::Git::Diff.new(hash) } - end - end - - def broken_diffs - [Gitlab::Git::Diff::BROKEN_DIFF] - end end diff --git a/app/observers/merge_request_observer.rb b/app/observers/merge_request_observer.rb index 0ac555fce7..9a3e90d83e 100644 --- a/app/observers/merge_request_observer.rb +++ b/app/observers/merge_request_observer.rb @@ -6,6 +6,7 @@ class MergeRequestObserver < ActivityObserver create_event(merge_request, Event.determine_action(merge_request)) end + merge_request.create_merge_request_diff notification.new_merge_request(merge_request, current_user) merge_request.create_cross_references!(merge_request.project, current_user) execute_hooks(merge_request) From 193a5ed3c3c352f043752c8ed3b0f3d1cb8c0ddc Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Wed, 22 Jan 2014 15:20:40 +0200 Subject: [PATCH 06/39] Render MR diff correctly Signed-off-by: Dmitriy Zaporozhets --- app/controllers/projects/merge_requests_controller.rb | 1 + app/views/projects/merge_requests/show/_diffs.html.haml | 8 ++++---- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/app/controllers/projects/merge_requests_controller.rb b/app/controllers/projects/merge_requests_controller.rb index 0792dbf041..0c7a44274e 100644 --- a/app/controllers/projects/merge_requests_controller.rb +++ b/app/controllers/projects/merge_requests_controller.rb @@ -213,6 +213,7 @@ class Projects::MergeRequestsController < Projects::ApplicationController # or from cache if already merged @commits = @merge_request.commits + @merge_request_diff = @merge_request.merge_request_diff @allowed_to_merge = allowed_to_merge? @show_merge_controls = @merge_request.opened? && @commits.any? && @allowed_to_merge end diff --git a/app/views/projects/merge_requests/show/_diffs.html.haml b/app/views/projects/merge_requests/show/_diffs.html.haml index 25f6380485..2c7507cfb8 100644 --- a/app/views/projects/merge_requests/show/_diffs.html.haml +++ b/app/views/projects/merge_requests/show/_diffs.html.haml @@ -1,10 +1,10 @@ -- if @merge_request.valid_diffs? +- if @merge_request_diff.collected? = render "projects/commits/diffs", diffs: @merge_request.diffs, project: @merge_request.source_project -- elsif @merge_request.broken_diffs? +- elsif @merge_request_diff.empty? + %h4.nothing_here_message Nothing to merge from #{@merge_request.source_branch} into #{@merge_request.target_branch} +- else %h4.nothing_here_message Can't load diff. You can = link_to "download it", project_merge_request_path(@merge_request.source_project, @merge_request), format: :diff, class: "vlink" instead. -- else - %h4.nothing_here_message Nothing to merge From 39a86963e93b4a24296ffe96e63c5a189f8d1d07 Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Wed, 22 Jan 2014 15:30:14 +0200 Subject: [PATCH 07/39] Set mr_diff state to collected if diff is ok Signed-off-by: Dmitriy Zaporozhets --- app/models/merge_request_diff.rb | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/app/models/merge_request_diff.rb b/app/models/merge_request_diff.rb index d06b95daa6..3ea610197e 100644 --- a/app/models/merge_request_diff.rb +++ b/app/models/merge_request_diff.rb @@ -130,7 +130,10 @@ class MergeRequestDiff < ActiveRecord::Base end end - new_diffs = dump_commits(new_diffs) if new_diffs.present? + if new_diffs.present? + new_diffs = dump_commits(new_diffs) + self.state = :collected + end self.st_diffs = new_diffs self.save From 51ea42e2386f109e3fb4f3619dd33eb9a5398080 Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Wed, 22 Jan 2014 15:54:53 +0200 Subject: [PATCH 08/39] Improve commit render performnace for MR show page Signed-off-by: Dmitriy Zaporozhets --- app/assets/stylesheets/sections/merge_requests.scss | 13 ------------- app/models/merge_request.rb | 5 ++++- app/views/projects/commits/_inline_commit.html.haml | 6 ++++-- .../projects/merge_requests/show/_commits.html.haml | 13 ++++++++++--- 4 files changed, 18 insertions(+), 19 deletions(-) diff --git a/app/assets/stylesheets/sections/merge_requests.scss b/app/assets/stylesheets/sections/merge_requests.scss index d3462d6aaa..4388da0073 100644 --- a/app/assets/stylesheets/sections/merge_requests.scss +++ b/app/assets/stylesheets/sections/merge_requests.scss @@ -89,16 +89,3 @@ .merge-request-form-info { padding-top: 15px; } - -.merge-request-branches { - .commit-row-message { - font-weight: normal !important; - } - - .select2-container .select2-single { - span { - font-weight: bold; - color: #555; - } - } -} diff --git a/app/models/merge_request.rb b/app/models/merge_request.rb index 01538cf8c1..076463f6c4 100644 --- a/app/models/merge_request.rb +++ b/app/models/merge_request.rb @@ -150,7 +150,10 @@ class MergeRequest < ActiveRecord::Base end def mr_and_commit_notes - commit_ids = commits.map(&:id) + # Fetch comments only from last 100 commits + commits_for_notes_limit = 100 + commit_ids = commits.last(commits_for_notes_limit).map(&:id) + project.notes.where( "(noteable_type = 'MergeRequest' AND noteable_id = :mr_id) OR (noteable_type = 'Commit' AND commit_id IN (:commit_ids))", mr_id: id, diff --git a/app/views/projects/commits/_inline_commit.html.haml b/app/views/projects/commits/_inline_commit.html.haml index f5863463fe..b36369b428 100644 --- a/app/views/projects/commits/_inline_commit.html.haml +++ b/app/views/projects/commits/_inline_commit.html.haml @@ -2,5 +2,7 @@ .commit-row-title = link_to commit.short_id(8), project_commit_path(project, commit), class: "commit_short_id"   - = link_to_gfm truncate(commit.title, length: 40), project_commit_path(project, commit.id), class: "commit-row-message" - #{time_ago_with_tooltip(commit.committed_date)}   + %span.str-truncated + = link_to_gfm commit.title, project_commit_path(project, commit.id), class: "commit-row-message" + .pull-right + #{time_ago_with_tooltip(commit.committed_date)} diff --git a/app/views/projects/merge_requests/show/_commits.html.haml b/app/views/projects/merge_requests/show/_commits.html.haml index 7b0e67053a..8ca1326c96 100644 --- a/app/views/projects/merge_requests/show/_commits.html.haml +++ b/app/views/projects/merge_requests/show/_commits.html.haml @@ -12,9 +12,16 @@ 8 of #{@commits.count} commits displayed. %strong %a.show-all-commits Click here to show all - %ul.all-commits.hide.well-list - - @commits.each do |commit| - = render "projects/commits/commit", commit: commit, project: @merge_request.source_project + - if @commits.size > MergeRequestDiff::COMMITS_SAFE_SIZE + %ul.all-commits.hide.well-list + - @commits.first(MergeRequestDiff::COMMITS_SAFE_SIZE).each do |commit| + = render "projects/commits/inline_commit", commit: commit, project: @merge_request.source_project + %li + other #{@commits.size - MergeRequestDiff::COMMITS_SAFE_SIZE} commits hidden top prevent performance issues. + - else + %ul.all-commits.hide.well-list + - @commits.each do |commit| + = render "projects/commits/inline_commit", commit: commit, project: @merge_request.source_project - else %ul.well-list From 96ed6c456981f0e71c8629ab6cc464f896b2ca3b Mon Sep 17 00:00:00 2001 From: Jacob Vosmaer Date: Wed, 22 Jan 2014 16:00:50 +0100 Subject: [PATCH 09/39] Replace 6.0-to-6.4.md with 6.0-to-6.5.md --- doc/update/{6.0-to-6.4.md => 6.0-to-6.5.md} | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) rename doc/update/{6.0-to-6.4.md => 6.0-to-6.5.md} (91%) diff --git a/doc/update/6.0-to-6.4.md b/doc/update/6.0-to-6.5.md similarity index 91% rename from doc/update/6.0-to-6.4.md rename to doc/update/6.0-to-6.5.md index 1e7af70804..8b2fcd4854 100644 --- a/doc/update/6.0-to-6.4.md +++ b/doc/update/6.0-to-6.5.md @@ -1,4 +1,4 @@ -# From 6.0 to 6.4 +# From 6.0 to 6.5 # In 6.1 we remove a lot of deprecated code. # You should update to 6.0 before installing 6.1 or higher so all the necessary conversions are run. @@ -28,8 +28,8 @@ sudo -u git -H bundle exec rake gitlab:backup:create RAILS_ENV=production ```bash cd /home/git/gitlab sudo -u git -H git fetch --all -sudo -u git -H git checkout 6-4-stable -# For GitLab Enterprise Edition: sudo -u git -H git checkout 6-4-stable-ee +sudo -u git -H git checkout 6-5-stable +# For GitLab Enterprise Edition: sudo -u git -H git checkout 6-5-stable-ee ``` @@ -72,11 +72,11 @@ sudo -u git -H bundle exec rake cache:clear RAILS_ENV=production TIP: to see what changed in gitlab.yml.example in this release use next command: ``` -git diff 6-0-stable:config/gitlab.yml.example 6-4-stable:config/gitlab.yml.example +git diff 6-0-stable:config/gitlab.yml.example 6-5-stable:config/gitlab.yml.example ``` -* Make `/home/git/gitlab/config/gitlab.yml` same as https://gitlab.com/gitlab-org/gitlab-ce/blob/6-4-stable/config/gitlab.yml.example but with your settings. -* Make `/home/git/gitlab/config/unicorn.rb` same as https://gitlab.com/gitlab-org/gitlab-ce/blob/6-4-stable/config/unicorn.rb.example but with your settings. +* Make `/home/git/gitlab/config/gitlab.yml` same as https://gitlab.com/gitlab-org/gitlab-ce/blob/6-5-stable/config/gitlab.yml.example but with your settings. +* Make `/home/git/gitlab/config/unicorn.rb` same as https://gitlab.com/gitlab-org/gitlab-ce/blob/6-5-stable/config/unicorn.rb.example but with your settings. * Copy rack attack middleware config ```bash From efbb4fbb7aa15ab3db613df826271869936692c8 Mon Sep 17 00:00:00 2001 From: dosire Date: Wed, 22 Jan 2014 16:54:53 +0100 Subject: [PATCH 10/39] Remove GitHub mention because we also have a GitLab issue tracker now. --- PROCESS.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/PROCESS.md b/PROCESS.md index 9486c9123e..bf757025c4 100644 --- a/PROCESS.md +++ b/PROCESS.md @@ -73,7 +73,7 @@ Thanks for the issue report. Please reformat your issue to conform to the issue ### Feature requests -Thanks for your interest in GitLab. We don't use the GitHub issue tracker for feature requests. Please use http://feedback.gitlab.com/ for this purpose or create a merge request implementing this feature. Have a look at the \[contribution guidelines\]\(https://gitlab.com/gitlab-org/gitlab-ce/blob/master/CONTRIBUTING.md) for more information. +Thanks for your interest in GitLab. We don't use the issue tracker for feature requests. Please use http://feedback.gitlab.com/ for this purpose or create a merge request implementing this feature. Have a look at the \[contribution guidelines\]\(https://gitlab.com/gitlab-org/gitlab-ce/blob/master/CONTRIBUTING.md) for more information. ### Issue report for old version @@ -81,7 +81,7 @@ Thanks for the issue report but we only support issues for the latest stable ver ### Support requests and configuration questions -Thanks for your interest in GitLab. We don't use the GitHub issue tracker for support requests and configuration questions. Please use the \[support forum\]\(https://groups.google.com/forum/#!forum/gitlabhq), \[Stack Overflow\]\(http://stackoverflow.com/questions/tagged/gitlab), the unofficial #gitlab IRC channel on Freenode or the http://www.gitlab.com paid services for this purpose. Have a look at the \[contribution guidelines\]\(https://gitlab.com/gitlab-org/gitlab-ce/blob/master/CONTRIBUTING.md) for more information. +Thanks for your interest in GitLab. We don't use the issue tracker for support requests and configuration questions. Please use the \[support forum\]\(https://groups.google.com/forum/#!forum/gitlabhq), \[Stack Overflow\]\(http://stackoverflow.com/questions/tagged/gitlab), the unofficial #gitlab IRC channel on Freenode or the http://www.gitlab.com paid services for this purpose. Have a look at the \[contribution guidelines\]\(https://gitlab.com/gitlab-org/gitlab-ce/blob/master/CONTRIBUTING.md) for more information. ### Code format From 3ba40f03ad4c5ba1de10a07e1acc09852858848c Mon Sep 17 00:00:00 2001 From: dosire Date: Wed, 22 Jan 2014 17:37:01 +0100 Subject: [PATCH 11/39] Warn against RVM. --- doc/install/installation.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/doc/install/installation.md b/doc/install/installation.md index 7c3497bb92..bf319e99ac 100644 --- a/doc/install/installation.md +++ b/doc/install/installation.md @@ -113,6 +113,8 @@ Then select 'Internet Site' and press enter to confirm the hostname. # 2. Ruby +The use of ruby version managers such as RVM, rbenv and chruby with GitLab in production frequently lead to hard to diagnose problems. Version managers are not supported and we stronly advise everyone to follow the instructions below to use a system ruby. + Remove the old Ruby 1.8 if present sudo apt-get remove ruby1.8 From a4f2da4763cbb84c649146bc3befbf0caa1c26e1 Mon Sep 17 00:00:00 2001 From: dosire Date: Wed, 22 Jan 2014 17:38:36 +0100 Subject: [PATCH 12/39] Spelling mistake and add links. --- doc/install/installation.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/install/installation.md b/doc/install/installation.md index bf319e99ac..675764a914 100644 --- a/doc/install/installation.md +++ b/doc/install/installation.md @@ -113,7 +113,7 @@ Then select 'Internet Site' and press enter to confirm the hostname. # 2. Ruby -The use of ruby version managers such as RVM, rbenv and chruby with GitLab in production frequently lead to hard to diagnose problems. Version managers are not supported and we stronly advise everyone to follow the instructions below to use a system ruby. +The use of ruby version managers such as [RVM](http://rvm.io/), [rbenv](https://github.com/sstephenson/rbenv) or [chruby](https://github.com/postmodern/chruby) with GitLab in production frequently leads to hard to diagnose problems. Version managers are not supported and we stronly advise everyone to follow the instructions below to use a system ruby. Remove the old Ruby 1.8 if present From 3ff27c4b1b69a83aff35b95dcf145bffd16651dd Mon Sep 17 00:00:00 2001 From: dosire Date: Wed, 22 Jan 2014 17:46:40 +0100 Subject: [PATCH 13/39] No need for code tag here. --- doc/install/installation.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/install/installation.md b/doc/install/installation.md index 7c3497bb92..74256214be 100644 --- a/doc/install/installation.md +++ b/doc/install/installation.md @@ -10,7 +10,7 @@ If this is unclear check the [GitLab Blog](http://blog.gitlab.org/) for installa This guide is long because it covers many cases and includes all commands you need, this is [one of the few installation scripts that actually works out of the box](https://twitter.com/robinvdvleuten/status/424163226532986880). -This installation guide was created for and tested on **Debian/Ubuntu** operating systems. Please read [`doc/install/requirements.md`](./requirements.md) for hardware and operating system requirements. +This installation guide was created for and tested on **Debian/Ubuntu** operating systems. Please read [doc/install/requirements.md](./requirements.md) for hardware and operating system requirements. This is the official installation guide to set up a production server. To set up a **development installation** or for many other installation options please consult [the installation section in the readme](https://github.com/gitlabhq/gitlabhq#installation). From 4b3afe2325e063943bdec123154a576f6a300bce Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Wed, 22 Jan 2014 20:22:20 +0200 Subject: [PATCH 14/39] Always create merge_request_diff if MR created Signed-off-by: Dmitriy Zaporozhets --- app/controllers/projects/merge_requests_controller.rb | 1 - app/models/merge_request.rb | 2 ++ app/observers/merge_request_observer.rb | 1 - lib/api/merge_requests.rb | 1 - 4 files changed, 2 insertions(+), 3 deletions(-) diff --git a/app/controllers/projects/merge_requests_controller.rb b/app/controllers/projects/merge_requests_controller.rb index 0c7a44274e..baaa3c7ba0 100644 --- a/app/controllers/projects/merge_requests_controller.rb +++ b/app/controllers/projects/merge_requests_controller.rb @@ -76,7 +76,6 @@ class Projects::MergeRequestsController < Projects::ApplicationController @merge_request.author = current_user @target_branches ||= [] if @merge_request.save - @merge_request.reload_code redirect_to [@merge_request.target_project, @merge_request], notice: 'Merge request was successfully created.' else @source_project = @merge_request.source_project diff --git a/app/models/merge_request.rb b/app/models/merge_request.rb index 076463f6c4..c53b24b817 100644 --- a/app/models/merge_request.rb +++ b/app/models/merge_request.rb @@ -30,7 +30,9 @@ class MergeRequest < ActiveRecord::Base belongs_to :target_project, foreign_key: :target_project_id, class_name: "Project" belongs_to :source_project, foreign_key: :source_project_id, class_name: "Project" + has_one :merge_request_diff, dependent: :destroy + after_create :create_merge_request_diff delegate :commits, :diffs, :last_commit, :last_commit_short_sha, to: :merge_request_diff, prefix: nil diff --git a/app/observers/merge_request_observer.rb b/app/observers/merge_request_observer.rb index 9a3e90d83e..0ac555fce7 100644 --- a/app/observers/merge_request_observer.rb +++ b/app/observers/merge_request_observer.rb @@ -6,7 +6,6 @@ class MergeRequestObserver < ActivityObserver create_event(merge_request, Event.determine_action(merge_request)) end - merge_request.create_merge_request_diff notification.new_merge_request(merge_request, current_user) merge_request.create_cross_references!(merge_request.project, current_user) execute_hooks(merge_request) diff --git a/lib/api/merge_requests.rb b/lib/api/merge_requests.rb index 3f4bec895b..4bd57f516d 100644 --- a/lib/api/merge_requests.rb +++ b/lib/api/merge_requests.rb @@ -88,7 +88,6 @@ module API end if merge_request.save - merge_request.reload_code present merge_request, with: Entities::MergeRequest else handle_merge_request_errors! merge_request.errors From c227aa44f9c54dd88f2ac8de7a3463a23f516dff Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Wed, 22 Jan 2014 21:03:52 +0200 Subject: [PATCH 15/39] Make changes to tests * project_with_code -> project * project -> ermpty_project Signed-off-by: Dmitriy Zaporozhets --- features/steps/dashboard/dashboard_issues.rb | 2 +- .../dashboard/dashboard_merge_requests.rb | 2 +- features/steps/project/project_fork.rb | 4 +- .../project/project_forked_merge_requests.rb | 4 +- .../steps/project/project_issue_tracker.rb | 2 +- .../steps/project/project_markdown_render.rb | 2 +- features/steps/project/redirects.rb | 2 +- features/steps/public/projects_feature.rb | 4 +- features/steps/shared/project.rb | 6 +- spec/controllers/blob_controller_spec.rb | 2 +- spec/controllers/commit_controller_spec.rb | 2 +- spec/controllers/commits_controller_spec.rb | 2 +- .../merge_requests_controller_spec.rb | 2 +- spec/controllers/tree_controller_spec.rb | 2 +- spec/factories.rb | 57 ++++--------------- .../features/gitlab_flavored_markdown_spec.rb | 2 +- spec/features/notes_on_merge_requests_spec.rb | 6 +- .../security/project/internal_access_spec.rb | 2 +- .../security/project/private_access_spec.rb | 2 +- .../security/project/public_access_spec.rb | 2 +- spec/helpers/gitlab_markdown_helper_spec.rb | 2 +- spec/helpers/search_helper_spec.rb | 2 +- spec/lib/gitlab/reference_extractor_spec.rb | 2 +- spec/lib/gitlab/satellite/action_spec.rb | 2 +- .../lib/gitlab/satellite/merge_action_spec.rb | 2 +- spec/mailers/notify_spec.rb | 2 +- spec/models/assembla_service_spec.rb | 2 +- spec/models/commit_spec.rb | 2 +- spec/models/flowdock_service_spec.rb | 2 +- spec/models/note_spec.rb | 2 +- spec/models/project_spec.rb | 4 +- spec/models/service_spec.rb | 2 +- spec/observers/merge_request_observer_spec.rb | 30 ++++------ spec/requests/api/files_spec.rb | 2 +- spec/requests/api/merge_requests_spec.rb | 6 +- spec/requests/api/project_hooks_spec.rb | 2 +- spec/requests/api/projects_spec.rb | 53 +++++++++++------ spec/requests/api/repositories_spec.rb | 2 +- spec/requests/api/services_spec.rb | 2 +- spec/services/git_push_service_spec.rb | 2 +- spec/services/test_hook_service_spec.rb | 2 +- spec/support/mentionable_shared_examples.rb | 2 +- spec/workers/post_receive_spec.rb | 2 +- 43 files changed, 109 insertions(+), 131 deletions(-) diff --git a/features/steps/dashboard/dashboard_issues.rb b/features/steps/dashboard/dashboard_issues.rb index a458acdae0..1344edfa80 100644 --- a/features/steps/dashboard/dashboard_issues.rb +++ b/features/steps/dashboard/dashboard_issues.rb @@ -66,7 +66,7 @@ class DashboardIssues < Spinach::FeatureSteps def project @project ||= begin - project =create :project_with_code + project =create :project project.team << [current_user, :master] project end diff --git a/features/steps/dashboard/dashboard_merge_requests.rb b/features/steps/dashboard/dashboard_merge_requests.rb index 73286532b9..62d84506c4 100644 --- a/features/steps/dashboard/dashboard_merge_requests.rb +++ b/features/steps/dashboard/dashboard_merge_requests.rb @@ -66,7 +66,7 @@ class DashboardMergeRequests < Spinach::FeatureSteps def project @project ||= begin - project =create :project_with_code + project =create :project project.team << [current_user, :master] project end diff --git a/features/steps/project/project_fork.rb b/features/steps/project/project_fork.rb index 858c7d11b3..b00903b339 100644 --- a/features/steps/project/project_fork.rb +++ b/features/steps/project/project_fork.rb @@ -12,7 +12,7 @@ class ForkProject < Spinach::FeatureSteps step 'I am a member of project "Shop"' do @project = Project.find_by_name "Shop" - @project ||= create(:project_with_code, name: "Shop", group: create(:group)) + @project ||= create(:project, name: "Shop", group: create(:group)) @project.team << [@user, :reporter] end @@ -26,7 +26,7 @@ class ForkProject < Spinach::FeatureSteps current_user.namespace ||= create(:namespace) current_user.namespace.should_not be_nil current_user.namespace.path.should_not be_nil - @my_project = create(:project_with_code, name: "Shop", namespace: current_user.namespace) + @my_project = create(:project, name: "Shop", namespace: current_user.namespace) end step 'I should see a "Name has already been taken" warning' do diff --git a/features/steps/project/project_forked_merge_requests.rb b/features/steps/project/project_forked_merge_requests.rb index d34aeac30b..57ab643956 100644 --- a/features/steps/project/project_forked_merge_requests.rb +++ b/features/steps/project/project_forked_merge_requests.rb @@ -7,7 +7,7 @@ class ProjectForkedMergeRequests < Spinach::FeatureSteps step 'I am a member of project "Shop"' do @project = Project.find_by_name "Shop" - @project ||= create(:project_with_code, name: "Shop") + @project ||= create(:project, name: "Shop") @project.team << [@user, :reporter] end @@ -15,7 +15,7 @@ class ProjectForkedMergeRequests < Spinach::FeatureSteps @forking_user = @user forked_project_link = build(:forked_project_link) @forked_project = Project.find_by_name "Forked Shop" - @forked_project ||= create(:source_project_with_code, name: "Forked Shop", forked_project_link: forked_project_link, creator_id: @forking_user.id , namespace: @forking_user.namespace) + @forked_project ||= create(:source_project, name: "Forked Shop", forked_project_link: forked_project_link, creator_id: @forking_user.id , namespace: @forking_user.namespace) forked_project_link.forked_from_project = @project forked_project_link.forked_to_project = @forked_project diff --git a/features/steps/project/project_issue_tracker.rb b/features/steps/project/project_issue_tracker.rb index a05d7a0bc3..65e7e4de9d 100644 --- a/features/steps/project/project_issue_tracker.rb +++ b/features/steps/project/project_issue_tracker.rb @@ -5,7 +5,7 @@ class ProjectIssueTracker < Spinach::FeatureSteps step 'project "Shop" has issues enabled' do @project = Project.find_by_name "Shop" - @project ||= create(:project_with_code, name: "Shop", namespace: @user.namespace) + @project ||= create(:project, name: "Shop", namespace: @user.namespace) @project.issues_enabled = true end diff --git a/features/steps/project/project_markdown_render.rb b/features/steps/project/project_markdown_render.rb index da044e46eb..bef62c61bc 100644 --- a/features/steps/project/project_markdown_render.rb +++ b/features/steps/project/project_markdown_render.rb @@ -4,7 +4,7 @@ class Spinach::Features::ProjectMarkdownRender < Spinach::FeatureSteps And 'I own project "Delta"' do @project = Project.find_by_name "Delta" - @project ||= create(:project_with_code, name: "Delta", namespace: @user.namespace) + @project ||= create(:project, name: "Delta", namespace: @user.namespace) @project.team << [@user, :master] end diff --git a/features/steps/project/redirects.rb b/features/steps/project/redirects.rb index 4ac5307570..8015ae833d 100644 --- a/features/steps/project/redirects.rb +++ b/features/steps/project/redirects.rb @@ -4,7 +4,7 @@ class Spinach::Features::ProjectRedirects < Spinach::FeatureSteps include SharedProject step 'public project "Community"' do - create :project_with_code, name: 'Community', visibility_level: Gitlab::VisibilityLevel::PUBLIC + create :project, name: 'Community', visibility_level: Gitlab::VisibilityLevel::PUBLIC end step 'private project "Enterprise"' do diff --git a/features/steps/public/projects_feature.rb b/features/steps/public/projects_feature.rb index 47e52f47d0..2292fdad6f 100644 --- a/features/steps/public/projects_feature.rb +++ b/features/steps/public/projects_feature.rb @@ -25,7 +25,7 @@ class Spinach::Features::PublicProjectsFeature < Spinach::FeatureSteps end step 'public project "Community"' do - create :project_with_code, name: 'Community', visibility_level: Gitlab::VisibilityLevel::PUBLIC + create :project, name: 'Community', visibility_level: Gitlab::VisibilityLevel::PUBLIC end step 'public empty project "Empty Public Project"' do @@ -76,7 +76,7 @@ class Spinach::Features::PublicProjectsFeature < Spinach::FeatureSteps end step 'internal project "Internal"' do - create :project_with_code, name: 'Internal', visibility_level: Gitlab::VisibilityLevel::INTERNAL + create :project, name: 'Internal', visibility_level: Gitlab::VisibilityLevel::INTERNAL end step 'I should see project "Internal"' do diff --git a/features/steps/shared/project.rb b/features/steps/shared/project.rb index 3dc4932a09..97b036ae74 100644 --- a/features/steps/shared/project.rb +++ b/features/steps/shared/project.rb @@ -3,21 +3,21 @@ module SharedProject # Create a project without caring about what it's called And "I own a project" do - @project = create(:project_with_code, namespace: @user.namespace) + @project = create(:project, namespace: @user.namespace) @project.team << [@user, :master] end # Create a specific project called "Shop" And 'I own project "Shop"' do @project = Project.find_by_name "Shop" - @project ||= create(:project_with_code, name: "Shop", namespace: @user.namespace) + @project ||= create(:project, name: "Shop", namespace: @user.namespace) @project.team << [@user, :master] end # Create another specific project called "Forum" And 'I own project "Forum"' do @project = Project.find_by_name "Forum" - @project ||= create(:project_with_code, name: "Forum", namespace: @user.namespace, path: 'forum_project') + @project ||= create(:project, name: "Forum", namespace: @user.namespace, path: 'forum_project') @project.team << [@user, :master] end diff --git a/spec/controllers/blob_controller_spec.rb b/spec/controllers/blob_controller_spec.rb index 479d8fc1a1..cea6922e1c 100644 --- a/spec/controllers/blob_controller_spec.rb +++ b/spec/controllers/blob_controller_spec.rb @@ -1,7 +1,7 @@ require 'spec_helper' describe Projects::BlobController do - let(:project) { create(:project_with_code) } + let(:project) { create(:project) } let(:user) { create(:user) } before do diff --git a/spec/controllers/commit_controller_spec.rb b/spec/controllers/commit_controller_spec.rb index fdf0884f4e..f5822157ea 100644 --- a/spec/controllers/commit_controller_spec.rb +++ b/spec/controllers/commit_controller_spec.rb @@ -1,7 +1,7 @@ require 'spec_helper' describe Projects::CommitController do - let(:project) { create(:project_with_code) } + let(:project) { create(:project) } let(:user) { create(:user) } let(:commit) { project.repository.commit("master") } diff --git a/spec/controllers/commits_controller_spec.rb b/spec/controllers/commits_controller_spec.rb index 8263afc97a..fbf4f29acf 100644 --- a/spec/controllers/commits_controller_spec.rb +++ b/spec/controllers/commits_controller_spec.rb @@ -1,7 +1,7 @@ require 'spec_helper' describe Projects::CommitsController do - let(:project) { create(:project_with_code) } + let(:project) { create(:project) } let(:user) { create(:user) } before do diff --git a/spec/controllers/merge_requests_controller_spec.rb b/spec/controllers/merge_requests_controller_spec.rb index f237f35845..1502bded97 100644 --- a/spec/controllers/merge_requests_controller_spec.rb +++ b/spec/controllers/merge_requests_controller_spec.rb @@ -1,7 +1,7 @@ require 'spec_helper' describe Projects::MergeRequestsController do - let(:project) { create(:project_with_code) } + let(:project) { create(:project) } let(:user) { create(:user) } let(:merge_request) { create(:merge_request_with_diffs, target_project: project, source_project: project, target_branch: "stable", source_branch: "master") } diff --git a/spec/controllers/tree_controller_spec.rb b/spec/controllers/tree_controller_spec.rb index bb1232e626..479118a346 100644 --- a/spec/controllers/tree_controller_spec.rb +++ b/spec/controllers/tree_controller_spec.rb @@ -1,7 +1,7 @@ require 'spec_helper' describe Projects::TreeController do - let(:project) { create(:project_with_code) } + let(:project) { create(:project) } let(:user) { create(:user) } before do diff --git a/spec/factories.rb b/spec/factories.rb index daf8417364..bf74063a30 100644 --- a/spec/factories.rb +++ b/spec/factories.rb @@ -27,43 +27,16 @@ FactoryGirl.define do factory :admin, traits: [:admin] end - factory :project do + factory :empty_project, class: 'Project' do sequence(:name) { |n| "project#{n}" } path { name.downcase.gsub(/\s/, '_') } namespace creator - - trait :source do - sequence(:name) { |n| "source project#{n}" } - end - trait :target do - sequence(:name) { |n| "target project#{n}" } - end - - factory :source_project, traits: [:source] - factory :target_project, traits: [:target] end - - factory :redmine_project, parent: :project do - issues_tracker { "redmine" } - issues_tracker_id { "project_name_in_redmine" } - end - - factory :project_with_code, parent: :project do + factory :project, parent: :empty_project do path { 'gitlabhq' } - trait :source_path do - path { 'source_gitlabhq' } - end - - trait :target_path do - path { 'target_gitlabhq' } - end - - factory :source_project_with_code, traits: [:source, :source_path] - factory :target_project_with_code, traits: [:target, :target_path] - after :create do |project| TestEnv.clear_repo_dir(project.namespace, project.path) TestEnv.reset_satellite_dir @@ -71,6 +44,11 @@ FactoryGirl.define do end end + factory :redmine_project, parent: :project do + issues_tracker { "redmine" } + issues_tracker_id { "project_name_in_redmine" } + end + factory :group do sequence(:name) { |n| "group#{n}" } path { name.downcase.gsub(/\s/, '_') } @@ -109,25 +87,12 @@ FactoryGirl.define do factory :merge_request do title author - source_project factory: :source_project_with_code - target_project factory: :target_project_with_code + source_project factory: :project + target_project { source_project } source_branch "master" target_branch "stable" - # pick 3 commits "at random" (from bcf03b5d~3 to bcf03b5d) trait :with_diffs do - target_branch "master" # pretend bcf03b5d~3 - source_branch "stable" # pretend bcf03b5d - st_commits do - [ - source_project.repository.commit('bcf03b5d').to_hash, - source_project.repository.commit('bcf03b5d~1').to_hash, - source_project.repository.commit('bcf03b5d~2').to_hash - ] - end - st_diffs do - source_project.repo.diff("bcf03b5d~3", "bcf03b5d") - end end trait :closed do @@ -156,7 +121,7 @@ FactoryGirl.define do factory :note_on_merge_request_with_attachment, traits: [:on_merge_request, :with_attachment] trait :on_commit do - project factory: :project_with_code + project factory: :project commit_id "bcf03b5de6c33f3869ef70d68cf06e679d1d7f9a" noteable_type "Commit" end @@ -166,7 +131,7 @@ FactoryGirl.define do end trait :on_merge_request do - project factory: :project_with_code + project factory: :project noteable_id 1 noteable_type "MergeRequest" end diff --git a/spec/features/gitlab_flavored_markdown_spec.rb b/spec/features/gitlab_flavored_markdown_spec.rb index 2ea569a620..a507f0314c 100644 --- a/spec/features/gitlab_flavored_markdown_spec.rb +++ b/spec/features/gitlab_flavored_markdown_spec.rb @@ -1,7 +1,7 @@ require 'spec_helper' describe "GitLab Flavored Markdown" do - let(:project) { create(:project_with_code) } + let(:project) { create(:project) } let(:issue) { create(:issue, project: project) } let(:merge_request) { create(:merge_request, source_project: project, target_project: project) } let(:fred) do diff --git a/spec/features/notes_on_merge_requests_spec.rb b/spec/features/notes_on_merge_requests_spec.rb index b534548a12..7b91853b13 100644 --- a/spec/features/notes_on_merge_requests_spec.rb +++ b/spec/features/notes_on_merge_requests_spec.rb @@ -1,7 +1,7 @@ require 'spec_helper' describe "On a merge request", js: true do - let!(:project) { create(:project_with_code) } + let!(:project) { create(:project) } let!(:merge_request) { create(:merge_request, source_project: project, target_project: project) } let!(:note) { create(:note_on_merge_request_with_attachment, project: project) } @@ -135,7 +135,7 @@ describe "On a merge request", js: true do end describe "On a merge request diff", js: true, focus: true do - let!(:project) { create(:source_project_with_code) } + let!(:project) { create(:source_project) } let!(:merge_request) { create(:merge_request_with_diffs, source_project: project, target_project: project) } before do @@ -185,7 +185,7 @@ describe "On a merge request diff", js: true, focus: true do end describe "with muliple note forms" do - let!(:project) { create(:source_project_with_code) } + let!(:project) { create(:source_project) } let!(:merge_request) { create(:merge_request_with_diffs, source_project: project, target_project: project) } before do diff --git a/spec/features/security/project/internal_access_spec.rb b/spec/features/security/project/internal_access_spec.rb index 5abccd259d..8bb1e259ef 100644 --- a/spec/features/security/project/internal_access_spec.rb +++ b/spec/features/security/project/internal_access_spec.rb @@ -1,7 +1,7 @@ require 'spec_helper' describe "Internal Project Access" do - let(:project) { create(:project_with_code) } + let(:project) { create(:project) } let(:master) { create(:user) } let(:guest) { create(:user) } diff --git a/spec/features/security/project/private_access_spec.rb b/spec/features/security/project/private_access_spec.rb index 481d8cec41..0402ff3973 100644 --- a/spec/features/security/project/private_access_spec.rb +++ b/spec/features/security/project/private_access_spec.rb @@ -1,7 +1,7 @@ require 'spec_helper' describe "Private Project Access" do - let(:project) { create(:project_with_code) } + let(:project) { create(:project) } let(:master) { create(:user) } let(:guest) { create(:user) } diff --git a/spec/features/security/project/public_access_spec.rb b/spec/features/security/project/public_access_spec.rb index 3f1016473f..7e6a39fad6 100644 --- a/spec/features/security/project/public_access_spec.rb +++ b/spec/features/security/project/public_access_spec.rb @@ -1,7 +1,7 @@ require 'spec_helper' describe "Public Project Access" do - let(:project) { create(:project_with_code) } + let(:project) { create(:project) } let(:master) { create(:user) } let(:guest) { create(:user) } diff --git a/spec/helpers/gitlab_markdown_helper_spec.rb b/spec/helpers/gitlab_markdown_helper_spec.rb index 33e69d4326..088a6a09bc 100644 --- a/spec/helpers/gitlab_markdown_helper_spec.rb +++ b/spec/helpers/gitlab_markdown_helper_spec.rb @@ -4,7 +4,7 @@ describe GitlabMarkdownHelper do include ApplicationHelper include IssuesHelper - let!(:project) { create(:project_with_code) } + let!(:project) { create(:project) } let(:user) { create(:user, username: 'gfm') } let(:commit) { project.repository.commit } diff --git a/spec/helpers/search_helper_spec.rb b/spec/helpers/search_helper_spec.rb index d04945dfe3..733f275472 100644 --- a/spec/helpers/search_helper_spec.rb +++ b/spec/helpers/search_helper_spec.rb @@ -43,7 +43,7 @@ describe SearchHelper do end context "with a current project" do - before { @project = create(:project_with_code) } + before { @project = create(:project) } it "includes project-specific sections" do search_autocomplete_opts("Files").size.should == 1 diff --git a/spec/lib/gitlab/reference_extractor_spec.rb b/spec/lib/gitlab/reference_extractor_spec.rb index 7d805f8c72..19259a8b79 100644 --- a/spec/lib/gitlab/reference_extractor_spec.rb +++ b/spec/lib/gitlab/reference_extractor_spec.rb @@ -43,7 +43,7 @@ describe Gitlab::ReferenceExtractor do end context 'with a project' do - let(:project) { create(:project_with_code) } + let(:project) { create(:project) } it 'accesses valid user objects on the project team' do @u_foo = create(:user, username: 'foo') diff --git a/spec/lib/gitlab/satellite/action_spec.rb b/spec/lib/gitlab/satellite/action_spec.rb index 5e0a825c3c..d65e7c42b7 100644 --- a/spec/lib/gitlab/satellite/action_spec.rb +++ b/spec/lib/gitlab/satellite/action_spec.rb @@ -1,7 +1,7 @@ require 'spec_helper' describe 'Gitlab::Satellite::Action' do - let(:project) { create(:project_with_code) } + let(:project) { create(:project) } let(:user) { create(:user) } describe '#prepare_satellite!' do diff --git a/spec/lib/gitlab/satellite/merge_action_spec.rb b/spec/lib/gitlab/satellite/merge_action_spec.rb index d2f026f96e..1808935728 100644 --- a/spec/lib/gitlab/satellite/merge_action_spec.rb +++ b/spec/lib/gitlab/satellite/merge_action_spec.rb @@ -12,7 +12,7 @@ describe 'Gitlab::Satellite::MergeAction' do @close_commit2 = ['scss_refactoring', 'f0f14c8eaba69ebddd766498a9d0b0e79becd633'] end - let(:project) { create(:project_with_code) } + let(:project) { create(:project) } let(:merge_request) { create(:merge_request, source_project: project, target_project: project) } let(:merge_request_fork) { create(:merge_request) } diff --git a/spec/mailers/notify_spec.rb b/spec/mailers/notify_spec.rb index b1e5348681..d53dc17d97 100644 --- a/spec/mailers/notify_spec.rb +++ b/spec/mailers/notify_spec.rb @@ -5,7 +5,7 @@ describe Notify do include EmailSpec::Matchers let(:recipient) { create(:user, email: 'recipient@example.com') } - let(:project) { create(:project_with_code) } + let(:project) { create(:project) } shared_examples 'a multiple recipients email' do it 'is sent to the given recipient' do diff --git a/spec/models/assembla_service_spec.rb b/spec/models/assembla_service_spec.rb index 0b961c81ac..ded6d87c33 100644 --- a/spec/models/assembla_service_spec.rb +++ b/spec/models/assembla_service_spec.rb @@ -25,7 +25,7 @@ describe AssemblaService do describe "Execute" do let(:user) { create(:user) } - let(:project) { create(:project_with_code) } + let(:project) { create(:project) } before do @assembla_service = AssemblaService.new diff --git a/spec/models/commit_spec.rb b/spec/models/commit_spec.rb index fa556f94a1..d8ab171d3e 100644 --- a/spec/models/commit_spec.rb +++ b/spec/models/commit_spec.rb @@ -1,7 +1,7 @@ require 'spec_helper' describe Commit do - let(:project) { create :project_with_code } + let(:project) { create :project } let(:commit) { project.repository.commit } describe '#title' do diff --git a/spec/models/flowdock_service_spec.rb b/spec/models/flowdock_service_spec.rb index 636aba2f01..cd553b33ad 100644 --- a/spec/models/flowdock_service_spec.rb +++ b/spec/models/flowdock_service_spec.rb @@ -25,7 +25,7 @@ describe FlowdockService do describe "Execute" do let(:user) { create(:user) } - let(:project) { create(:project_with_code) } + let(:project) { create(:project) } before do @flowdock_service = FlowdockService.new diff --git a/spec/models/note_spec.rb b/spec/models/note_spec.rb index b86603dd4a..7a00ee83ba 100644 --- a/spec/models/note_spec.rb +++ b/spec/models/note_spec.rb @@ -206,7 +206,7 @@ describe Note do end describe '#create_cross_reference_note' do - let(:project) { create(:project_with_code) } + let(:project) { create(:project) } let(:author) { create(:user) } let(:issue) { create(:issue, project: project) } let(:mergereq) { create(:merge_request, target_project: project) } diff --git a/spec/models/project_spec.rb b/spec/models/project_spec.rb index 373accfe41..9449782425 100644 --- a/spec/models/project_spec.rb +++ b/spec/models/project_spec.rb @@ -128,7 +128,7 @@ describe Project do end describe :update_merge_requests do - let(:project) { create(:project_with_code) } + let(:project) { create(:project) } before do @merge_request = create(:merge_request, source_project: project, target_project: project) @@ -237,7 +237,7 @@ describe Project do end describe :open_branches do - let(:project) { create(:project_with_code) } + let(:project) { create(:project) } before do project.protected_branches.create(name: 'master') diff --git a/spec/models/service_spec.rb b/spec/models/service_spec.rb index 667c80bcf1..b1b837c226 100644 --- a/spec/models/service_spec.rb +++ b/spec/models/service_spec.rb @@ -49,7 +49,7 @@ describe Service do end describe "With commits" do - let (:project) { create :project_with_code } + let (:project) { create :project } before do @service.stub( diff --git a/spec/observers/merge_request_observer_spec.rb b/spec/observers/merge_request_observer_spec.rb index a450b4d518..6ad7c4d81d 100644 --- a/spec/observers/merge_request_observer_spec.rb +++ b/spec/observers/merge_request_observer_spec.rb @@ -4,16 +4,17 @@ describe MergeRequestObserver do let(:some_user) { create :user } let(:assignee) { create :user } let(:author) { create :user } + let(:project) { create :project } let(:mr_mock) { double(:merge_request, id: 42, assignee: assignee, author: author).as_null_object } - let(:assigned_mr) { create(:merge_request, assignee: assignee, author: author, target_project: create(:project)) } - let(:unassigned_mr) { create(:merge_request, author: author, target_project: create(:project)) } - let(:closed_assigned_mr) { create(:closed_merge_request, assignee: assignee, author: author, target_project: create(:project)) } - let(:closed_unassigned_mr) { create(:closed_merge_request, author: author, target_project: create(:project)) } + let(:assigned_mr) { create(:merge_request, assignee: assignee, author: author, source_project: project) } + let(:unassigned_mr) { create(:merge_request, author: author, source_project: project) } + let(:closed_assigned_mr) { create(:closed_merge_request, assignee: assignee, author: author, source_project: project) } + let(:closed_unassigned_mr) { create(:closed_merge_request, author: author, source_project: project) } before { subject.stub(:current_user).and_return(some_user) } before { subject.stub(notification: double('NotificationService').as_null_object) } before { mr_mock.stub(:author_id) } - before { mr_mock.stub(:target_project) } + before { mr_mock.stub(:source_project) } before { mr_mock.stub(:source_project) } before { mr_mock.stub(:project) } before { mr_mock.stub(:create_cross_references!).and_return(true) } @@ -46,7 +47,7 @@ describe MergeRequestObserver do end it 'is called when a merge request is changed' do - changed = create(:merge_request, source_project: create(:project)) + changed = create(:merge_request, source_project: project) subject.should_receive(:after_update) MergeRequest.observers.enable :merge_request_observer do @@ -81,13 +82,13 @@ describe MergeRequestObserver do context '#after_close' do context 'a status "closed"' do it 'note is created if the merge request is being closed' do - Note.should_receive(:create_status_change_note).with(assigned_mr, assigned_mr.target_project, some_user, 'closed', nil) + Note.should_receive(:create_status_change_note).with(assigned_mr, assigned_mr.source_project, some_user, 'closed', nil) assigned_mr.close end it 'notification is delivered only to author if the merge request is being closed' do - Note.should_receive(:create_status_change_note).with(unassigned_mr, unassigned_mr.target_project, some_user, 'closed', nil) + Note.should_receive(:create_status_change_note).with(unassigned_mr, unassigned_mr.source_project, some_user, 'closed', nil) unassigned_mr.close end @@ -97,13 +98,13 @@ describe MergeRequestObserver do context '#after_reopen' do context 'a status "reopened"' do it 'note is created if the merge request is being reopened' do - Note.should_receive(:create_status_change_note).with(closed_assigned_mr, closed_assigned_mr.target_project, some_user, 'reopened', nil) + Note.should_receive(:create_status_change_note).with(closed_assigned_mr, closed_assigned_mr.source_project, some_user, 'reopened', nil) closed_assigned_mr.reopen end it 'notification is delivered only to author if the merge request is being reopened' do - Note.should_receive(:create_status_change_note).with(closed_unassigned_mr, closed_unassigned_mr.target_project, some_user, 'reopened', nil) + Note.should_receive(:create_status_change_note).with(closed_unassigned_mr, closed_unassigned_mr.source_project, some_user, 'reopened', nil) closed_unassigned_mr.reopen end @@ -118,20 +119,13 @@ describe MergeRequestObserver do it { @event.project.should == project } end - let(:project) { create(:project) } before do - TestEnv.enable_observers - @merge_request = create(:merge_request, source_project: project, target_project: project) + @merge_request = create(:merge_request, source_project: project, source_project: project) @event = Event.last end - after do - TestEnv.disable_observers - end - it_should_be_valid_event it { @event.action.should == Event::CREATED } it { @event.target.should == @merge_request } end - end diff --git a/spec/requests/api/files_spec.rb b/spec/requests/api/files_spec.rb index 2d1f8df47d..acef7df877 100644 --- a/spec/requests/api/files_spec.rb +++ b/spec/requests/api/files_spec.rb @@ -6,7 +6,7 @@ describe API::API do after(:each) { ActiveRecord::Base.observers.disable(:user_observer) } let(:user) { create(:user) } - let!(:project) { create(:project_with_code, namespace: user.namespace ) } + let!(:project) { create(:project, namespace: user.namespace ) } before { project.team << [user, :developer] } describe "POST /projects/:id/repository/files" do diff --git a/spec/requests/api/merge_requests_spec.rb b/spec/requests/api/merge_requests_spec.rb index f31b4da90c..908f73be85 100644 --- a/spec/requests/api/merge_requests_spec.rb +++ b/spec/requests/api/merge_requests_spec.rb @@ -5,7 +5,7 @@ describe API::API do before(:each) { ActiveRecord::Base.observers.enable(:user_observer) } after(:each) { ActiveRecord::Base.observers.disable(:user_observer) } let(:user) { create(:user) } - let!(:project) {create(:project_with_code, creator_id: user.id, namespace: user.namespace) } + let!(:project) {create(:project, creator_id: user.id, namespace: user.namespace) } let!(:merge_request) { create(:merge_request, author: user, assignee: user, source_project: project, target_project: project, title: "Test") } before { project.team << [user, :reporters] @@ -80,8 +80,8 @@ describe API::API do context 'forked projects' do let!(:user2) {create(:user)} let!(:forked_project_link) { build(:forked_project_link) } - let!(:fork_project) { create(:source_project_with_code, forked_project_link: forked_project_link, namespace: user2.namespace, creator_id: user2.id) } - let!(:unrelated_project) { create(:target_project_with_code, namespace: user2.namespace, creator_id: user2.id) } + let!(:fork_project) { create(:source_project, forked_project_link: forked_project_link, namespace: user2.namespace, creator_id: user2.id) } + let!(:unrelated_project) { create(:target_project, namespace: user2.namespace, creator_id: user2.id) } before :each do |each| fork_project.team << [user2, :reporters] diff --git a/spec/requests/api/project_hooks_spec.rb b/spec/requests/api/project_hooks_spec.rb index beccd61866..c8ace0b946 100644 --- a/spec/requests/api/project_hooks_spec.rb +++ b/spec/requests/api/project_hooks_spec.rb @@ -7,7 +7,7 @@ describe API::API, 'ProjectHooks' do let(:user) { create(:user) } let(:user3) { create(:user) } - let!(:project) { create(:project_with_code, creator_id: user.id, namespace: user.namespace) } + let!(:project) { create(:project, creator_id: user.id, namespace: user.namespace) } let!(:hook) { create(:project_hook, project: project, url: "http://example.com") } before do diff --git a/spec/requests/api/projects_spec.rb b/spec/requests/api/projects_spec.rb index 8e0b906767..342587ba5d 100644 --- a/spec/requests/api/projects_spec.rb +++ b/spec/requests/api/projects_spec.rb @@ -9,14 +9,14 @@ describe API::API do let(:user2) { create(:user) } let(:user3) { create(:user) } let(:admin) { create(:admin) } - let!(:project) { create(:project_with_code, creator_id: user.id, namespace: user.namespace) } - let!(:snippet) { create(:project_snippet, author: user, project: project, title: 'example') } - let!(:users_project) { create(:users_project, user: user, project: project, project_access: UsersProject::MASTER) } - let!(:users_project2) { create(:users_project, user: user3, project: project, project_access: UsersProject::DEVELOPER) } - - before { project.team << [user, :reporter] } + let(:project) { create(:project, creator_id: user.id, namespace: user.namespace) } + let(:snippet) { create(:project_snippet, author: user, project: project, title: 'example') } + let(:users_project) { create(:users_project, user: user, project: project, project_access: UsersProject::MASTER) } + let(:users_project2) { create(:users_project, user: user3, project: project, project_access: UsersProject::DEVELOPER) } describe "GET /projects" do + before { project } + context "when unauthenticated" do it "should return authentication error" do get api("/projects") @@ -36,6 +36,8 @@ describe API::API do end describe "GET /projects/all" do + before { project } + context "when unauthenticated" do it "should return authentication error" do get api("/projects/all") @@ -174,6 +176,7 @@ describe API::API do end describe "POST /projects/user/:id" do + before { project } before { admin } it "should create new project without path" do @@ -255,6 +258,8 @@ describe API::API do end describe "GET /projects/:id" do + before { project } + it "should return a project by id" do get api("/projects/#{project.id}", user) response.status.should == 200 @@ -282,6 +287,8 @@ describe API::API do end describe "GET /projects/:id/events" do + before { users_project } + it "should return a project events" do get api("/projects/#{project.id}/events", user) response.status.should == 200 @@ -305,6 +312,9 @@ describe API::API do end describe "GET /projects/:id/members" do + before { users_project } + before { users_project2 } + it "should return project team members" do get api("/projects/#{project.id}/members", user) response.status.should == 200 @@ -328,6 +338,8 @@ describe API::API do end describe "GET /projects/:id/members/:user_id" do + before { users_project } + it "should return project team member" do get api("/projects/#{project.id}/members/#{user.id}", user) response.status.should == 200 @@ -383,6 +395,8 @@ describe API::API do end describe "PUT /projects/:id/members/:user_id" do + before { users_project2 } + it "should update project team member" do put api("/projects/#{project.id}/members/#{user3.id}", user), access_level: UsersProject::MASTER response.status.should == 200 @@ -407,6 +421,9 @@ describe API::API do end describe "DELETE /projects/:id/members/:user_id" do + before { users_project } + before { users_project2 } + it "should remove user from project team" do expect { delete api("/projects/#{project.id}/members/#{user3.id}", user) @@ -425,9 +442,7 @@ describe API::API do delete api("/projects/#{project.id}/members/#{user3.id}", user) response.status.should == 200 end - end - describe "DELETE /projects/:id/members/:user_id" do it "should return 200 OK when the user was not member" do expect { delete api("/projects/#{project.id}/members/1000000", user) @@ -439,6 +454,8 @@ describe API::API do end describe "GET /projects/:id/snippets" do + before { snippet } + it "should return an array of project snippets" do get api("/projects/#{project.id}/snippets", user) response.status.should == 200 @@ -505,6 +522,8 @@ describe API::API do end describe "DELETE /projects/:id/snippets/:snippet_id" do + before { snippet } + it "should delete existing project snippet" do expect { delete api("/projects/#{project.id}/snippets/#{snippet.id}", user) @@ -657,15 +676,15 @@ describe API::API do describe "GET /projects/search/:query" do let!(:query) { 'query'} - let!(:search) { create(:project, name: query, creator_id: user.id, namespace: user.namespace) } - let!(:pre) { create(:project, name: "pre_#{query}", creator_id: user.id, namespace: user.namespace) } - let!(:post) { create(:project, name: "#{query}_post", creator_id: user.id, namespace: user.namespace) } - let!(:pre_post) { create(:project, name: "pre_#{query}_post", creator_id: user.id, namespace: user.namespace) } - let!(:unfound) { create(:project, name: 'unfound', creator_id: user.id, namespace: user.namespace) } - let!(:internal) { create(:project, name: "internal #{query}", visibility_level: Gitlab::VisibilityLevel::INTERNAL) } - let!(:unfound_internal) { create(:project, name: 'unfound internal', visibility_level: Gitlab::VisibilityLevel::INTERNAL) } - let!(:public) { create(:project, name: "public #{query}", visibility_level: Gitlab::VisibilityLevel::PUBLIC) } - let!(:unfound_public) { create(:project, name: 'unfound public', visibility_level: Gitlab::VisibilityLevel::PUBLIC) } + let!(:search) { create(:empty_project, name: query, creator_id: user.id, namespace: user.namespace) } + let!(:pre) { create(:empty_project, name: "pre_#{query}", creator_id: user.id, namespace: user.namespace) } + let!(:post) { create(:empty_project, name: "#{query}_post", creator_id: user.id, namespace: user.namespace) } + let!(:pre_post) { create(:empty_project, name: "pre_#{query}_post", creator_id: user.id, namespace: user.namespace) } + let!(:unfound) { create(:empty_project, name: 'unfound', creator_id: user.id, namespace: user.namespace) } + let!(:internal) { create(:empty_project, name: "internal #{query}", visibility_level: Gitlab::VisibilityLevel::INTERNAL) } + let!(:unfound_internal) { create(:empty_project, name: 'unfound internal', visibility_level: Gitlab::VisibilityLevel::INTERNAL) } + let!(:public) { create(:empty_project, name: "public #{query}", visibility_level: Gitlab::VisibilityLevel::PUBLIC) } + let!(:unfound_public) { create(:empty_project, name: 'unfound public', visibility_level: Gitlab::VisibilityLevel::PUBLIC) } context "when unauthenticated" do it "should return authentication error" do diff --git a/spec/requests/api/repositories_spec.rb b/spec/requests/api/repositories_spec.rb index f73ac4372b..4700872825 100644 --- a/spec/requests/api/repositories_spec.rb +++ b/spec/requests/api/repositories_spec.rb @@ -8,7 +8,7 @@ describe API::API do let(:user) { create(:user) } let(:user2) { create(:user) } - let!(:project) { create(:project_with_code, creator_id: user.id) } + let!(:project) { create(:project, creator_id: user.id) } let!(:master) { create(:users_project, user: user, project: project, project_access: UsersProject::MASTER) } let!(:guest) { create(:users_project, user: user2, project: project, project_access: UsersProject::GUEST) } diff --git a/spec/requests/api/services_spec.rb b/spec/requests/api/services_spec.rb index e2fd945bad..aecd18bc14 100644 --- a/spec/requests/api/services_spec.rb +++ b/spec/requests/api/services_spec.rb @@ -6,7 +6,7 @@ describe API::API do after(:each) { ActiveRecord::Base.observers.disable(:user_observer) } let(:user) { create(:user) } - let(:project) {create(:project_with_code, creator_id: user.id, namespace: user.namespace) } + let(:project) {create(:project, creator_id: user.id, namespace: user.namespace) } describe "POST /projects/:id/services/gitlab-ci" do it "should update gitlab-ci settings" do diff --git a/spec/services/git_push_service_spec.rb b/spec/services/git_push_service_spec.rb index b46022fb2d..90738c681f 100644 --- a/spec/services/git_push_service_spec.rb +++ b/spec/services/git_push_service_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' describe GitPushService do let (:user) { create :user } - let (:project) { create :project_with_code } + let (:project) { create :project } let (:service) { GitPushService.new } before do diff --git a/spec/services/test_hook_service_spec.rb b/spec/services/test_hook_service_spec.rb index fbe9066096..76af5bf7b8 100644 --- a/spec/services/test_hook_service_spec.rb +++ b/spec/services/test_hook_service_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' describe TestHookService do let (:user) { create :user } - let (:project) { create :project_with_code } + let (:project) { create :project } let (:hook) { create :project_hook, project: project } describe :execute do diff --git a/spec/support/mentionable_shared_examples.rb b/spec/support/mentionable_shared_examples.rb index 948fff27b8..3802e94ecf 100644 --- a/spec/support/mentionable_shared_examples.rb +++ b/spec/support/mentionable_shared_examples.rb @@ -11,7 +11,7 @@ def common_mentionable_setup let(:mentioned_issue) { create :issue, project: mproject } let(:other_issue) { create :issue, project: mproject } - let(:mentioned_mr) { create :merge_request, target_project: mproject, source_branch: 'different' } + let(:mentioned_mr) { create :merge_request, source_project: mproject, source_branch: 'different' } let(:mentioned_commit) { double('commit', sha: '1234567890abcdef').as_null_object } # Override to add known commits to the repository stub. diff --git a/spec/workers/post_receive_spec.rb b/spec/workers/post_receive_spec.rb index 46e86dbe00..a4751bd0ba 100644 --- a/spec/workers/post_receive_spec.rb +++ b/spec/workers/post_receive_spec.rb @@ -9,7 +9,7 @@ describe PostReceive do end context "web hook" do - let(:project) { create(:project_with_code) } + let(:project) { create(:project) } let(:key) { create(:key, user: project.owner) } let(:key_id) { key.shell_id } From cee68dec8a9b9531690da0f81fbe1ebdc31a7eea Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Wed, 22 Jan 2014 21:59:09 +0200 Subject: [PATCH 16/39] Fix api merge request specs Signed-off-by: Dmitriy Zaporozhets --- spec/requests/api/merge_requests_spec.rb | 33 ++++++++++++------------ 1 file changed, 16 insertions(+), 17 deletions(-) diff --git a/spec/requests/api/merge_requests_spec.rb b/spec/requests/api/merge_requests_spec.rb index 908f73be85..412b6c95ff 100644 --- a/spec/requests/api/merge_requests_spec.rb +++ b/spec/requests/api/merge_requests_spec.rb @@ -47,32 +47,32 @@ describe API::API do context 'between branches projects' do it "should return merge_request" do post api("/projects/#{project.id}/merge_requests", user), - title: 'Test merge_request', source_branch: "stable", target_branch: "master", author: user + title: 'Test merge_request', source_branch: "stable", target_branch: "master", author: user response.status.should == 201 json_response['title'].should == 'Test merge_request' end it "should return 422 when source_branch equals target_branch" do post api("/projects/#{project.id}/merge_requests", user), - title: "Test merge_request", source_branch: "master", target_branch: "master", author: user + title: "Test merge_request", source_branch: "master", target_branch: "master", author: user response.status.should == 422 end it "should return 400 when source_branch is missing" do post api("/projects/#{project.id}/merge_requests", user), - title: "Test merge_request", target_branch: "master", author: user + title: "Test merge_request", target_branch: "master", author: user response.status.should == 400 end it "should return 400 when target_branch is missing" do post api("/projects/#{project.id}/merge_requests", user), - title: "Test merge_request", source_branch: "stable", author: user + title: "Test merge_request", source_branch: "stable", author: user response.status.should == 400 end it "should return 400 when title is missing" do post api("/projects/#{project.id}/merge_requests", user), - target_branch: 'master', source_branch: 'stable' + target_branch: 'master', source_branch: 'stable' response.status.should == 400 end end @@ -80,8 +80,8 @@ describe API::API do context 'forked projects' do let!(:user2) {create(:user)} let!(:forked_project_link) { build(:forked_project_link) } - let!(:fork_project) { create(:source_project, forked_project_link: forked_project_link, namespace: user2.namespace, creator_id: user2.id) } - let!(:unrelated_project) { create(:target_project, namespace: user2.namespace, creator_id: user2.id) } + let!(:fork_project) { create(:project, forked_project_link: forked_project_link, namespace: user2.namespace, creator_id: user2.id) } + let!(:unrelated_project) { create(:project, namespace: create(:user).namespace, creator_id: user2.id) } before :each do |each| fork_project.team << [user2, :reporters] @@ -92,7 +92,7 @@ describe API::API do it "should return merge_request" do post api("/projects/#{fork_project.id}/merge_requests", user2), - title: 'Test merge_request', source_branch: "stable", target_branch: "master", author: user2, target_project_id: project.id + title: 'Test merge_request', source_branch: "stable", target_branch: "master", author: user2, target_project_id: project.id response.status.should == 201 json_response['title'].should == 'Test merge_request' end @@ -102,44 +102,44 @@ describe API::API do fork_project.forked?.should be_true fork_project.forked_from_project.should == project post api("/projects/#{fork_project.id}/merge_requests", user2), - title: 'Test merge_request', source_branch: "master", target_branch: "master", author: user2, target_project_id: project.id + title: 'Test merge_request', source_branch: "master", target_branch: "master", author: user2, target_project_id: project.id response.status.should == 201 json_response['title'].should == 'Test merge_request' end it "should return 400 when source_branch is missing" do post api("/projects/#{fork_project.id}/merge_requests", user2), - title: 'Test merge_request', target_branch: "master", author: user2, target_project_id: project.id + title: 'Test merge_request', target_branch: "master", author: user2, target_project_id: project.id response.status.should == 400 end it "should return 400 when target_branch is missing" do post api("/projects/#{fork_project.id}/merge_requests", user2), - title: 'Test merge_request', target_branch: "master", author: user2, target_project_id: project.id + title: 'Test merge_request', target_branch: "master", author: user2, target_project_id: project.id response.status.should == 400 end it "should return 400 when title is missing" do post api("/projects/#{fork_project.id}/merge_requests", user2), - target_branch: 'master', source_branch: 'stable', author: user2, target_project_id: project.id + target_branch: 'master', source_branch: 'stable', author: user2, target_project_id: project.id response.status.should == 400 end it "should return 400 when target_branch is specified and not a forked project" do post api("/projects/#{project.id}/merge_requests", user), - title: 'Test merge_request', target_branch: 'master', source_branch: 'stable', author: user, target_project_id: fork_project.id + title: 'Test merge_request', target_branch: 'master', source_branch: 'stable', author: user, target_project_id: fork_project.id response.status.should == 400 end it "should return 400 when target_branch is specified and for a different fork" do post api("/projects/#{fork_project.id}/merge_requests", user2), - title: 'Test merge_request', target_branch: 'master', source_branch: 'stable', author: user2, target_project_id: unrelated_project.id + title: 'Test merge_request', target_branch: 'master', source_branch: 'stable', author: user2, target_project_id: unrelated_project.id response.status.should == 400 end it "should return 201 when target_branch is specified and for the same project" do post api("/projects/#{fork_project.id}/merge_requests", user2), - title: 'Test merge_request', target_branch: 'master', source_branch: 'stable', author: user2, target_project_id: fork_project.id + title: 'Test merge_request', target_branch: 'master', source_branch: 'stable', author: user2, target_project_id: fork_project.id response.status.should == 201 end end @@ -170,7 +170,7 @@ describe API::API do it "should return 422 when source_branch and target_branch are renamed the same" do put api("/projects/#{project.id}/merge_request/#{merge_request.id}", user), - source_branch: "master", target_branch: "master" + source_branch: "master", target_branch: "master" response.status.should == 422 end @@ -198,5 +198,4 @@ describe API::API do response.status.should == 404 end end - end From 7c3a705365bbf014ba6ccf2125c8ea6a6679d40d Mon Sep 17 00:00:00 2001 From: Drew Blessing Date: Wed, 22 Jan 2014 19:46:01 -0600 Subject: [PATCH 17/39] Enhance responsive UI for the login screen. --- app/assets/stylesheets/sections/login.scss | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/app/assets/stylesheets/sections/login.scss b/app/assets/stylesheets/sections/login.scss index 186294424a..a78a9cd487 100644 --- a/app/assets/stylesheets/sections/login.scss +++ b/app/assets/stylesheets/sections/login.scss @@ -6,11 +6,10 @@ } .login-box{ - width: 304px; + max-width: 304px; position: relative; @include border-radius(5px); margin: auto; - padding: 20px; background: white; } @@ -23,7 +22,7 @@ background-color: #f1f1f1; font-size: 16px; padding: 14px 10px; - width: 280px; + width: 100%; height: auto; &.top { From 69ff7657d7741558eff120eb9dfde1c5cab87609 Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Thu, 23 Jan 2014 09:23:58 +0200 Subject: [PATCH 18/39] Fix HELP layout Signed-off-by: Dmitriy Zaporozhets --- app/views/help/_layout.html.haml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/views/help/_layout.html.haml b/app/views/help/_layout.html.haml index fc0ac277a4..a413616bad 100644 --- a/app/views/help/_layout.html.haml +++ b/app/views/help/_layout.html.haml @@ -1,5 +1,5 @@ .row - .col-md-3{:"data-spy" => 'affix'} + .col-md-3 %h3.page-title Help %ul.nav.nav-pills.nav-stacked - links = {:"Workflow" => help_workflow_path, :"SSH Keys" => help_ssh_path, :"GitLab Markdown" => help_markdown_path, :"Permissions" => help_permissions_path, :"API" => help_api_path, :"Web Hooks" => help_web_hooks_path, :"Rake Tasks" => help_raketasks_path, :"System Hooks" => help_system_hooks_path, :"Public Access" => help_public_access_path, :"Security" => help_security_path} @@ -7,5 +7,5 @@ %li{class: current_page?(path) ? 'active' : nil} = link_to title, path - .col-md-9.pull-right + .col-md-9 = yield From ccae561f9bf5ff091760a3a0d7fa091e46d38a59 Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Thu, 23 Jan 2014 10:08:26 +0200 Subject: [PATCH 19/39] Fix selectbox when submit MR from fork to origin Signed-off-by: Dmitriy Zaporozhets --- app/controllers/projects/merge_requests_controller.rb | 4 ++++ app/views/projects/merge_requests/update_branches.js.haml | 8 ++++++-- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/app/controllers/projects/merge_requests_controller.rb b/app/controllers/projects/merge_requests_controller.rb index 65eec93ede..7d56f09157 100644 --- a/app/controllers/projects/merge_requests_controller.rb +++ b/app/controllers/projects/merge_requests_controller.rb @@ -152,6 +152,10 @@ class Projects::MergeRequestsController < Projects::ApplicationController @target_project = selected_target_project @target_branches = @target_project.repository.branch_names @target_branches + + respond_to do |format| + format.js + end end def ci_status diff --git a/app/views/projects/merge_requests/update_branches.js.haml b/app/views/projects/merge_requests/update_branches.js.haml index 6a21551e81..ca21b3bc0d 100644 --- a/app/views/projects/merge_requests/update_branches.js.haml +++ b/app/views/projects/merge_requests/update_branches.js.haml @@ -1,5 +1,9 @@ :plain $(".target_branch").html("#{escape_javascript(options_for_select(@target_branches))}"); - $(".target_branch").trigger("select2:updated"); + + $('select.target_branch').select2({ + width: 'resolve', + dropdownAutoWidth: true + }); + $(".mr_target_commit").html(""); - $(".target_branch").trigger("change"); From 68590fddd860c5d840d8f04314ed11f0d02ddd44 Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Thu, 23 Jan 2014 10:13:23 +0200 Subject: [PATCH 20/39] Version 6.5.1 Signed-off-by: Dmitriy Zaporozhets --- CHANGELOG | 3 +++ VERSION | 2 +- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/CHANGELOG b/CHANGELOG index 981fd0e77a..2e5cd78c8a 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,3 +1,6 @@ +v 6.5.1 + - Fix branch selectbox when create merge request from fork + v 6.5.0 - Dropdown menus on issue#show page for assignee and milestone (Jason Blanchard) - Add color custimization and previewing to broadcast messages diff --git a/VERSION b/VERSION index f22d756da3..a194c18e86 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -6.5.0 +6.5.1 From 5e08f8134ebb695c15bf9c8f1899efdb68c7336f Mon Sep 17 00:00:00 2001 From: Marin Jankovski Date: Thu, 23 Jan 2014 10:09:19 +0100 Subject: [PATCH 21/39] Replace context with service in development seed data. --- db/fixtures/development/04_project.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/db/fixtures/development/04_project.rb b/db/fixtures/development/04_project.rb index 990575306c..50726a5a51 100644 --- a/db/fixtures/development/04_project.rb +++ b/db/fixtures/development/04_project.rb @@ -40,7 +40,7 @@ project_urls.each_with_index do |url, i| description: Faker::Lorem.sentence } - project = Projects::CreateContext.new(User.first, params).execute + project = Projects::CreateService.new(User.first, params).execute if project.valid? print '.' From 9e6fc8b5269f8583e88c67c7cdc356f76a8237ed Mon Sep 17 00:00:00 2001 From: Jacob Vosmaer Date: Thu, 23 Jan 2014 11:19:43 +0100 Subject: [PATCH 22/39] Report failure of DB backup commands --- lib/backup/database.rb | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/lib/backup/database.rb b/lib/backup/database.rb index 7af7140246..ebb4f289c5 100644 --- a/lib/backup/database.rb +++ b/lib/backup/database.rb @@ -11,23 +11,29 @@ module Backup end def dump - case config["adapter"] + success = case config["adapter"] when /^mysql/ then + print "Dumping MySQL database #{config['database']} ... " system('mysqldump', *mysql_args, config['database'], out: db_file_name) when "postgresql" then + print "Dumping PostgreSQL database #{config['database']} ... " pg_env system('pg_dump', config['database'], out: db_file_name) end + report_success(success) end def restore - case config["adapter"] + success = case config["adapter"] when /^mysql/ then + print "Restoring MySQL database #{config['database']} ... " system('mysql', *mysql_args, config['database'], in: db_file_name) when "postgresql" then + print "Restoring PostgreSQL database #{config['database']} ... " pg_env system('psql', config['database'], '-f', db_file_name) end + report_success(success) end protected @@ -54,5 +60,13 @@ module Backup ENV['PGPORT'] = config["port"].to_s if config["port"] ENV['PGPASSWORD'] = config["password"].to_s if config["password"] end + + def report_success(success) + if success + puts '[DONE]'.green + else + puts '[FAILED]'.red + end + end end end From 380342784d3efbecb98de81c9b2679e3d720f7c9 Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Thu, 23 Jan 2014 12:55:43 +0200 Subject: [PATCH 23/39] Fix MR spinach tests Signed-off-by: Dmitriy Zaporozhets --- app/models/merge_request.rb | 2 +- features/project/merge_requests.feature | 8 +-- features/steps/project/deploy_keys.rb | 2 +- .../project/project_forked_merge_requests.rb | 2 +- .../steps/project/project_merge_requests.rb | 51 +++++++++++-------- spec/factories.rb | 33 ++++++++++++ spec/support/test_env.rb | 4 ++ 7 files changed, 74 insertions(+), 28 deletions(-) diff --git a/app/models/merge_request.rb b/app/models/merge_request.rb index c53b24b817..712d01626b 100644 --- a/app/models/merge_request.rb +++ b/app/models/merge_request.rb @@ -142,7 +142,7 @@ class MergeRequest < ActiveRecord::Base end def automerge!(current_user, commit_message = nil) - if Gitlab::Satellite::MergeAction.new(current_user, self).merge!(commit_message) && self.unmerged_commits.empty? + if Gitlab::Satellite::MergeAction.new(current_user, self).merge!(commit_message) self.merge!(current_user.id) true end diff --git a/features/project/merge_requests.feature b/features/project/merge_requests.feature index 4e4ac1a68e..946f676012 100644 --- a/features/project/merge_requests.feature +++ b/features/project/merge_requests.feature @@ -55,18 +55,18 @@ Feature: Project Merge Requests Given project "Shop" have "Bug NS-05" open merge request with diffs inside And I visit merge request page "Bug NS-05" And I click on the first commit in the merge request - And I leave a comment like "Line is wrong" on line 185 of the first file + And I leave a comment like "Line is wrong" on line 185 of the first file in commit And I switch to the merge request's comments tab - Then I should see a discussion has started on commit bcf03b5de6c:L185 + Then I should see a discussion has started on commit b1e6a9dbf1:L185 @javascript Scenario: I comment on a commit in merge request Given project "Shop" have "Bug NS-05" open merge request with diffs inside And I visit merge request page "Bug NS-05" And I click on the first commit in the merge request - And I leave a comment on the diff page + And I leave a comment on the diff page in commit And I switch to the merge request's comments tab - Then I should see a discussion has started on commit bcf03b5de6c + Then I should see a discussion has started on commit b1e6a9dbf1 @javascript Scenario: I accept merge request with custom commit message diff --git a/features/steps/project/deploy_keys.rb b/features/steps/project/deploy_keys.rb index 7f7492bfd6..914da31322 100644 --- a/features/steps/project/deploy_keys.rb +++ b/features/steps/project/deploy_keys.rb @@ -34,7 +34,7 @@ class Spinach::Features::ProjectDeployKeys < Spinach::FeatureSteps end step 'other project has deploy key' do - @second_project = create :project, namespace: current_user.namespace + @second_project = create :project, namespace: create(:group) @second_project.team << [current_user, :master] create(:deploy_keys_project, project: @second_project) end diff --git a/features/steps/project/project_forked_merge_requests.rb b/features/steps/project/project_forked_merge_requests.rb index 57ab643956..48e7627748 100644 --- a/features/steps/project/project_forked_merge_requests.rb +++ b/features/steps/project/project_forked_merge_requests.rb @@ -15,7 +15,7 @@ class ProjectForkedMergeRequests < Spinach::FeatureSteps @forking_user = @user forked_project_link = build(:forked_project_link) @forked_project = Project.find_by_name "Forked Shop" - @forked_project ||= create(:source_project, name: "Forked Shop", forked_project_link: forked_project_link, creator_id: @forking_user.id , namespace: @forking_user.namespace) + @forked_project ||= create(:project, name: "Forked Shop", forked_project_link: forked_project_link, creator_id: @forking_user.id , namespace: @forking_user.namespace) forked_project_link.forked_from_project = @project forked_project_link.forked_to_project = @forked_project diff --git a/features/steps/project/project_merge_requests.rb b/features/steps/project/project_merge_requests.rb index 8ef952cf3d..e848a0b455 100644 --- a/features/steps/project/project_merge_requests.rb +++ b/features/steps/project/project_merge_requests.rb @@ -81,6 +81,8 @@ class ProjectMergeRequests < Spinach::FeatureSteps title: "Bug NS-04", source_project: project, target_project: project, + source_branch: 'stable', + target_branch: 'master', author: project.users.first) end @@ -109,33 +111,29 @@ class ProjectMergeRequests < Spinach::FeatureSteps end step 'I click on the first commit in the merge request' do - click_link merge_request.commits.first.short_id(8) + within '.first-commits' do + click_link merge_request.commits.first.short_id(8) + end end step 'I leave a comment on the diff page' do init_diff_note + leave_comment "One comment to rule them all" + end - within('.js-discussion-note-form') do - fill_in "note_note", with: "One comment to rule them all" - click_button "Add Comment" - end - - within ".note-text" do - page.should have_content "One comment to rule them all" - end + step 'I leave a comment on the diff page in commit' do + find('a[data-line-code="4735dfc552ad7bf15ca468adc3cad9d05b624490_185_185"]').click + leave_comment "One comment to rule them all" end step 'I leave a comment like "Line is wrong" on line 185 of the first file' do init_diff_note + leave_comment "Line is wrong" + end - within(".js-discussion-note-form") do - fill_in "note_note", with: "Line is wrong" - click_button "Add Comment" - end - - within ".note-text" do - page.should have_content "Line is wrong" - end + step 'I leave a comment like "Line is wrong" on line 185 of the first file in commit' do + find('a[data-line-code="4735dfc552ad7bf15ca468adc3cad9d05b624490_185_185"]').click + leave_comment "Line is wrong" end step 'I should see a discussion has started on line 185' do @@ -144,14 +142,14 @@ class ProjectMergeRequests < Spinach::FeatureSteps page.should have_content "Line is wrong" end - step 'I should see a discussion has started on commit bcf03b5de6c:L185' do + step 'I should see a discussion has started on commit b1e6a9dbf1:L185' do page.should have_content "#{current_user.name} started a discussion on commit" page.should have_content "app/assets/stylesheets/tree.scss:L185" page.should have_content "Line is wrong" end - step 'I should see a discussion has started on commit bcf03b5de6c' do - page.should have_content "#{current_user.name} started a discussion on commit bcf03b5de6c" + step 'I should see a discussion has started on commit b1e6a9dbf1' do + page.should have_content "#{current_user.name} started a discussion on commit" page.should have_content "One comment to rule them all" page.should have_content "app/assets/stylesheets/tree.scss:L185" end @@ -188,6 +186,17 @@ class ProjectMergeRequests < Spinach::FeatureSteps end def init_diff_note - find('a[data-line-code="4735dfc552ad7bf15ca468adc3cad9d05b624490_185_185"]').click + find('a[data-line-code="4735dfc552ad7bf15ca468adc3cad9d05b624490_172_185"]').click + end + + def leave_comment(message) + within(".js-discussion-note-form") do + fill_in "note_note", with: message + click_button "Add Comment" + end + + within ".note-text" do + page.should have_content message + end end end diff --git a/spec/factories.rb b/spec/factories.rb index bf74063a30..8c12c9b3e1 100644 --- a/spec/factories.rb +++ b/spec/factories.rb @@ -89,6 +89,39 @@ FactoryGirl.define do author source_project factory: :project target_project { source_project } + + # → git log stable..master --pretty=oneline + # b1e6a9dbf1c85e6616497a5e7bad9143a4bd0828 tree css fixes + # 8716fc78f3c65bbf7bcf7b574febd583bc5d2812 Added loading animation for notes + # cd5c4bac5042c5469dcdf7e7b2f768d3c6fd7088 notes count for wall + # 8470d70da67355c9c009e4401746b1d5410af2e3 notes controller refactored + # 1e689bfba39525ead225eaf611948cfbe8ac34cf fixed notes logic + # f0f14c8eaba69ebddd766498a9d0b0e79becd633 finished scss refactoring + # 3a4b4fb4cde7809f033822a171b9feae19d41fff Moving ui styles to one scss file, Added ui class to body + # 065c200c33f68c2bb781e35a43f9dc8138a893b5 removed unnecessary hr tags & titles + # 1e8b111be85df0db6c8000ef9a710bc0221eae83 Merge branch 'master' of github.com:gitlabhq/gitlabhq + # f403da73f5e62794a0447aca879360494b08f678 Fixed ajax loading image. Fixed wrong wording + # e6ea73c77600d413d370249b8e392734f7d1dbee Merge pull request #468 from bencevans/patch-1 + # 4a3c05b69355deee25767a74d0512ec4b510d4ef Merge pull request #470 from bgondy/patch-1 + # 0347fe2412eb51d3efeccc35210e9268bc765ac5 Update app/views/projects/team.html.haml + # 2b5c61bdece1f7eb2b901ceea7d364065cdf76ac Title for a link fixed + # 460eeb13b7560b40104044973ff933b1a6dbbcaa Increased count of notes loaded when visit wall page + # 21c141afb1c53a9180a99d2cca29ffa613eb7e3a Merge branch 'notes_refactoring' + # 292a41cbe295f16f7148913b31eb0fb91f3251c3 Fixed comments for snippets. Tests fixed + # d41d8ffb02fa74fd4571603548bd7e401ec99e0c Reply button, Comments for Merge Request diff + # b1a36b552be2a7a6bc57fbed6c52dc6ed82111f8 Merge pull request #466 from skroutz/no-rbenv + # db75dae913e8365453ca231f101b067314a7ea71 Merge pull request #465 from skroutz/branches_commit_link + # 75f040fbfe4b5af23ff004ad3207c3976df097a8 Don't enforce rbenv version + # e42fb4fda475370dcb0d8f8f1268bfdc7a0cc437 Fix broken commit link in branches page + # 215a01f63ccdc085f75a48f6f7ab6f2b15b5852c move notes login to one controller + # 81092c01984a481e312de10a28e3f1a6dda182a3 Status codes for errors, New error pages + # 7d279f9302151e3c8f4c5df9c5200a72799409b9 better error handling for not found resource, gitolite error + # 9e6d0710e927aa8ea834b8a9ae9f277be617ac7d Merge pull request #443 from CedricGatay/fix/incorrectLineNumberingInDiff + # 6ea87c47f0f8a24ae031c3fff17bc913889ecd00 Incorrect line numbering in diff + # + # → git log master..stable --pretty=oneline + # empty + source_branch "master" target_branch "stable" diff --git a/spec/support/test_env.rb b/spec/support/test_env.rb index e2bc2a5d7d..43aec1cd43 100644 --- a/spec/support/test_env.rb +++ b/spec/support/test_env.rb @@ -73,6 +73,10 @@ module TestEnv version: '6.3.0' ) + Gitlab::Satellite::MergeAction.any_instance.stub( + merge!: true, + ) + Gitlab::Satellite::Satellite.any_instance.stub( exists?: true, destroy: true, From c3270875edd4d381b11401545b100e7b0408d6ef Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Thu, 23 Jan 2014 13:02:43 +0200 Subject: [PATCH 24/39] Fix project team tests Signed-off-by: Dmitriy Zaporozhets --- features/steps/project/project_team_management.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/features/steps/project/project_team_management.rb b/features/steps/project/project_team_management.rb index efebba1be2..9071b8cc6d 100644 --- a/features/steps/project/project_team_management.rb +++ b/features/steps/project/project_team_management.rb @@ -79,7 +79,7 @@ class ProjectTeamManagement < Spinach::FeatureSteps end Given 'I own project "Website"' do - @project = create(:project, name: "Website", namespace: @user.namespace) + @project = create(:empty_project, name: "Website", namespace: @user.namespace) @project.team << [@user, :master] end From 418660b9713fbb6bad156dc15fafcc80ecd3e7c0 Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Thu, 23 Jan 2014 13:05:34 +0200 Subject: [PATCH 25/39] Fix public tests Signed-off-by: Dmitriy Zaporozhets --- features/steps/public/projects_feature.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/features/steps/public/projects_feature.rb b/features/steps/public/projects_feature.rb index 2292fdad6f..6872872271 100644 --- a/features/steps/public/projects_feature.rb +++ b/features/steps/public/projects_feature.rb @@ -29,7 +29,7 @@ class Spinach::Features::PublicProjectsFeature < Spinach::FeatureSteps end step 'public empty project "Empty Public Project"' do - create :project, name: 'Empty Public Project', visibility_level: Gitlab::VisibilityLevel::PUBLIC + create :empty_project, name: 'Empty Public Project', visibility_level: Gitlab::VisibilityLevel::PUBLIC end step 'I visit empty project page' do From a91faf40221fc574513f7e17a93a0a5a941b8fce Mon Sep 17 00:00:00 2001 From: dosire Date: Thu, 23 Jan 2014 12:07:21 +0100 Subject: [PATCH 26/39] Better ssh key docs. --- app/views/help/ssh.html.haml | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/app/views/help/ssh.html.haml b/app/views/help/ssh.html.haml index 773e490ef8..5d35d18c98 100644 --- a/app/views/help/ssh.html.haml +++ b/app/views/help/ssh.html.haml @@ -5,13 +5,19 @@ SSH key allows you to establish a secure connection between your computer and GitLab %p.slead - To generate a new SSH key just open your terminal and use code below. Press enter to accept the defaults when generating the key. + Before generating an SSH key, check if your system already has one by running cat ~/.ssh/id_rsa.pub . If your see a long string starting with 'ssh-rsa' or 'ssh-dsa', you can skip the ssh-keygen step. + + %p.slead + To generate a new SSH key just open your terminal and use code below. The ssh-keygen command prompts you for a location and filename to store the key pair and for a password. When prompted for the location/filename, you can press enter to use the default. It is a best practice to use a password for an SSH key but it is not required and you can skip the step by pressing enter. Note that the password you choose here can't be altered or retrieved. %pre.dark ssh-keygen -t rsa -C "#{current_user.email}" %p.slead - Next just use code below to dump your public key and add to GitLab SSH Keys + Use code below to show your public key. %pre.dark cat ~/.ssh/id_rsa.pub + + %p.slead + Copy-paste the key to the 'My SSH Keys' section under the 'SSH' tab in your user profile. Please copy the complete key starting with 'ssh-' and ending with your username and host. From 9db8cb3fecca819c2d48fbff9ad69d969a336801 Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Thu, 23 Jan 2014 13:17:31 +0200 Subject: [PATCH 27/39] fix tests notes_on_merge_requests Signed-off-by: Dmitriy Zaporozhets --- spec/features/notes_on_merge_requests_spec.rb | 25 ++++++------------- 1 file changed, 8 insertions(+), 17 deletions(-) diff --git a/spec/features/notes_on_merge_requests_spec.rb b/spec/features/notes_on_merge_requests_spec.rb index 7b91853b13..da723ae39b 100644 --- a/spec/features/notes_on_merge_requests_spec.rb +++ b/spec/features/notes_on_merge_requests_spec.rb @@ -135,7 +135,7 @@ describe "On a merge request", js: true do end describe "On a merge request diff", js: true, focus: true do - let!(:project) { create(:source_project) } + let!(:project) { create(:project) } let!(:merge_request) { create(:merge_request_with_diffs, source_project: project, target_project: project) } before do @@ -149,7 +149,7 @@ describe "On a merge request diff", js: true, focus: true do describe "when adding a note" do before do - find('a[data-line-code="4735dfc552ad7bf15ca468adc3cad9d05b624490_185_185"]').click + find('a[data-line-code="4735dfc552ad7bf15ca468adc3cad9d05b624490_172_185"]').click end describe "the notes holder" do @@ -159,23 +159,14 @@ describe "On a merge request diff", js: true, focus: true do end describe "the note form" do - # FIXME - #it 'should be valid' do - #within(".js-temp-notes-holder") { find("#note_noteable_type").value.should == "MergeRequest" } - #within(".js-temp-notes-holder") { find("#note_noteable_id").value.should == merge_request.id.to_s } - #within(".js-temp-notes-holder") { find("#note_commit_id").value.should == "" } - #within(".js-temp-notes-holder") { find("#note_line_code").value.should == "4735dfc552ad7bf15ca468adc3cad9d05b624490_185_185" } - #should have_css(".js-close-discussion-note-form", text: "Cancel") - #end - it "shouldn't add a second form for same row" do - find('a[data-line-code="4735dfc552ad7bf15ca468adc3cad9d05b624490_185_185"]').click + find('a[data-line-code="4735dfc552ad7bf15ca468adc3cad9d05b624490_172_185"]').click - should have_css("tr[id='4735dfc552ad7bf15ca468adc3cad9d05b624490_185_185'] + .js-temp-notes-holder form", count: 1) + should have_css("tr[id='4735dfc552ad7bf15ca468adc3cad9d05b624490_172_185'] + .js-temp-notes-holder form", count: 1) end it "should be removed when canceled" do - within(".file form[rel$='4735dfc552ad7bf15ca468adc3cad9d05b624490_185_185']") do + within(".file form[rel$='4735dfc552ad7bf15ca468adc3cad9d05b624490_172_185']") do find(".js-close-discussion-note-form").trigger("click") end @@ -185,11 +176,11 @@ describe "On a merge request diff", js: true, focus: true do end describe "with muliple note forms" do - let!(:project) { create(:source_project) } + let!(:project) { create(:project) } let!(:merge_request) { create(:merge_request_with_diffs, source_project: project, target_project: project) } before do - find('a[data-line-code="4735dfc552ad7bf15ca468adc3cad9d05b624490_185_185"]').click + find('a[data-line-code="4735dfc552ad7bf15ca468adc3cad9d05b624490_172_185"]').click find('a[data-line-code="342e16cbbd482ac2047dc679b2749d248cc1428f_18_17"]').click end @@ -198,7 +189,7 @@ describe "On a merge request diff", js: true, focus: true do describe "previewing them separately" do before do # add two separate texts and trigger previews on both - within("tr[id='4735dfc552ad7bf15ca468adc3cad9d05b624490_185_185'] + .js-temp-notes-holder") do + within("tr[id='4735dfc552ad7bf15ca468adc3cad9d05b624490_172_185'] + .js-temp-notes-holder") do fill_in "note[note]", with: "One comment on line 185" find(".js-note-preview-button").trigger("click") end From 4cde3593b91b2aff4681bc8a3cece8be3d194b42 Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Thu, 23 Jan 2014 13:21:58 +0200 Subject: [PATCH 28/39] Fix satellites specs Signed-off-by: Dmitriy Zaporozhets --- spec/lib/gitlab/satellite/merge_action_spec.rb | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/spec/lib/gitlab/satellite/merge_action_spec.rb b/spec/lib/gitlab/satellite/merge_action_spec.rb index 1808935728..25ddf87dc8 100644 --- a/spec/lib/gitlab/satellite/merge_action_spec.rb +++ b/spec/lib/gitlab/satellite/merge_action_spec.rb @@ -12,9 +12,10 @@ describe 'Gitlab::Satellite::MergeAction' do @close_commit2 = ['scss_refactoring', 'f0f14c8eaba69ebddd766498a9d0b0e79becd633'] end - let(:project) { create(:project) } + let(:project) { create(:project, namespace: create(:group)) } + let(:fork_project) { create(:project, namespace: create(:group)) } let(:merge_request) { create(:merge_request, source_project: project, target_project: project) } - let(:merge_request_fork) { create(:merge_request) } + let(:merge_request_fork) { create(:merge_request, source_project: fork_project, target_project: project) } describe '#commits_between' do def verify_commits(commits, first_commit_sha, last_commit_sha) From e013cd44e0da544cd23e0cdb1eed44b2f8cdf494 Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Thu, 23 Jan 2014 13:24:25 +0200 Subject: [PATCH 29/39] Fix mr specs Signed-off-by: Dmitriy Zaporozhets --- spec/models/merge_request_spec.rb | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/spec/models/merge_request_spec.rb b/spec/models/merge_request_spec.rb index 039a0c087b..f1ad679b65 100644 --- a/spec/models/merge_request_spec.rb +++ b/spec/models/merge_request_spec.rb @@ -73,14 +73,13 @@ describe MergeRequest do describe '#for_fork?' do it 'returns true if the merge request is for a fork' do - subject.source_project = create(:source_project) - subject.target_project = create(:target_project) + subject.source_project = create(:project, namespace: create(:group)) + subject.target_project = create(:project, namespace: create(:group)) subject.for_fork?.should be_true end + it 'returns false if is not for a fork' do - subject.source_project = create(:source_project) - subject.target_project = subject.source_project subject.for_fork?.should be_false end end From 71851a7e4e6784105b727ae7fde8fae72343ef3c Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Thu, 23 Jan 2014 13:31:16 +0200 Subject: [PATCH 30/39] Fix tests Signed-off-by: Dmitriy Zaporozhets --- spec/models/project_spec.rb | 7 +++---- spec/models/service_spec.rb | 2 +- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/spec/models/project_spec.rb b/spec/models/project_spec.rb index 9449782425..77467fb389 100644 --- a/spec/models/project_spec.rb +++ b/spec/models/project_spec.rb @@ -136,7 +136,7 @@ describe Project do end it "should close merge request if last commit from source branch was pushed to target branch" do - @merge_request.reloaded_commits + @merge_request.reload_code @merge_request.last_commit.id.should == "b1e6a9dbf1c85e6616497a5e7bad9143a4bd0828" project.update_merge_requests("8716fc78f3c65bbf7bcf7b574febd583bc5d2812", "b1e6a9dbf1c85e6616497a5e7bad9143a4bd0828", "refs/heads/stable", @key.user) @merge_request.reload @@ -144,7 +144,6 @@ describe Project do end it "should update merge request commits with new one if pushed to source branch" do - @merge_request.last_commit.should == nil project.update_merge_requests("8716fc78f3c65bbf7bcf7b574febd583bc5d2812", "b1e6a9dbf1c85e6616497a5e7bad9143a4bd0828", "refs/heads/master", @key.user) @merge_request.reload @merge_request.last_commit.id.should == "b1e6a9dbf1c85e6616497a5e7bad9143a4bd0828" @@ -156,10 +155,10 @@ describe Project do context 'with namespace' do before do @group = create :group, name: 'gitlab' - @project = create(:project, name: 'gitlab-ci', namespace: @group) + @project = create(:project, name: 'gitlabhq', namespace: @group) end - it { Project.find_with_namespace('gitlab/gitlab-ci').should == @project } + it { Project.find_with_namespace('gitlab/gitlabhq').should == @project } it { Project.find_with_namespace('gitlab-ci').should be_nil } end end diff --git a/spec/models/service_spec.rb b/spec/models/service_spec.rb index b1b837c226..46b3bf39ae 100644 --- a/spec/models/service_spec.rb +++ b/spec/models/service_spec.rb @@ -44,7 +44,7 @@ describe Service do end describe :can_test do - it { @testable.should == false } + it { @testable.should == true } end end From 573f1f4ade80cc3b66723ad12594467e881b4510 Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Thu, 23 Jan 2014 14:23:21 +0200 Subject: [PATCH 31/39] Fix project model spec Signed-off-by: Dmitriy Zaporozhets --- spec/models/project_spec.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/spec/models/project_spec.rb b/spec/models/project_spec.rb index 77467fb389..8fe669487f 100644 --- a/spec/models/project_spec.rb +++ b/spec/models/project_spec.rb @@ -167,10 +167,10 @@ describe Project do context 'with namespace' do before do @group = create :group, name: 'gitlab' - @project = create(:project, name: 'gitlab-ci', namespace: @group) + @project = create(:project, name: 'gitlabhq', namespace: @group) end - it { @project.to_param.should == "gitlab/gitlab-ci" } + it { @project.to_param.should == "gitlab/gitlabhq" } end end From f909739f396e71895829955f40ced755f4fbe772 Mon Sep 17 00:00:00 2001 From: dosire Date: Thu, 23 Jan 2014 13:28:19 +0100 Subject: [PATCH 32/39] Split into one sentence per line for future edits. --- app/views/help/ssh.html.haml | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/app/views/help/ssh.html.haml b/app/views/help/ssh.html.haml index 5d35d18c98..1c7b08aa7c 100644 --- a/app/views/help/ssh.html.haml +++ b/app/views/help/ssh.html.haml @@ -5,10 +5,14 @@ SSH key allows you to establish a secure connection between your computer and GitLab %p.slead - Before generating an SSH key, check if your system already has one by running cat ~/.ssh/id_rsa.pub . If your see a long string starting with 'ssh-rsa' or 'ssh-dsa', you can skip the ssh-keygen step. + Before generating an SSH key, check if your system already has one by running cat ~/.ssh/id_rsa.pub + If your see a long string starting with 'ssh-rsa' or 'ssh-dsa', you can skip the ssh-keygen step. %p.slead - To generate a new SSH key just open your terminal and use code below. The ssh-keygen command prompts you for a location and filename to store the key pair and for a password. When prompted for the location/filename, you can press enter to use the default. It is a best practice to use a password for an SSH key but it is not required and you can skip the step by pressing enter. Note that the password you choose here can't be altered or retrieved. + To generate a new SSH key just open your terminal and use code below. The ssh-keygen command prompts you for a location and filename to store the key pair and for a password. + When prompted for the location and filename you can press enter to use the default. + It is a best practice to use a password for an SSH key but it is not required and you can skip creating a password by pressing enter. + Note that the password you choose here can't be altered or retrieved. %pre.dark ssh-keygen -t rsa -C "#{current_user.email}" @@ -20,4 +24,5 @@ cat ~/.ssh/id_rsa.pub %p.slead - Copy-paste the key to the 'My SSH Keys' section under the 'SSH' tab in your user profile. Please copy the complete key starting with 'ssh-' and ending with your username and host. + Copy-paste the key to the 'My SSH Keys' section under the 'SSH' tab in your user profile. + Please copy the complete key starting with 'ssh-' and ending with your username and host. From 42220f2a18f69ab23c496aa93a1b8d528d2d0004 Mon Sep 17 00:00:00 2001 From: dosire Date: Thu, 23 Jan 2014 15:14:07 +0100 Subject: [PATCH 33/39] Remove version since we don't keep it up to date. --- lib/support/init.d/gitlab | 1 - lib/support/nginx/gitlab | 1 - 2 files changed, 2 deletions(-) diff --git a/lib/support/init.d/gitlab b/lib/support/init.d/gitlab index cb2db44c97..c6e570784e 100755 --- a/lib/support/init.d/gitlab +++ b/lib/support/init.d/gitlab @@ -3,7 +3,6 @@ # GITLAB # Maintainer: @randx # Authors: rovanion.luckey@gmail.com, @randx -# App Version: 6.0 ### BEGIN INIT INFO # Provides: gitlab diff --git a/lib/support/nginx/gitlab b/lib/support/nginx/gitlab index d1d959e152..c49dce501a 100644 --- a/lib/support/nginx/gitlab +++ b/lib/support/nginx/gitlab @@ -1,6 +1,5 @@ # GITLAB # Maintainer: @randx -# App Version: 5.0 upstream gitlab { server unix:/home/git/gitlab/tmp/sockets/gitlab.socket; From be150fa9913d760802dc4c673ed59930f03ffec0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=94=D0=B0=D0=BC=D1=98=D0=B0=D0=BD=20=D0=93=D0=B5=D0=BE?= =?UTF-8?q?=D1=80=D0=B3=D0=B8=D0=B5=D0=B2=D1=81=D0=BA=D0=B8?= Date: Thu, 23 Jan 2014 18:24:31 +0100 Subject: [PATCH 34/39] Check specifically for Unicorn in rack config.ru file Don't assume that if the Rack server is not Passenger then it must be Unicorn. There are many other Rack servers in the world (uwsgi being one example that people use a lot). The reverse check is much more logical, i.e. check explicitly for Unicorn --- config.ru | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/config.ru b/config.ru index c45449dd03..e90863a5c2 100644 --- a/config.ru +++ b/config.ru @@ -1,6 +1,6 @@ # This file is used by Rack-based servers to start the application. -unless defined?(PhusionPassenger) +if defined?(Unicorn) require 'unicorn' # Unicorn self-process killer require 'unicorn/worker_killer' From b373158077d7033019172e5105717542d46e326a Mon Sep 17 00:00:00 2001 From: Carlos Paramio Date: Fri, 24 Jan 2014 08:42:24 +0100 Subject: [PATCH 35/39] Project name was hardcoded (oops) --- app/models/project_services/assembla_service.rb | 7 +++++-- spec/models/assembla_service_spec.rb | 7 ++++--- 2 files changed, 9 insertions(+), 5 deletions(-) diff --git a/app/models/project_services/assembla_service.rb b/app/models/project_services/assembla_service.rb index 66ecf39478..ad7eade5c7 100644 --- a/app/models/project_services/assembla_service.rb +++ b/app/models/project_services/assembla_service.rb @@ -16,6 +16,8 @@ # class AssemblaService < Service + attr_accessible :subdomain + include HTTParty validates :token, presence: true, if: :activated? @@ -34,12 +36,13 @@ class AssemblaService < Service def fields [ - { type: 'text', name: 'token', placeholder: '' } + { type: 'text', name: 'token', placeholder: '' }, + { type: 'text', name: 'subdomain', placeholder: '' } ] end def execute(push) - url = "https://atlas.assembla.com/spaces/ouposp/github_tool?secret_key=#{token}" + url = "https://atlas.assembla.com/spaces/#{subdomain}/github_tool?secret_key=#{token}" AssemblaService.post(url, body: { payload: push }.to_json, headers: { 'Content-Type' => 'application/json' }) end end diff --git a/spec/models/assembla_service_spec.rb b/spec/models/assembla_service_spec.rb index ded6d87c33..395aa4a444 100644 --- a/spec/models/assembla_service_spec.rb +++ b/spec/models/assembla_service_spec.rb @@ -33,14 +33,15 @@ describe AssemblaService do project_id: project.id, project: project, service_hook: true, - token: 'verySecret' + token: 'verySecret', + subdomain: 'project_name' ) @sample_data = GitPushService.new.sample_data(project, user) - @api_url = 'https://atlas.assembla.com/spaces/ouposp/github_tool?secret_key=verySecret' + @api_url = 'https://atlas.assembla.com/spaces/project_name/github_tool?secret_key=verySecret' WebMock.stub_request(:post, @api_url) end - it "should call FlowDock API" do + it "should call Assembla API" do @assembla_service.execute(@sample_data) WebMock.should have_requested(:post, @api_url).with( body: /#{@sample_data[:before]}.*#{@sample_data[:after]}.*#{project.path}/ From f89df5b496b3d2f64c9c7493848755c5baad46f4 Mon Sep 17 00:00:00 2001 From: dosire Date: Fri, 24 Jan 2014 09:14:28 +0100 Subject: [PATCH 36/39] Do not branch from master until release is done. --- doc/release/monthly.md | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/doc/release/monthly.md b/doc/release/monthly.md index bad7794d42..17f69915d1 100644 --- a/doc/release/monthly.md +++ b/doc/release/monthly.md @@ -58,12 +58,13 @@ Check if changed since last release (~22nd of last month depending on when last After making the release branch new commits are cherry-picked from master. When the release gets closer we get more selective what is cherry-picked. The days of the month are approximately as follows: -* 17th: feature freeze (branch and stop merging new features) -* 18th: UI freeze (stop cherry-picking changes to the user interface) -* 19th: code freeze (stop cherry-picking non-essential code improvements) -* 20th: release candidate 1 (tag and tweet about x.x.rc1) -* 21st: release candidate 2 (optional, only if rc1 had problems) -* 22nd: release (update VERSION and CHANGELOG, tag, blog and tweet) +* 17th: feature freeze (stop merging new features in master) +* 18th: UI freeze (stop merging changes to the user interface) +* 19th: code freeze (stop merging non-essential code improvements) +* 20th: release candidate 1 (VERSION x.x.0.pre, tag and tweet about x.x.0.rc1) +* 21st: optional release candidate 2 (x.x.0.rc2, only if rc1 had problems) +* 22nd: release (VERSION x.x.0, create x-x-stable branch, tag, blog and tweet) +* 23nd: optional patch releases (x.x.1, x.x.2, etc., only if there are serious problems) # Write a blog post From 17b422cf97c9f66ac9e87f9e22480042ccb37ce5 Mon Sep 17 00:00:00 2001 From: dosire Date: Fri, 24 Jan 2014 12:09:33 +0100 Subject: [PATCH 37/39] Jira integration documentation. --- doc/integration/external-issue-tracker.md | 7 +++++++ doc/integration/jira-integration-points.png | Bin 0 -> 67854 bytes 2 files changed, 7 insertions(+) create mode 100644 doc/integration/external-issue-tracker.md create mode 100644 doc/integration/jira-integration-points.png diff --git a/doc/integration/external-issue-tracker.md b/doc/integration/external-issue-tracker.md new file mode 100644 index 0000000000..fb645a5c9e --- /dev/null +++ b/doc/integration/external-issue-tracker.md @@ -0,0 +1,7 @@ +GitLab has a great issue tracker but you can also use an external issue tracker such as JIRA or Redmine. This is something that you can turn on per GitLab project. If for example you configure JIRA it provides the following functionality: + +- 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; +- textual references to PROJECT-1234 in comments, commit messages get turned into HTML links to the corresponding JIRA issue. + +Also see the [screenshot](jira-intergration-points.png) below. diff --git a/doc/integration/jira-integration-points.png b/doc/integration/jira-integration-points.png new file mode 100644 index 0000000000000000000000000000000000000000..0692a7b458a3eef7486c0c665b16eb4222cfd11a GIT binary patch literal 67854 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 z z>ub}ix}~_$lv8qM4JCv#ChQ$O#Lv2>^@TBTLJ7HUi?ncZ#1;(*3XWs%+<`zq}gPBAwHfrp0C} zVnx>%TUFP)xdDK&7l8NuTF~p`VMSYp&WuAnKp_%x0gb9S8gn6FywKe(cQFT)vjq!P~OXRMJvHKPFFCU)i(HzPnbpUqmC!M@f^%gTiSp%rU=Gbe({}#;N(_+UK=W zFmpM1FG+>H@Vw(?VZm#fVXUpMy6f^zh6qTx=L8#z?V3DhZW!O?R6t7XG0C6>&7#Qi zqE`(VDd9u`@zk7OFW4P%>aH*7M|UCcx+AF+35Apl%9iHIk2VFzaAOF>gy-m;BeG0W2VA4U0b8M*hw(q2lgMlZmq)h9iMQ*MuyHKTkvEty3!?l8N2l0cSqAICP6&UqhI6+vMe3FU)#F) z$UNd7p9iTiVlYJuao3Q|%KLqSD1 zY|1*}w*>-|Sxh+6OCEzGBZjvJJ$>db^rRpq3 zXSt98Z7j4SgSP0OUCkV2p2l3UaF@7rvWk_fxRI{@}AzZbvLQu43pX zlF%U~s(j$1z1eGmwI7+cZpQo_7dkq6+kOnE7&SXe)vFQEQ?;#kBo{3>`QuNi0|y5O z4wN)5?&Rquf-_v(y~+V%Hg$I-(I;EcWgUjNm1sc`5?$JnL)I};q;hph$CLGG;8DuP zCdl&R6kBTnV{;xB>&jSU*!AHhG2+pvDhcuC(c#D7QH-SCvZ|W&3O%9 zkWfj=F^+uGe2Xs`1?b+e*gMHt3_T$^%o8YP4?>G+2I!Wqm|6)6$V9EKouo#wVl1;7*G3ppZPe> zrKKkxN@|(})Z)!bq>Z&b&rE4)6`2|_5{p15+MIa(G6~EYec8bBRDU?*L~SHRVzI%2 zm&{ue6ty~oQO#KKSMv&qOMwuu5b~-t^vv@>cgLJZR_W~_;3E0R+aKuW8k7!Fq+d`q z!rmo*YJqt927|X^ch^L3IbOraJ@p|qKb)-;24nsDys-5hi1mFpMEWh`LJTRP6Etzy zq{le5x_Q@cvf`e$S9cIm9EKND@1+9U@QB5?EK=G}J=3PuLk5UQ%2_$^^^8fm z^Nj1y&B_mhew<%Mu@1{YQO1;Ud>1Yh#9MUYYJPtlGk%=68ljMvJ2S-_uAw;QmyTgt z%*N)NIl=(N?P97@^mWfvuITI~?3No(=pg*00$Kfifu?&w+G~+Zsoc=-E~CQ}c3NrpLj1s``c{Cc5^Sb>iKpQ5JbM3JW$ zuw?(?WcmWF_2|@;a@abE!j`t<6tmNSyCKFwe|ry@G&LXu6!Tn$88$nmr<+M9Wde=6 z)|p+7$pVu)nY7%Y)<^emZ#fIAOls; z=UbZC{4j|}U#G;*_AK1bc~H#wX46)zfp<$^Kc-Z<8b=OQbW^gLnn%gOT7>8O1=(a} zxz|p45kr8_=WAW+hKpa zL_mKGN|NEw-}5hw2)HGo@mPBek#L#Hff2|}m!#tR)9jWUQ(8E(JrMV1km7x|IO?&j zEf)gZkc+GMH8E&mrNt#!MzE?r4OOAk2}Y%XezmqYCrRu@?rSO+C7Ct~TAo58BClqV zIb!Q%>t0$Vn2Vf%XLdTcAi7-Al1S)WlnhZ$Nbgm<7jN7O@dd873Sc;bDB(Bxgs|Jkx}vj2Y7 z`YAZAhL&L4EDS8L_;WR;#lXu3&uYGHa~q^t8(6<^xgNW#Xz}jLYv>O_@xC*UOmh|HcJb)WM==IijK`Du`E5Z~45DO<$FLE@c%&VnvDvq=Qj%pU?XI#iH&Ko<5c zr^cZKSmrAk5R<<1M;OTl7Pi^wbB+6aQse{f}m{>T0#-brAZ36`c5YZV!Zm|_j{MW}=Gee|;fXuSx zNcx8X5*02Xf?UKp&a+lHiIgRa|A#ryAwYm6O2VnMHdbR$3SLaH{0#UNmy+Ypem7kR zsoy{Q6KGaS#|CrERD+V;z%XFsrC_vKil};TVby8~*3$OZ*ZVa|8d+@!$yRfd8lps_ z=mis^zv_>KZ;L~yV`60$qyB?p=*=Ri@l6mr*v$gvaAc%&Jyc0~efiq-eSPksL4=19 zg|>Jc0|AM1V}KA&fh{dWDZ5M!Bjctusf)W-u+Ap--%8E=ow) zH5rk#%)n(Al9t<2G=xlAP{O<-M08ZZvduv6*9UD^+l?{T?Jn-Y8hR1^<2Pc`XyP_j z7LH6x;I}Cv_BRltmxriV;PQN}FC;2TS(yvtAMjp_KI%f9U=k=Jfe{%NMy50y6!=hU^=r%59dLMVjEvnK z%KnD_8}cYvD?YdkRI1|0COZPNl==v$vNv6OZfiRgZ|IqJLvadJx~( z6bne6Wb*%<3J>D`hyU;H0Kn>r((0O!eI?K)=A~ICmOlQ>l6swR%gN~3>sMvWY` z;;X5Hjdp4{4N};q6pVIM^9alX{d2@Um4Lysov zV*WpvSr!e@KtPpwg)Cq(@oX}7Xvky6sf1Ytg;|8TcJ1}=hXt;HXmKp-rp;>4UFEqf z%EI>C3j}z`Ktc|%m{EDVLDD>C8!A3e@R#!Vf8lTee6omag(iUwrpDBg!%*<#nKcKN zW)m^}b5is5j6`NYfqJo+q02!xc12POES%zpOc^#OJLvO*<|Y52HQ!bs1@e(z{^77J zbU;N5zCPeSizqJmCp_mVcQM685h5c{Kpzf@ADX&cAOE3f$Sf#0Wwvg9TV#aA0ql5o ze%-ujIo(lqFg%7IddDIh&myT?d+qF^dN$ExNw2=o%+f#p$q8%LDkOXzV^s-0v7KMO z^06(ya5yhHEYo{WiLIn$K*k#7cG>Wr=s#e{Uprfcc+J^RQYGoq@FOG3dlu&zsUtyv zEsV+;#R`z$EG$e!TaD;cU|^0A!SqITT>0WtLku{nm3yKlIi7G}TO?NOD$xXoz4KPB;@ zv`>+4csq>QN|Hq)5LI3MYc<1RaB)daor!Wu(kw<+=wmUxESCYhdQsNa`XNDD2J*iT zX&-u&Ux?UnUIKG5M@IMBYrhGbi&b#;rl}K*iy@v&JVhM=4I;Bq)D>PQgEEH+5hvre zTfggeTGkDHA}w>Y#6j9*Sy0J-&Y9ATbCquQG78h>%3|AF&OQbHK6fG$i5+T#{rA!$ z#qNejy2{O&jJ{C$6G;rlBM^lt^s0;774Mo3ScDp{364=|fz4dZRX>iC)MfsQV+Zu1 z2lwTDpS;n=BoH+9v_i(rxc2w^Ol|_dFmN)nppzz$=G$mB7#zuqqwJDX1}(U6%ElW9#i!$#HZ?dT?r>iBl2?m4Rn zF6U&!SlmHn`=Z%AyPFs__`G%*jYs^gPM}PX;y52Jk|gr~#2`Kdwm`(6b`2$QNyx@# z-e)Lm4ZOtjd+h3Y!6aZwQduDpH;Dil2ze4yX=&vk(chb)MulN-8B^TGQ9n&eX zr?gjcsf>7-|`})(=(FBCy|b>v-W_Ef#11{E23{Ni;)xnOPP`r|f|$R0(`tQo*Jk zF`UpCGtaoA&Cyu%eN6gP(Va=5ZdkA^L`ijBBC(aW8jM9NBJk-Wl!D?Orzj^&E|&Wnudmi7~ue{%q-*;iiA@X(&J+yQgiz7 z^Chs+evcK*v(p)z1a^*FdPs=>6dQ!#1ARy=|7hT6#I&a6f_+QPb?;Ng%#9jAZ`3DN z{XxZS=zxlZRA5y>jUfy3(;Q?9n5Z={W-$66(< z(%+;j$C>7SryDR2y@}BO+`~x+?w?W#fBgWy-fy2ntA1&>>Rudaf^j+p+ zB8pKZGR@D=-<{GRJmsn4$T3T75#FX3?i0B=@c z->x7n4O`XBoYr8-_-j12^K@ZS8)o3icl6aHzM)+%KJ1?uxZ4YHA6``s(*L^0*eCj3 z1W1X?3o3e~8>E*|A}k_8Ataq#(k_c-XB;Qii{EGXi^aMM!Y`3e>YwN7S`_5I+d4^N(dw$_5C5XX7*Dm+HYfyX0V+0j zbs4vC#^*KqP`VGDKQgeKtnt5rTOJbOC=j-H8Hg ziW!5sqN?}q&D>m3(4444mUaG3BS}eL9EnPmlO>K-d8ThGAAbN>`y zks4U1hh*!qD>ukRMMf?x;|VT%09*Q$t&~`E!*TS^LdkrHzjWxP-b44^ZWo0b~$6omy2Ee}jw-$-1wq5#g+qT8F1q{J?H6!p1!M@-p9EL28>XtL>z30})8a%n>F2c_WPsd#kB4X&jVj^7^ z!ZAH#T>>Y>$5C#ZhcAI+jsg4-1q;3fjarw8k}5`5jHzhBF#0o=uAwVtR!c81GK+Hw zSuEN{{mpZ^|48zP>aS5jy|SyR_|Ud{wZHt!f17aDa4f_6E0wM#Eg54Hu`n+?t-|Ym zYs>Mz=XLvtY{m!J_HaahYN;to`Kl4#15QV|50n3H34z3#>cc=`Dc2toQ}WuaE3Jxo z?)io-!(#L^Za8@a?GE+PG`Xfh!hEu!p)$VC4kbkz&N*9^VA-In<+t`?=yacRWr&HC zB(Ep%)#38Oq0we9<`@Pyj(ayz`N}m%3ynpXzrVn^kDww(??|`E^ahux| z1yPIs^bt!}eB>fZB|Y!lVoK!?+o~CX$zMwl)Na6_@sV{FJ_L_89)RpWdNcO0fprxZ zoV!RyfFt=%wx>qdd*F*vn&u_-U=-%RJ!N7>IJ7lsMa0SLb2HXhs#}1BR2JADM{@bx z{Y`r*3nRCpjK@7%mIR=pVk%h=fDq+njcijj>=3Z3us6b_T-Y`&Lxc7RoeUE5FL&Fh z%a)K)t_*s6?vQy@EaKn=4-N)hy*YG2=)H#c)43z;!jBK-5Mm=$3GFB+7Z=IkKrk5- zR9Sf@pV0}gj)~L1&l$uJ^BiW%*a_a$&{dyv zH@LGUKd%U2qXn(0wZw_Gm|O^b?jvBU-N{yUftk^PEJsr;C{K~Dv-r$OUIqpasF-tQ zzdo8%ZWAj!YOOIINj-LR%hq6PKa;b&l!K*k|L(}0%5WW#mYv5NM5`g_GGcyCBhjLc zNLJ{_%gy&bpT6|3p202}bpvwSJnJ!yOJZAr4=OO&=HK77-kiRP9S~NnIpG z-N7ZnV#Z>=>2oss09_|5Hec}cWMepHklt53mvUgPEm7Lp6lvt4cec z1V&lyw3r(^mv_bxU6D3!tb9SJ@9bwC7Fiy-QF z5<9#{(PR&nCC!Wy4%f~~)$02*#}6VOwALyyd5H#8o8b;q$?L7o6@nqXVbfafNY+Nl zBujt$^tMlu($fLgbZkv9V+Q`C#wH@u7dR`t0v7L~2Q>r_h%;Re%-U$2NaY2NN^W-n zpu~z#n2HaKH@$_SXh)Q9L)RpJpw!26N#h0}Xac)f(GIq!a@vcsi&KbQ_nnHWd~gKP zzE7>*9~;(DYrt9U_-z@Rx83Bdu?jKibZU(qi z8&J(F-V?#fE52Ev>DCS(qAeSW(n!ktwV^j6O5k3PD);vNNqqS5=}ors!8&tgyPAP@ z{QzrR*$jt{zqnJE!}#+UdPRAakDA-t3Y>d2BSOg_-ij1A zXCilnZwTgvJiAr7lCI|YU)b6ae!N6ptGh}Eu< z78@thQfDi2vwg@r_Qr`92F-MyOH((e_nxeJ##v>(Cm~|>{PbtiyrtBgQsa9X=7YV0?x1Qcd<5u1eT? z)St?Fmnn&3N7ur-qib#Li0;9qJ(Hq^ zk)4nR1CN=s4I3-4zP^GCgQ~A3!&Oz(@TFF*SRvaJw(1~25xgJf@7v@X!Op!M;AgsS zz?_YaayT9|%iCVf2C2tq>9Ob6?^D^$t9R~EE1l8Zuqc1-WeSQvD-=@=r`DImB8zaV zFyXzFVyjL*?j4gu$|~H*)$0jc2@^ zQi&EvqQ(O779yfTjojOya*<&8(4yswG+~IsRzbQ}5jo26@D17M-!ENpFPMEx@Q5EM z5q%9t+mj|(+<>lb<0{7BY`{cl^+MdM)U`u3n(8;veOA>ymqKO(ZryQYCJ5)+Ni`PS z{FSLCvcapX8Qr;jMW8R|gZ4-3vLr-#Lw4VGVhH){Qdzd?LeTDE=|t$W(@a&E;vsaM zzP1~ib;tY{_mhnkZDsBiYa%)J#PrlqjQ2xYs{s!ZBs5&9qb&y}CkC3pp(>{m<`5;vBPV|gCFN2_#dNt2nh`EthM4d zFK}b5+Lt%)H?o=H9IZ$3!#=GWX%xL{NGbb|l}D6+N~@^)v}fY6ZM}I~ZaN1xIHknb z?o2zV+s{Mjfw(_4HlmxBNo8I0^B6Njw@Fj=8En)Wv1V*0e+@rOgN{GMo2zxZFc=Va zwk-!^1JyGMW9ejfBR-jU#(3zvcU`@9P%Je5{24~Jwo7Dj9=2>oq>Rix_5QZ8ihsd} z(?AKY?bzuQKjO*<{6J5~gxn~oGjN#=+NP%KC-9n4{jF&g>xRW8)Ym*%ow>T6M~MNZ zP#$^OQ0ZV>hP9YD@gMBOW}4yprkqg?&U{xB6J~1+ACDsop>?qUDP9qZ#~y#u?aff> z%t-r*0-AA3M}wakt2D(ygrh zqC%D%RabDSf9QCEi_G|JTv&j_Pcs@e+4;XK2W-?m#XE-ALqUuNT|*+2Kgtfn!LcIv z*FA_{uY?SXlLy{n(T84!Ac!>wl~)!-vYRt1;QR$Uf)%B1tuNE zmbKrSE9H(%kAilX(?4s^@b4^fO0nka_OMQ899-G)<&79svvUFQo0Rfb*Cd>;47aXf z!=ghiky(Weu6yF(A!{>An5P_rDMZ@1>67BL5qC#grjLs%)IVEWdO8Yjm?m$Ry-yZb zy|XXpY&?=MqZuAO8WfeRo1s?Jz8<;?_!Fyc7r~DQu2=EY^wnn-^4%f@A%zph{6=hx z@`ve=cr|DO#o5uZlVR4ZecU_~Mk_IR%BI9$M$?Ua=Oh*5m}gSTxsk*Lo%*)9Ig$S)c-Y+jd}_ zsUjv65Ff`k2l{G*7$|3Irmo(@95*&xYoKmXkWc&$uDrRT@4!#l_s>+kIj_axUpA!0 zd+50mcwR?e`*9ttO0ySz zXo)3FKze)t6nX1YTf1<^9thGg^q22wzeL* zy*mYmYOQUKtT;OW5X2uuu_j1)OoS;HYrEB$!V*zGg!9I8#OjF+5h(B`U$_BfKB6M4 z?}Uf48c}}3^_5K{f82hYy7SST%u2CX9am`cpGasEtIO_2pBr?TLfxz*&$OT4rh&kX zeheqFgc+e49Tj%e_+CoSY`c0h#XXs#QIYleBYy6Th_ohoxbzH zIr#CSh$H;{k}BkeU{MHt^9ogudHd{n$g>h>ct^ONChNLi$YKIyyKZ+NrhB4Hz|by6 zi0aQZ>MM%K&>!zx|HH19+Z;#&K*oT^z#^uMRXP7O_ryHzae4b^_3>x9Ebd$3e6Co= z>w?yW5%As0cF>-vnaNJbNLB)tLKU@^V5889YU<2uk^4BN1L%)6xO@XJyB{-Y=HateJr z7gW`EopAed>ao&7s+P;-RDR^+JEg}yyJ_8DU1a)I9JhEg9Zov^7@u3ygm7@#h;Qi7 zSw$t+txO*8xf$00v|@ai5E%x$%Jl{pYx%jn^LqmaS!MH6adnwDa;tM&2(XtgDNl6$ zwwZ{Tm?Y4oR`*)Z{vfIIvC1rGY?N>e{J*W6V4)|HJg zFCV_OkQ958*A75D_6rchGBRQFHjxv7iCU0e=}P?5U&@delLPbRL_u4&ePwBhnQ;nY zDN(3q!Eq2&ZHg%~mJOdh?&9Zn6yc`k#JLb#T~(2?&(v>?yH$~;wIGN%kjO6_Pg=Nd z-GFPh)>2*Y@22~F@cEN8fZ$h<=^H(^P*N@);la3dxTy+$$ zN65o{Dqm-lgpH4Q&qcG|k}NzFwBTT1X(;b;BH(z_D+0qIyGn)y%kw17R15yz>0YXZ zQsdW>y3;B1G>eDre$1SUYLSPVOw;n9-y3AiLX6C025i&XFyq3iWZ^jBm>-G7_yjsS zWmGnftG1ix2lXGn?)uDqyj(8Kc3o1!UmnbHSnAOmZ^NZR>pTT*h?f71aY-j}$y<*j ztjn-?U+rCB%T`;}19zSJ5#_} z7+#uKr7_>b=Ov@9HT&qE7)&CgMNazB=D4ZrqC%~_zqW8o=sBeYq;jb<<^x@Roa`u{ z7(*o~Y4UK z)c7e`zg9JVz@V~npB%V$sN|VI!-y_qh+@g^jqcGH{3cxl%(Q&8y=gtCC$j7y3 z2)bFJBbpNTlz6%|XgEsQRKz~~6%0I;BAumj?we?moC;7SdwG$lQJ9bf-NG!oa=&4Oh1?S4Mh#b3@Ij+g~4cvivJIoOgwFr&ia{BKFj(!e23#t zfk7YCv=BTK(mu(#ql+5^Z^BtB$NCH&cjSLPR6h_gqB;epC#IL`#N-RSrwJcH# ztx|PpuS9C$cZD{Rq{zQ0FAcam53Y(e>lEG|c9fHoQ%OaI2oQl5^Jzf8fe80;BTxOo z1G9>2<7eZLhQx;6BDl`1XgM(z^l>7-Q^I>t*2=;PMlsbcL2RBc7Nw+;!vmWn*#iC_ zyi)+_S{~e8b}Y>5aNmLY~%=}{@wDW6lfPvqy|57_zJJr{&mz=Sp1BPWm zL1K+4vYSMfG_3ex;;*0eSFXK7)z+wy{c}ZY$p}YC2EQ1|j~~H2P9fA5*2yJdD%MEf z#moL}%zOjcG9TGMishW{+z3 zd-4S;G*XGoLQzqX02M|g?-1lK-oI%*?=XSv5u7J6ax1HTKtyu=2Tr+&1}}~?2V$w7 zC#X(+dZKK8(BXOOG+j3+jz-aGgAEkK+pLkH(e1vF7FdAdbyRCfI)|#F zOWkP#1!|45Zj&PF!jZWkL+XDD4*Uc~w;P7jR+WAr$Sk{lDEzPh{nUJAbF zf(fM4;U3K}nv+VVKjum2NKYw5#Cahin@z01zAd_J6G^6VOMRhXhiO zi8Co0HBwBys)T7GmdE}6_q`EqLqgrdYV3J48tkR!ozLdi)+!QP$}DqKRh9|detwYz zCzsw5VJ6DsvLmbxj^(6xenUu*R4LH4fdQx)vE@5G4b}M6U_aIw5tOF9tC7j|%$xud z%lHAnWLi*3P)G=ky{=Tasb~1=92gttziKcE1^-Dcbe%-~A!KoVQPz}<@f$EG;;kdE0$(mbYA zsc_q$7!yP!k{X!ojb@7~tA%+g6|sHDFg2y?J=Dmn3b7+OB9evEZs3n+O(L>?n^R`;;6ExHIVj3Zt4OAWktKGl21?AS4E#6cpV0~h z2c==ek>ct~YE5gbESa8P2r(1%5=z4t7@IKEnOE{`na&8&hMhVsBOAg-j7>&=oAwyV zBdH|eF`~$E>oDDR<+v^3O;MV^S{*!Nq?pVBtxA=U3k{_}W-2qQo(70-h$fRQFsF9- z?+hBb^0~-0lMF@DsVf85P3@(sL zOH?uYfntyv3!`%juDMEmAE|Ih70;aZXU09z>M0tn$37)ggZQFT0&^i+ONi9Y@cnm& zj9gGsfti&L;8a$1VT6p%HxyTTR{emAnOAlHzvG8P1pl5AH$~05kRkNP962urlepouKwdIIvx$us1uGqjj7(74gRUJSi~u4~v_$f|kKQjZ zaaHp3ecgWV4lGJ4&}bkJ76kHvSRGj{pF2w#;72YsAM{};r7;Et>d)j1CQc(vyp9`A zr&da0^8o$neWFU(@_+k=pf$14id4T2G3MFRcZ~f*dyu9^^ZqBwz>CKo%#gz{mplCLmv?N>^zq z?>(H@68+d9!E4pviO~q=Y`Sh>4w8mrKmm=7gDb$L!;xlIUi#f^k)~`ktU$HLpz+y4 zt@sWj4Nn0VHAK1grX)<7h~NB2P+)CCWT6=~=N<jS{gRnxv z`cqd#GE@)+CcWxmR<4~w zUp~N#t;>}|u_Q!kI7)EfNF-^<&oVn#&qy7$bjwVt0QD01RBEO@4qKT`71m;;hF&bz zQsMtt>@`35yMIM%|7=`K?YwMK#ZA^oS{aw|ZIP~Wp`*+;$K-(-m5o(JNZ5QLNI@H1 zO;haeDr~Wz$48x;hDDX4l0)XK4Ws_Sw-&3r2z7*xNTm+3Q|!@eRFmmZ^F?g=VPuAW zHL(SePjtcG8e*juWGvLA?MmXK!^je7lTz&0b=(1gkzqKtw2I2r_FPUzRwDj~-XRkI zmNsB%Kt1DYIELtv+jJa7Nn+WS?aLFrLQgieA;o0YEkhtO`0+DNVPWI!i)f*lV!R&@R?Q98#SvK%x4f zHXU2e9^YV}5%#z3mt>06;xkVI(}TKfd2-?9#@WvQh6708D&UipbwzBN|MN&9s7N$$ z2^liM|IEk#t>Zm<{}3!xlagNiFJpu6KYR_%e*aOIf3mgS|6lkThSS!;{_CxXpq`n4 zm3Z&2b_M4DdlgC}!Q)@bh<~Kx7Zb?N%)A%^dXE1o97+xL?bR1hPyiA>pdcY3*%h&F zU9FaLI-RP#l^u95@tDW{SMCgRDD_IUf4Cx=nlQ}G&4rfb9KVUeyQh7V`Zrw+44*`N z$t~mJ;(!GM0+NzpN1~jktUw@47~HZ`O!nu$!Gpg*GgJ-r{r*V8Mo|K|4r$Jk8H-MF zZ2A9=;T{Aee+Eh|Op1dS{I`Ga$qq%UJQxT@Tufrl+zDEGR7nYCjk`eKuux86A;eHL zzOb@#f@jNjw_{b|C;L6X!?2AMpv)9(UQ63Ut*qcS$TxUCClB%=C_00X5xmKIEqHu< z9E4_T3&zIUTGY#nx2(LJ$@yHJ*y@u_0Bo7y^ZDrLC}0HiOTa)fAh1`s$FMf1t`21= zhHz-URJonZibu`O&25wx(9GyyH&9q>Td*g0)yX`My=XY}CYlFVdK^O|zG zBVuf1MfTGcziXq2vB66l^pH3<5LYh0y#0oLipuLf?)br(t~jvzf^wUeZ^>j$gV8-2)=xRw$uU~%CHyU$G>zL&m1${(rua~RfZh%4cF+&>FyEvyowe{!{e!c zs^(&hB!ff4uS|L9X2$0;=*^}Rz1!Q|HhXPWr}J`Yg5q)KV}mefvFv2&RkIvnC!a2) zm+xld>`bzQg56MlRB`TlnWx6Q8B!4z7Gc2UP*&LUPf9r#tmNkB{UiYkn-`7#tQTi3TpCS>bjU5szJ>zeALGz7 zTpvZPFjt}jYmhCNE956og4+^1if9CMfSEj_DuSc^gMO2GVgoClBAKjXt}B8WoXqb2 zZm&1q=S#99OWkr-qqY9#9R{tezVdoPfD0fy+H9qh?aE%~+gPW6uA)_%W+%nzfkrZA zaF9c*my6n3_7p+$(J-`pGdku}MySub8N^~|E$o@@*YHCB_xO&arSv#7{8O%CCX1X= z&R-u+urOD;!QV)H!zZ*E8EJ@eJgCab8*-!WDXN6mP`@g4hSPka$3m@DQ9ov_%&h?f zHRfhEHfnZQMiOLBM&B%~Gp&Va3)k$mF2!VE!uq3wY014>ZjM@*?<~mX#wH!kdDqp< zdg1p29yjAXYB^q?p7VfOl6gmiH`;}^2KE&gVj}CZyWxO##@B^>Qfg~tZ1^qus3SUL z^wU@Az=GvaY%?akNOUhZraP+Bv+6aym^UE*teycriv3M?N@-qu z14XQ3*FGEU9B9PzHb}SMUlzQ$B#EKmU_h__c9qW87alwD{QZip<4t(`X5~!tsnrF> zbJD}h!2&N*R2Noquq&R>v^_EsLo$8~W%G7VSdtrvkcnQH?17%=?EDlz|cq93cxxDogVX1%z z=3v3}na?}blb)ok{-%B%HxBoi=<_~`u7#Bv+7`bX?Thx&x<9XL|M%9X0bZ4Q%T{$~ z*jp1rY-y zXn7>zdG9P#=Vh1eed{xq9KFdtUQa1;HrE{DlA8{buGS2~ck~^~o)VI)KQh%&ZpJM4 zdBSd@knQ{XR6W2g4R(`XTzBnUi!i4IcKr&;S)u?qq0E}J9<-^;Emr}Q!lm=o>wBK6 ziz+SEZhrC+Kxx0VN0~afWw{KduA`d2)d*~7hkTaZleX^~S<$-~L_$pqIrB38cc@8;OKGS^qL{F^AQ0()~ItV5q(HA7h+hB^?W&FXb=%lYX-^ z<6aoa5M%qz-#ftEZ$F9qlxH2~OMbmmpB{yz4+*m`xHpMI-BS29^3I-(mopCem%-;e z6UXxdv&grpe!@vELg-wB6xKUA+T8i8L@si8sU7^!>k##(I6n|XuU~{e^_G_T!k`y- zMepqIqAaytrd_IE5Y(z#usROOi*M2hIGQyZS{K8bW6c%jd&k~AS(EKk&EOEW6*_o&ueEfjV=^vWod`p zDJ3u(e5(L+xu1s$R2T*8T zKSaAw@mda@b|d83=ahr2her|8Na1*mCb`qa%bPprRcF5^ zHUI#)Z+PD(WV@Q1F7cPOU~cS;nv>n*`#o~!T^UQr2?G1ArcXL$yECF3_bN+lnT6(J zfl>`(j{1}R7?j! zR6Eup0al4@uYC&hTOy%&2mg4rN3q_S|~Su{Lfp z@L)lyL2=nWVJXIFl7v5@=(Xyw_&ZO0hFNlg7O|uHuRgCsZv_v)kwxs5Ga-x5_|)xh zIn0rdCImt+nWeIV&9qR*|4cc42AvZ}UI>cR>wo7Tbn zahmE5lo;N}l%duv0yyw0-bxR$0@OM-6fw8uCwq1WX&gqjO>;);a*n)lG~7xGl){dD z>giPpYRN;D%iKY~7s;)mgpln1WUoENsH?sB-%``y`xl=CpVh=5Pg4_voacM_FVdc- zbIm6tOFL$7NTm?BA$xDjHK+8ExmY2nZ%sr~j9_tSPmdZWDQlD^O;Obm+b3IMQ zT3cVkq;7JTf}VG~5faozL%>m0B?nEWBj5SOKY|RKr-^sZdrSv%H)fC`8UL& zX{2AHZ^E>UVp;`~w1rX^#TX)2VXw0XWpY(yzx9_l{M6E-L2nyNh7L2X&*vDfD*=Vw z;)JQ7^oy1Chee@ld2lJNa&;?V^Vs|ncCJA zHYNCsnjaT6f1PZ&>v;r2s5NykRFyZCq{nk{yXllp{Gv|W&{h~^+0kD?y3y}ufxU|=LDhHs{Q>FSvcIDXEKHgPoV_W_wYr1^-FS-% zyt5}iz`9?jaEBS_#rRgvwf}yRb_gtWAhSxHr{zs`iy7l?VqLpF{cwFdUa_ilr8(1i zKZ~LbDyi)FgZ;q~){ofb!wL!p*0D-fyW?%X`S%|hE=b46y-XjT&~(C=SP}aO`-#@L zls`MhiH7`_uD@x*%jI&f%Vk?GTJiJ`T^Px0&`~iMNM|MmJ)<}>c+~=YZ?GBF5lMz{ zqLWSv&dxMh|-stc*3gfcraF{7-8PcI*F5${L1O&{Sj=_N#-h5Vb^R##m@GF5j|l!Oyg1hr-}u}zLrKSd!aTMnvhE69cBH#3VKHr|IW(K& z*|GpfyS1B5t=D7n{M}Us=>&@(!*pypVf7T=G}TJyZ%tlo}_|&veirI z!;87-u5=$#y!&(aw=IMzNtU;>x<85?v36TD@FDUK{f+L4|8YXxX)d3JVbq=(X zBm-f=%2?985YaUBTtZhS@V!a@LVWtVRV#!yGL;h-S@E{=`ORGAVZfTzbwOt1el7cc ziaE&^Ezh=nmi9=JG!VtamJxmZakw<|cZ7?D450O@JRJ z;;?4W*py8%&zR=$J=P6!X$(~`EfV#*cn#%d3NixOY`PbPjWFm-D+=A`1!a!^MXB^i z>u7SIA2X_$FhTZ@*U!ZeA3s6}a)ZbKz(`_bWAN9mDXJ-vhWy^V&?CN1plZ3AU-RaA zzJ)!tn&&!xl?B1d6Fdlf7?WzL)0R}Mw!Z)&(sGkE?oVcB?gO}DM8xiIUP11!p*1m7 ztm>nm0hW%Nz4VGU}qILEwLC?x+&e6hc?L0>1< z)O8?rBvNh-t?de%d$px)B<6$LE`X_DWK7H>XR*9~Y`^t&ZJBho$|0TK?G>@HNF>}{ zh2p1{=}+%|wnVps9<0|w``X|C78V^?zMt1K#qO&abWMS~GKx>_bM5nUT!)7&~MEv8aRoDW@B!E`ar&DyGkVfWLoFJWB{4 z6!E~%6$))@x;HFKB|9j%`Pq8Yptw;Jlu$jjc!I(*oX-u1r2^o z#+YIqC7$0pn>AgNz=erc0OrHw()mBLc(IEwUuTxiEZQR^^QY0PjE#+Tx1PKzUC0hm zM^+{9ocJ#tt?AO|A4!%|5%2|-Md8bY;eVea&a2K1gFmIzqFT8yjYMUNF57g1W2mOqToDL^t)$@9*-P%0yc(}Q-#Y1*x} zwY3pQQ>*kHM$;$Ic_(v8aj%mT;~gRLC4i7;R$@3=&*IZZRF_ZXONDb0IO;xWlxBoT zqBV!Hf2Q1VM!%IsoS7)?S_$J@=!`|EqZ#gz(XzlM&8C*h%UTs;5SUeXaI5PnRn6 zQn8>(x^iA_%|bZgrm)N0`C9`n2y6>F4Ow1#$jZ2q#P%cvBJk*3$ul=8cP>0f-sc2Q zs(-8REYhF368yhRue7(zsOLVufc0-cjJbpOgkB;ea5e`z>4y{~SCBf`!GjD3>kNzY z)B90LX1BYX$wWy4e!5ukj|@};h#`>+h9Xk*B8-xtq%|V;a9#3dXJbTJRV*|aV>k>vAGeXj2c`?*?6}Yu)GA>vhe6gBaLltdu zYmF{ivgqV>vnjRZUD*^U*BV$A@YqFI+;UGVjYPjH3{Y!j`34=g_K@#;`=fmV&Wb9$4NU*Ny~0O&KR zKyg5UylkAMLQ-ja1ea@;hq5LGW&{EA0ie7h0$s!IP*#X4V^dPR?m6xuWl9_mn|o-r ziyjq)uJ{Vzfg-&NImUPv-eL~jBt z7<$8|Sco^nnon8`{ZTJqL)_C~*+X?nrfl(Zn~_?JF z*azG-Nv->H_R?p#x^=JvUf9izGZ@}-{puylTn|%N zR5Yj#UrcM^x_;MM(sd01!}>IQvS}1<-h*~B1-V-LVwjBrEJ@krL2E$MB`(oDPyiSF zIR*!om9L|-bM1Z03wL3-(p$n;6z58K@U7@3OS8jNEgR;(@JvY?eCgfDjyE^t>?DC~ zd>mA|agMrcK9GQ`o@gE|TLt04*hUTqb3Te7pbghw5tD`B?*|yyftPYK)6N#}rf?-4 zV(e>$>l-qL1+9=s4Xe-ccx*GV0m!&kWW!LS8+`n%2B=)N=dGme2Z8e<+sM^6xTojy zL@F5R^>ug~NRjK}cK~zq1vzZ6j0tm} z8cvndOkUpum-f7weeWQ;>OMqyZYQLrc}o4FBp9i6sHH<5@u#5NC|?LXnoAx#ZjJnS z*k)5sZVRs4MFR`ZsaSu(<-YwLnf;+C_bVb3_Kxxs>bjYH|D(SoH`c+Yk-eA;Dt-J@ zWhVpUr{TX@T0mH{jBby|oN)BP zsNzlz`K}8-O@?LO=W{ZROqsh^5kq)tb{rRk)jb-D7+p^hwC8ykFgMTB)F=Bva#U{t znf;;wfg=wK{PMtg*=FH$ujs^i+?qV5aWwN!YD+kK6%Sw~sbe&swZKPUq7VwT4=O zJqA-gt3BE7nitJRd24NSYoOdwYvC*pmETS^&~3D*N>(l2D-J=uol8*y=pr!ZUtc^; z=GE~CU0}-w=1d|A*LL5vU+^dULlA#$K3Tl2Tklx}yxXV~cq72TC?)KBqJt0AJEKn* zgaX$kp>0i6g`ik!Usq(XYLku|04~$`8f=lZx!Lfz0IzjnZm=LrOoib*7TN|2h$;w| zw^7>x`OYC`-QC!tn>VIUYn{3>ues+TgW<#W>pX+WLq$_=7N<_5qO9_iMcakOMaZea z9&-e1mM|b;YMzoO0uJhVN9#E;LxguCOu3(E^~V6!4}>&q=mw|Ihy}HW zu8eju-w@UqeC{GwAvb$L>1^1?k{idp0KHp!8nJf3Iu!+lIFF@{5oO{3t*@O@0_bd~ ztt~BBs6S+SWZ5?Y-G%w8-Y=Y3GU#eo2l@k#0N}ZHebyy+H>!bHuPr^ct+j4fd&+J7r}0s!7=`K zw%Gt8omi+Q8&5S0)euC&?-L#&-Q8}-8tB%ZCbd)9)o0b+x`Amh6|klhuR%z)ix9p_ zD*ss0bUOI6eA7kmo!?{zXFgOTP49qewf)tveoKM4)*|_HE(FT1ZJqC1zB& z{(^z*WeoMSd%dmfno@Vx^LSs>RMRHgWxIP#>|6#zf6KZR92Ku|W%!c~F3Sig6w^r>UCLce7zxqjVD66=8+AJneMe)*nsdZI$`i_9S`jG^@ zI7=5Rey{i^i=Rt#Y`Cx4U!X}1gAg7wJUl$xCnu$@+{+07;Y>PsTTPnd0OZSV_iIKf z#E{!*N{?U3*i3i%$zSrmshH^KRQ*?F z%SX(R$X36m8qFnF(3+``TQNX|1fcE>K+Dt(asmE9M~Dyv+=dkM^ayuDwZmp`dA~Sc z5U}%PpiFB4B(j+iMec&HcE8e7O)QyVK?$0SuZR$v?Z4DHu6M&D=uu;t*9rIPT?~d> z4GRe{>Ubgxhiht9I;d=sR)US)1-u|o)jRFmBQ&hzu-0T(M;SVFG zQC$%}dWCoO@oKxhV(uLmYCWnI0sje>Q+G3OKGA_d_^~Rn7k>EnY)Eg6(<9}mI}M>F z=uq`DF5yza|I-K>@OcIyzB|l)ba&GuSv_NoHF}C%lN4wEj$l{6Eu=o7Cjwq~ySe^>PVBN?PUEK$bl5A!1 z_l^e=wf3TMurX&z2V(HRe?k$jB;QxjVblxAi)THKnX@#G`Dv4;;1VCd<|zeZL|Q#P zU>ia#uiUA2Ue{{zWlcm7$Wy}GSbyHS&n9f78zbgne{L4r0;{!~9&-D}Ox1jEd&#^O z;=>)4cH3Xy(8kLHszzuKpoY0ee)BA8zM^%V{WAK9E?B-B(l=`_pkvhyPc@-DN0C*{o z9xE(u0vWI^id22L$7zo~i<tyor5YE!xlV=wTmB|f(p2vD~+^gWS zLKqSvLs`D>K#hX(^A_{%hSM3F(x`OCaSW()5`A);53jYJ!0}YHYG|4vByA#K+cfMm zuUM%Ec+F&R&k?rIQ&_7Frn+Ayh&?*yi&Q+^K~f&V0v#|TG+Z4m?e?Y~`}n)kg$?d2 zi<*I#1$FeVR7{3@)4no&<)#NBISae8a@Bl?OA-(aa}@Vv;ACVS&@=-7PXykU`OSw@ zHy1Opytgr0w^3xxu}1x@YFiM!)%ln4QVYRhpJz$}&Z$lVa5y?-`e%x$JBy+zm1tL8 zTjy#xvA==004mQhAL!{{g9#*C%fhO{!42y93Urz{>fhuHg08MD4nRr~!73-$h6fM8 zuFSv?ZAfofOysaOLCitw_d+!zd-~*|^fNfb7;*Qi7g?}JYnLr_ShmB0;OyfI1Qej| zysoHBZD_sqRLKsk_IQ8Jdi*mHRDQ6epcToMh(6{UKYP=bWs&=vMAaK~W0I~4h)J!% zejF8%P|>4T^scsrv^k(9ALWh$qE9=7&KZj1Ra;YV{|0{Kj>X0&2QN&$8L2Aa&Eh6y z%9dV+-AajG>;x>1mWglaM@fr7-8+GjEWW;?qP+c|kFte%y%V5X z39ycijqRM``VVq5OXv^g*(239dK}`(hA6qYF4S0(!Z2Z%V~X`=H!Y;_>_Lp*K(G}N zTIUw)$Q$MYJgc}Lqm;0(q<``5ELH)}Fo5#YB_XO#KP8`@jr_+A=V(DspT&oN*!Gmn z@%ul)J8r(a%zy24Gak3~sv$4oU!0g!08VdN)f*_GEt6opm`o4OpcY?pD?R8MHz?OR znh0SpJJ+0=(_WA$5RPo1g6~RZbjp6g!1`^H5gAspn@el` zpN`s)^f1uyGu4AlJyA_pF8maz_i&oYfcX0i|K?V|2lwDUNVfA?+yP6EA8i>q?Mo6&91s7#41O#IM7Io(Khd5DeYCQEu* z$;(v0=+~DlCloQuLlpHucAsuHA6S)z$)G#1+3CS#&6Ll)?+Jl}7IMw{q?pY4FwvbWFD>W@=*8nE{7F9itaM+}{q zpqW1uel2+kt7h7G`eK+#R@Cb6F$iJE3x^;KwgO`bKyOwH6+3Q=1NH+enF?E#XuoN5 zkK3f}_C9}`WnR>(xnNOh_VB`H{w!U1ce(2%O#bd%OS}{;9c?*Zl0}BjwXixFeXxu_ zq5ZB);O!b*MrLMp9y--5ir?5@hJY{nWpB9`evDIG)@R4jE3+iK2XK)J9bRrK;5+k0 zYB2$ShK=pS`V1G*5?B&h zV?DDUgHIRLM6R;>(qq|=7mva~E9pHx3Aief6YoD}x+c#BWIW^N($1%3gA-5dK>Q8sh?ab`3-brAhwA1b; zR?@S>`{nQmrsw7NI(lp3{5Pr-I#|m)`ummvme6iwNN8tAN8&oin~o&K8|UWfkHmHrjdv5>3$eN#Yb9aJ%_ujVLlcW15U(CmY(zmq!& zzk5Nc9(&DGGde1zUEtXDq>#bG4sA3%#`cb8o#QcB@J9ieE89w#7e7F~WhSFau%W#B zZc1o+`*Mb&L!M{gL`6A@W{Z&APf}OtF{hDe`a7qk-Qz2+eSC+xQ$r@S<91RV5C6o* zhRzN#LF4B`D~9C-Fc7OhBL3x-EWj!ySrQfP_B}?FrK_in*U=4y?JLgNk=bYd0BnnZ zsdY;ay2fm8iVK!qH*Uy3N))yltFj3C;f2i5yP_*pk>4{!k>Y-OUc13r6b>F5xS+;fRbBp|et3ZM(*z4I zIYgQ@Z`@~MY<27DC+X3&sJTCO?nuvy!09?Um#zlvR1-N>{~_{uGAX#2qtQaPOGfTx zlE|p+7q7MwD7E>KmB|~IVBWw=XxkYNI&m)^hqdFEIWoebZf1XFE>2|POhWR9?(J05 zhE(Y0T$NxWta%nu^Zc$4>Pl0^;>Yd^#bx0S7gD!7zC^7<$+z$Fq-!KIU0>5yb?is>E2s{>Bq;Qno!DVR;r|k;3!$R3C$9SSD?u(Qt?o#YvQH zbuXo{4O>z&hU*f@!(wH;2ltMIbl3}bFov>^bWY;S1#Ey|YTgv*swVHBkbs$~QhSB2 zB$(#i8EewHhONGoet&2{rl;2x5EkXc8Jz?<8uN`Onb+g6wXSX)MrU_Pgjg5oE@t1E zh4QhG%7;?UiUB}+%(hI?s;7cLB3o3>B;J1t0TBluHzlz3$yE}~3sJZ(Zy)@wrW!i} zdm0SBn{R2aD>9<(wSIv(>tOaiRvZ>F=Kum;Xxa;j!rvFQ6B5L^hv+=$h=Gtfl%^Dq zC(LomZE%95nYl}*q+2Y=g7<5RZe+N{r90+r-|*JnVW3%2Z9080gw{uEn7t5xvRjJ{ z*A18ml|8VLAepa5Ig!n8qlczG1?SV6azCO^BdAR#mC#K9+R)O#FL`k0OyVzw5Mr%8 zYJO-07>6N)y(<%KTmg+erAEPk0oNmWxql$*2Zpt$cH19l{{?T4VDyoc1tN_C44012^eRlUdcWGh^~G`rd#*K7@Ppjw1~ssHw5mA-Rdc| z0?HxWs&N236$~8~!EjhVOF4moRaPHxLjiH96pM1I^yI)S*ITK#p$8!?|bVk^J-Xjh)96`8g${>D)9=a}6Uti4p0xq84;w{7}?DMs5Sj zU9q_S(At~bwi&tq5BF^Wwu_caCrA>BBYfp>JwYc8@^zBFxaVVu{a@{k9FSF&Y#lMR zUR^2Tk5tJqOS$e3<A_zzYC1%15Mzv5Ba~pUa(!&5)BxkS)NAk z$hO_ReRwINXe`X4H^^^yRbQTW{I8(2N#qHtHH~LRhLBKF*AX#*xCrlDi)~YXCdn+< zJ#w7PN9Z@7BuU^FEX!AX*oqd`oW;@b+!K%cmHPhWC9y;z3y?lqfomJt@bV`l5He0Z ze+LT&hyQjkDc;3Wv`7|PnuQ3Zx$UZdiS}7Yj3fll!H=1=M>S~N8&q`UYInO=25q|6 z;Loy5U?if#ZWI5iRltSgqp%SbdnDrYt|jkM51Tt_kI8RVGm?Y(BN`X0wb&M!sxc|Y#?1-GD0Pho7rx`!A#ZDz1;Dw)1K_?IDn35wzUP_vLaVj zZOZPVOA4+fAz^z8oLf8*!>O<)82da&u&|2nt77?CQ!FeNB)Lu+XWtXfoc=84IoCj1 z@1OZ)A6vsVvP8P49%kOqIH_xwg;1=F8Acv$uY@zp?RC{W#Udh*%%Z{F_Jcq#duDR# zUlm9r2yZVxcJJns;A6~W&;tv%MBvZTFpetiqb*{m#<@f+I1F=WP z-24vHqHQi|mNl8)7IcC8Y3cuqm zX9jz?w zgN-3bYx6t~I{b*P26W8lVpDyx8>zZ(gXqvLTqyctW0ut|8Fj>!2WgdimTSyI3(gD7 z%@g)~D!GI9@P+Lf9j0YSMsM>R*{WA**7z2kQvJ8WP#lyXZ?;&F7X^RHzfh;Ai*NzV zkT;9so1ukFlERD5$L91a$FVmPT%MISlhve(9SkAj%ykW$ZFMBo^B53S0 zFv`Mw&NiF5<00jhCT>R{SJx7eo3&wwRoFWOJY%OIG`uxnTCgrTW`{f?@xymH3>XNT zbWnh%RfP*_jW6UC_PFsiIJTIr15`97T7~NRs@SJ#WPUS2QF;;S6dvr|> ztR={ySzC0R2nyRj)ExU&7Zc6p8-`Estvf-hKj z15+8?_-9}>O(d{q0aXDa)*7BRjqD%5&jpHO=F4~7`>e|-L7fC#lS02t)QRpQQ%uXH zVSBocVaY@n)!JAfF9bZk4g$(;rOcAb#tpac@`0wNnhj1Gb5Ju_2e+JUX8&CCmJJy9 zWH)^^&pF_x)qyQ%s0Nq3AolRMYlclQR0i;Ed*c|wH?zzaSQ*_d@c@L4QQZH2`$|0w z;Qdv$6v3G^iab2p#9n{)qN!zPaNeSv64g}*D%S456?nDQUv43MD0sPgB$lTJc zi{XdK>Q`j2dca=3CYlkBrq?19s-{i9NLFoMUv;f{AxLj8siOJxoQTc#VyGAc!BqAh z^fpjMSc&y3`W_!j_XXt!Td3X`g-vM~!sA}=VcLY(ss;h1=V=l#)MN=>K}M1p5LyMl zlL$)5wigW%emdy-ezAfqspX3m49N}x#Fb(>*;^_j9ps@{NP#gmHi{(HG`K{An@3EM zHFw^%fW%ZNxopp$cVcrg=gUb!MRTf)1?jh5S)Xq^EQoUcNXInbD*O@-uZrWYeogl^ z;Q4;!8Jx>f91q^MS(w!tQLebeFP@h;>*$sZ<>4)xEG3yu+9$u(_tHYwoZ%AI zfbPJp(=nS}84eA!Q@BSKGi(ThFBp;}z`a4RIgZ#>-n=b=NA93)him9J&PY~}b&W3_Z% z@GEKNwWO#wiHpm&q(A=-8Mze+npZ!#m&Yb`4D=D>F-cm+YRQP1TI~;>ALaUG z4ovLy&~L(jiOK2U%d?+`$_h9NXrzj9THDq1b!TA)=(U4Oh}|S4)B`^ZrfA&sVycBs zAGPnn)-S!3ApiLUv zXl&bQY};t;rm^ju*tUIQ+eu@yVPiY*w$-q@V zb~i`5gvr zoiHVc4KPXGo|RSM#sM9;lpL6eV91iRn|UyFg%OfuK(MvPZVe%?VqUK2xM6u=1f{-- zM7xptJ&!dhFqOi;FOM;m8VeU6K$YudCzfd=K(=uYJ)8mTyqD=G{y_W$v%eXTN}_R_ zVIwtRxD8TKZZzPhTqC@UILtSbr;tr}(>CARdZYtzX;&!V;)Q7=J{=G1bFeR%mMBGR z9Wom5VcK+LQC}r#TGll7oHDG%_;C?+hSOC!kxA&s`2uO!^HTcNwQuJShY?UxP7am& znyDQ9fPc8G$XH>T7EW)x4B6C@t9$Z9B^##wAl&BEI^}xjMM*d1BgZQL~lU{ zwd_Rrsy~_IpUYut{c08%Cb7 zFRW@YYQ~8ijS#mQW%XR8Y~_-)9WaVYlQ{KGZ8)b(rj1-2_+PCd=EB<Q<>@M5j7Xp$D)`lx0CK@UN+77d@vF`& zE?oHK%51qkbijAJcS{N#p@|EPm%Ran_5l-m-QFlf+QF-(9OqG|mpj1fW_Op@FO)v0 zCbhxO9CEEtjs%@hU}^zY7w>vc@&!2bJzl+i8ux3NQ9=bk%N1FMLH!Z{R4DAEuFzUU z^*2L*;P=8`=UqKHy7}7U-3&el$!m2*7E~8Wn5Au_=7|=Oq9>|Ed~dea8J7smsKS+^ zE9FCJwE?jUfAcwDD9Ph{f`7@#G8*Ym>Kyx#P0L=}ScSWbb2Vw%@$8*YJNUx71$>_p z5V@?lkvIXqG)v*^B)C6>N4#(ZgPrC%uPn&_9?0pID}CM3kmBWmGEboF`8wUI5< zb+w|#6~;F_SA%)#i4uW@ z=AVmi;^nuE%9EWKEhylps37u%pJW6?Q3<*r*%L9#vpj!Ogi3OD9uu!J2MBNKZ~|i|n;Q#erHlmKeroOBq15$NsCg62zkiP}O7E zXIX=#|8s=PZ)nZ2q!uzIuw-So)U+C_?MTskl4*74_VgEoJ)Eqj2Upl=E_L|`bU$a% zMTj2)UAxRtgS9ppX|$22=XHMdaYKqnmz7G^>zun#D8p7lUWtNJ;_Oa0D4aUMqwb`$8+B z?rrFY&8S2M{?Jb-`gU}hK~sqXV3_v93IR1=yNk$tYTe6hJ+`o4&U!9Oxa6w2wI2QA zyopWF-!|ubw)BHnZV>TI@idgx#_G+8Z7fJT~FUdG+WptT-m{iCe+Y+-W?(3J}QZm5UFzHiz;)v~As`2VjrS{&51%HL++ zqXhxhpTjwo&w}*FF+Ceh8LH;$Wz!f`Lf9Kjs5CF?IG!9KSMc%U_v6B!cUe!21a0ex z$%!pi?Z38}qvJGIB!yE>FrJ6%=Ak!ksD;wo<`oE;i&S`D*!v$Ljs~13 zVrw@^oU+THI~dn)!6!2cc?(Wlkxz(3e`SdbCLdhb#rBohVW3NC=IxTNsPD7&ylGW^ zykSld%ZPUtD-{yxYm9=$=Md?{+%+R?Ctw2JNo_3WSvvWi*OutE)R>QsKxbXSe)?wq zk~d;Gt-mI_b5ST>dj=g*hH}EC7d9<9@%qEehttAFB2j+f;{mYqMhReAle+RD%s^YC>Iic_cO3zV0a;PXyylkIT>3w+BE#-48K-%$l;+q&V zs+h87hME-68u2NSh0?l8bvrq+%j@LLe zlH=A>exr=7)~;)f!QT&U4Pvn0MTK@iJ&=l0Ik*oAD8@hd&NS&rmA;(7xAR_6@w!dH zKOD_*NG#uw?GV~6M1Ft^TY?|!o$gDh`mmCMDAAE0qTI@+8Zn3c|}@Z!08<9=bEucNZ{@d)yh zT{>m}b=BZW;416hE*fDaN7vf+eo`?2BK)SeZdYzJlf{{on{|E-k zY9xt1Qaj%uUn`_6Nj!jA{KRwnsi!fzGkXBbmoY+sdD2Se*Q>(iOx8krqUol862e>F zejL!OCn7&wwwvE{6zsM-CnP)z_|p%?*#zfhNM6zN+vM(6?I$0^~>9zDyTN zg67}>xTySMhqZrsuL1%={5Irkr#v)BGi-iPm$^QBN8^R$HW8J^)I znvQ_{fz^O%D6RaFXn_5*V5CFZkNAs>{P7>f-@pF=4Ft(#h^;N8{%;r(cqSPL$f@rq z?fS^8{xjb_79@w!3#60%N1FuNn;)W!deCI2q?A9H|2Hg9kO2i0ibm8FQvG|=f3EQB zLrXJ>694kwt9|TkQIIKjM{Z;#1HH`u+{kb8W3r}Eoc{l;rb7ZmCo%LU75y{pHK=>J z-t0M|)TkKA-W5D8JRBzE9K>yYm_$NCLh+NNn^Ht1jYezij@3DIP{$B4BcnW{-;dV^ zhRmsqo(~robgW57wO+I2?M*bv8wSPLLJEH_NC-HE=}=B8Mu7&bOxrX`RE3R*$3UO{!SvBuGVJOx$?q?ELD zY(hdHBL9ORSob1B$4wmZRu)L$4Eg!I3|8cG{l40=6i{RHFZGN6Q%Zo~ly z!dPRJ#~Qn?$*Stp@a+k`X)axQkbq%6__8`bfI0Y+Pf3|0HAuIF->-HOz&X_lwFR!gHLKa=?dWGtZbpgZD zbUk0f$}=)pYW)I$ASnf8r$8SdJh+~oo)pWm+fIKNB^6Z*c4;ErgkWduE>>@n)F8n}(CR8T^~ERugSl_Y;$)`Dq~(5uH| z+TMmPCh;EeVANp7flrmts)K)8`xkpd^NEcnmEO3xz^YhIDxb5WEo#4%zS!^>OKjIs zpGlKZ(M+pg{$VKD-U45!Q?xOdqEkRoUAtnSJxLxf5+n%tNRf6!3&B42rQkccf~IEJ z?hpWUWb>K%LTp^SJQdvs1mif%2{k32-^W0UoO*m<0_TpSADx^~<`a_k(Wf5jvTFY-KXpGThn!cZ}1Ew=VUtCKJ zM^7Iwcn)3KJ^@`5e~)f02xv7{3##iruh0u!n=6!{@Czx^Atj~lt=c-cl+(gtuZR>o zo^jKN(;V+m5IS~;!04JS$Z%Jl6v|2d06iG|l1%^oIz)Z)nAz|+=d)gKMepqF+}i$K z7`yi8LGrQZiV)QKY@Uh!Tu3Zw6GMYnOoT z2Ry@-U~0#_$JkvIgiIQG8s7D)f*b{ zcH)~|fWV;R6yIW=!tUfl$iU2$P{n4|(2~q>(*7h!6WQB*4K+Jmxk_FL>h>j8P*!Hid0N%Yv@tjTM0k69JE~{azKKnk z%%Cr3V`JmOW?Xr2_&fjN;-b6Rfz`FNBD`V4lHfAk-z5vN&tLWWLS^2v9SK*ApoaR7 zS1W;h^@`|YUs^KL^Spv9FJiEf{^3h{a|bP1(o9XU{-6<#5SziSe_;ZS)mIeR-A$S$rZa>dTx)Mw zv`OUR$s|-~wqsEvu9<=90=lWMHr{Gon)Wv+GJ5GEZkl*;yak4>%}($_d_C?ROUidCtSq=$5F~( z>7k@e*b(*4e4Ys*>N#~Z6DM$g&`T{d;#T1jl241=oKLw>Rx3<>H~xI4G&D4{cX0Us z#xh$RMiL;_2ju(Rok66}M}!&!X*!h!&(BTRKsvL6<#OT~R57!HGtyB0TW{J4gt4M0 zG_{>J*2~Zb3NAtqg9lVy#?Sn(lU4k1vS`&R|G1}ry}4f%GRP9Lc`IrCkCWw-0y$a0 zPU7hQ#s+Ml$*qI(QvWDm|1md0IpQBNhhn=@%m2g%tzv?WXNNcfRO=Ct)YpJ5a|>Xd z4`Me@vlS8}6CO9K# zp%_4?ah%|T>xMoij^DYQRLdlaa_WA%h;S1DDScyU{u9isegrP32P6xcUsduG0#^=G z%q}zno7jLI&|LztE;IilK4SQAS0L3ul&`1DEs%ovu0bYe!I!udRfxN?u?~ft1JP9j zQbYQ)6u@?3U0^$A8h$k{~gFQkK9`ZckO!cV9xmL^Si$8IZ!_BI%4&~Yty{C<`F~wXL z^ORVSr}!NhWFFgM+uaC9t5akz;IqUUMf1Gg4W&s*W&izLo_N4C4W>7+%1_F#3(qz zW`%2Bn;KfyU``%_bTr&3ARUdv_v|Ro1!pvBz>i&4HoOAZ?%D|-vRt(&?epv)x69cr zE8c){*>pvlNz42CTXss^<)-MMH1%($abC)j5?NHmE~rVWd5x^NR!R~jhO9-up9zY; z00djS5f?}aYs&TM|J^ADTS!P#E8T7judT&JT1g^WC{pzfcA-s4_JTC0CWl<#0s(}GO)mPq2x;|$--WN&dV7C`Mn?IH(~Wc}T{RyubSr3u zJfKrw`B1#)s3n|0cN8ZIBP;GN1w1ki0^s#+nlOsi?*WyGy^-bEl??MMSSyHwqH- zd^yBcJX?i(10*U^*G+H)aHQ$T&KJUE(wURY1xan4Hbbg4FM=XP5V-z;n~C|B!=%1K zhR1CV^aP|*<^=Q|)}%sX6Xx{W_%tkkSv@!j8C0^xBFq_Bbg%NWxe@c77`B`i87-Ys zKU-=fav+*khI}A9Gn>i+s-6G&6X^50=rf=!&-Xdng%oS-W~tKxbz?OV*7XpHcaOe* zXi6|;a#p9E8gT>{K;mx5`|`McE_OxVbUSl*cjnShIYI)GjDIMLixF*eQoXF7^)E;D zT~?qmP}nN0v@)6oXUbM=L+9-K4Md$;>9AXhWkcQme5TcIgd2Oa7syC#)0u=V%>q;g~l0Y3F&#-8Fy|nk=X=L@(&Z{T7 zdQ7NcHyR#yT-Q*m0j$?^P_N*U>(rFmCxesf@QSjyX_x9W0U}%XrF&$jk?rGBO+&?_)2><{C zOdT%v%FRemoRx8b8tn7Gl5m>)6{(+*zmlU?GP2=)zp~;UeioG} zkl<1pzB3Lc#+xX5bZWVA+Q*F!!_hmrKzVCj=lwQjBMmBs6*ZVEQT%9gNW3t|J~K1J z{cUNqhRN_VdRU<-?~w$l-Ad$xi1qMDH=e%1Y22?Go!R4kVhReV+!NLOt>f#c8QXn5`ff(c_pnurcv}5tm=yI6# zF8V08&JbUT`PSa0*ct;$LqY{@%>gWx3b)2^RxQE(fjSE~>*1{3?!cOTs>VRQ6$w&` zFmZyEBEzY{Yn4%y_{QCMhr6|ep4PjB?&jMoko~kH4OKI0 zt>)H`-j|q15-^D3ph66TiAEi(7HVOPtnk{k2z`IHvG|w<@-g==sNa(FARh>wq6@*N z1XQ7hY>oGYA~s_XDJaF52R69i*sTBd7am*5q5sLBB-#*{ykAJCh2eK>iNZ%3lRzgp zJf@~A?H~;=D$1%k!8fiK>J~ZlB06SJRw+u?GP%afyM(=9G~Mt!crYdk5dEn>nLa?S zGzTSJUn>OG8%*k%0J;9sC~#zh-!`c6PNN}`&kpn&rcfT1r@VvDJD;oO#WZRh9{LF1 zrmYdQB{zzH{X;8*avG8;j{JCi4Pxe5F2A_ra778>TvaXoaW^-z<0RSv`gJ_obX3c8 zeXDJLxT8=Hcl12WuIPr5H_DAJWcg|hA!RIPWYZV$uU{h+2wr)W2(taJ7#6mUfGyoi z=5rn0V+o*W`b|6sc%JsQh+6AvfMnoMNL_a4zGkWiKX0rY8+>PzKeqCcsnM0%IG;nb zu=P-aF_01*BDiX$-Lm-;m;5Rc9m6|HmIfXgfgnsOfWWMzLz@Jr!?j@i7=bNimaS>#)bx_s1|q(Yb`CLi#5loWj0IFYDUJ-on_R_`$VS4;A3m7lQ_XH zcQ)Oe5!OG0{-x@@OK(60_bA79>V#UY`sl&`m)NkDl)>gQx8*QY`JZ3P&Z*Hd>t(?f zlCN7+oM3PL^%cx_zjL13%%dtZ&q`G#o?uU7!oDQrRwO;mt0o)R;2 zOsyjWGdpcTU>%02GX4P>qK;M1StrG76`t(SIxi&mtt}~Or46l`x|m)A;|iWQycVQ* z$YmM{sL){(1ynl=VpNS><&o@XMR#h0V)+z-x|y~l!WZ2yNNo*Z4vHQy*sFCG5*3&7 zh+QZ$JglGM&s$ORts7}ul6Ymzx_XjyzpP~;g{bK%{HD5YRm(;mLi7sH52kKz)(2>l zZ-NVC?Jo5Zk&=oaTf<_~TmSCcmqY!oUZt}<4)b24A+;KGyL!8X1k&%p3ak`I1rXhH zz7}}FYr~iEQ~}}kpM!5mX=QJRf+M}4cfACLJuu}rch5!tv zeeoJ|x%i3|Igj}>6woKplFGV=bD2!KKk{UCBq+2qK76F%s`An=;i*=c@+D2{j zPyXxLc1;#7S8;Y!7AOR71C-nxpYqT89T#WyOg5A6(lm_IReA<-ci)~CyVR<N&q&4));+oViG|>FU3a;l|3a}fdT%S^ywY(x9bs}n*}{( zH7hk&q4;2uwbVSZgt#8CKIDR3R~_!F$W7!kqeTVA=Vk4f-0B|mUC}hZAEdd?$Q+wa zgr+jELHkBTjW#bxqhqm?-lBP-fjDBs%-lHJetimxF;P*31eSv|0wh6!TJW}6>=1|> zm|qEZxjfSv;n@pJ!22{P14UE=Nk>i=qqV9%{r7rLv*z^@;BykApj^3UHcBjuZW(p7j=DQv60V?J z#xew~62r+OtJWGvDX?1&W|MR=Mvsc+CuFPgz)92s=?uSt6fahvbkoqlAyPj90+Zq% zR)(L($vL4mLbQip3pX8o17{3mB3fYo2nN`$uqM2C;ldysF`cqI`gI?QBeVE-DA+Vs6#sVzkq*h-q3ty=`OTUO4oCd1^c2CJ-mFqZi`?RUF@l8{&m7 zr%wzS=cY0F*VQovYby1=H+`cHh0PQ?&Sr>JfbA!7v=#q8sILV??ZFUkNkJL+v25vV zTmk-Q%xY*bWRY8->I<$~P>F8t9XQjXuYfe4Th;(mtX3%J9o3)~1u4}Rn*&jmS3NBa<%jKZaIZhDmO+e!i{^|@Z`OoQ zalLE_C9ysx)JnLYKAGWHTVn_+u?R5BCB(t%Qmo+EsM&4CJ5wAXT1E|#xI&~%|K0uE zKYetZo)5}sGd+es%vt>dT!(8dI3psv3UU*Uy)S-q#=HY|Dp%dWnyB2;7J3&mEfzI& z5#WH;h2gqBq?`1!^5uOK{A0ddGyjn~Kx74evPb&}fA=J%1Of#Gh`N7{rUoOgo9DIW zm97QY>(6OiMWg%OCW*zWk}y5Da4DF~mfA@Sb3w&VMe>=6X(?(+=Z#hj%N$50WLa6T z`95Y=u(85P5ipS@iX?8glbQN(r|X9rHVFhC5d0LMSXSmtcxC!|*K~X_qvb;b_lo%>&7QtBPP_**naKevJ5Hz43#Tj9GPD2@vZ=0+jgm6Y%@U0s-7}nSpZaJNdzQeb)rlt&B}yQ} zt$(f#*^z3FDd^^=U|YBp8rQS|CD)ceH^7)EZZ-NRmXi(S)O=FCBMB- zRl2Wq;{6eqm9*kC1F;J=T2;Xk3N`+#@#=Jz-#s=c}ukO}~jCRPh>-pYT zav})_2PTWzWJ9Iaj!=&J*AEo@zsMTATj?Vft2t6eMn*#4{JeLVOf}Borzo~}+=EY< zar7VP8t4d_1~9950mab*)|K`EaS_P^HtgkwqhGKlHfJkhY__&^p?s@&rvp42Nj9>X zR>@6;2DNH-smW&A@%Ea+>>CQVyGx@EOV~iKIZvt5P#s?qFO8e z!0rEGiByqd=5y4+WW)dY{Rzi!XJ@C=G;WFI6Eq0xK=jqqd!`T9XuF#dr2Ut>OZD}% zaK_G60eLmr53g1a5QF=lg?;)c*#G>0>jd#aeILl&b_hw)|4@aXRuP_G{(ZWCo@hGc z14ryb6qos*OZkSfJ;MFF%zybsMAVo{o~MgG*qe3TNdTX<%HR~XR)`W={zZ5E}F zk=ZK@0A){ii*7wRr~^=eKH>%CKr24h5)yDo@E6^+_$ z^ogKlftdgP`h7t}Jae|&7KEsTT z4;|dgx0~u@MOn}}vOhqcFDzuo2nm$~YUPx@jTHu!ZNtiu zP^EdcaQPt`sO@A9>ud~Hv0***EV2gTRYs6hV zAQl!rROYEZVYN0A{uA9@0yyS1OYNgF$yplY$y388uvzbb=U}{{5bWiW=H7j75=LeO zho-*|;K5TY7Y=fM^APN`7xbheh&}rpO}YLoXx@q3o{<2+ovwP!l2qesJvIJ0j_MX zqGQt~$l2{TR(LOuG#b38?kbt%gW<)=J7d@I=2%`7y}>WOsVrvfR^L%Ro)7OsLX}}g z#fJ>4@)F#3;aw{hH85~|L}B$ph})MBxeG@gjQAX`aQzj!pRP(^>y(akE*O&7eb6gK zB)$!%uIZbwe!$8LoHbEy5j@;bB$U}VUVG?CkZEg==(G3uK^e@5d@2#RNdR}cEL^!@ zO#O&QMLYKeFwlU_f>a6t1H+)CsVzE^m?~Vnq6)j5HHK)sXSn4uOVRD90)3Y6@pq#M zZgC-VXyjV_l-FinTz;q94JU?9z*qnMNz{|=QnLMWLHl9qx$KhbR{z5kM$3ZszOjJ* zQ6|!%GNepH#wRSe`y{rQ%t|nq3E>@Khwe*;(z$;kAh15MojZ$JbEL%nIU+t*VSi*C zsjP-(o?KimxO}lxKEvW+FOKay3AkP45#Lq&13GRrJkDuLzR&u5ic!LhyTA3flXAYT z5hRCN7?;}9pe}IF+Dhxvy`1=zbnw`R)Rh@fo_V-ZPWoI3P^zprs)AaSQY-F-K)urP zrU-5HdcoUQ2w)2Zu-J)tl4%Q#pp{B{ zx#hZj3|UfRghZ4xWdSxn?r-De3g(42v=Wgf%mnYFNkg`XBLhuTQ_7?wW8)x(VxzTxCtkyKZT0@2( z_2d1=hl;XdXJ`hWER#^yKe#LOR%K?Y5m5^rP5Wv@|xj05);*sPaqMR zx%7}}TP7l>#(p(cw!MuRcu`^>d9p>(yikLCZVGX2ky2T|%6Q|L;5GWiD*M17_wQM zowhvXaDAQNOBlNg$Q^9yP5O(iqabo`DIo@~_sgF0DSCD(WRdrfXTHkou`EB^&$N6y z^|myHe-zyb?I8PI`1N_~6vFieTkaBQzg6e-uuYoH6%)sE%jUM|J;DUz#5l}YA|&Ju z4JJ+wvggq+zn(2NW#)%sUd{*(9RYb-rvW3rO=?wr(OxaX9Dhh$HW92f9&w^ISW2+9 z`O~Q*?9)19+8m8TleFXJ8llar0R5ymrR^#gOmQsyA-R8OC$nZqc2CjJ;*xN%nMSCU zR4OrCpC?pIs2U4Qx95UjId5gjXYTOC^kRSSu#zx27lPz}7=&+LfV|7dWDV!k4kLB? z<6HqJ4CB=j3i}z(QGLILKX6!+dcNBVU)&ytUl&I+*y`)6j89jd_aiwkdbkY^S(?uq zYcKHG!h>zaf4k9|@^NP-^;Pv7&T7={F}@wJq&2Cj`cLUSR}!CTWJGlslfSNo1^K*C zOsZsmKMQ%sJjYZ}a)B}i)nQeC|M|1-R->LAJGCWvK`dCiDF=jZTg@nrZ_HIel1!MK zNIjm>YbQmpt^ck*Ym`2AlmNe36a%H^B#@Q>qu27I96tib90sXd2rYL54moAZi&qd} z(9B^8@D?fG>l9N{<0l{dQc9MV>4y6SBt7C7t17YdnqZa^VnCk$Mt#ZA9b&<$6B9u9 zD{9b;RkaaZ2jd?5?UcnB>*ua z3Y~IdaxiEWRQ+cQ4FhA2*u;wJeZ2;unM?Xa>^Zny+vKGI@3APDs2hj;CcC z+*q)ezd_i5x;L2oz|J6HJ~2T~6tDBHR|mtwyDbU^y$2rQ^(m8!f;&;m=I{ZhC3oZN zDNGXoUG~GR+_mL&SRbfmYNrNz+{m>$r!#Y2z(i8g!I_Zdv3sO$GuTm>A-?VCKghWi zaw8+b8$SI!YyJm*UV9mf_G1!wJIp?@=&=aWrCcrr9@5{I-=8EVJ#m0No*i#aP1RN` zx(Z`*Vr<-q>T0U^{=`idvEY{m{thM19qgeag)x?_Ku=PoUX=AoAXtxfnRT=~_Y$#(Loxe%@tX!$p)5Vj%uJs3fNgKLQe7!0^^FpRgtsQ1 z7aj_hA?5$Avq!9GToVgqhSPTYMX@0zU|u@~OVVzoSehDYmfeh5^s+9o(T=!>u^4A} z!CFU$!rQaPQ;fEFiH}rlC)8p<79VT36&<-XvOxO z2f@zsGU#@Oe#Z@$UHiPlkAZ;QBd$S<4hKgf<@e?65uWuk%!7c(UHAQ!iB6}E-!0;K zLwOMo1I9<~Tc(=pZSCKs3E>d5??jr!B)i<~K`?5{UE zg2bEkh^cdCOQA&Ta)QC%+wezbM!mXZ>Z3))w zCUuw!KP)G9vN@;N%>g4<J1~r)Zluny*01HTQSg@rdj%`n%XaY**GeRjg(& z7glp*er$4MSnBzuNZ!ek5xEs*bf!qUE+m;6%YrKSQHo~G&nrrMNEE6z1K38OtSwz) zO450P5eenQ^A)Vx%y639+Bjg?toF%|a7JhMf6kIWR^BQE>d6k+lxR)gsa?CqyRX{qk)m8ay%Ht`d>tC5xqIWsDf@{ycya_LRdxz6UgmAs|Nm2`)V<$#@%{hX5kNYt z<%2o3$WpQ(+m{D)M>pMXcmI}xl)dTpvwjM`08ys}UjbBw)j4S*iP|EZD1`W7@0%Oz z-J+`dueTXru)tDN9DRlE;>*rIihqt>vdl&gUy{b1$cjE`MA3)~)Wl zhICi!Y+&y(MR9HU3oOdZ8=JMh6Q}t3!80FI!h{C&e0qA%VqxLzhRbvO0`-`&2y42Z z@mFWjX(M2K=r8wy!jHr*p3*A2r%E8Z5NyKRZ9m>o_8*BOeYA=xfsj`=!B`!^+#9dK zx)7vlm5dnQ(8z<@M*HH7>}1Fzl;la;X_l|r9B=S#?B~5^TwI(!yWqUsxqChu4d0Z8 za&_y|GKLz>770q-VS3@!{&-$NjX#R$(P{Z5=!G!eZs_maxA-| zse}57GbIeG9BLLSn>k)|&jr=UY5Lt@25&$3=ylfx{q#s02dR*+KPf3EZ{PG6x;_W3 z8qnxO1j GPtnw7ln4&Qv;&@9G!l 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 YE2!4=dogwp6!1@0Qc0pn%*g+L0MP}Gr~m)} literal 0 HcmV?d00001 From b9062368ab9c2df1b371568609e8b05b54773f3c Mon Sep 17 00:00:00 2001 From: dosire Date: Fri, 24 Jan 2014 12:12:04 +0100 Subject: [PATCH 38/39] Embed screenshot. --- doc/integration/external-issue-tracker.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/integration/external-issue-tracker.md b/doc/integration/external-issue-tracker.md index fb645a5c9e..b2500a4751 100644 --- a/doc/integration/external-issue-tracker.md +++ b/doc/integration/external-issue-tracker.md @@ -4,4 +4,4 @@ GitLab has a great issue tracker but you can also use an external issue tracker - clicking 'New issue' on the project dashboard creates a new JIRA issue; - textual references to PROJECT-1234 in comments, commit messages get turned into HTML links to the corresponding JIRA issue. -Also see the [screenshot](jira-intergration-points.png) below. +[jira screenshot](jira-intergration-points.png) From 3de736ed0f48fc00073b6e2b8699a48ec64466fd Mon Sep 17 00:00:00 2001 From: dosire Date: Fri, 24 Jan 2014 12:12:36 +0100 Subject: [PATCH 39/39] Need ! to embed. --- doc/integration/external-issue-tracker.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/integration/external-issue-tracker.md b/doc/integration/external-issue-tracker.md index b2500a4751..02eadfd410 100644 --- a/doc/integration/external-issue-tracker.md +++ b/doc/integration/external-issue-tracker.md @@ -4,4 +4,4 @@ GitLab has a great issue tracker but you can also use an external issue tracker - clicking 'New issue' on the project dashboard creates a new JIRA issue; - textual references to PROJECT-1234 in comments, commit messages get turned into HTML links to the corresponding JIRA issue. -[jira screenshot](jira-intergration-points.png) +![jira screenshot](jira-intergration-points.png)