Remove user from all projects and set blocked attribute to true
+
+
+
+
+
# File app/roles/account.rb, line 47
+defblock
+ users_projects.find_eachdo|membership|
+ returnfalseunlessmembership.destroy
+ end
+
+ self.blocked = true
+ save
+end
+
+
+
+
+
+
+
+
+
+
+
+
+
+ can_create_group?()
+ click to toggle source
+
+
+
+
+
+
+
+
+
+
+
# File app/roles/account.rb, line 25
+defcan_create_group?
+ is_admin?
+end
+
+
+
+
+
+
+
+
+
+
+
+
+
+ can_create_project?()
+ click to toggle source
+
+
+
+
+
+
+
+
+
+
+
# File app/roles/account.rb, line 21
+defcan_create_project?
+ projects_limit>my_own_projects.count
+end
+
+
+
+
+
+
+
+
+
+
+
+
+
+ cared_merge_requests()
+ click to toggle source
+
+
+
+
+
+
+
+
+
+
+
# File app/roles/account.rb, line 37
+defcared_merge_requests
+ MergeRequest.where("author_id = :id or assignee_id = :id", id:self.id).opened
+end
+
+
+
+
+
+
+
+
+
+
+
+
+
+ first_name()
+ click to toggle source
+
+
+
+
+
+
+
+
+
+
+
# File app/roles/account.rb, line 33
+deffirst_name
+ name.split.firstunlessname.blank?
+end
+
+
+
+
+
+
+
+
+
+
+
+
+
+ identifier()
+ click to toggle source
+
+
+
+
+
+
Returns a string for use as a Gitolite user identifier
+
+
Note that Gitolite 2.x requires the following
+pattern for users:
+
+
^@?[0-9a-zA-Z][0-9a-zA-Z._\@+-]*$
+
+
+
+
+
# File app/roles/account.rb, line 7
+defidentifier
+ # Replace non-word chars with underscores, then make sure it starts with
+ # valid chars
+ email.gsub(%r\W/, '_').gsub(%r\A([\W\_])+/, '')
+end
+
+
+
+
+
+
+
+
+
+
+
+
+
+ is_admin?()
+ click to toggle source
+
+
+
+
+
+
+
+
+
+
+
# File app/roles/account.rb, line 13
+defis_admin?
+ admin
+end
+
+
+
+
+
+
+
+
+
+
+
+
+
+ last_activity_project()
+ click to toggle source
+
+
+
+
+
+
+
+
+
+
+
# File app/roles/account.rb, line 29
+deflast_activity_project
+ projects.first
+end
+
+
+
+
+
+
+
+
+
+
+
+
+
+ project_ids()
+ click to toggle source
+
+
+
+
+
+
+
+
+
+
+
# File app/roles/account.rb, line 41
+defproject_ids
+ projects.map(&:id)
+end
+
+
+
+
+
+
+
+
+
+
+
+
+
+ projects_limit_percent()
+ click to toggle source
+
+ emoji_autocomplete_source()
+ click to toggle source
+
+
+
+
+
+
+
+
+
+
+
# File app/helpers/application_helper.rb, line 115
+defemoji_autocomplete_source
+ # should be an array of strings
+ # so to_s can be called, because it is sufficient and to_json is too slow
+ Emoji.names.to_s
+end
Returns a link to the commit author. If the author has a matching user and
+is a member of the current @project it will link to the team member page.
+Otherwise it will link to the author email as specified in the commit.
Usually, the commit title is the first line of the commit message. In case
+this first line is longer than 80 characters, it is cut off after 70
+characters and ellipses (`&hellp;`) are appended.
+
+
+
+
+
# File app/decorators/commit_decorator.rb, line 18
+deftitle
+ title = safe_message
+
+ returnno_commit_messageiftitle.blank?
+
+ title_end = title.index(%r\n/)
+ if (!title_end&&title.length>80) || (title_end&&title_end>80)
+ title[0..69] <<"…".html_safe
+ else
+ title.split(%r\n/, 2).first
+ end
+end
Given a string containing both a Git tree-ish, such as a branch or tag, and
+a filesystem path joined by forward slashes, attempts to separate the two.
+
+
Expects a @project instance variable to contain the active project. This is
+used to check the input against a list of valid repository refs.
+
+
Examples
+
+
# No @project available
+extract_ref('master')
+# => ['', '']
+
+extract_ref('master')
+# => ['master', '']
+
+extract_ref("f4b14494ef6abf3d144c28e4af0c20143383e062/CHANGELOG")
+# => ['f4b14494ef6abf3d144c28e4af0c20143383e062', 'CHANGELOG']
+
+extract_ref("v2.0.0/README.md")
+# => ['v2.0.0', 'README.md']
+
+extract_ref('issues/1234/app/models/project.rb')
+# => ['issues/1234', 'app/models/project.rb']
+
+# Given an invalid branch, we fall back to just splitting on the first slash
+extract_ref('non/existent/branch/README.md')
+# => ['non', 'existent/branch/README.md']
+
+
+
Returns an Array where the first value is the tree-ish and the second is
+the path
+
+
+
+
+
# File lib/extracts_path.rb, line 45
+defextract_ref(input)
+ pair = ['', '']
+
+ returnpairunless@project
+
+ ifinput.match(%r^([[:alnum:]]{40})(.+)/)
+ # If the ref appears to be a SHA, we're done, just split the string
+ pair = $~.captures
+ else
+ # Otherwise, attempt to detect the ref using a list of the project's
+ # branches and tags
+
+ # Append a trailing slash if we only get a ref and no file path
+ id = input
+ id+='/'unlessid.ends_with?('/')
+
+ valid_refs = @project.ref_names
+ valid_refs.select! { |v|id.start_with?("#{v}/") }
+
+ ifvalid_refs.length!=1
+ # No exact ref match, so just try our best
+ pair = id.match(%r([^\/]+)(.*)/).captures
+ else
+ # Partition the string into the ref and the path, ignoring the empty first value
+ pair = id.partition(valid_refs.first)[1..-1]
+ end
+ end
+
+ # Remove ending slashes from path
+ pair[1].gsub!(%r^\/|\/$/, '')
+
+ pair
+end
# File lib/file_size_validator.rb, line 8
+definitialize(options)
+ ifrange = (options.delete(:in) ||options.delete(:within))
+ raiseArgumentError, ":in and :within must be a Range"unlessrange.is_a?(Range)
+ options[:minimum], options[:maximum] = range.begin, range.end
+ options[:maximum] -=1ifrange.exclude_end?
+ end
+
+ super
+end
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Public Instance Methods
+
+
+
+
+
+ check_validity!()
+ click to toggle source
+
+
+
+
+
+
+
+
+
+
+
# File lib/file_size_validator.rb, line 18
+defcheck_validity!
+ keys = CHECKS.keys & options.keys
+
+ ifkeys.empty?
+ raiseArgumentError, 'Range unspecified. Specify the :within, :maximum, :minimum, or :is option.'
+ end
+
+ keys.eachdo|key|
+ value = options[key]
+
+ unlessvalue.is_a?(Integer) &&value>=0
+ raiseArgumentError, ":#{key} must be a nonnegative Integer"
+ end
+ end
+end
+
+
+
+
+
+
+
+
+
+
+
+
+
+ help()
+ click to toggle source
+
+
+
+
+
+
+
+
+
+
+
# File lib/file_size_validator.rb, line 57
+defhelp
+ Helper.instance
+end
+
+
+
+
+
+
+
+
+
+
+
+
+
+ validate_each(record, attribute, value)
+ click to toggle source
+
Public: Parse the provided text with GitLab-Flavored Markdown
+
+
text - the source text #html_options - extra
+options for the reference links as given to link_to
+
+
Note: reference links will only be generated if @project is set
+
+
+
+
+
# File lib/gitlab/markdown.rb, line 48
+defgfm(text, html_options = {})
+ returntextiftext.nil?
+
+ # Duplicate the string so we don't alter the original, then call to_str
+ # to cast it back to a String instead of a SafeBuffer. This is required
+ # for gsub calls to work as we need them to.
+ text = text.dup.to_str
+
+ @html_options = html_options
+
+ # Extract pre blocks so they are not altered
+ # from http://github.github.com/github-flavored-markdown/
+ extractions = {}
+ text.gsub!(%r{<pre>.*?</pre>|<code>.*?</code>}) do|match|
+ md5 = Digest::MD5.hexdigest(match)
+ extractions[md5] = match
+ "{gfm-extraction-#{md5}}"
+ end
+
+ # TODO: add popups with additional information
+
+ text = parse(text)
+
+ # Insert pre block extractions
+ text.gsub!(%r\{gfm-extraction-(\h{32})\}/) do
+ extractions[$1]
+ end
+
+ sanitizetext.html_safe, attributes:ActionView::Base.sanitized_allowed_attributes+%w(id class)
+end
+ new(merge_request, user)
+ click to toggle source
+
+
+
+
+
+
+
+
+
+
+
# File lib/gitlab/merge.rb, line 5
+definitialize(merge_request, user)
+ @merge_request = merge_request
+ @project = merge_request.project
+ @user = user
+end
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Public Instance Methods
+
+
+
+
+
+ can_be_merged?()
+ click to toggle source
+
+
+
+
+
+
+
+
+
+
+
# File lib/gitlab/merge.rb, line 11
+defcan_be_merged?
+ in_locked_and_timed_satellitedo|merge_repo|
+ merge_in_satellite!(merge_repo)
+ end
+end
+
+
+
+
+
+
+
+
+
+
+
+
+
+ merge!()
+ click to toggle source
+
+
+
+
+
+
Merges the source branch into the target branch in the satellite and pushes
+it back to Gitolite. It also removes the source
+branch if requested in the merge request.
+
+
Returns false if the merge produced conflicts Returns false if pushing from
+the satallite to Gitolite failed or was
+rejected Returns true otherwise
+
+
+
+
+
# File lib/gitlab/merge.rb, line 24
+defmerge!
+ in_locked_and_timed_satellitedo|merge_repo|
+ ifmerge_in_satellite!(merge_repo)
+ # push merge back to Gitolite
+ # will raise CommandFailed when push fails
+ merge_repo.git.push({raise:true}, :origin, merge_request.target_branch)
+
+ # remove source branch
+ ifmerge_request.should_remove_source_branch&&!project.root_ref?(merge_request.source_branch)
+ # will raise CommandFailed when push fails
+ merge_repo.git.push({raise:true}, :origin, ":#{merge_request.source_branch}")
+ end
+
+ # merge, push and branch removal successful
+ true
+ end
+ end
+rescueGrit::Git::CommandFailed
+ false
+end
Use this in places where you would normally use link_to(gfm(…), …).
+
+
It solves a problem occurring with nested links (i.e. “<a>outer text
+<a>gfm ref</a> more outer text</a>”). This will not be
+interpreted as intended. Browsers will parse something like “<a>outer
+text </a><a>gfm ref</a> more outer text” (notice the last
+part is not linked any more). #link_to_gfm
+corrects that. It wraps all parts to explicitly produce the correct linking
+behavior (i.e. “<a>outer text </a><a>gfm
+ref</a><a> more outer text</a>”).
+ find_all_by_branch(branch_name)
+ click to toggle source
+
+
+
+
+
+
+
+
+
+
+
# File app/models/merge_request.rb, line 25
+defself.find_all_by_branch(branch_name)
+ where("source_branch LIKE :branch OR target_branch LIKE :branch", branch:branch_name)
+end
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Public Instance Methods
+
+
+
+
+
+ automerge!(current_user)
+ click to toggle source
+
# File app/models/merge_request.rb, line 94
+defunmerged_diffs
+ # Only show what is new in the source branch compared to the target branch, not the other way around.
+ # The linex below with merge_base is equivalent to diff with three dots (git diff branch1...branch2)
+ # From the git documentation: "git diff A...B" is equivalent to "git diff $(git-merge-base A B) B"
+ common_commit = project.repo.git.native(:merge_base, {}, [target_branch, source_branch]).strip
+ diffs = project.repo.diff(common_commit, source_branch)
+end
+
+
+
+
+
+
+
+
+
+
+
+
+
+ valid_diffs?()
+ click to toggle source
+
+
+
+
+
+
+
+
+
+
+
# File app/models/merge_request.rb, line 90
+defvalid_diffs?
+ !broken_diffs?
+end
+
+
+
+
+
+
+
+
+
+
+
+
+
+ validate_branches()
+ click to toggle source
+
+
+
+
+
+
+
+
+
+
+
# File app/models/merge_request.rb, line 38
+defvalidate_branches
+ iftarget_branch==source_branch
+ errors.add:base, "You can not use same branch for source and target branches"
+ end
+end
# File app/controllers/merge_requests_controller.rb, line 135
+defdefine_show_vars
+ # Build a note object for comment form
+ @note = @project.notes.new(noteable:@merge_request)
+
+ # Get commits from repository
+ # or from cache if already merged
+ @commits = @merge_request.commits
+ @commits = CommitDecorator.decorate(@commits)
+end
+
+
+
+
+
+
+
+
+
+
+
+
+
+ merge_request()
+ click to toggle source
+
+
+
+
+
+
+
+
+
+
+
# File app/controllers/merge_requests_controller.rb, line 110
+defmerge_request
+ @merge_request||=@project.merge_requests.find(params[:id])
+end
+
+
+
+
+
+
+
+
+
+
+
+
+
+ module_enabled()
+ click to toggle source
+
+
+
+
+
+
+
+
+
+
+
# File app/controllers/merge_requests_controller.rb, line 122
+defmodule_enabled
+ returnrender_404unless@project.merge_requests_enabled
+end
+
+
+
+
+
+
+
+
+
+
+
+
+
+ validates_merge_request()
+ click to toggle source
+
+
+
+
+
+
+
+
+
+
+
# File app/controllers/merge_requests_controller.rb, line 126
+defvalidates_merge_request
+ # Show git not found page if target branch doesnt exist
+ returngit_not_found!unless@project.repo.heads.map(&:name).include?(@merge_request.target_branch)
+
+ # Show git not found page if source branch doesnt exist
+ # and there is no saved commits between source & target branch
+ returngit_not_found!if!@project.repo.heads.map(&:name).include?(@merge_request.source_branch) &&@merge_request.commits.blank?
+end
# File app/observers/note_observer.rb, line 3
+defafter_create(note)
+ send_notify_mails(note)
+end
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Protected Instance Methods
+
+
+
+
+
+ notify_team(note)
+ click to toggle source
+
+
+
+
+
+
Notifies the whole team except the author of note
+
+
+
+
+
# File app/observers/note_observer.rb, line 22
+defnotify_team(note)
+ # Note: wall posts are not "attached" to anything, so fall back to "Wall"
+ noteable_type = note.noteable_type||"Wall"
+ notify_method = "note_#{noteable_type.underscore}_email".to_sym
+
+ ifNotify.respond_to?notify_method
+ team_without_note_author(note).mapdo|u|
+ Notify.send(notify_method, u.id, note.id).deliver
+ end
+ end
+end
+
+
+
+
+
+
+
+
+
+
+
+
+
+ send_notify_mails(note)
+ click to toggle source
+
+
+
+
+
+
+
+
+
+
+
# File app/observers/note_observer.rb, line 9
+defsend_notify_mails(note)
+ ifnote.notify
+ notify_team(note)
+ elsifnote.notify_author
+ # Notify only author of resource
+ Notify.note_commit_email(note.commit_author.id, note.id).deliver
+ else
+ # Otherwise ignore it
+ nil
+ end
+end
+
+
+
+
+
+
+
+
+
+
+
+
+
+ team_without_note_author(note)
+ click to toggle source
+
# File app/controllers/omniauth_callbacks_controller.rb, line 18
+defldap
+ # We only find ourselves here if the authentication to LDAP was successful.
+ @user = User.find_for_ldap_auth(request.env["omniauth.auth"], current_user)
+ if@user.persisted?
+ @user.remember_me = true
+ end
+ sign_in_and_redirect@user
+end
+ create_by_user(params, user)
+ click to toggle source
+
+
+
+
+
+
+
+
+
+
+
# File app/models/project.rb, line 60
+defcreate_by_user(params, user)
+ project = Project.newparams
+
+ Project.transactiondo
+ project.owner = user
+ project.save!
+
+ # Add user as project master
+ project.users_projects.create!(project_access:UsersProject::MASTER, user:user)
+
+ # when project saved no team member exist so
+ # project repository should be updated after first user add
+ project.update_repository
+ end
+
+ project
+rescueGitlab::Gitolite::AccessDenied =>ex
+ project.error_code = :gitolite
+ project
+rescue =>ex
+ project.error_code = :db
+ project.errors.add(:base, "Can't save project. Please try again later")
+ project
+end
+
+
+
+
+
+
+
+
+
+
+
+
+
+ search(query)
+ click to toggle source
+
+
+
+
+
+
+
+
+
+
+
# File app/models/project.rb, line 56
+defsearchquery
+ where("name LIKE :query OR code LIKE :query OR path LIKE :query", query:"%#{query}%")
+end
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Public Instance Methods
+
+
+
+
+
+ build_commit_note(commit)
+ click to toggle source
+
+
+
+
+
+
+
+
+
+
+
# File app/models/project.rb, line 124
+defbuild_commit_note(commit)
+ notes.new(noteable_id:commit.id, noteable_type:"Commit")
+end
+
+
+
+
+
+
+
+
+
+
+
+
+
+ check_limit()
+ click to toggle source
+
+
+
+
+
+
+
+
+
+
+
# File app/models/project.rb, line 98
+defcheck_limit
+ unlessowner.can_create_project?
+ errors[:base] << ("Your own projects limit is #{owner.projects_limit}! Please contact administrator to increase it")
+ end
+rescue
+ errors[:base] << ("Can't check your ability to create project")
+end
+
+
+
+
+
+
+
+
+
+
+
+
+
+ commit_line_notes(commit)
+ click to toggle source
+
+
+
+
+
+
+
+
+
+
+
# File app/models/project.rb, line 132
+defcommit_line_notes(commit)
+ notes.where(noteable_id:commit.id, noteable_type:"Commit").where("line_code IS NOT NULL")
+end
# File app/models/project.rb, line 90
+defgit_error?
+ error_code==:gitolite
+end
+
+
+
+
+
+
+
+
+
+
+
+
+
+ issues_labels()
+ click to toggle source
+
+
+
+
+
+
+
+
+
+
+
# File app/models/project.rb, line 160
+defissues_labels
+ issues.tag_counts_on(:labels)
+end
+
+
+
+
+
+
+
+
+
+
+
+
+
+ last_activity()
+ click to toggle source
+
+
+
+
+
+
+
+
+
+
+
# File app/models/project.rb, line 144
+deflast_activity
+ last_event
+end
+
+
+
+
+
+
+
+
+
+
+
+
+
+ last_activity_date()
+ click to toggle source
+
+
+
+
+
+
+
+
+
+
+
# File app/models/project.rb, line 148
+deflast_activity_date
+ last_event.try(:created_at) ||updated_at
+end
+
+
+
+
+
+
+
+
+
+
+
+
+
+ private?()
+ click to toggle source
+
+
+
+
+
+
+
+
+
+
+
# File app/models/project.rb, line 140
+defprivate?
+ private_flag
+end
+
+
+
+
+
+
+
+
+
+
+
+
+
+ project_id()
+ click to toggle source
+
+
+
+
+
+
+
+
+
+
+
# File app/models/project.rb, line 156
+defproject_id
+ self.id
+end
+
+
+
+
+
+
+
+
+
+
+
+
+
+ public?()
+ click to toggle source
+
+
+
+
+
+
+
+
+
+
+
# File app/models/project.rb, line 136
+defpublic?
+ !private_flag
+end
+
+
+
+
+
+
+
+
+
+
+
+
+
+ repo_name()
+ click to toggle source
+
+
+
+
+
+
+
+
+
+
+
# File app/models/project.rb, line 106
+defrepo_name
+ ifpath=="gitolite-admin"
+ errors.add(:path, " like 'gitolite-admin' is not allowed")
+ end
+end
+
+
+
+
+
+
+
+
+
+
+
+
+
+ saved?()
+ click to toggle source
+
+
+
+
+
+
+
+
+
+
+
# File app/models/project.rb, line 94
+defsaved?
+ id&&valid?
+end
+
+
+
+
+
+
+
+
+
+
+
+
+
+ to_param()
+ click to toggle source
+
+
+
+
+
+
+
+
+
+
+
# File app/models/project.rb, line 112
+defto_param
+ code
+end
+
+
+
+
+
+
+
+
+
+
+
+
+
+ web_url()
+ click to toggle source
+
+
+
+
+
+
+
+
+
+
+
# File app/models/project.rb, line 116
+defweb_url
+ [Gitlab.config.url, code].join("/")
+end
+ after_create(project)
+ click to toggle source
+
+
+
+
+
+
+
+
+
+
+
# File app/observers/project_observer.rb, line 12
+defafter_createproject
+ log_info("#{project.owner.name} created a new project \"#{project.name}\"")
+end
+
+
+
+
+
+
+
+
+
+
+
+
+
+ after_destroy(project)
+ click to toggle source
+
+
+
+
+
+
+
+
+
+
+
# File app/observers/project_observer.rb, line 6
+defafter_destroy(project)
+ log_info("Project \"#{project.name}\" was removed")
+
+ project.destroy_repository
+end
+
+
+
+
+
+
+
+
+
+
+
+
+
+ after_save(project)
+ click to toggle source
+
+
+
+
+
+
+
+
+
+
+
# File app/observers/project_observer.rb, line 2
+defafter_save(project)
+ project.update_repository
+end
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Protected Instance Methods
+
+
+
+
+
+ log_info(message)
+ click to toggle source
+
+
+
+
+
+
+
+
+
+
+
# File app/observers/project_observer.rb, line 18
+deflog_infomessage
+ Gitlab::AppLogger.infomessage
+end
# File app/controllers/projects_controller.rb, line 20
+defcreate
+ @project = Project.create_by_user(params[:project], current_user)
+
+ respond_todo|format|
+ format.htmldo
+ if@project.saved?
+ redirect_to(@project, notice:'Project was successfully created.')
+ else
+ renderaction:"new"
+ end
+ end
+ format.js
+ end
+end
+
+
+
+
+
+
+
+
+
+
+
+
+
+ destroy()
+ click to toggle source
+
+
+
+
+
+
+
+
+
+
+
# File app/controllers/projects_controller.rb, line 85
+defdestroy
+ # Disable the UsersProject update_repository call, otherwise it will be
+ # called once for every person removed from the project
+ UsersProject.skip_callback(:destroy, :after, :update_repository)
+ project.destroy
+ UsersProject.set_callback(:destroy, :after, :update_repository)
+
+ respond_todo|format|
+ format.html { redirect_toroot_path }
+ end
+end
+
+
+
+
+
+
+
+
+
+
+
+
+
+ edit()
+ click to toggle source
+
+
+
+
+
+
+
+
+
+
+
# File app/controllers/projects_controller.rb, line 17
+defedit
+end
+ grouper_project_members(project)
+ click to toggle source
+
+
+
+
+
+
+
+
+
+
+
# File app/helpers/projects_helper.rb, line 2
+defgrouper_project_members(project)
+ @project.users_projects.sort_by(&:project_access).reverse.group_by(&:project_access)
+end
+
+
+
+
+
+
+
+
+
+
+
+
+
+ link_to_project(project)
+ click to toggle source
+
+
+
+
+
+
+
+
+
+
+
# File app/helpers/projects_helper.rb, line 10
+deflink_to_projectproject
+ link_toproject.name, project
+end
+
+
+
+
+
+
+
+
+
+
+
+
+
+ remove_from_team_message(project, member)
+ click to toggle source
+
+
+
+
+
+
+
+
+
+
+
# File app/helpers/projects_helper.rb, line 6
+defremove_from_team_message(project, member)
+ "You are going to remove #{member.user_name} from #{project.name}. Are you sure?"
+end
# File app/roles/push_observer.rb, line 33
+defexecute_hooks(oldrev, newrev, ref, user)
+ ref_parts = ref.split('/')
+
+ # Return if this is not a push to a branch (e.g. new commits)
+ returnifref_parts[1] !~%rheads/||oldrev=="00000000000000000000000000000000"
+
+ data = post_receive_data(oldrev, newrev, ref, user)
+
+ hooks.each { |hook|hook.execute(data) }
+end
Returns an `li` element with an ‘active’ class if the supplied
+controller(s) and/or action(s) are currently active. The content of the
+element is the value passed to the block.
+
+
options - The options hash used to determine if the element is “active”
+(default: {})
+
+
:controller - One or more controller names to check (optional).
+:action - One or more action names to check (optional).
+:path - A shorthand path, such as 'dashboard#index', to check (optional).
+:html_options - Extra options to be passed to the list element (optional).
+
+
block - An optional block that will become the contents of the returned
+
+
`li` element.
+
+
When both :controller and :action are specified, BOTH must match in order
+to be marked as active. When only one is given, either can match.
# File app/helpers/tab_helper.rb, line 40
+defnav_link(options = {}, &block)
+ ifpath = options.delete(:path)
+ c, a, _ = path.split('#')
+ else
+ c = options.delete(:controller)
+ a = options.delete(:action)
+ end
+
+ ifc&&a
+ # When given both options, make sure BOTH are active
+ klass = current_controller?(*c) &¤t_action?(*a) ?'active':''
+ else
+ # Otherwise check EITHER option
+ klass = current_controller?(*c) ||current_action?(*a) ?'active':''
+ end
+
+ # Add our custom class into the html_options, which may or may not exist
+ # and which may or may not already have a :class key
+ o = options.delete(:html_options) || {}
+ o[:class] ||=''
+ o[:class] +=' '+klass
+ o[:class].strip!
+
+ ifblock_given?
+ content_tag(:li, capture(&block), o)
+ else
+ content_tag(:li, nil, o)
+ end
+end
+
+
+
+
+
+
+
+
+
+
+
+
+
+ project_tab_class()
+ click to toggle source
+
+
+
+
+
+
+
+
+
+
+
# File app/helpers/tab_helper.rb, line 70
+defproject_tab_class
+ [:show, :files, :edit, :update].eachdo|action|
+ return"active"ifcurrent_page?(controller:"projects", action:action, id:@project)
+ end
+
+ if ['snippets', 'hooks', 'deploy_keys', 'team_members'].include?controller.controller_name
+ "active"
+ end
+end
# File app/controllers/team_members_controller.rb, line 27
+defupdate
+ @team_member = project.users_projects.find(params[:id])
+ @team_member.update_attributes(params[:team_member])
+
+ unless@team_member.valid?
+ flash[:alert] = "User should have at least one role"
+ end
+ redirect_toproject_team_index_path(@project)
+end
Use this README file to introduce your application and point to useful
+places in the API for learning more. Run “rake doc:app” to generate API
+documentation for your models, controllers, helpers, and libraries.
+
+
+
+
+
+
+
diff --git a/doc/app/images/add.png b/doc/app/images/add.png
new file mode 100755
index 00000000..6332fefe
Binary files /dev/null and b/doc/app/images/add.png differ
diff --git a/doc/app/images/brick.png b/doc/app/images/brick.png
new file mode 100644
index 00000000..7851cf34
Binary files /dev/null and b/doc/app/images/brick.png differ
diff --git a/doc/app/images/brick_link.png b/doc/app/images/brick_link.png
new file mode 100644
index 00000000..9ebf013a
Binary files /dev/null and b/doc/app/images/brick_link.png differ
diff --git a/doc/app/images/bug.png b/doc/app/images/bug.png
new file mode 100644
index 00000000..2d5fb90e
Binary files /dev/null and b/doc/app/images/bug.png differ
diff --git a/doc/app/images/bullet_black.png b/doc/app/images/bullet_black.png
new file mode 100644
index 00000000..57619706
Binary files /dev/null and b/doc/app/images/bullet_black.png differ
diff --git a/doc/app/images/bullet_toggle_minus.png b/doc/app/images/bullet_toggle_minus.png
new file mode 100644
index 00000000..b47ce55f
Binary files /dev/null and b/doc/app/images/bullet_toggle_minus.png differ
diff --git a/doc/app/images/bullet_toggle_plus.png b/doc/app/images/bullet_toggle_plus.png
new file mode 100644
index 00000000..9ab4a896
Binary files /dev/null and b/doc/app/images/bullet_toggle_plus.png differ
diff --git a/doc/app/images/date.png b/doc/app/images/date.png
new file mode 100644
index 00000000..783c8335
Binary files /dev/null and b/doc/app/images/date.png differ
diff --git a/doc/app/images/delete.png b/doc/app/images/delete.png
new file mode 100755
index 00000000..08f24936
Binary files /dev/null and b/doc/app/images/delete.png differ
diff --git a/doc/app/images/find.png b/doc/app/images/find.png
new file mode 100644
index 00000000..15474796
Binary files /dev/null and b/doc/app/images/find.png differ
diff --git a/doc/app/images/loadingAnimation.gif b/doc/app/images/loadingAnimation.gif
new file mode 100644
index 00000000..82290f48
Binary files /dev/null and b/doc/app/images/loadingAnimation.gif differ
diff --git a/doc/app/images/macFFBgHack.png b/doc/app/images/macFFBgHack.png
new file mode 100644
index 00000000..c6473b32
Binary files /dev/null and b/doc/app/images/macFFBgHack.png differ
diff --git a/doc/app/images/package.png b/doc/app/images/package.png
new file mode 100644
index 00000000..da3c2a2d
Binary files /dev/null and b/doc/app/images/package.png differ
diff --git a/doc/app/images/page_green.png b/doc/app/images/page_green.png
new file mode 100644
index 00000000..de8e003f
Binary files /dev/null and b/doc/app/images/page_green.png differ
diff --git a/doc/app/images/page_white_text.png b/doc/app/images/page_white_text.png
new file mode 100644
index 00000000..813f712f
Binary files /dev/null and b/doc/app/images/page_white_text.png differ
diff --git a/doc/app/images/page_white_width.png b/doc/app/images/page_white_width.png
new file mode 100644
index 00000000..1eb88094
Binary files /dev/null and b/doc/app/images/page_white_width.png differ
diff --git a/doc/app/images/plugin.png b/doc/app/images/plugin.png
new file mode 100644
index 00000000..6187b15a
Binary files /dev/null and b/doc/app/images/plugin.png differ
diff --git a/doc/app/images/ruby.png b/doc/app/images/ruby.png
new file mode 100644
index 00000000..f763a168
Binary files /dev/null and b/doc/app/images/ruby.png differ
diff --git a/doc/app/images/tag_blue.png b/doc/app/images/tag_blue.png
new file mode 100755
index 00000000..3f02b5f8
Binary files /dev/null and b/doc/app/images/tag_blue.png differ
diff --git a/doc/app/images/tag_green.png b/doc/app/images/tag_green.png
new file mode 100644
index 00000000..83ec984b
Binary files /dev/null and b/doc/app/images/tag_green.png differ
diff --git a/doc/app/images/transparent.png b/doc/app/images/transparent.png
new file mode 100644
index 00000000..d665e179
Binary files /dev/null and b/doc/app/images/transparent.png differ
diff --git a/doc/app/images/wrench.png b/doc/app/images/wrench.png
new file mode 100644
index 00000000..5c8213fe
Binary files /dev/null and b/doc/app/images/wrench.png differ
diff --git a/doc/app/images/wrench_orange.png b/doc/app/images/wrench_orange.png
new file mode 100644
index 00000000..565a9330
Binary files /dev/null and b/doc/app/images/wrench_orange.png differ
diff --git a/doc/app/images/zoom.png b/doc/app/images/zoom.png
new file mode 100644
index 00000000..908612e3
Binary files /dev/null and b/doc/app/images/zoom.png differ
diff --git a/doc/app/index.html b/doc/app/index.html
new file mode 100644
index 00000000..a46b4fbc
--- /dev/null
+++ b/doc/app/index.html
@@ -0,0 +1,392 @@
+
+
+
+
+
+
+Rails Application Documentation
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/doc/install/databases.md b/doc/install/databases.md
index fade5d4f..6799a46e 100644
--- a/doc/install/databases.md
+++ b/doc/install/databases.md
@@ -11,8 +11,11 @@ GitLab supports the following databases:
# Install the database packages
sudo apt-get install -y mysql-server mysql-client libmysqlclient-dev
+ # Install only the necessary gems
+ sudo -u gitlab -H bundle install --deployment --without development test postgres
+
# Login to MySQL
- mysql -u root -p
+ $ mysql -u root -p
# Create a user for GitLab. (change $password to a real password)
mysql> CREATE USER 'gitlab'@'localhost' IDENTIFIED BY '$password';
@@ -27,25 +30,28 @@ GitLab supports the following databases:
mysql> \q
# Try connecting to the new database with the new user
- sudo -u git -H mysql -u gitlab -p -D gitlabhq_production
+ sudo -u gitlab -H mysql -u gitlab -p -D gitlabhq_production
## PostgreSQL
# Install the database packages
sudo apt-get install -y postgresql-9.1 libpq-dev
+ # Install only the necessary gems
+ sudo -u gitlab -H bundle install --deployment --without development test mysql
+
# Login to PostgreSQL
sudo -u postgres psql -d template1
# Create a user for GitLab. (change $password to a real password)
- template1=# CREATE USER git WITH PASSWORD '$password';
+ template1=# CREATE USER gitlab WITH PASSWORD '$password';
# Create the GitLab production database & grant all privileges on database
- template1=# CREATE DATABASE gitlabhq_production OWNER git;
+ template1=# CREATE DATABASE gitlabhq_production OWNER gitlab;
# Quit the database session
template1=# \q
# Try connecting to the new database with the new user
- sudo -u git -H psql -d gitlabhq_production
+ sudo -u gitlab -H psql -d gitlabhq_production
diff --git a/doc/install/installation.md b/doc/install/installation.md
index a9ae4b1e..ef42770e 100644
--- a/doc/install/installation.md
+++ b/doc/install/installation.md
@@ -1,23 +1,30 @@
-# Important notes
+This installation guide was created for Debian/Ubuntu and tested on it.
-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.
+Please read `doc/install/requirements.md` for hardware and platform 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).
-The following steps have been known to work. Please **use caution when you deviate** from this guide. Make sure you don't violate any assumptions GitLab makes about its environment.
+**Important Note:**
+The following steps have been known to work.
+If you deviate from this guide, do it with caution and make sure you don't
+violate any assumptions GitLab makes about its environment.
+For things like AWS installation scripts, init scripts or config files for
+alternative web server have a look at the "Advanced Setup Tips" section.
-If you find a bug/error in this guide please **submit a pull request** following the [`contributing guide`](../../CONTRIBUTING.md).
+
+**Important Note:**
+If you find a bug/error in this guide please submit an issue or pull request
+following the contribution guide (see `CONTRIBUTING.md`).
- - -
# Overview
-The GitLab installation consists of setting up the following components:
+The GitLab installation consists of setting up th following components:
1. Packages / Dependencies
2. Ruby
3. System Users
-4. GitLab shell
+4. Gitolite
5. Database
6. GitLab
7. Nginx
@@ -25,13 +32,16 @@ The GitLab installation consists of setting up the following components:
# 1. Packages / Dependencies
-`sudo` is not installed on Debian by default. Make sure your system is
-up-to-date and install it.
+`sudo` is not installed on Debian by default. If you don't have it you'll need
+to install it first.
# run as root
- apt-get update
- apt-get upgrade
- apt-get install sudo
+ apt-get update && apt-get upgrade && apt-get install sudo vim
+
+Make sure your system is up-to-date:
+
+ sudo apt-get update
+ sudo apt-get upgrade
**Note:**
Vim is an editor that is used here whenever there are files that need to be
@@ -42,7 +52,7 @@ edited by hand. But, you can use any editor you like instead.
Install the required packages:
- sudo apt-get install -y build-essential zlib1g-dev libyaml-dev libssl-dev libgdbm-dev libreadline-dev libncurses5-dev libffi-dev curl git-core openssh-server redis-server postfix checkinstall libxml2-dev libxslt-dev libcurl4-openssl-dev libicu-dev
+ sudo apt-get install -y build-essential zlib1g-dev libyaml-dev libssl-dev libgdbm-dev libreadline-dev libncurses5-dev libffi-dev wget curl git-core openssh-server redis-server postfix checkinstall libxml2-dev libxslt-dev libcurl4-openssl-dev libicu-dev
Make sure you have the right version of Python installed.
@@ -66,9 +76,9 @@ Make sure you have the right version of Python installed.
Download and compile it:
- mkdir /tmp/ruby && cd /tmp/ruby
- curl --progress http://ftp.ruby-lang.org/pub/ruby/1.9/ruby-1.9.3-p392.tar.gz | tar xz
- cd ruby-1.9.3-p392
+ wget http://ftp.ruby-lang.org/pub/ruby/1.9/ruby-1.9.3-p327.tar.gz
+ tar xfvz ruby-1.9.3-p327.tar.gz
+ cd ruby-1.9.3-p327
./configure
make
sudo make install
@@ -80,86 +90,111 @@ Install the Bundler Gem:
# 3. System Users
-Create a `git` user for Gitlab:
+Create a user for Git and Gitolite:
- sudo adduser --disabled-login --gecos 'GitLab' git
+ sudo adduser \
+ --system \
+ --shell /bin/sh \
+ --gecos 'Git Version Control' \
+ --group \
+ --disabled-password \
+ --home /home/git \
+ git
+
+Create a user for GitLab:
+
+ sudo adduser --disabled-login --gecos 'GitLab' gitlab
+
+ # Add it to the git group
+ sudo usermod -a -G git gitlab
+
+ # Generate the SSH key
+ sudo -u gitlab -H ssh-keygen -q -N '' -t rsa -f /home/gitlab/.ssh/id_rsa
-# 4. GitLab shell
+# 4. Gitolite
-GitLab Shell is a ssh access and repository management software developed specially for GitLab.
+Clone GitLab's fork of the Gitolite source code:
- # Login as git
- sudo su git
-
- # Go to home directory
cd /home/git
+ sudo -u git -H git clone -b gl-v320 https://github.com/gitlabhq/gitolite.git /home/git/gitolite
- # Clone gitlab shell
- git clone https://github.com/gitlabhq/gitlab-shell.git
+Setup Gitolite with GitLab as its admin:
- cd gitlab-shell
- cp config.yml.example config.yml
+**Important Note:**
+GitLab assumes *full and unshared* control over this Gitolite installation.
- # Edit config and replace gitlab_url
- # with something like 'http://domain.com/'
- vim config.yml
+ # Add Gitolite scripts to $PATH
+ sudo -u git -H mkdir /home/git/bin
+ sudo -u git -H sh -c 'printf "%b\n%b\n" "PATH=\$PATH:/home/git/bin" "export PATH" >> /home/git/.profile'
+ sudo -u git -H sh -c 'gitolite/install -ln /home/git/bin'
- # Do setup
- ./bin/install
+ # Copy the gitlab user's (public) SSH key ...
+ sudo cp /home/gitlab/.ssh/id_rsa.pub /home/git/gitlab.pub
+ sudo chmod 0444 /home/git/gitlab.pub
+
+ # ... and use it as the admin key for the Gitolite setup
+ sudo -u git -H sh -c "PATH=/home/git/bin:$PATH; gitolite setup -pk /home/git/gitlab.pub"
+
+Fix the directory permissions for the repositories:
+
+ # Make sure the repositories dir is owned by git and it stays that way
+ sudo chmod -R ug+rwXs,o-rwx /home/git/repositories/
+ sudo chown -R git:git /home/git/repositories/
+
+## Test if everything works so far
+
+ # Clone the admin repo so SSH adds localhost to known_hosts ...
+ # ... and to be sure your users have access to Gitolite
+ sudo -u gitlab -H git clone git@localhost:gitolite-admin.git /tmp/gitolite-admin
+
+ # If it succeeded without errors you can remove the cloned repo
+ sudo rm -rf /tmp/gitolite-admin
+
+**Important Note:**
+If you can't clone the `gitolite-admin` repository: **DO NOT PROCEED WITH INSTALLATION**!
+Check the [Trouble Shooting Guide](https://github.com/gitlabhq/gitlab-public-wiki/wiki/Trouble-Shooting-Guide)
+and make sure you have followed all of the above steps carefully.
# 5. Database
-To setup the MySQL/PostgreSQL database and dependencies please see [`doc/install/databases.md`](./databases.md).
+See `doc/install/databases.md`
# 6. GitLab
- # We'll install GitLab into home directory of the user "git"
- cd /home/git
+ # We'll install GitLab into home directory of the user "gitlab"
+ cd /home/gitlab
## Clone the Source
- # Clone GitLab repository
- sudo -u git -H git clone https://github.com/gitlabhq/gitlabhq.git gitlab
-
- # Go to gitlab dir
- cd /home/git/gitlab
-
- # Checkout to stable release
- sudo -u git -H git checkout 5-0-stable
+ # Clone the latest stable release
+ sudo -u gitlab -H git clone -b stable https://github.com/gitlabhq/gitlabhq.git gitlab
**Note:**
-You can change `5-0-stable` to `master` if you want the *bleeding edge* version, but
+You can change `stable` to `master` if you want the *bleeding edge* version, but
do so with caution!
## Configure it
- cd /home/git/gitlab
+ cd /home/gitlab/gitlab
# Copy the example GitLab config
- sudo -u git -H cp config/gitlab.yml.example config/gitlab.yml
+ sudo -u gitlab -H cp config/gitlab.yml.example config/gitlab.yml
# Make sure to change "localhost" to the fully-qualified domain name of your
# host serving GitLab where necessary
- sudo -u git -H vim config/gitlab.yml
+ sudo -u gitlab -H vim config/gitlab.yml
# Make sure GitLab can write to the log/ and tmp/ directories
- sudo chown -R git log/
- sudo chown -R git tmp/
+ sudo chown -R gitlab log/
+ sudo chown -R gitlab tmp/
sudo chmod -R u+rwX log/
sudo chmod -R u+rwX tmp/
- # Create directory for satellites
- sudo -u git -H mkdir /home/git/gitlab-satellites
-
- # Create directory for pids and make sure GitLab can write to it
- sudo -u git -H mkdir tmp/pids/
- sudo chmod -R u+rwX tmp/pids/
-
# Copy the example Unicorn config
- sudo -u git -H cp config/unicorn.rb.example config/unicorn.rb
+ sudo -u gitlab -H cp config/unicorn.rb.example config/unicorn.rb
**Important Note:**
Make sure to edit both files to match your setup.
@@ -167,36 +202,63 @@ Make sure to edit both files to match your setup.
## Configure GitLab DB settings
# Mysql
- sudo -u git cp config/database.yml.mysql config/database.yml
+ sudo -u gitlab cp config/database.yml.mysql config/database.yml
# PostgreSQL
- sudo -u git cp config/database.yml.postgresql config/database.yml
+ sudo -u gitlab cp config/database.yml.postgresql config/database.yml
Make sure to update username/password in config/database.yml.
## Install Gems
- cd /home/git/gitlab
+ cd /home/gitlab/gitlab
sudo gem install charlock_holmes --version '0.6.9'
- # For MySQL (note, the option says "without")
- sudo -u git -H bundle install --deployment --without development test postgres
+ # For mysql db
+ sudo -u gitlab -H bundle install --deployment --without development test postgres
- # Or for PostgreSQL
- sudo -u git -H bundle install --deployment --without development test mysql
+ # Or For postgres db
+ sudo -u gitlab -H bundle install --deployment --without development test mysql
+## Configure Git
+
+GitLab needs to be able to commit and push changes to Gitolite. In order to do
+that Git requires a username and email. (We recommend using the same address
+used for the `email.from` setting in `config/gitlab.yml`)
+
+ sudo -u gitlab -H git config --global user.name "GitLab"
+ sudo -u gitlab -H git config --global user.email "gitlab@localhost"
+
+## Setup GitLab Hooks
+
+ sudo cp ./lib/hooks/post-receive /home/git/.gitolite/hooks/common/post-receive
+ sudo chown git:git /home/git/.gitolite/hooks/common/post-receive
## Initialise Database and Activate Advanced Features
- sudo -u git -H bundle exec rake gitlab:setup RAILS_ENV=production
+ sudo -u gitlab -H bundle exec rake gitlab:app:setup RAILS_ENV=production
+
+
+## Check Application Status
+
+Check if GitLab and its environment is configured correctly:
+
+ sudo -u gitlab -H bundle exec rake gitlab:env:info RAILS_ENV=production
+
+To make sure you didn't miss anything run a more thorough check with:
+
+ sudo -u gitlab -H bundle exec rake gitlab:check RAILS_ENV=production
+
+If you are all green: congratulations, you successfully installed GitLab!
+Although this is the case, there are still a few steps to go.
## Install Init Script
Download the init script (will be /etc/init.d/gitlab):
- sudo curl --output /etc/init.d/gitlab https://raw.github.com/gitlabhq/gitlab-recipes/master/init.d/gitlab
+ sudo wget https://raw.github.com/gitlabhq/gitlab-recipes/master/init.d/gitlab -P /etc/init.d/
sudo chmod +x /etc/init.d/gitlab
Make GitLab start on boot:
@@ -204,20 +266,7 @@ Make GitLab start on boot:
sudo update-rc.d gitlab defaults 21
-## Check Application Status
-
-Check if GitLab and its environment are configured correctly:
-
- sudo -u git -H bundle exec rake gitlab:env:info RAILS_ENV=production
-
-To make sure you didn't miss anything run a more thorough check with:
-
- sudo -u git -H bundle exec rake gitlab:check RAILS_ENV=production
-
-If all items are green, then congratulations on successfully installing GitLab!
-However there are still a few steps left.
-
-## Start Your GitLab Instance
+Start your GitLab instance:
sudo service gitlab start
# or
@@ -228,7 +277,7 @@ However there are still a few steps left.
**Note:**
If you can't or don't want to use Nginx as your web server, have a look at the
-[`Advanced Setup Tips`](./installation.md#advanced-setup-tips) section.
+"Advanced Setup Tips" section.
## Installation
sudo apt-get install nginx
@@ -237,7 +286,7 @@ If you can't or don't want to use Nginx as your web server, have a look at the
Download an example site config:
- sudo curl --output /etc/nginx/sites-available/gitlab https://raw.github.com/gitlabhq/gitlab-recipes/master/nginx/gitlab
+ sudo wget https://raw.github.com/gitlabhq/gitlab-recipes/master/nginx/gitlab -P /etc/nginx/sites-available/
sudo ln -s /etc/nginx/sites-available/gitlab /etc/nginx/sites-enabled/gitlab
Make sure to edit the config file to match your setup:
@@ -245,11 +294,11 @@ Make sure to edit the config file to match your setup:
# Change **YOUR_SERVER_IP** and **YOUR_SERVER_FQDN**
# to the IP address and fully-qualified domain name
# of your host serving GitLab
- sudo vim /etc/nginx/sites-available/gitlab
+ sudo vim /etc/nginx/sites-enabled/gitlab
## Restart
- sudo service nginx restart
+ sudo /etc/init.d/nginx restart
# Done!
@@ -279,40 +328,10 @@ a different host, you can configure its connection string via the
`config/resque.yml` file.
# example
- production: redis://redis.example.tld:6379
+ production: redis.example.tld:6379
-## Custom SSH Connection
-If you are running SSH on a non-standard port, you must change the gitlab user's SSH config.
+## User-contributed Configurations
- # Add to /home/git/.ssh/config
- host localhost # Give your setup a name (here: override localhost)
- user git # Your remote git user
- port 2222 # Your port number
- hostname 127.0.0.1; # Your server name or IP
-
-You also need to change the corresponding options (e.g. ssh_user, ssh_host, admin_uri) in the `config\gitlab.yml` file.
-
-## LDAP authentication
-
-You can configure LDAP authentication in config/gitlab.yml. Please restart GitLab after editing this file.
-
-## Using Custom Omniauth Providers
-
-GitLab uses [Omniauth](http://www.omniauth.org/) for authentication and already ships with a few providers preinstalled (e.g. LDAP, GitHub, Twitter). But sometimes that is not enough and you need to integrate with other authentication solutions. For these cases you can use the Omniauth provider.
-
-### Steps
-
-These steps are fairly general and you will need to figure out the exact details from the Omniauth provider's documentation.
-
-* Add `gem "omniauth-your-auth-provider"` to the [Gemfile](https://github.com/gitlabhq/gitlabhq/blob/master/Gemfile#L18)
-* Run `sudo -u gitlab -H bundle install` to install the new gem(s)
-* Add provider specific configuration options to your `config/gitlab.yml` (you can use the [auth providers section of the example config](https://github.com/gitlabhq/gitlabhq/blob/master/config/gitlab.yml.example#L53) as a reference)
-* Add icons for the new provider into the [vendor/assets/images/authbuttons](https://github.com/gitlabhq/gitlabhq/tree/master/vendor/assets/images/authbuttons) directory (you can find some more popular ones over at https://github.com/intridea/authbuttons)
-* Restart GitLab
-
-### Examples
-
-If you have successfully set up a provider that is not shipped with GitLab itself, please let us know.
-You can help others by reporting successful configurations and probably share a few insights or provide warnings for common errors or pitfalls by sharing your experience [in the public Wiki](https://github.com/gitlabhq/gitlab-public-wiki/wiki/Working-Custom-Omniauth-Provider-Configurations).
-While we can't officially support every possible auth mechanism out there, we'd like to at least help those with special needs.
+You can find things like AWS installation scripts, init scripts or config files
+for alternative web server in our [recipes collection](https://github.com/gitlabhq/gitlab-recipes/).
diff --git a/doc/install/requirements.md b/doc/install/requirements.md
index 9209fad5..ec5b013c 100644
--- a/doc/install/requirements.md
+++ b/doc/install/requirements.md
@@ -1,3 +1,13 @@
+# Hardware
+
+We recommend you to run GitLab on a server with at least 1GB RAM.
+
+The necessary hard disk space largely depends on the size of the repos you want
+to use GitLab with. But as a *rule of thumb* you should have at least as much
+free space as your all repos combined take up.
+
+
+
# Operating Systems
## Linux
@@ -26,7 +36,8 @@ systems. This means you may get it to work on systems running FreeBSD or OS X.
## Windows
GitLab does **not** run on Windows and we have no plans of supporting it in the
-near future. Please consider using a virtual machine to run GitLab.
+near future.
+
# Rubies
@@ -37,24 +48,6 @@ While it is generally possible to use other Rubies (like
some work on your part.
-# Hardware requirements
-
-## CPU
-
-We recommend a processor with **4 cores**. At a minimum you need a processor with 2 cores to responsively run an unmodified installation.
-
-## Memory
-
-We recommend you to run GitLab on a server with at least **1GB of RAM** memory. You can use it with 512MB of memory but you need to setup unicorn to use only 1 worker and you need at least 200MB of swap. The minimal requirement for an unmodified installation is 768MB. With 1.5GB of memory you should be able to support 1000+ users.
-
-## Storage
-
-The necessary hard drive space largely depends on the size of the repos you want
-to store in GitLab. But as a *rule of thumb* you should have at least twice as much
-free space as your all repos combined take up. You need twice the storage because [GitLab satellites](https://github.com/gitlabhq/gitlabhq/blob/master/doc/install/structure.md) contain an extra copy of each repo. Apart from a local hard drive you can also mount a volume that supports the network file system (NFS) protocol. This volume might be located on a file server, a network attached storage (NAS) device, a storage area network (SAN) or on an Amazon Web Services (AWS) Elastic Block Store (EBS) volume.
-
-If you have enough RAM memory and a recent CPU the speed of GitLab is mainly limited by hard drive seek times. Having a fast drive (7200 RPM and up) or a solid state drive (SSD) will improve the responsiveness of GitLab.
-
# Installation troubles and reporting success or failure
diff --git a/doc/install/structure.md b/doc/install/structure.md
deleted file mode 100644
index f580ea15..00000000
--- a/doc/install/structure.md
+++ /dev/null
@@ -1,27 +0,0 @@
-# GitLab directory structure
-
-This is the directory structure you will end up with following the instructions in the Installation Guide.
-
- |-- home
- | |-- git
- | |-- .ssh
- | |-- gitlab
- | |-- gitlab-satellites
- | |-- gitlab-shell
- | |-- repositories
-
-
-**/home/git/.ssh**
-
-**/home/git/gitlab**
- This is where GitLab lives.
-
-**/home/git/gitlab-satellites**
- Contains a copy of all repositories with a working tree.
- It's used for merge requests, editing files, etc.
-
-**/home/git/repositories**
- Holds all your repositories in bare format.
- This is the place Git uses when you pull/push to your projects.
-
-You can change them in your `config/gitlab.yml` file.
diff --git a/doc/raketasks/backup_restore.md b/doc/raketasks/backup_restore.md
index d2da64f3..bbfeeb71 100644
--- a/doc/raketasks/backup_restore.md
+++ b/doc/raketasks/backup_restore.md
@@ -4,7 +4,7 @@ Creates a backup archive of the database and all repositories. This archive will
The filename will be `[TIMESTAMP]_gitlab_backup.tar`. This timestamp can be used to restore an specific backup.
```
-bundle exec rake gitlab:backup:create RAILS_ENV=production
+bundle exec rake gitlab:backup:create
```
Example output:
@@ -31,6 +31,7 @@ Dumping database tables:
- Dumping table wikis... [DONE]
Dumping repositories:
- Dumping repository abcd... [DONE]
+- Dumping repository gitolite-admin.git... [DONE]
Creating backup archive: $TIMESTAMP_gitlab_backup.tar [DONE]
Deleting tmp directories...[DONE]
Deleting old backups... [SKIPPING]
@@ -39,7 +40,7 @@ Deleting old backups... [SKIPPING]
### Restore a previously created backup
```
-bundle exec rake gitlab:backup:restore RAILS_ENV=production
+bundle exec rake gitlab:backup:restore
```
Options:
@@ -76,5 +77,6 @@ Restoring database tables:
- Loading fixture wikis...[SKIPPING]
Restoring repositories:
- Restoring repository abcd... [DONE]
+- Restoring repository gitolite-admin.git... [DONE]
Deleting tmp directories...[DONE]
```
diff --git a/doc/raketasks/cleanup.md b/doc/raketasks/cleanup.md
deleted file mode 100644
index 30a5d362..00000000
--- a/doc/raketasks/cleanup.md
+++ /dev/null
@@ -1,14 +0,0 @@
-### Remove grabage from filesystem. Important! Data loss!
-
-Remove namespaces(dirs) from /home/git/repositories if they dont exist in GitLab database
-
-```
-bundle exec rake gitlab:cleanup:dirs RAILS_ENV=production
-```
-
-Remove repositories (global only for now) from /home/git/repositories if they dont exist in GitLab database
-
-```
-bundle exec rake gitlab:cleanup:repos RAILS_ENV=production
-```
-
diff --git a/doc/raketasks/features.md b/doc/raketasks/features.md
index 018817d2..7a2a4b66 100644
--- a/doc/raketasks/features.md
+++ b/doc/raketasks/features.md
@@ -13,16 +13,16 @@ Old path: `git@example.org:myrepo.git`
New path: `git@example.org:username/myrepo.git` or `git@example.org:groupname/myrepo.git`
```
-bundle exec rake gitlab:enable_namespaces RAILS_ENV=production
+bundle exec rake gitlab:enable_namespaces
```
-### Rebuild project satellites
+### Enable auto merge
-This command will build missing satellites for projects. After this you will be able to **merge a merge request** via GitLab and use the **online editor**.
+This command will enable the auto merge feature. After this you will be able to **merge a merge request** via GitLab and use the **online editor**.
```
-bundle exec rake gitlab:satellites:create RAILS_ENV=production
+bundle exec rake gitlab:enable_automerge
```
Example output:
diff --git a/doc/raketasks/maintenance.md b/doc/raketasks/maintenance.md
index b5514705..bb8e1ed2 100644
--- a/doc/raketasks/maintenance.md
+++ b/doc/raketasks/maintenance.md
@@ -1,10 +1,23 @@
+### Setup production application
+
+Runs the following rake tasks:
+
+* db:setup (Create the database, load the schema, and initialize with the seed data)
+* db:seed_fu (Loads seed data for the current environment.)
+* gitlab:app:enable_automerge (see "Features")
+
+```
+bundle exec rake gitlab:app:setup
+```
+
+
### Gather information about GitLab and the system it runs on
This command gathers information about your GitLab installation and the System
it runs on. These may be useful when asking for help or reporting issues.
```
-bundle exec rake gitlab:env:info RAILS_ENV=production
+bundle exec rake gitlab:env:info
```
Example output:
@@ -15,7 +28,7 @@ System: Debian 6.0.6
Current User: gitlab
Using RVM: yes
RVM Version: 1.17.2
-Ruby Version: ruby-1.9.3-p392
+Ruby Version: ruby-1.9.3-p327
Gem Version: 1.8.24
Bundler Version:1.2.3
Rake Version: 10.0.1
@@ -31,10 +44,12 @@ SSH Clone URL: git@localhost:some-project.git
Using LDAP: no
Using Omniauth: no
-GitLab Shell
-Version: 1.0.4
+Gitolite information
+Version: v3.04-4-g4524f01
+Admin URI: git@localhost:gitolite-admin
+Admin Key: gitlab
Repositories: /home/git/repositories/
-Hooks: /home/git/gitlab-shell/hooks/
+Hooks: /home/git/.gitolite/hooks/
Git: /usr/bin/git
```
@@ -44,8 +59,8 @@ Git: /usr/bin/git
Runs the following rake tasks:
* gitlab:env:check
-* gitlab:gitlab_shell:check
-* gitlab:sidekiq:check
+* gitlab:gitolite:check
+* gitlab:resque:check
* gitlab:app:check
It will check that each component was setup according to the installation guide and suggest fixes for issues found.
@@ -53,7 +68,7 @@ It will check that each component was setup according to the installation guide
You may also have a look at our [Trouble Shooting Guide](https://github.com/gitlabhq/gitlab-public-wiki/wiki/Trouble-Shooting-Guide).
```
-bundle exec rake gitlab:check RAILS_ENV=production
+bundle exec rake gitlab:check
```
Example output:
@@ -72,12 +87,16 @@ Checking Environment ... Finished
Checking Gitolite ...
Using recommended version ... yes
+Repo umask is 0007 in .gitolite.rc? ... yes
+Allow all Git config keys in .gitolite.rc ... yes
Config directory exists? ... yes
Config directory owned by git:git? ... yes
Config directory access is drwxr-x---? ... yes
Repo base directory exists? ... yes
Repo base owned by git:git? ... yes
-Repo base access is drwxrws---? ... yes
+Repo base access is drwsrws---? ... yes
+Can clone gitolite-admin? ... yes
+Can commit to gitolite-admin? ... yes
post-receive hook exists? ... yes
post-receive hook up-to-date? ... yes
post-receive hooks in repos are links: ...
@@ -126,7 +145,25 @@ This will create satellite repos for all your projects.
If necessary, remove the `tmp/repo_satellites` directory and rerun the command below.
```
-bundle exec rake gitlab:satellites:create RAILS_ENV=production
+bundle exec rake gitlab:satellites:create
+```
+
+
+### Rebuild each key at gitolite config
+
+This will send all users ssh public keys to gitolite and grant them access (based on their permission) to their projects.
+
+```
+bundle exec rake gitlab:gitolite:update_keys
+```
+
+
+### Rebuild each project at gitolite config
+
+This makes sure that all projects are present in gitolite and can be accessed.
+
+```
+bundle exec rake gitlab:gitolite:update_repos
```
### Import bare repositories into GitLab project instance
diff --git a/features/admin/groups.feature b/features/admin/groups.feature
index 28f35e3a..e5eab8e6 100644
--- a/features/admin/groups.feature
+++ b/features/admin/groups.feature
@@ -1,8 +1,6 @@
Feature: Admin Groups
Background:
Given I sign in as an admin
- And I have group with projects
- And Create gitlab user "John"
And I visit admin groups page
Scenario: Create a group
@@ -10,8 +8,3 @@ Feature: Admin Groups
And submit form with new group info
Then I should be redirected to group page
And I should see newly created group
-
- Scenario: Add user into projects in group
- When I visit admin group page
- When I select user "John" from user list as "Reporter"
- Then I should see "John" in team list in every project as "Reporter"
diff --git a/features/admin/logs.feature b/features/admin/logs.feature
deleted file mode 100644
index d07f0048..00000000
--- a/features/admin/logs.feature
+++ /dev/null
@@ -1,7 +0,0 @@
-Feature: Admin Logs
- Background:
- Given I sign in as an admin
-
- Scenario: On Admin Logs
- Given I visit admin logs page
- Then I should see tabs with available logs
diff --git a/features/admin/projects.feature b/features/admin/projects.feature
deleted file mode 100644
index 4a4ee1c1..00000000
--- a/features/admin/projects.feature
+++ /dev/null
@@ -1,13 +0,0 @@
-Feature: Admin Projects
- Background:
- Given I sign in as an admin
- And there are projects in system
-
- Scenario: Projects list
- When I visit admin projects page
- Then I should see all projects
-
- Scenario: Projects show
- When I visit admin projects page
- And I click on first project
- Then I should see project details
diff --git a/features/admin/teams.feature b/features/admin/teams.feature
deleted file mode 100644
index 6a15fddc..00000000
--- a/features/admin/teams.feature
+++ /dev/null
@@ -1,70 +0,0 @@
-Feature: Admin Teams
- Background:
- Given I sign in as an admin
- And Create gitlab user "John"
-
- Scenario: Create a team
- When I visit admin teams page
- And I click new team link
- And submit form with new team info
- Then I should be redirected to team page
- And I should see newly created team
-
- Scenario: Add user to team
- When I visit admin teams page
- When I have clean "HardCoders" team
- And I visit "HardCoders" team page
- When I click to "Add members" link
- When I select user "John" from user list as "Developer"
- And submit form with new team member info
- Then I should see "John" in teams members list as "Developer"
-
- Scenario: Assign team to existing project
- When I visit admin teams page
- When I have "HardCoders" team with "John" member with "Developer" role
- When I have "Shop" project
- And I visit "HardCoders" team page
- Then I should see empty projects table
- When I click to "Add projects" link
- When I select project "Shop" with max access "Reporter"
- And submit form with new team project info
- Then I should see "Shop" project in projects list
- When I visit "Shop" project admin page
- Then I should see "John" user with role "Reporter" in team table
-
- Scenario: Add user to team with ptojects
- When I visit admin teams page
- When I have "HardCoders" team with "John" member with "Developer" role
- And "HardCoders" team assigned to "Shop" project with "Developer" max role access
- When I have gitlab user "Jimm"
- And I visit "HardCoders" team page
- Then I should see members table without "Jimm" member
- When I click to "Add members" link
- When I select user "Jimm" ub team members list as "Master"
- And submit form with new team member info
- Then I should see "Jimm" in teams members list as "Master"
-
- Scenario: Remove member from team
- Given I have users team "HardCoders"
- And gitlab user "John" is a member "HardCoders" team
- And gitlab user "Jimm" is a member "HardCoders" team
- And "HardCoders" team is assigned to "Shop" project
- When I visit admin teams page
- When I visit "HardCoders" team admin page
- Then I shoould see "John" in members list
- And I should see "Jimm" in members list
- And I should see "Shop" in projects list
- When I click on remove "Jimm" user link
- Then I should be redirected to "HardCoders" team admin page
- And I should not to see "Jimm" user in members list
-
- Scenario: Remove project from team
- Given I have users team "HardCoders"
- And gitlab user "John" is a member "HardCoders" team
- And gitlab user "Jimm" is a member "HardCoders" team
- And "HardCoders" team is assigned to "Shop" project
- When I visit admin teams page
- When I visit "HardCoders" team admin page
- Then I should see "Shop" project in projects list
- When I click on "Relegate" link on "Shop" project
- Then I should see projects liston team page without "Shop" project
diff --git a/features/admin/users.feature b/features/admin/users.feature
deleted file mode 100644
index 4c951df9..00000000
--- a/features/admin/users.feature
+++ /dev/null
@@ -1,16 +0,0 @@
-Feature: Admin Users
- Background:
- Given I sign in as an admin
- And system has users
-
- Scenario: On Admin Users
- Given I visit admin users page
- Then I should see all users
-
- Scenario: Edit user and change username to non ascii char
- When I visit admin users page
- And Click edit
- And Input non ascii char in username
- And Click save
- Then See username error message
- And Not chenged form action url
diff --git a/features/dashboard/dashboard.feature b/features/dashboard/dashboard.feature
index 695148b5..972f8e36 100644
--- a/features/dashboard/dashboard.feature
+++ b/features/dashboard/dashboard.feature
@@ -5,7 +5,6 @@ Feature: Dashboard
And project "Shop" has push event
And I visit dashboard page
- @javascript
Scenario: I should see projects list
Then I should see "New Project" link
Then I should see "Shop" project link
@@ -16,18 +15,22 @@ Feature: Dashboard
And I visit dashboard page
Then I should see groups list
+ Scenario: I should see correct projects count
+ Given I have group with projects
+ And group has a projects that does not belongs to me
+ When I visit dashboard page
+ Then I should see 1 project at group list
+
Scenario: I should see last push widget
Then I should see last push widget
And I click "Create Merge Request" link
Then I see prefilled new Merge Request page
- @javascript
Scenario: I should see User joined Project event
Given user with name "John Doe" joined project "Shop"
When I visit dashboard page
Then I should see "John Doe joined project at Shop" event
- @javascript
Scenario: I should see User left Project event
Given user with name "John Doe" joined project "Shop"
And user with name "John Doe" left project "Shop"
diff --git a/features/dashboard/event_filters.feature b/features/dashboard/event_filters.feature
deleted file mode 100644
index e0c6b84b..00000000
--- a/features/dashboard/event_filters.feature
+++ /dev/null
@@ -1,51 +0,0 @@
-Feature: Event filters
- Background:
- Given I sign in as a user
- And I own a project
- And this project has push event
- And this project has new member event
- And this project has merge request event
- And I visit dashboard page
-
- @javascript
- Scenario: I should see all events
- Then I should see push event
- And I should see new member event
- And I should see merge request event
-
- @javascript
- Scenario: I should see only pushed events
- When I click "push" event filter
- Then I should see push event
- And I should not see new member event
- And I should not see merge request event
-
- @javascript
- Scenario: I should see only joined events
- When I click "team" event filter
- Then I should see new member event
- And I should not see push event
- And I should not see merge request event
-
- @javascript
- Scenario: I should see only merged events
- When I click "merge" event filter
- Then I should see merge request event
- And I should not see push event
- And I should not see new member event
-
- @javascript
- Scenario: I should see only selected events while page reloaded
- When I click "push" event filter
- And I visit dashboard page
- Then I should see push event
- And I should not see new member event
- When I click "team" event filter
- And I visit dashboard page
- Then I should see push event
- And I should see new member event
- And I should not see merge request event
- When I click "push" event filter
- Then I should not see push event
- And I should see new member event
- And I should not see merge request event
diff --git a/features/dashboard/projects.feature b/features/dashboard/projects.feature
deleted file mode 100644
index 7e617bd1..00000000
--- a/features/dashboard/projects.feature
+++ /dev/null
@@ -1,12 +0,0 @@
-Feature: Dashboard projects
- Background:
- Given I sign in as a user
- And I own project "Shop"
- And I visit dashboard projects page
-
- Scenario: I should see projects list
- Then I should see projects list
-
- Scenario: I should see project I am looking for
- Given I search for "Sho"
- Then I should see "Shop" project link
diff --git a/features/group/create_group.feature b/features/group/create_group.feature
deleted file mode 100644
index b77f3599..00000000
--- a/features/group/create_group.feature
+++ /dev/null
@@ -1,11 +0,0 @@
-Feature: Groups
- Background:
- Given I sign in as a user
-
- Scenario: Create a group from dasboard
- Given I have group with projects
- And I visit dashboard page
- When I click new group link
- And submit form with new group info
- Then I should be redirected to group page
- And I should see newly created group
diff --git a/features/group/group.feature b/features/group/group.feature
index a48affe8..07308112 100644
--- a/features/group/group.feature
+++ b/features/group/group.feature
@@ -3,7 +3,6 @@ Feature: Groups
Given I sign in as a user
And I have group with projects
- @javascript
Scenario: I should see group dashboard list
When I visit group page
Then I should see projects list
@@ -18,15 +17,3 @@ Feature: Groups
Given project from group has merge requests assigned to me
When I visit group merge requests page
Then I should see merge requests from this group assigned to me
-
- Scenario: I should add user to projects in Group
- Given I have new user "John"
- When I visit group people page
- And I select user "John" from list with role "Reporter"
- Then I should see user "John" in team list
-
- Scenario: I should see edit group page
- When I visit group settings page
- And I change group name
- Then I should see new group name
-
diff --git a/features/project/active_tab.feature b/features/project/active_tab.feature
index f33e4b9e..2d3e41d3 100644
--- a/features/project/active_tab.feature
+++ b/features/project/active_tab.feature
@@ -49,52 +49,51 @@ Feature: Project active tab
Scenario: On Project Home/Show
Given I visit my project's home page
- Then the active main tab should be Home
- And no other main tabs should be active
+ Then the active sub tab should be Show
+ And no other sub tabs should be active
+ And the active main tab should be Home
- #Scenario: On Project Settings/Attachments
- #Given I visit my project's home page
- #And I click the "Attachments" tab
- #Then the active sub tab should be Attachments
- #And no other sub tabs should be active
- #And the active main tab should be Home
-
- #Scenario: On Project Settings/Snippets
- #Given I visit my project's home page
- #And I click the "Snippets" tab
- #Then the active sub tab should be Snippets
- #And no other sub tabs should be active
- #And the active main tab should be Home
-
- # Sub Tabs: Settings
-
- Scenario: On Project Settings/Team
- Given I visit my project's settings page
+ Scenario: On Project Home/Team
+ Given I visit my project's home page
And I click the "Team" tab
Then the active sub tab should be Team
And no other sub tabs should be active
- And the active main tab should be Settings
+ And the active main tab should be Home
- Scenario: On Project Settings/Edit
- Given I visit my project's settings page
+ Scenario: On Project Home/Attachments
+ Given I visit my project's home page
+ And I click the "Attachments" tab
+ Then the active sub tab should be Attachments
+ And no other sub tabs should be active
+ And the active main tab should be Home
+
+ Scenario: On Project Home/Snippets
+ Given I visit my project's home page
+ And I click the "Snippets" tab
+ Then the active sub tab should be Snippets
+ And no other sub tabs should be active
+ And the active main tab should be Home
+
+ Scenario: On Project Home/Edit
+ Given I visit my project's home page
And I click the "Edit" tab
Then the active sub tab should be Edit
And no other sub tabs should be active
- And the active main tab should be Settings
+ And the active main tab should be Home
- Scenario: On Project Settings/Hooks
- Given I visit my project's settings page
+ Scenario: On Project Home/Hooks
+ Given I visit my project's home page
And I click the "Hooks" tab
Then the active sub tab should be Hooks
And no other sub tabs should be active
- And the active main tab should be Settings
+ And the active main tab should be Home
- Scenario: On Project Settings/Deploy Keys
- Given I visit my project's settings page
+ Scenario: On Project Home/Deploy Keys
+ Given I visit my project's home page
And I click the "Deploy Keys" tab
Then the active sub tab should be Deploy Keys
And no other sub tabs should be active
- And the active main tab should be Settings
+ And the active main tab should be Home
# Sub Tabs: Commits
diff --git a/features/project/commits/commit_comments.feature b/features/project/commits/commit_comments.feature
index a1aa745a..5acf541a 100644
--- a/features/project/commits/commit_comments.feature
+++ b/features/project/commits/commit_comments.feature
@@ -1,48 +1,10 @@
-Feature: Comments on commits
+Feature: Project Comment commit
Background:
Given I sign in as a user
And I own project "Shop"
- And I visit project commit page
+ Given I visit project commit page
@javascript
- Scenario: I can comment on a commit
+ Scenario: I comment commit
Given I leave a comment like "XML attached"
- Then I should see a comment saying "XML attached"
-
- @javascript
- Scenario: I can't cancel the main form
- Then I should not see the cancel comment button
-
- @javascript
- Scenario: I can't preview without text
- Given I haven't written any comment text
- Then I should not see the comment preview button
-
- @javascript
- Scenario: I can preview with text
- Given I write a comment like "Nice"
- Then I should see the comment preview button
-
- @javascript
- Scenario: I preview a comment
- Given I preview a comment text like "Bug fixed :smile:"
- Then I should see the comment preview
- And I should not see the comment text field
-
- @javascript
- Scenario: I can edit after preview
- Given I preview a comment text like "Bug fixed :smile:"
- Then I should see the comment edit button
-
- @javascript
- Scenario: I have a reset form after posting from preview
- Given I preview a comment text like "Bug fixed :smile:"
- And I submit the comment
- Then I should see an empty comment text field
- And I should not see the comment preview
-
- @javascript
- Scenario: I can delete a comment
- Given I leave a comment like "XML attached"
- And I delete a comment
- Then I should not see a comment saying "XML attached"
+ Then I should see comment "XML attached"
diff --git a/features/project/commits/commit_diff_comments.feature b/features/project/commits/commit_diff_comments.feature
deleted file mode 100644
index 884fab52..00000000
--- a/features/project/commits/commit_diff_comments.feature
+++ /dev/null
@@ -1,92 +0,0 @@
-Feature: Comments on commit diffs
- Background:
- Given I sign in as a user
- And I own project "Shop"
- And I visit project commit page
-
- @javascript
- Scenario: I can access add diff comment buttons
- Then I should see add a diff comment button
-
- @javascript
- Scenario: I can comment on a commit diff
- Given I leave a diff comment like "Typo, please fix"
- Then I should see a diff comment saying "Typo, please fix"
-
- @javascript
- Scenario: I get a temporary form for the first comment on a diff line
- Given I open a diff comment form
- Then I should see a temporary diff comment form
-
- @javascript
- Scenario: I have a cancel button on the diff form
- Given I open a diff comment form
- Then I should see the cancel comment button
-
- @javascript
- Scenario: I can cancel a diff form
- Given I open a diff comment form
- And I cancel the diff comment
- Then I should not see the diff comment form
-
- @javascript
- Scenario: I can't open a second form for a diff line
- Given I open a diff comment form
- And I open a diff comment form
- Then I should only see one diff form
-
- @javascript
- Scenario: I can have multiple forms
- Given I open a diff comment form
- And I write a diff comment like ":-1: I don't like this"
- And I open another diff comment form
- Then I should see a diff comment form with ":-1: I don't like this"
- And I should see an empty diff comment form
-
- @javascript
- Scenario: I can preview multiple forms separately
- Given I preview a diff comment text like "Should fix it :smile:"
- And I preview another diff comment text like "DRY this up"
- Then I should see two separate previews
-
- @javascript
- Scenario: I have a reply button in discussions
- Given I leave a diff comment like "Typo, please fix"
- Then I should see a discussion reply button
-
- @javascript
- Scenario: I can't preview without text
- Given I open a diff comment form
- And I haven't written any diff comment text
- Then I should not see the diff comment preview button
-
- @javascript
- Scenario: I can preview with text
- Given I open a diff comment form
- And I write a diff comment like ":-1: I don't like this"
- Then I should see the diff comment preview button
-
- @javascript
- Scenario: I preview a diff comment
- Given I preview a diff comment text like "Should fix it :smile:"
- Then I should see the diff comment preview
- And I should not see the diff comment text field
-
- @javascript
- Scenario: I can edit after preview
- Given I preview a diff comment text like "Should fix it :smile:"
- Then I should see the diff comment edit button
-
- @javascript
- Scenario: The form gets removed after posting
- Given I preview a diff comment text like "Should fix it :smile:"
- And I submit the diff comment
- Then I should not see the diff comment form
- And I should see a discussion reply button
-
-
- #@wip @javascript
- #Scenario: I can delete a discussion comment
- # Given I leave a diff comment like "Typo, please fix"
- # And I delete a diff comment
- # Then I should not see a diff comment saying "Typo, please fix"
diff --git a/features/project/merge_requests.feature b/features/project/merge_requests.feature
index 5b8becbb..80f00986 100644
--- a/features/project/merge_requests.feature
+++ b/features/project/merge_requests.feature
@@ -35,34 +35,8 @@ Feature: Project Merge Requests
Then I should see merge request "Wiki Feature"
@javascript
- Scenario: I comment on a merge request
+ Scenario: I comment merge request
Given I visit merge request page "Bug NS-04"
And I leave a comment like "XML attached"
Then I should see comment "XML attached"
- @javascript
- Scenario: I comment on a merge request diff
- Given project "Shop" have "Bug NS-05" open merge request with diffs inside
- And I visit merge request page "Bug NS-05"
- And I switch to the diff tab
- And I leave a comment like "Line is wrong" on line 185 of the first file
- And I switch to the merge request's comments tab
- Then I should see a discussion has started on line 185
-
- @javascript
- Scenario: I comment on a line of 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 like "Line is wrong" on line 185 of the first file
- And I switch to the merge request's comments tab
- Then I should see a discussion has started on commit bcf03b5de6c: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 switch to the merge request's comments tab
- Then I should see a discussion has started on commit bcf03b5de6c
diff --git a/features/project/network.feature b/features/project/network.feature
index a6cbd2c4..31ce5ad3 100644
--- a/features/project/network.feature
+++ b/features/project/network.feature
@@ -7,19 +7,3 @@ Feature: Project Network Graph
@javascript
Scenario: I should see project network
Then page should have network graph
- And page should select "master" in select box
- And page should have "master" on graph
-
- @javascript
- Scenario: I should switch ref to "stable"
- When I switch ref to "stable"
- Then page should have network graph
- And page should select "stable" in select box
- And page should have "stable" on graph
-
- @javascript
- Scenario: I should looking for a commit by SHA of "v2.1.0"
- When I looking for a commit by SHA of "v2.1.0"
- Then page should have network graph
- And page should select "master" in select box
- And page should have "v2.1.0" on graph
diff --git a/features/project/project.feature b/features/project/project.feature
index 0c8c97c8..1c9f201d 100644
--- a/features/project/project.feature
+++ b/features/project/project.feature
@@ -1,20 +1,14 @@
-Feature: Project Feature
+Feature: Projects
Background:
- Given I sign in as a user
+ Given I signin as a user
And I own project "Shop"
- And project "Shop" has push event
And I visit project "Shop" page
- Scenario: I should see project activity
- When I visit project "Shop" page
- Then I should see project "Shop" activity feed
+ # @wip
+ # Scenario: I should see project activity
- Scenario: I visit edit project
- When I visit edit project "Shop" page
- Then I should see project settings
+ # @wip
+ # Scenario: I edit project
- Scenario: I edit project
- When I visit edit project "Shop" page
- And change project settings
- And I save project
- Then I should see project with new settings
+ # @wip
+ # Scenario: I visit attachments
diff --git a/features/project/service.feature b/features/project/service.feature
deleted file mode 100644
index ca8a4756..00000000
--- a/features/project/service.feature
+++ /dev/null
@@ -1,14 +0,0 @@
-Feature: Project Services
- Background:
- Given I sign in as a user
- And I own project "Shop"
-
- Scenario: I should see project services
- When I visit project "Shop" services page
- Then I should see list of available services
-
- Scenario: Activate gitlab-ci service
- When I visit project "Shop" services page
- And I click gitlab-ci service link
- And I fill gitlab-ci settings
- Then I should see service settings saved
diff --git a/features/project/source/browse_files.feature b/features/project/source/browse_files.feature
index ee26f537..0b8495ff 100644
--- a/features/project/source/browse_files.feature
+++ b/features/project/source/browse_files.feature
@@ -12,7 +12,7 @@ Feature: Project Browse files
Then I should see files from repository for "8470d70"
Scenario: I browse file content
- Given I click on "Gemfile.lock" file in repo
+ Given I click on "Gemfile" file in repo
Then I should see it content
Scenario: I browse raw file
@@ -22,6 +22,6 @@ Feature: Project Browse files
@javascript
Scenario: I can edit file
- Given I click on "Gemfile.lock" file in repo
+ Given I click on "Gemfile" file in repo
And I click button "edit"
Then I can edit code
diff --git a/features/project/source/git_blame.feature b/features/project/source/git_blame.feature
index 3b20437a..93ed20a8 100644
--- a/features/project/source/git_blame.feature
+++ b/features/project/source/git_blame.feature
@@ -5,6 +5,6 @@ Feature: Project Browse git repo
Given I visit project source page
Scenario: I blame file
- Given I click on "Gemfile.lock" file in repo
+ Given I click on "Gemfile" file in repo
And I click blame button
Then I should see git file blame
diff --git a/features/project/team_management.feature b/features/project/team_management.feature
index 04545a08..0ac37620 100644
--- a/features/project/team_management.feature
+++ b/features/project/team_management.feature
@@ -11,7 +11,6 @@ Feature: Project Team management
Then I should be able to see myself in team
And I should see "Sam" in team list
- @javascript
Scenario: Add user to project
Given I click link "New Team Member"
And I select "Mike" as "Reporter"
@@ -24,8 +23,13 @@ Feature: Project Team management
Then I visit project "Shop" team page
And I should see "Sam" in team list as "Reporter"
+ Scenario: View team member profile
+ Given I click link "Sam"
+ Then I should see "Sam" team profile
+
Scenario: Cancel team member
- Given I click cancel link for "Sam"
+ Given I click link "Sam"
+ And I click link "Remove from team"
Then I visit project "Shop" team page
And I should not see "Sam" in team list
diff --git a/features/project/wiki.feature b/features/project/wiki.feature
index 90eb2b79..f052e2f2 100644
--- a/features/project/wiki.feature
+++ b/features/project/wiki.feature
@@ -5,43 +5,5 @@ Feature: Project Wiki
Given I visit project wiki page
Scenario: Add new page
- Given I create the Wiki Home page
- Then I should see the newly created wiki page
-
- Scenario: Pressing Cancel while editing a brand new Wiki
- Given I click on the Cancel button
- Then I should be redirected back to the Edit Home Wiki page
-
- Scenario: Edit existing page
- Given I have an existing Wiki page
- And I browse to that Wiki page
- And I click on the Edit button
- And I change the content
- Then I should see the updated content
-
- Scenario: Pressing Cancel while editing an existing Wiki page
- Given I have an existing Wiki page
- And I browse to that Wiki page
- And I click on the Edit button
- And I click on the Cancel button
- Then I should be redirected back to that Wiki page
-
- Scenario: View page history
- Given I have an existing wiki page
- And That page has two revisions
- And I browse to that Wiki page
- And I click the History button
- Then I should see both revisions
-
- Scenario: Destroy Wiki page
- Given I have an existing wiki page
- And I browse to that Wiki page
- And I click on the Edit button
- And I click on the "Delete this page" button
- Then The page should be deleted
-
- Scenario: View all pages
- Given I have an existing wiki page
- And I browse to that Wiki page
- And I click on the "Pages" button
- Then I should see the existing page in the pages list
+ Given I create Wiki page
+ Then I should see newly created wiki page
diff --git a/features/steps/admin/admin_active_tab.rb b/features/steps/admin/admin_active_tab.rb
index f14c5f39..05a9a686 100644
--- a/features/steps/admin/admin_active_tab.rb
+++ b/features/steps/admin/admin_active_tab.rb
@@ -4,7 +4,7 @@ class AdminActiveTab < Spinach::FeatureSteps
include SharedActiveTab
Then 'the active main tab should be Home' do
- ensure_active_main_tab('Home')
+ ensure_active_main_tab('Stats')
end
Then 'the active main tab should be Projects' do
@@ -28,6 +28,6 @@ class AdminActiveTab < Spinach::FeatureSteps
end
Then 'the active main tab should be Resque' do
- ensure_active_main_tab('Background Jobs')
+ ensure_active_main_tab('Resque')
end
end
diff --git a/features/steps/admin/admin_groups.rb b/features/steps/admin/admin_groups.rb
index 167763b6..5386f473 100644
--- a/features/steps/admin/admin_groups.rb
+++ b/features/steps/admin/admin_groups.rb
@@ -3,59 +3,21 @@ class AdminGroups < Spinach::FeatureSteps
include SharedPaths
include SharedActiveTab
- When 'I visit admin group page' do
- visit admin_group_path(current_group)
- end
-
When 'I click new group link' do
click_link "New Group"
end
- And 'I have group with projects' do
- @group = create(:group)
- @project = create(:project, group: @group)
- @event = create(:closed_issue_event, project: @project)
-
- @project.team << [current_user, :master]
- end
-
- And 'Create gitlab user "John"' do
- create(:user, :name => "John")
- end
-
And 'submit form with new group info' do
fill_in 'group_name', :with => 'gitlab'
- fill_in 'group_description', :with => 'Group description'
click_button "Create group"
end
Then 'I should see newly created group' do
page.should have_content "Group: gitlab"
- page.should have_content "Group description"
end
Then 'I should be redirected to group page' do
current_path.should == admin_group_path(Group.last)
end
-
- When 'I select user "John" from user list as "Reporter"' do
- user = User.find_by_name("John")
- within "#new_team_member" do
- select user.name, :from => "user_ids"
- select "Reporter", :from => "project_access"
- end
- click_button "Add user to projects in group"
- end
-
- Then 'I should see "John" in team list in every project as "Reporter"' do
- user = User.find_by_name("John")
- projects_with_access = find(".user_#{user.id} .projects_access")
- projects_with_access.should have_link("Reporter")
- end
-
- protected
-
- def current_group
- @group ||= Group.first
- end
end
+
diff --git a/features/steps/admin/admin_logs.rb b/features/steps/admin/admin_logs.rb
deleted file mode 100644
index 83958545..00000000
--- a/features/steps/admin/admin_logs.rb
+++ /dev/null
@@ -1,11 +0,0 @@
-class AdminLogs < Spinach::FeatureSteps
- include SharedAuthentication
- include SharedPaths
- include SharedAdmin
-
- Then 'I should see tabs with available logs' do
- page.should have_content 'production.log'
- page.should have_content 'githost.log'
- page.should have_content 'application.log'
- end
-end
diff --git a/features/steps/admin/admin_projects.rb b/features/steps/admin/admin_projects.rb
deleted file mode 100644
index b410b238..00000000
--- a/features/steps/admin/admin_projects.rb
+++ /dev/null
@@ -1,22 +0,0 @@
-class AdminProjects < Spinach::FeatureSteps
- include SharedAuthentication
- include SharedPaths
- include SharedAdmin
-
- And 'I should see all projects' do
- Project.all.each do |p|
- page.should have_content p.name_with_namespace
- end
- end
-
- And 'I click on first project' do
- click_link Project.first.name_with_namespace
- end
-
- Then 'I should see project details' do
- project = Project.first
- current_path.should == admin_project_path(project)
- page.should have_content(project.name_with_namespace)
- page.should have_content(project.creator.name)
- end
-end
diff --git a/features/steps/admin/admin_teams.rb b/features/steps/admin/admin_teams.rb
deleted file mode 100644
index 65c7e485..00000000
--- a/features/steps/admin/admin_teams.rb
+++ /dev/null
@@ -1,236 +0,0 @@
-class AdminTeams < Spinach::FeatureSteps
- include SharedAuthentication
- include SharedPaths
- include SharedActiveTab
- include SharedAdmin
-
- And 'I have own project' do
- create :project
- end
-
- And 'Create gitlab user "John"' do
- @user = create(:user, name: "John")
- end
-
- And 'I click new team link' do
- click_link "New Team"
- end
-
- And 'submit form with new team info' do
- fill_in 'user_team_name', with: 'gitlab'
- fill_in 'user_team_description', with: 'description'
- click_button 'Create team'
- end
-
- Then 'I should be redirected to team page' do
- current_path.should == admin_team_path(UserTeam.last)
- end
-
- And 'I should see newly created team' do
- page.should have_content "Team: gitlab"
- page.should have_content "description"
- end
-
- When 'I visit admin teams page' do
- visit admin_teams_path
- end
-
- When 'I have clean "HardCoders" team' do
- @team = create :user_team, name: "HardCoders", owner: current_user
- end
-
- And 'I visit "HardCoders" team page' do
- visit admin_team_path(UserTeam.find_by_name("HardCoders"))
- end
-
- Then 'I should see only me in members table' do
- members_list = find("#members_list .member")
- members_list.should have_content(current_user.name)
- members_list.should have_content(current_user.username)
- end
-
- When 'I select user "John" from user list as "Developer"' do
- @user ||= User.find_by_name("John")
- within "#team_members" do
- select "#{@user.name} (#{@user.username})", from: "user_ids"
- select "Developer", from: "default_project_access"
- end
- end
-
- And 'submit form with new team member info' do
- click_button 'add_members_to_team'
- end
-
- Then 'I should see "John" in teams members list as "Developer"' do
- @user ||= User.find_by_name("John")
- find_in_list("#members_list .member", @user).must_equal true
- end
-
- When 'I visit "John" user admin page' do
- pending 'step not implemented'
- end
-
- Then 'I should see "HardCoders" team in teams table' do
- pending 'step not implemented'
- end
-
- When 'I have "HardCoders" team with "John" member with "Developer" role' do
- @team = create :user_team, name: "HardCoders", owner: current_user
- @user ||= User.find_by_name("John")
- @team.add_member(@user, UserTeam.access_roles["Developer"], group_admin: false)
- end
-
- When 'I have "Shop" project' do
- @project = create :project, name: "Shop"
- end
-
- Then 'I should see empty projects table' do
- page.has_no_css?("#projects_list").must_equal true
- end
-
- When 'I select project "Shop" with max access "Reporter"' do
- @project ||= Project.find_by_name("Shop")
- within "#assign_projects" do
- select @project.name, from: "project_ids"
- select "Reporter", from: "greatest_project_access"
- end
-
- end
-
- And 'submit form with new team project info' do
- click_button 'assign_projects_to_team'
- end
-
- Then 'I should see "Shop" project in projects list' do
- project = Project.find_by_name("Shop")
- find_in_list("#projects_list .project", project).must_equal true
- end
-
- When 'I visit "Shop" project admin page' do
- project = Project.find_by_name("Shop")
- visit admin_project_path(project)
- end
-
- And '"HardCoders" team assigned to "Shop" project with "Developer" max role access' do
- @team = UserTeam.find_by_name("HardCoders")
- @project = create :project, name: "Shop"
- @team.assign_to_project(@project, UserTeam.access_roles["Developer"])
- end
-
- When 'I have gitlab user "Jimm"' do
- create :user, name: "Jimm"
- end
-
- Then 'I should see members table without "Jimm" member' do
- user = User.find_by_name("Jimm")
- find_in_list("#members_list .member", user).must_equal false
- end
-
- When 'I select user "Jimm" ub team members list as "Master"' do
- user = User.find_by_name("Jimm")
- within "#team_members" do
- select "#{user.name} (#{user.username})", from: "user_ids"
- select "Developer", from: "default_project_access"
- end
- end
-
- Then 'I should see "Jimm" in teams members list as "Master"' do
- user = User.find_by_name("Jimm")
- find_in_list("#members_list .member", user).must_equal true
- end
-
- Given 'I have users team "HardCoders"' do
- @team = create :user_team, name: "HardCoders"
- end
-
- And 'gitlab user "John" is a member "HardCoders" team' do
- @team = UserTeam.find_by_name("HardCoders")
- @user = User.find_by_name("John")
- @user = create :user, name: "John" unless @user
- @team.add_member(@user, UserTeam.access_roles["Master"], group_admin: false)
- end
-
- And 'gitlab user "Jimm" is a member "HardCoders" team' do
- @team = UserTeam.find_by_name("HardCoders")
- @user = User.find_by_name("Jimm")
- @user = create :user, name: "Jimm" unless @user
- @team.add_member(@user, UserTeam.access_roles["Master"], group_admin: false)
- end
-
- And '"HardCoders" team is assigned to "Shop" project' do
- @team = UserTeam.find_by_name("HardCoders")
- @project = create :project, name: "Shop"
- @team.assign_to_project(@project, UserTeam.access_roles["Developer"])
- end
-
- When 'I visit "HardCoders" team admin page' do
- visit admin_team_path(UserTeam.find_by_name("HardCoders"))
- end
-
- Then 'I shoould see "John" in members list' do
- user = User.find_by_name("John")
- find_in_list("#members_list .member", user).must_equal true
- end
-
- And 'I should see "Jimm" in members list' do
- user = User.find_by_name("Jimm")
- find_in_list("#members_list .member", user).must_equal true
- end
-
- And 'I should see "Shop" in projects list' do
- project = Project.find_by_name("Shop")
- find_in_list("#projects_list .project", project).must_equal true
- end
-
- When 'I click on remove "Jimm" user link' do
- user = User.find_by_name("Jimm")
- click_link "remove_member_#{user.id}"
- end
-
- Then 'I should be redirected to "HardCoders" team admin page' do
- current_path.should == admin_team_path(UserTeam.find_by_name("HardCoders"))
- end
-
- And 'I should not to see "Jimm" user in members list' do
- user = User.find_by_name("Jimm")
- find_in_list("#members_list .member", user).must_equal false
- end
-
- When 'I click on "Relegate" link on "Shop" project' do
- project = Project.find_by_name("Shop")
- click_link "relegate_project_#{project.id}"
- end
-
- Then 'I should see projects liston team page without "Shop" project' do
- project = Project.find_by_name("Shop")
- find_in_list("#projects_list .project", project).must_equal false
- end
-
- Then 'I should see "John" user with role "Reporter" in team table' do
- user = User.find_by_name("John")
- find_in_list(".team_members", user).must_equal true
- end
-
- When 'I click to "Add members" link' do
- click_link "Add members"
- end
-
- When 'I click to "Add projects" link' do
- click_link "Add projects"
- end
-
- protected
-
- def current_team
- @team ||= Team.first
- end
-
- def find_in_list(selector, item)
- members_list = all(selector)
- entered = false
- members_list.each do |member_item|
- entered = true if member_item.has_content?(item.name)
- end
- entered
- end
-end
diff --git a/features/steps/admin/admin_users.rb b/features/steps/admin/admin_users.rb
deleted file mode 100644
index 61b3ed91..00000000
--- a/features/steps/admin/admin_users.rb
+++ /dev/null
@@ -1,34 +0,0 @@
-class AdminUsers < Spinach::FeatureSteps
- include SharedAuthentication
- include SharedPaths
- include SharedAdmin
-
- Then 'I should see all users' do
- User.all.each do |user|
- page.should have_content user.name
- end
- end
-
- And 'Click edit' do
- @user = User.first
- find("#edit_user_#{@user.id}").click
- end
-
- And 'Input non ascii char in username' do
- fill_in 'user_username', with: "\u3042\u3044"
- end
-
- And 'Click save' do
- click_button("Save")
- end
-
- Then 'See username error message' do
- within "#error_explanation" do
- page.should have_content "Username"
- end
- end
-
- And 'Not chenged form action url' do
- page.should have_selector %(form[action="/admin/users/#{@user.username}"])
- end
-end
diff --git a/features/steps/dashboard/dashboard.rb b/features/steps/dashboard/dashboard.rb
index c6832056..775a721f 100644
--- a/features/steps/dashboard/dashboard.rb
+++ b/features/steps/dashboard/dashboard.rb
@@ -1,7 +1,6 @@
class Dashboard < Spinach::FeatureSteps
include SharedAuthentication
include SharedPaths
- include SharedProject
Then 'I should see "New Project" link' do
page.should have_link "New Project"
@@ -11,6 +10,11 @@ class Dashboard < Spinach::FeatureSteps
page.should have_link "Shop"
end
+ Then 'I should see project "Shop" activity feed' do
+ project = Project.find_by_name("Shop")
+ page.should have_content "#{@user.name} pushed new branch new_design at #{project.name}"
+ end
+
Then 'I should see last push widget' do
page.should have_content "You pushed to new_design"
page.should have_link "Create Merge Request"
@@ -33,7 +37,7 @@ class Dashboard < Spinach::FeatureSteps
Event.create(
project: project,
author_id: user.id,
- action: Event::JOINED
+ action: Event::Joined
)
end
@@ -47,7 +51,7 @@ class Dashboard < Spinach::FeatureSteps
Event.create(
project: project,
author_id: user.id,
- action: Event::LEFT
+ action: Event::Left
)
end
@@ -55,18 +59,43 @@ class Dashboard < Spinach::FeatureSteps
page.should have_content "John Doe left project at Shop"
end
+ And 'I own project "Shop"' do
+ @project = create :project, name: 'Shop'
+ @project.add_access(@user, :admin)
+ end
+
And 'I have group with projects' do
@group = create(:group)
@project = create(:project, group: @group)
@event = create(:closed_issue_event, project: @project)
- @project.team << [current_user, :master]
+ @project.add_access current_user, :admin
end
- Then 'I should see projects list' do
- @user.authorized_projects.all.each do |project|
- page.should have_link project.name_with_namespace
- end
+ And 'project "Shop" has push event' do
+ @project = Project.find_by_name("Shop")
+
+ data = {
+ before: "0000000000000000000000000000000000000000",
+ after: "0220c11b9a3e6c69dc8fd35321254ca9a7b98f7e",
+ ref: "refs/heads/new_design",
+ user_id: @user.id,
+ user_name: @user.name,
+ repository: {
+ name: @project.name,
+ url: "localhost/rubinius",
+ description: "",
+ homepage: "localhost/rubinius",
+ private: true
+ }
+ }
+
+ @event = Event.create(
+ project: @project,
+ action: Event::Pushed,
+ data: data,
+ author_id: @user.id
+ )
end
Then 'I should see groups list' do
@@ -83,4 +112,5 @@ class Dashboard < Spinach::FeatureSteps
Then 'I should see 1 project at group list' do
page.find('span.last_activity/span').should have_content('1')
end
+
end
diff --git a/features/steps/dashboard/dashboard_event_filters.rb b/features/steps/dashboard/dashboard_event_filters.rb
deleted file mode 100644
index afa15c31..00000000
--- a/features/steps/dashboard/dashboard_event_filters.rb
+++ /dev/null
@@ -1,87 +0,0 @@
-class EventFilters < Spinach::FeatureSteps
- include SharedAuthentication
- include SharedPaths
- include SharedProject
-
- Then 'I should see push event' do
- page.should have_selector('span.pushed')
- end
-
- Then 'I should not see push event' do
- page.should_not have_selector('span.pushed')
- end
-
- Then 'I should see new member event' do
- page.should have_selector('span.joined')
- end
-
- And 'I should not see new member event' do
- page.should_not have_selector('span.joined')
- end
-
- Then 'I should see merge request event' do
- page.should have_selector('span.merged')
- end
-
- And 'I should not see merge request event' do
- page.should_not have_selector('span.merged')
- end
-
- And 'this project has push event' do
- data = {
- before: "0000000000000000000000000000000000000000",
- after: "0220c11b9a3e6c69dc8fd35321254ca9a7b98f7e",
- ref: "refs/heads/new_design",
- user_id: @user.id,
- user_name: @user.name,
- repository: {
- name: @project.name,
- url: "localhost/rubinius",
- description: "",
- homepage: "localhost/rubinius",
- private: true
- }
- }
-
- @event = Event.create(
- project: @project,
- action: Event::PUSHED,
- data: data,
- author_id: @user.id
- )
- end
-
- And 'this project has new member event' do
- user = create(:user, {name: "John Doe"})
- Event.create(
- project: @project,
- author_id: user.id,
- action: Event::JOINED
- )
- end
-
- And 'this project has merge request event' do
- merge_request = create :merge_request, author: @user, project: @project
- Event.create(
- project: @project,
- action: Event::MERGED,
- target_id: merge_request.id,
- target_type: "MergeRequest",
- author_id: @user.id
- )
- end
-
- When 'I click "push" event filter' do
- click_link("push_event_filter")
- end
-
- When 'I click "team" event filter' do
- click_link("team_event_filter")
- end
-
- When 'I click "merge" event filter' do
- click_link("merged_event_filter")
- end
-
-end
-
diff --git a/features/steps/dashboard/dashboard_issues.rb b/features/steps/dashboard/dashboard_issues.rb
index fcf4296a..5ace8802 100644
--- a/features/steps/dashboard/dashboard_issues.rb
+++ b/features/steps/dashboard/dashboard_issues.rb
@@ -13,7 +13,7 @@ class DashboardIssues < Spinach::FeatureSteps
And 'I have assigned issues' do
project = create :project
- project.team << [@user, :master]
+ project.add_access(@user, :read, :write)
2.times { create :issue, author: @user, assignee: @user, project: project }
end
diff --git a/features/steps/dashboard/dashboard_merge_requests.rb b/features/steps/dashboard/dashboard_merge_requests.rb
index 7cfa8a13..485a4ccc 100644
--- a/features/steps/dashboard/dashboard_merge_requests.rb
+++ b/features/steps/dashboard/dashboard_merge_requests.rb
@@ -14,8 +14,8 @@ class DashboardMergeRequests < Spinach::FeatureSteps
project1 = create :project
project2 = create :project
- project1.team << [@user, :master]
- project2.team << [@user, :master]
+ project1.add_access(@user, :read, :write)
+ project2.add_access(@user, :read, :write)
merge_request1 = create :merge_request, author: @user, project: project1
merge_request2 = create :merge_request, author: @user, project: project2
diff --git a/features/steps/dashboard/dashboard_projects.rb b/features/steps/dashboard/dashboard_projects.rb
deleted file mode 100644
index 670e25a9..00000000
--- a/features/steps/dashboard/dashboard_projects.rb
+++ /dev/null
@@ -1,23 +0,0 @@
-class DashboardProjects < Spinach::FeatureSteps
- include SharedAuthentication
- include SharedPaths
- include SharedProject
-
- Then 'I should see projects list' do
- @user.authorized_projects.all.each do |project|
- page.should have_link project.name_with_namespace
- end
- end
-
- Given 'I search for "Sho"' do
- fill_in "dashboard_projects_search", with: "Sho"
-
- within ".dashboard-search-filter" do
- find('button').click
- end
- end
-
- Then 'I should see "Shop" project link' do
- page.should have_link "Shop"
- end
-end
diff --git a/features/steps/dashboard/dashboard_search.rb b/features/steps/dashboard/dashboard_search.rb
index 9c8c8794..a34c14d0 100644
--- a/features/steps/dashboard/dashboard_search.rb
+++ b/features/steps/dashboard/dashboard_search.rb
@@ -1,7 +1,6 @@
class DashboardSearch < Spinach::FeatureSteps
include SharedAuthentication
include SharedPaths
- include SharedProject
Given 'I search for "Sho"' do
fill_in "dashboard_search", with: "Sho"
@@ -12,6 +11,11 @@ class DashboardSearch < Spinach::FeatureSteps
page.should have_link "Shop"
end
+ And 'I own project "Shop"' do
+ @project = create(:project, :name => "Shop")
+ @project.add_access(@user, :admin)
+ end
+
Given 'I search for "Contibuting"' do
fill_in "dashboard_search", with: "Contibuting"
click_button "Search"
diff --git a/features/steps/group/group.rb b/features/steps/group/group.rb
index 5ac958e3..4de260ec 100644
--- a/features/steps/group/group.rb
+++ b/features/steps/group/group.rb
@@ -3,17 +3,17 @@ class Groups < Spinach::FeatureSteps
include SharedPaths
Then 'I should see projects list' do
- current_user.authorized_projects.each do |project|
+ current_user.projects.each do |project|
page.should have_link project.name
end
end
And 'I have group with projects' do
- @group = create(:group, owner: current_user)
+ @group = create(:group)
@project = create(:project, group: @group)
@event = create(:closed_issue_event, project: @project)
- @project.team << [current_user, :master]
+ @project.add_access current_user, :admin
end
And 'I should see projects activity feed' do
@@ -28,28 +28,10 @@ class Groups < Spinach::FeatureSteps
Then 'I should see merge requests from this group assigned to me' do
assigned_to_me(:merge_requests).each do |issue|
- page.should have_content issue.title[0..80]
+ page.should have_content issue.title
end
end
- Given 'I have new user "John"' do
- create(:user, name: "John")
- end
-
- And 'I select user "John" from list with role "Reporter"' do
- user = User.find_by_name("John")
- within "#new_team_member" do
- select user.name, :from => "user_ids"
- select "Reporter", :from => "project_access"
- end
- click_button "Add"
- end
-
- Then 'I should see user "John" in team list' do
- projects_with_access = find(".ui-box .well-list")
- projects_with_access.should have_content("John")
- end
-
Given 'project from group has issues assigned to me' do
create :issue,
project: project,
@@ -64,37 +46,6 @@ class Groups < Spinach::FeatureSteps
author: current_user
end
- When 'I click new group link' do
- click_link "New Group"
- end
-
- And 'submit form with new group info' do
- fill_in 'group_name', with: 'Samurai'
- fill_in 'group_description', with: 'Tokugawa Shogunate'
- click_button "Create group"
- end
-
- Then 'I should see newly created group' do
- page.should have_content "Samurai"
- page.should have_content "Tokugawa Shogunate"
- page.should have_content "You will only see events from projects in this group"
- end
-
- Then 'I should be redirected to group page' do
- current_path.should == group_path(Group.last)
- end
-
- And 'I change group name' do
- fill_in 'group_name', :with => 'new-name'
- click_button "Save group"
- end
-
- Then 'I should see new group name' do
- within ".navbar-gitlab" do
- page.should have_content "group: new-name"
- end
- end
-
protected
def current_group
diff --git a/features/steps/profile/profile.rb b/features/steps/profile/profile.rb
index a02ed057..b6833f2b 100644
--- a/features/steps/profile/profile.rb
+++ b/features/steps/profile/profile.rb
@@ -23,19 +23,15 @@ class Profile < Spinach::FeatureSteps
end
Then 'I change my password' do
- within '.update-password' do
- fill_in "user_password", :with => "222333"
- fill_in "user_password_confirmation", :with => "222333"
- click_button "Save"
- end
+ fill_in "user_password", :with => "222333"
+ fill_in "user_password_confirmation", :with => "222333"
+ click_button "Save"
end
When 'I unsuccessfully change my password' do
- within '.update-password' do
- fill_in "user_password", with: "password"
- fill_in "user_password_confirmation", with: "confirmation"
- click_button "Save"
- end
+ fill_in "user_password", with: "password"
+ fill_in "user_password_confirmation", with: "confirmation"
+ click_button "Save"
end
Then "I should see a password error message" do
@@ -47,10 +43,8 @@ class Profile < Spinach::FeatureSteps
end
Then 'I reset my token' do
- within '.update-token' do
- @old_token = @user.private_token
- click_button "Reset"
- end
+ @old_token = @user.private_token
+ click_button "Reset"
end
And 'I should see new token' do
@@ -67,15 +61,11 @@ class Profile < Spinach::FeatureSteps
end
When "I change my application theme" do
- within '.application-theme' do
- choose "Violet"
- end
+ choose "Violet"
end
When "I change my code preview theme" do
- within '.code-preview-theme' do
- choose "Solarized Dark"
- end
+ choose "Dark code preview"
end
Then "I should see the theme change immediately" do
diff --git a/features/steps/profile/profile_active_tab.rb b/features/steps/profile/profile_active_tab.rb
index ee9f5f20..1924a6fa 100644
--- a/features/steps/profile/profile_active_tab.rb
+++ b/features/steps/profile/profile_active_tab.rb
@@ -4,7 +4,7 @@ class ProfileActiveTab < Spinach::FeatureSteps
include SharedActiveTab
Then 'the active main tab should be Home' do
- ensure_active_main_tab('Home')
+ ensure_active_main_tab('Profile')
end
Then 'the active main tab should be Account' do
diff --git a/features/steps/profile/profile_ssh_keys.rb b/features/steps/profile/profile_ssh_keys.rb
index fbb92077..8ae1fa91 100644
--- a/features/steps/profile/profile_ssh_keys.rb
+++ b/features/steps/profile/profile_ssh_keys.rb
@@ -43,6 +43,6 @@ class ProfileSshKeys < Spinach::FeatureSteps
end
And 'I have ssh key "ssh-rsa Work"' do
- create(:key, :user => @user, :title => "ssh-rsa Work", :key => "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQC+L3TbFegm3k8QjejSwemk4HhlRh+DuN679Pc5ckqE/MPhVtE/+kZQDYCTB284GiT2aIoGzmZ8ee9TkaoejAsBwlA+Wz2Q3vhz65X6sMgalRwpdJx8kSEUYV8ZPV3MZvPo8KdNg993o4jL6G36GDW4BPIyO6FPZhfsawdf6liVD0Xo5kibIK7B9VoE178cdLQtLpS2YolRwf5yy6XR6hbbBGQR+6xrGOdP16eGZDb1CE2bMvvJijjloFqPscGktWOqW+nfh5txwFfBzlfARDTBsS8WZtg3Yoj1kn33kPsWRlgHfNutFRAIynDuDdQzQq8tTtVwm+Yi75RfcPHW8y3P Work")
+ create(:key, :user => @user, :title => "ssh-rsa Work", :key => "jfKLJDFKSFJSHFJssh-rsa Work")
end
end
diff --git a/features/steps/project/comments_on_commit_diffs.rb b/features/steps/project/comments_on_commit_diffs.rb
deleted file mode 100644
index fc397a4f..00000000
--- a/features/steps/project/comments_on_commit_diffs.rb
+++ /dev/null
@@ -1,6 +0,0 @@
-class CommentsOnCommitDiffs < Spinach::FeatureSteps
- include SharedAuthentication
- include SharedDiffNote
- include SharedPaths
- include SharedProject
-end
diff --git a/features/steps/project/create_project.rb b/features/steps/project/create_project.rb
index 0d972773..b9b4534e 100644
--- a/features/steps/project/create_project.rb
+++ b/features/steps/project/create_project.rb
@@ -3,13 +3,13 @@ class CreateProject < Spinach::FeatureSteps
include SharedPaths
And 'fill project form with valid data' do
- fill_in 'project_name', with: 'Empty'
+ fill_in 'project_name', :with => 'NewProject'
click_button "Create project"
end
Then 'I should see project page' do
current_path.should == project_path(Project.last)
- page.should have_content "Empty"
+ page.should have_content "NewProject"
end
And 'I should see empty project instuctions' do
diff --git a/features/steps/project/project.rb b/features/steps/project/project.rb
index e9ef1495..f33f12eb 100644
--- a/features/steps/project/project.rb
+++ b/features/steps/project/project.rb
@@ -1,18 +1,5 @@
-class ProjectFeature < Spinach::FeatureSteps
+class Projects < Spinach::FeatureSteps
include SharedAuthentication
include SharedProject
include SharedPaths
-
- And 'change project settings' do
- fill_in 'project_name', with: 'NewName'
- uncheck 'project_issues_enabled'
- end
-
- And 'I save project' do
- click_button 'Save'
- end
-
- Then 'I should see project with new settings' do
- find_field('project_name').value.should == 'NewName'
- end
end
diff --git a/features/steps/project/project_active_tab.rb b/features/steps/project/project_active_tab.rb
index 4c6d890f..a5c80353 100644
--- a/features/steps/project/project_active_tab.rb
+++ b/features/steps/project/project_active_tab.rb
@@ -7,11 +7,7 @@ class ProjectActiveTab < Spinach::FeatureSteps
# Main Tabs
Then 'the active main tab should be Home' do
- ensure_active_main_tab('Home')
- end
-
- Then 'the active main tab should be Settings' do
- ensure_active_main_tab('Settings')
+ ensure_active_main_tab(@project.name)
end
Then 'the active main tab should be Files' do
diff --git a/features/steps/project/project_browse_commits.rb b/features/steps/project/project_browse_commits.rb
index b4c595fa..2c03ce14 100644
--- a/features/steps/project/project_browse_commits.rb
+++ b/features/steps/project/project_browse_commits.rb
@@ -4,7 +4,7 @@ class ProjectBrowseCommits < Spinach::FeatureSteps
include SharedPaths
Then 'I see project commits' do
- commit = @project.repository.commit
+ commit = @project.commit
page.should have_content(@project.name)
page.should have_content(commit.message)
page.should have_content(commit.id.to_s[0..5])
@@ -15,7 +15,7 @@ class ProjectBrowseCommits < Spinach::FeatureSteps
end
Then 'I see commits atom feed' do
- commit = @project.repository.commit
+ commit = CommitDecorator.decorate(@project.commit)
page.response_headers['Content-Type'].should have_content("application/atom+xml")
page.body.should have_selector("title", :text => "Recent commits to #{@project.name}")
page.body.should have_selector("author email", :text => commit.author_email)
@@ -48,7 +48,7 @@ class ProjectBrowseCommits < Spinach::FeatureSteps
page.should have_selector('ul.breadcrumb span.divider', count: 3)
page.should have_selector('ul.breadcrumb a', count: 4)
- find('ul.breadcrumb li:first a')['href'].should match(/#{@project.path_with_namespace}\/commits\/master\z/)
+ find('ul.breadcrumb li:first a')['href'].should match(/#{@project.path}\/commits\/master\z/)
find('ul.breadcrumb li:last a')['href'].should match(%r{master/app/models/project\.rb\z})
end
diff --git a/features/steps/project/project_browse_files.rb b/features/steps/project/project_browse_files.rb
index 71360fb6..4efce0dc 100644
--- a/features/steps/project/project_browse_files.rb
+++ b/features/steps/project/project_browse_files.rb
@@ -16,12 +16,12 @@ class ProjectBrowseFiles < Spinach::FeatureSteps
page.should have_content "Gemfile"
end
- Given 'I click on "Gemfile.lock" file in repo' do
- click_link "Gemfile.lock"
+ Given 'I click on "Gemfile" file in repo' do
+ click_link "Gemfile"
end
Then 'I should see it content' do
- page.should have_content "DEPENDENCIES"
+ page.should have_content "rubygems.org"
end
And 'I click link "raw"' do
diff --git a/features/steps/project/project_browse_git_repo.rb b/features/steps/project/project_browse_git_repo.rb
index cd9a60f4..e966f407 100644
--- a/features/steps/project/project_browse_git_repo.rb
+++ b/features/steps/project/project_browse_git_repo.rb
@@ -3,8 +3,8 @@ class ProjectBrowseGitRepo < Spinach::FeatureSteps
include SharedProject
include SharedPaths
- Given 'I click on "Gemfile.lock" file in repo' do
- click_link "Gemfile.lock"
+ Given 'I click on "Gemfile" file in repo' do
+ click_link "Gemfile"
end
And 'I click blame button' do
@@ -12,8 +12,8 @@ class ProjectBrowseGitRepo < Spinach::FeatureSteps
end
Then 'I should see git file blame' do
- page.should have_content "DEPENDENCIES"
+ page.should have_content "rubygems.org"
page.should have_content "Dmitriy Zaporozhets"
- page.should have_content "Moving to rails 3.2"
+ page.should have_content "bc3735004cb Moving to rails 3.2"
end
end
diff --git a/features/steps/project/comments_on_commits.rb b/features/steps/project/project_comment_commit.rb
similarity index 66%
rename from features/steps/project/comments_on_commits.rb
rename to features/steps/project/project_comment_commit.rb
index 56bb12a8..cb8385e1 100644
--- a/features/steps/project/comments_on_commits.rb
+++ b/features/steps/project/project_comment_commit.rb
@@ -1,6 +1,6 @@
-class CommentsOnCommits < Spinach::FeatureSteps
+class ProjectCommentCommit < Spinach::FeatureSteps
include SharedAuthentication
+ include SharedProject
include SharedNote
include SharedPaths
- include SharedProject
end
diff --git a/features/steps/project/project_issues.rb b/features/steps/project/project_issues.rb
index 7d540099..2103aeb1 100644
--- a/features/steps/project/project_issues.rb
+++ b/features/steps/project/project_issues.rb
@@ -122,9 +122,10 @@ class ProjectIssues < Spinach::FeatureSteps
And 'project "Shop" have "Release 0.3" closed issue' do
project = Project.find_by_name("Shop")
- create(:closed_issue,
+ create(:issue,
:title => "Release 0.3",
:project => project,
- :author => project.users.first)
+ :author => project.users.first,
+ :closed => true)
end
end
diff --git a/features/steps/project/project_merge_requests.rb b/features/steps/project/project_merge_requests.rb
index 4c22119b..d153ad28 100644
--- a/features/steps/project/project_merge_requests.rb
+++ b/features/steps/project/project_merge_requests.rb
@@ -4,148 +4,77 @@ class ProjectMergeRequests < Spinach::FeatureSteps
include SharedNote
include SharedPaths
- Given 'I click link "New Merge Request"' do
- click_link "New Merge Request"
- end
-
- Given 'I click link "Bug NS-04"' do
- click_link "Bug NS-04"
- end
-
- Given 'I click link "All"' do
- click_link "All"
- end
-
- Given 'I click link "Closed"' do
- click_link "Closed"
- end
-
- Then 'I should see merge request "Wiki Feature"' do
- page.should have_content "Wiki Feature"
- end
-
- Then 'I should see closed merge request "Bug NS-04"' do
- merge_request = MergeRequest.find_by_title!("Bug NS-04")
- merge_request.closed?.should be_true
- page.should have_content "Closed by"
- end
-
- Then 'I should see merge request "Bug NS-04"' do
- page.should have_content "Bug NS-04"
- end
-
Then 'I should see "Bug NS-04" in merge requests' do
page.should have_content "Bug NS-04"
end
- Then 'I should see "Feature NS-03" in merge requests' do
- page.should have_content "Feature NS-03"
- end
-
And 'I should not see "Feature NS-03" in merge requests' do
page.should_not have_content "Feature NS-03"
end
+ Given 'I click link "Closed"' do
+ click_link "Closed"
+ end
+
+ Then 'I should see "Feature NS-03" in merge requests' do
+ page.should have_content "Feature NS-03"
+ end
And 'I should not see "Bug NS-04" in merge requests' do
page.should_not have_content "Bug NS-04"
end
+ Given 'I click link "All"' do
+ click_link "All"
+ end
+
+ Given 'I click link "Bug NS-04"' do
+ click_link "Bug NS-04"
+ end
+
+ Then 'I should see merge request "Bug NS-04"' do
+ page.should have_content "Bug NS-04"
+ end
+
And 'I click link "Close"' do
click_link "Close"
end
+ Then 'I should see closed merge request "Bug NS-04"' do
+ mr = MergeRequest.find_by_title("Bug NS-04")
+ mr.closed.should be_true
+ page.should have_content "Closed by"
+ end
+
+ Given 'I click link "New Merge Request"' do
+ click_link "New Merge Request"
+ end
+
And 'I submit new merge request "Wiki Feature"' do
fill_in "merge_request_title", :with => "Wiki Feature"
select "master", :from => "merge_request_source_branch"
select "stable", :from => "merge_request_target_branch"
- click_button "Submit merge request"
+ click_button "Save"
+ end
+
+ Then 'I should see merge request "Wiki Feature"' do
+ page.should have_content "Wiki Feature"
end
And 'project "Shop" have "Bug NS-04" open merge request' do
+ project = Project.find_by_name("Shop")
create(:merge_request,
- title: "Bug NS-04",
- project: project,
- author: project.users.first)
- end
-
- And 'project "Shop" have "Bug NS-05" open merge request with diffs inside' do
- create(:merge_request_with_diffs,
- title: "Bug NS-05",
- project: project,
- author: project.users.first)
+ :title => "Bug NS-04",
+ :project => project,
+ :author => project.users.first)
end
And 'project "Shop" have "Feature NS-03" closed merge request' do
- create(:closed_merge_request,
- title: "Feature NS-03",
- project: project,
- author: project.users.first)
- end
-
- And 'I switch to the diff tab' do
- visit diffs_project_merge_request_path(project, merge_request)
- end
-
- And 'I switch to the merge request\'s comments tab' do
- visit project_merge_request_path(project, merge_request)
- end
-
- And 'I click on the first commit in the merge request' do
-
- click_link merge_request.commits.first.short_id(8)
- end
-
- And 'I leave a comment on the diff page' do
- find("#4735dfc552ad7bf15ca468adc3cad9d05b624490_185_185 .add-diff-note").click
-
- within('.js-temp-notes-holder') do
- fill_in "note_note", with: "One comment to rule them all"
- click_button "Add Comment"
- end
- end
-
- And 'I leave a comment like "Line is wrong" on line 185 of the first file' do
- find("#4735dfc552ad7bf15ca468adc3cad9d05b624490_185_185 .add-diff-note").click
-
- within(".js-temp-notes-holder") do
- fill_in "note_note", with: "Line is wrong"
- click_button "Add Comment"
- sleep 0.05
- end
- end
-
- Then 'I should see a discussion has started on line 185' do
- first_commit = merge_request.commits.first
- first_diff = first_commit.diffs.first
- page.should have_content "#{current_user.name} started a discussion on this merge request diff"
- page.should have_content "#{first_diff.b_path}:L185"
- page.should have_content "Line is wrong"
- end
-
- Then 'I should see a discussion has started on commit bcf03b5de6c:L185' do
- first_commit = merge_request.commits.first
- first_diff = first_commit.diffs.first
- page.should have_content "#{current_user.name} started a discussion on commit"
- page.should have_content first_commit.short_id(8)
- page.should have_content "#{first_diff.b_path}:L185"
- page.should have_content "Line is wrong"
- end
-
- Then 'I should see a discussion has started on commit bcf03b5de6c' do
- first_commit = merge_request.st_commits.first
- first_diff = first_commit.diffs.first
- page.should have_content "#{current_user.name} started a discussion on commit bcf03b5de6c"
- page.should have_content first_commit.short_id(8)
- page.should have_content "One comment to rule them all"
- page.should have_content "#{first_diff.b_path}:L185"
- end
-
- def project
- @project ||= Project.find_by_name!("Shop")
- end
-
- def merge_request
- @merge_request ||= MergeRequest.find_by_title!("Bug NS-05")
+ project = Project.find_by_name("Shop")
+ create(:merge_request,
+ :title => "Feature NS-03",
+ :project => project,
+ :author => project.users.first,
+ :closed => true)
end
end
diff --git a/features/steps/project/project_milestones.rb b/features/steps/project/project_milestones.rb
index 1350938e..1c9ad6da 100644
--- a/features/steps/project/project_milestones.rb
+++ b/features/steps/project/project_milestones.rb
@@ -50,12 +50,12 @@ class ProjectMilestones < Spinach::FeatureSteps
end
Then "I should see 3 issues" do
- page.should have_selector('.milestone-issue-filter .well-list li', count: 4)
- page.should have_selector('.milestone-issue-filter .well-list li.hide', count: 1)
+ page.should have_selector('.milestone-issue-filter tbody tr', count: 4)
+ page.should have_selector('.milestone-issue-filter tbody tr.hide', count: 1)
end
Then "I should see 4 issues" do
- page.should have_selector('.milestone-issue-filter .well-list li', count: 4)
- page.should_not have_selector('.milestone-issue-filter .well-list li.hide')
+ page.should have_selector('.milestone-issue-filter tbody tr', count: 4)
+ page.should_not have_selector('.milestone-issue-filter tbody tr.hide')
end
end
diff --git a/features/steps/project/project_network_graph.rb b/features/steps/project/project_network_graph.rb
index cf5fa751..6fde532f 100644
--- a/features/steps/project/project_network_graph.rb
+++ b/features/steps/project/project_network_graph.rb
@@ -4,53 +4,17 @@ class ProjectNetworkGraph < Spinach::FeatureSteps
Then 'page should have network graph' do
page.should have_content "Project Network Graph"
- page.should have_selector ".graph"
+ within ".graph" do
+ page.should have_content "master"
+ page.should have_content "scss_refactor..."
+ end
end
- When 'I visit project "Shop" network page' do
- # Stub Graph max_size to speed up test (10 commits vs. 650)
- Network::Graph.stub(max_count: 10)
+ And 'I visit project "Shop" network page' do
+ # Stub Graph::JsonBuilder max_size to speed up test (10 commits vs. 650)
+ Gitlab::Graph::JsonBuilder.stub(max_count: 10)
project = Project.find_by_name("Shop")
- visit project_graph_path(project, "master")
- end
-
- And 'page should select "master" in select box' do
- page.should have_selector '#ref_chzn span', :text => "master"
- end
-
- And 'page should have "master" on graph' do
- within '.graph' do
- page.should have_content 'master'
- end
- end
-
- When 'I switch ref to "stable"' do
- page.select 'stable', :from => 'ref'
- sleep 2
- end
-
- And 'page should select "stable" in select box' do
- page.should have_selector '#ref_chzn span', :text => "stable"
- end
-
- And 'page should have "stable" on graph' do
- within '.graph' do
- page.should have_content 'stable'
- end
- end
-
- When 'I looking for a commit by SHA of "v2.1.0"' do
- within ".content .search" do
- fill_in 'q', :with => '98d6492'
- find('button').click
- end
- sleep 2
- end
-
- And 'page should have "v2.1.0" on graph' do
- within '.graph' do
- page.should have_content 'v2.1.0'
- end
+ visit graph_project_path(project)
end
end
diff --git a/features/steps/project/project_services.rb b/features/steps/project/project_services.rb
deleted file mode 100644
index b1668ff7..00000000
--- a/features/steps/project/project_services.rb
+++ /dev/null
@@ -1,30 +0,0 @@
-class ProjectServices < Spinach::FeatureSteps
- include SharedAuthentication
- include SharedProject
- include SharedPaths
-
- When 'I visit project "Shop" services page' do
- visit project_services_path(@project)
- end
-
- Then 'I should see list of available services' do
- page.should have_content 'Services'
- page.should have_content 'Jenkins'
- page.should have_content 'GitLab CI'
- end
-
- And 'I click gitlab-ci service link' do
- click_link 'GitLab CI'
- end
-
- And 'I fill gitlab-ci settings' do
- check 'Active'
- fill_in 'Project URL', with: 'http://ci.gitlab.org/projects/3'
- fill_in 'CI Project token', with: 'verySecret'
- click_button 'Save'
- end
-
- Then 'I should see service settings saved' do
- find_field('Project URL').value.should == 'http://ci.gitlab.org/projects/3'
- end
-end
diff --git a/features/steps/project/project_team_management.rb b/features/steps/project/project_team_management.rb
index e8e05435..6bde0b64 100644
--- a/features/steps/project/project_team_management.rb
+++ b/features/steps/project/project_team_management.rb
@@ -2,17 +2,16 @@ class ProjectTeamManagement < Spinach::FeatureSteps
include SharedAuthentication
include SharedProject
include SharedPaths
- include Select2Helper
Then 'I should be able to see myself in team' do
page.should have_content(@user.name)
- page.should have_content(@user.username)
+ page.should have_content(@user.email)
end
And 'I should see "Sam" in team list' do
user = User.find_by_name("Sam")
page.should have_content(user.name)
- page.should have_content(user.username)
+ page.should have_content(user.email)
end
Given 'I click link "New Team Member"' do
@@ -21,12 +20,11 @@ class ProjectTeamManagement < Spinach::FeatureSteps
And 'I select "Mike" as "Reporter"' do
user = User.find_by_name("Mike")
-
- select2(user.id, from: "#user_ids", multiple: true)
within "#new_team_member" do
+ select user.name, :from => "user_ids"
select "Reporter", :from => "project_access"
end
- click_button "Add users"
+ click_button "Save"
end
Then 'I should see "Mike" in team list as "Reporter"' do
@@ -54,6 +52,17 @@ class ProjectTeamManagement < Spinach::FeatureSteps
role_id.should == UsersProject.access_roles["Reporter"].to_s
end
+ Given 'I click link "Sam"' do
+ click_link "Sam"
+ end
+
+ Then 'I should see "Sam" team profile' do
+ user = User.find_by_name("Sam")
+ page.should have_content(user.name)
+ page.should have_content(user.email)
+ page.should have_content("To team list")
+ end
+
And 'I click link "Remove from team"' do
click_link "Remove from team"
end
@@ -61,7 +70,7 @@ class ProjectTeamManagement < Spinach::FeatureSteps
And 'I should not see "Sam" in team list' do
user = User.find_by_name("Sam")
page.should_not have_content(user.name)
- page.should_not have_content(user.username)
+ page.should_not have_content(user.email)
end
And 'gitlab user "Mike"' do
@@ -75,18 +84,18 @@ class ProjectTeamManagement < Spinach::FeatureSteps
And '"Sam" is "Shop" developer' do
user = User.find_by_name("Sam")
project = Project.find_by_name("Shop")
- project.team << [user, :developer]
+ project.add_access(user, :write)
end
Given 'I own project "Website"' do
@project = create(:project, :name => "Website")
- @project.team << [@user, :master]
+ @project.add_access(@user, :admin)
end
And '"Mike" is "Website" reporter' do
user = User.find_by_name("Mike")
project = Project.find_by_name("Website")
- project.team << [user, :reporter]
+ project.add_access(user, :read)
end
And 'I click link "Import team from another project"' do
@@ -97,10 +106,4 @@ class ProjectTeamManagement < Spinach::FeatureSteps
select 'Website', 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
- click_link('Remove user from team')
- end
- end
end
diff --git a/features/steps/project/project_wall.rb b/features/steps/project/project_wall.rb
index 7c61580e..ba9d3533 100644
--- a/features/steps/project/project_wall.rb
+++ b/features/steps/project/project_wall.rb
@@ -3,16 +3,4 @@ class ProjectWall < Spinach::FeatureSteps
include SharedProject
include SharedNote
include SharedPaths
-
-
- Given 'I write new comment "my special test message"' do
- within(".wall-note-form") do
- fill_in "note[note]", with: "my special test message"
- click_button "Add Comment"
- end
- end
-
- Then 'I should see project wall note "my special test message"' do
- page.should have_content "my special test message"
- end
end
diff --git a/features/steps/project/project_wiki.rb b/features/steps/project/project_wiki.rb
index 745e9ede..902e9ce1 100644
--- a/features/steps/project/project_wiki.rb
+++ b/features/steps/project/project_wiki.rb
@@ -4,89 +4,17 @@ class ProjectWiki < Spinach::FeatureSteps
include SharedNote
include SharedPaths
- Given 'I click on the Cancel button' do
- within(:css, ".actions") do
- click_on "Cancel"
- end
- end
-
- Then 'I should be redirected back to the Edit Home Wiki page' do
- url = URI.parse(current_url)
- url.path.should == project_wiki_path(project, :home)
- end
-
- Given 'I create the Wiki Home page' do
+ Given 'I create Wiki page' do
+ fill_in "Title", :with => 'Test title'
fill_in "Content", :with => '[link test](test)'
click_on "Save"
end
- Then 'I should see the newly created wiki page' do
- page.should have_content "Home"
+ Then 'I should see newly created wiki page' do
+ page.should have_content "Test title"
page.should have_content "link test"
click_link "link test"
page.should have_content "Editing page"
end
-
- Given 'I have an existing Wiki page' do
- wiki.create_page("existing", "content", :markdown, "first commit")
- @page = wiki.find_page("existing")
- end
-
- And 'I browse to that Wiki page' do
- visit project_wiki_path(project, @page)
- end
-
- And 'I click on the Edit button' do
- click_on "Edit"
- end
-
- And 'I change the content' do
- fill_in "Content", :with => 'Updated Wiki Content'
- click_on "Save"
- end
-
- Then 'I should see the updated content' do
- page.should have_content "Updated Wiki Content"
- end
-
- Then 'I should be redirected back to that Wiki page' do
- url = URI.parse(current_url)
- url.path.should == project_wiki_path(project, @page)
- end
-
- And 'That page has two revisions' do
- @page.update("new content", :markdown, "second commit")
- end
-
- And 'I click the History button' do
- click_on "History"
- end
-
- Then 'I should see both revisions' do
- page.should have_content current_user.name
- page.should have_content "first commit"
- page.should have_content "second commit"
- end
-
- And 'I click on the "Delete this page" button' do
- click_on "Delete this page"
- end
-
- Then 'The page should be deleted' do
- page.should have_content "Page was successfully deleted"
- end
-
- And 'I click on the "Pages" button' do
- click_on "Pages"
- end
-
- Then 'I should see the existing page in the pages list' do
- page.should have_content current_user.name
- page.should have_content @page.title.titleize
- end
-
- def wiki
- @gollum_wiki = GollumWiki.new(project, current_user)
- end
end
diff --git a/features/steps/shared/active_tab.rb b/features/steps/shared/active_tab.rb
index 617a077b..884f2d5f 100644
--- a/features/steps/shared/active_tab.rb
+++ b/features/steps/shared/active_tab.rb
@@ -2,11 +2,7 @@ module SharedActiveTab
include Spinach::DSL
def ensure_active_main_tab(content)
- if content == "Home"
- page.find('.main-nav li.active').should have_css('i.icon-home')
- else
- page.find('.main-nav li.active').should have_content(content)
- end
+ page.find('ul.main_menu li.active').should have_content(content)
end
def ensure_active_sub_tab(content)
@@ -14,7 +10,7 @@ module SharedActiveTab
end
And 'no other main tabs should be active' do
- page.should have_selector('.main-nav li.active', count: 1)
+ page.should have_selector('ul.main_menu li.active', count: 1)
end
And 'no other sub tabs should be active' do
diff --git a/features/steps/shared/admin.rb b/features/steps/shared/admin.rb
deleted file mode 100644
index 1b712dc6..00000000
--- a/features/steps/shared/admin.rb
+++ /dev/null
@@ -1,12 +0,0 @@
-module SharedAdmin
- include Spinach::DSL
-
- And 'there are projects in system' do
- 2.times { create(:project) }
- end
-
- And 'system has users' do
- 2.times { create(:user) }
- end
-end
-
diff --git a/features/steps/shared/diff_note.rb b/features/steps/shared/diff_note.rb
deleted file mode 100644
index 9dbbc553..00000000
--- a/features/steps/shared/diff_note.rb
+++ /dev/null
@@ -1,160 +0,0 @@
-module SharedDiffNote
- include Spinach::DSL
-
- Given 'I cancel the diff comment' do
- within(".file") do
- find(".js-close-discussion-note-form").trigger("click")
- end
- end
-
- Given 'I delete a diff comment' do
- sleep 1
- within(".file") do
- first(".js-note-delete").trigger("click")
- end
- end
-
- Given 'I haven\'t written any diff comment text' do
- within(".file") do
- fill_in "note[note]", with: ""
- end
- end
-
- Given 'I leave a diff comment like "Typo, please fix"' do
- find("#586fb7c4e1add2d4d24e27566ed7064680098646_29_14.line_holder .js-add-diff-note-button").trigger("click")
- within(".file form[rel$='586fb7c4e1add2d4d24e27566ed7064680098646_29_14']") do
- fill_in "note[note]", with: "Typo, please fix"
- #click_button("Add Comment")
- find(".js-comment-button").trigger("click")
- sleep 0.05
- end
- end
-
- Given 'I preview a diff comment text like "Should fix it :smile:"' do
- find("#586fb7c4e1add2d4d24e27566ed7064680098646_29_14.line_holder .js-add-diff-note-button").trigger("click")
- within(".file form[rel$='586fb7c4e1add2d4d24e27566ed7064680098646_29_14']") do
- fill_in "note[note]", with: "Should fix it :smile:"
- find(".js-note-preview-button").trigger("click")
- end
- end
-
- Given 'I preview another diff comment text like "DRY this up"' do
- find("#586fb7c4e1add2d4d24e27566ed7064680098646_57_41.line_holder .js-add-diff-note-button").trigger("click")
- within(".file form[rel$='586fb7c4e1add2d4d24e27566ed7064680098646_57_41']") do
- fill_in "note[note]", with: "DRY this up"
- find(".js-note-preview-button").trigger("click")
- end
- end
-
- Given 'I open a diff comment form' do
- find("#586fb7c4e1add2d4d24e27566ed7064680098646_29_14.line_holder .js-add-diff-note-button").trigger("click")
- end
-
- Given 'I open another diff comment form' do
- find("#586fb7c4e1add2d4d24e27566ed7064680098646_57_41.line_holder .js-add-diff-note-button").trigger("click")
- end
-
- Given 'I write a diff comment like ":-1: I don\'t like this"' do
- within(".file") do
- fill_in "note[note]", with: ":-1: I don\'t like this"
- end
- end
-
- Given 'I submit the diff comment' do
- within(".file") do
- click_button("Add Comment")
- end
- end
-
-
-
- Then 'I should not see the diff comment form' do
- within(".file") do
- page.should_not have_css("form.new_note")
- end
- end
-
- Then 'I should not see the diff comment preview button' do
- within(".file") do
- page.should have_css(".js-note-preview-button", visible: false)
- end
- end
-
- Then 'I should not see the diff comment text field' do
- within(".file") do
- page.should have_css(".js-note-text", visible: false)
- end
- end
-
- Then 'I should only see one diff form' do
- within(".file") do
- page.should have_css("form.new_note", count: 1)
- end
- end
-
- Then 'I should see a diff comment form with ":-1: I don\'t like this"' do
- within(".file") do
- page.should have_field("note[note]", with: ":-1: I don\'t like this")
- end
- end
-
- Then 'I should see a diff comment saying "Typo, please fix"' do
- within(".file .note") do
- page.should have_content("Typo, please fix")
- end
- end
-
- Then 'I should see a discussion reply button' do
- within(".file") do
- page.should have_link("Reply")
- end
- end
-
- Then 'I should see a temporary diff comment form' do
- within(".file") do
- page.should have_css(".js-temp-notes-holder form.new_note")
- end
- end
-
- Then 'I should see add a diff comment button' do
- page.should have_css(".js-add-diff-note-button", visible: false)
- end
-
- Then 'I should see an empty diff comment form' do
- within(".file") do
- page.should have_field("note[note]", with: "")
- end
- end
-
- Then 'I should see the cancel comment button' do
- within(".file form") do
- page.should have_css(".js-close-discussion-note-form", text: "Cancel")
- end
- end
-
- Then 'I should see the diff comment preview' do
- within(".file form") do
- page.should have_css(".js-note-preview", visible: false)
- end
- end
-
- Then 'I should see the diff comment edit button' do
- within(".file") do
- page.should have_css(".js-note-edit-button", visible: true)
- end
- end
-
- Then 'I should see the diff comment preview button' do
- within(".file") do
- page.should have_css(".js-note-preview-button", visible: true)
- end
- end
-
- Then 'I should see two separate previews' do
- within(".file") do
- page.should have_css(".js-note-preview", visible: true, count: 2)
- page.should have_content("Should fix it")
- page.should have_content("DRY this up")
- end
- end
-end
diff --git a/features/steps/shared/note.rb b/features/steps/shared/note.rb
index e0ff52a7..923e69b6 100644
--- a/features/steps/shared/note.rb
+++ b/features/steps/shared/note.rb
@@ -1,105 +1,21 @@
module SharedNote
include Spinach::DSL
- Given 'I delete a comment' do
- sleep 1
- first(".js-note-delete").trigger("click")
- end
-
- Given 'I haven\'t written any comment text' do
- within(".js-main-target-form") do
- fill_in "note[note]", with: ""
- end
- end
-
Given 'I leave a comment like "XML attached"' do
- within(".js-main-target-form") do
- fill_in "note[note]", with: "XML attached"
- click_button "Add Comment"
- sleep 0.05
- end
- end
-
- Given 'I preview a comment text like "Bug fixed :smile:"' do
- within(".js-main-target-form") do
- fill_in "note[note]", with: "Bug fixed :smile:"
- find(".js-note-preview-button").trigger("click")
- end
- end
-
- Given 'I submit the comment' do
- within(".js-main-target-form") do
- click_button "Add Comment"
- end
- end
-
- Given 'I write a comment like "Nice"' do
- within(".js-main-target-form") do
- fill_in "note[note]", with: "Nice"
- end
- end
-
- Then 'I should not see a comment saying "XML attached"' do
- page.should_not have_css(".note")
- end
-
- Then 'I should not see the cancel comment button' do
- within(".js-main-target-form") do
- should_not have_link("Cancel")
- end
- end
-
- Then 'I should not see the comment preview' do
- within(".js-main-target-form") do
- page.should have_css(".js-note-preview", visible: false)
- end
- end
-
- Then 'I should not see the comment preview button' do
- within(".js-main-target-form") do
- page.should have_css(".js-note-preview-button", visible: false)
- end
- end
-
- Then 'I should not see the comment text field' do
- within(".js-main-target-form") do
- page.should have_css(".js-note-text", visible: false)
- end
- end
-
- Then 'I should see a comment saying "XML attached"' do
- within(".note") do
- page.should have_content("XML attached")
- end
- end
-
- Then 'I should see an empty comment text field' do
- within(".js-main-target-form") do
- page.should have_field("note[note]", with: "")
- end
- end
-
- Then 'I should see the comment edit button' do
- within(".js-main-target-form") do
- page.should have_css(".js-note-edit-button", visible: true)
- end
- end
-
- Then 'I should see the comment preview' do
- within(".js-main-target-form") do
- page.should have_css(".js-note-preview", visible: true)
- end
- end
-
- Then 'I should see the comment preview button' do
- within(".js-main-target-form") do
- page.should have_css(".js-note-preview-button", visible: true)
- end
+ fill_in "note_note", :with => "XML attached"
+ click_button "Add Comment"
end
Then 'I should see comment "XML attached"' do
- within(".note") do
- page.should have_content("XML attached")
- end
+ page.should have_content "XML attached"
+ end
+
+ Given 'I write new comment "my special test message"' do
+ fill_in "note_note", :with => "my special test message"
+ click_button "Add Comment"
+ end
+
+ Then 'I should see project wall note "my special test message"' do
+ page.should have_content "my special test message"
end
end
diff --git a/features/steps/shared/paths.rb b/features/steps/shared/paths.rb
index 1af8b478..a1257628 100644
--- a/features/steps/shared/paths.rb
+++ b/features/steps/shared/paths.rb
@@ -21,14 +21,6 @@ module SharedPaths
visit merge_requests_group_path(current_group)
end
- When 'I visit group people page' do
- visit people_group_path(current_group)
- end
-
- When 'I visit group settings page' do
- visit edit_group_path(current_group)
- end
-
# ----------------------------------------
# Dashboard
# ----------------------------------------
@@ -37,16 +29,12 @@ module SharedPaths
visit dashboard_path
end
- Given 'I visit dashboard projects page' do
- visit projects_dashboard_path
- end
-
Given 'I visit dashboard issues page' do
- visit issues_dashboard_path
+ visit dashboard_issues_path
end
Given 'I visit dashboard merge requests page' do
- visit merge_requests_dashboard_path
+ visit dashboard_merge_requests_path
end
Given 'I visit dashboard search page' do
@@ -113,10 +101,6 @@ module SharedPaths
visit admin_groups_path
end
- When 'I visit admin teams page' do
- visit admin_teams_path
- end
-
# ----------------------------------------
# Generic Project
# ----------------------------------------
@@ -125,20 +109,16 @@ module SharedPaths
visit project_path(@project)
end
- Given "I visit my project's settings page" do
- visit edit_project_path(@project)
- end
-
Given "I visit my project's files page" do
- visit project_tree_path(@project, root_ref)
+ visit project_tree_path(@project, @project.root_ref)
end
Given "I visit my project's commits page" do
- visit project_commits_path(@project, root_ref, {limit: 5})
+ visit project_commits_path(@project, @project.root_ref, {limit: 5})
end
Given "I visit my project's commits page for a specific path" do
- visit project_commits_path(@project, root_ref + "/app/models/project.rb", {limit: 5})
+ visit project_commits_path(@project, @project.root_ref + "/app/models/project.rb", {limit: 5})
end
Given 'I visit my project\'s commits stats page' do
@@ -146,10 +126,10 @@ module SharedPaths
end
Given "I visit my project's network page" do
- # Stub Graph max_size to speed up test (10 commits vs. 650)
- Network::Graph.stub(max_count: 10)
+ # Stub Graph::JsonBuilder max_size to speed up test (10 commits vs. 650)
+ Gitlab::Graph::JsonBuilder.stub(max_count: 10)
- visit project_graph_path(@project, root_ref)
+ visit graph_project_path(@project)
end
Given "I visit my project's issues page" do
@@ -161,11 +141,11 @@ module SharedPaths
end
Given "I visit my project's wall page" do
- visit project_wall_path(@project)
+ visit wall_project_path(@project)
end
Given "I visit my project's wiki page" do
- visit project_wiki_path(@project, :home)
+ visit project_wiki_path(@project, :index)
end
When 'I visit project hooks page' do
@@ -177,13 +157,10 @@ module SharedPaths
# ----------------------------------------
And 'I visit project "Shop" page' do
+ project = Project.find_by_name("Shop")
visit project_path(project)
end
- When 'I visit edit project "Shop" page' do
- visit edit_project_path(project)
- end
-
Given 'I visit project branches page' do
visit branches_project_repository_path(@project)
end
@@ -193,7 +170,7 @@ module SharedPaths
end
Given 'I visit project commits page' do
- visit project_commits_path(@project, root_ref, {limit: 5})
+ visit project_commits_path(@project, @project.root_ref, {limit: 5})
end
Given 'I visit project commits page for stable branch' do
@@ -201,7 +178,7 @@ module SharedPaths
end
Given 'I visit project source page' do
- visit project_tree_path(@project, root_ref)
+ visit project_tree_path(@project, @project.root_ref)
end
Given 'I visit blob file from repo' do
@@ -221,7 +198,7 @@ module SharedPaths
end
And 'I visit project "Shop" issues page' do
- visit project_issues_path(project)
+ visit project_issues_path(Project.find_by_name("Shop"))
end
Given 'I visit issue page "Release 0.4"' do
@@ -230,7 +207,7 @@ module SharedPaths
end
Given 'I visit project "Shop" labels page' do
- visit project_labels_path(project)
+ visit project_labels_path(Project.find_by_name("Shop"))
end
Given 'I visit merge request page "Bug NS-04"' do
@@ -238,36 +215,25 @@ module SharedPaths
visit project_merge_request_path(mr.project, mr)
end
- Given 'I visit merge request page "Bug NS-05"' do
- mr = MergeRequest.find_by_title("Bug NS-05")
- visit project_merge_request_path(mr.project, mr)
- end
-
And 'I visit project "Shop" merge requests page' do
- visit project_merge_requests_path(project)
+ visit project_merge_requests_path(Project.find_by_name("Shop"))
end
Given 'I visit project "Shop" milestones page' do
- visit project_milestones_path(project)
+ @project = Project.find_by_name("Shop")
+ visit project_milestones_path(@project)
end
Then 'I visit project "Shop" team page' do
- visit project_team_index_path(project)
+ visit project_team_index_path(Project.find_by_name("Shop"))
end
Then 'I visit project "Shop" wall page' do
- visit project_wall_path(project)
+ project = Project.find_by_name("Shop")
+ visit wall_project_path(project)
end
Given 'I visit project wiki page' do
- visit project_wiki_path(@project, :home)
- end
-
- def root_ref
- @project.repository.root_ref
- end
-
- def project
- project = Project.find_by_name!("Shop")
+ visit project_wiki_path(@project, :index)
end
end
diff --git a/features/steps/shared/project.rb b/features/steps/shared/project.rb
index b16032a8..dfc8ce9d 100644
--- a/features/steps/shared/project.rb
+++ b/features/steps/shared/project.rb
@@ -3,52 +3,14 @@ module SharedProject
# Create a project without caring about what it's called
And "I own a project" do
- @project = create(:project_with_code)
- @project.team << [@user, :master]
+ @project = create(:project)
+ @project.add_access(@user, :admin)
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")
- @project.team << [@user, :master]
- end
-
- And 'project "Shop" has push event' do
- @project = Project.find_by_name("Shop")
-
- data = {
- before: "0000000000000000000000000000000000000000",
- after: "0220c11b9a3e6c69dc8fd35321254ca9a7b98f7e",
- ref: "refs/heads/new_design",
- user_id: @user.id,
- user_name: @user.name,
- repository: {
- name: @project.name,
- url: "localhost/rubinius",
- description: "",
- homepage: "localhost/rubinius",
- private: true
- }
- }
-
- @event = Event.create(
- project: @project,
- action: Event::PUSHED,
- data: data,
- author_id: @user.id
- )
- end
-
- Then 'I should see project "Shop" activity feed' do
- project = Project.find_by_name("Shop")
- page.should have_content "#{@user.name} pushed new branch new_design at #{project.name}"
- end
-
- Then 'I should see project settings' do
- current_path.should == edit_project_path(@project)
- page.should have_content("Project name is")
- page.should have_content("Features:")
+ @project = create(:project, :name => "Shop")
+ @project.add_access(@user, :admin)
end
def current_project
diff --git a/features/steps/userteams/userteams.rb b/features/steps/userteams/userteams.rb
deleted file mode 100644
index 9a86572e..00000000
--- a/features/steps/userteams/userteams.rb
+++ /dev/null
@@ -1,257 +0,0 @@
-class Userteams < Spinach::FeatureSteps
- include SharedAuthentication
- include SharedPaths
- include SharedProject
- include Select2Helper
-
- When 'I do not have teams with me' do
- UserTeam.with_member(current_user).destroy_all
- end
-
- Then 'I should see dashboard page without teams info block' do
- page.has_no_css?(".teams-box").must_equal true
- end
-
- When 'I have teams with my membership' do
- team = create :user_team, owner: current_user
- team.add_member(current_user, UserTeam.access_roles["Master"], true)
- end
-
- Then 'I should see dashboard page with teams information block' do
- page.should have_css(".teams-box")
- end
-
- When 'exist user teams' do
- team = create :user_team
- team.add_member(current_user, UserTeam.access_roles["Master"], true)
- end
-
- And 'I click on "All teams" link' do
- click_link("All Teams")
- end
-
- Then 'I should see "All teams" page' do
- current_path.should == teams_path
- end
-
- And 'I should see exist teams in teams list' do
- team = UserTeam.last
- find_in_list(".teams_list tr", team).must_equal true
- end
-
- When 'I click to "New team" link' do
- click_link("New Team")
- end
-
- And 'I submit form with new team info' do
- fill_in 'name', with: 'gitlab'
-
- fill_in 'user_team_description', with: 'team description'
- click_button 'Create team'
- end
-
- And 'I should see newly created team' do
- page.should have_content "gitlab"
- page.should have_content "team description"
- end
-
- Then 'I should be redirected to new team page' do
- team = UserTeam.last
- current_path.should == team_path(team)
- end
-
- When 'I have teams with projects and members' do
- team = create :user_team, owner: current_user
- @project = create :project
- team.add_member(current_user, UserTeam.access_roles["Master"], true)
- team.assign_to_project(@project, UserTeam.access_roles["Master"])
- @event = create(:closed_issue_event, project: @project)
- end
-
- When 'I visit team page' do
- visit team_path(UserTeam.last)
- end
-
- Then 'I should see projects list' do
- within(".side .ui-box") do
- page.should have_content(@project.name)
- end
- end
-
- And 'project from team has issues assigned to me' do
- team = UserTeam.last
- team.projects.each do |project|
- project.issues << create(:issue, assignee: current_user)
- end
- end
-
- When 'I visit team issues page' do
- team = UserTeam.last
- visit issues_team_path(team)
- end
-
- Then 'I should see issues from this team assigned to me' do
- team = UserTeam.last
- team.projects.each do |project|
- project.issues.assigned(current_user).each do |issue|
- page.should have_content issue.title
- end
- end
- end
-
- Given 'I have team with projects and members' do
- team = create :user_team, owner: current_user
- project = create :project
- user = create :user
- team.add_member(current_user, UserTeam.access_roles["Master"], true)
- team.add_member(user, UserTeam.access_roles["Developer"], false)
- team.assign_to_project(project, UserTeam.access_roles["Master"])
- end
-
- Given 'project from team has issues assigned to teams members' do
- team = UserTeam.last
- team.projects.each do |project|
- team.members.each do |member|
- project.issues << create(:issue, assignee: member)
- end
- end
- end
-
- Then 'I should see issues from this team assigned to teams members' do
- team = UserTeam.last
- team.projects.each do |project|
- team.members.each do |member|
- project.issues.assigned(member).each do |issue|
- page.should have_content issue.title
- end
- end
- end
- end
-
- Given 'project from team has merge requests assigned to me' do
- team = UserTeam.last
- team.projects.each do |project|
- team.members.each do |member|
- 3.times { create(:merge_request, assignee: member, project: project) }
- end
- end
- end
-
- When 'I visit team merge requests page' do
- team = UserTeam.last
- visit merge_requests_team_path(team)
- end
-
- Then 'I should see merge requests from this team assigned to me' do
- team = UserTeam.last
- team.projects.each do |project|
- team.members.each do |member|
- project.issues.assigned(member).each do |merge_request|
- page.should have_content merge_request.title
- end
- end
- end
- end
-
- Given 'project from team has merge requests assigned to team members' do
- team = UserTeam.last
- team.projects.each do |project|
- team.members.each do |member|
- 3.times { create(:merge_request, assignee: member, project: project) }
- end
- end
- end
-
- Then 'I should see merge requests from this team assigned to me' do
- team = UserTeam.last
- team.projects.each do |project|
- team.members.each do |member|
- project.issues.assigned(member).each do |merge_request|
- page.should have_content merge_request.title
- end
- end
- end
- end
-
- Given 'I have new user "John"' do
- create :user, name: "John"
- end
-
- When 'I visit team people page' do
- team = UserTeam.last
- visit team_members_path(team)
- end
-
- And 'I select user "John" from list with role "Reporter"' do
- user = User.find_by_name("John")
- select2(user.id, from: "#user_ids", multiple: true)
- within "#team_members" do
- select "Reporter", from: "default_project_access"
- end
- click_button "Add"
- end
-
- Then 'I should see user "John" in team list' do
- user = User.find_by_name("John")
- team_members_list = find(".team-table")
- team_members_list.should have_content user.name
- end
-
- And 'I have my own project without teams' do
- @project = create :project, namespace: current_user.namespace
- end
-
- And 'I visit my team page' do
- team = UserTeam.where(owner_id: current_user.id).last
- visit team_path(team)
- end
-
- When 'I click on link "Assign Project"' do
- click_link "Assign Project"
- end
-
- Then 'I should see form with my own project in available projects list' do
- projects_select = find("#project_ids")
- projects_select.should have_content(@project.name)
- end
-
- When 'I submit form with selected project and max access' do
- within "#assign_projects" do
- select @project.name_with_namespace, from: "project_ids"
- select "Reporter", from: "greatest_project_access"
- end
- click_button "Add"
- end
-
- Then 'I should see my own project in team projects list' do
- projects = find(".projects-table")
- projects.should have_content(@project.name)
- end
-
- When 'I click link "New Team Member"' do
- click_link "New Team Member"
- end
-
- protected
-
- def current_team
- @user_team ||= UserTeam.first
- end
-
- def project
- current_team.projects.first
- end
-
- def assigned_to_user key, user
- project.send(key).where(assignee_id: user)
- end
-
- def find_in_list(selector, item)
- members_list = all(selector)
- entered = false
- members_list.each do |member_item|
- entered = true if member_item.has_content?(item.name)
- end
- entered
- end
-end
diff --git a/features/support/env.rb b/features/support/env.rb
index 08b627f5..500de0f3 100644
--- a/features/support/env.rb
+++ b/features/support/env.rb
@@ -1,26 +1,23 @@
-require 'simplecov' unless ENV['CI']
-
-if ENV['TRAVIS']
- require 'coveralls'
- Coveralls.wear!
-end
-
ENV['RAILS_ENV'] = 'test'
require './config/environment'
require 'rspec'
require 'database_cleaner'
require 'spinach/capybara'
-require 'sidekiq/testing/inline'
-
-%w(valid_commit select2_helper test_env).each do |f|
+%w(gitolite_stub stubbed_repository valid_commit).each do |f|
require Rails.root.join('spec', 'support', f)
end
Dir["#{Rails.root}/features/steps/shared/*.rb"].each {|file| require file}
+#
+# Stub gitolite
+#
+include GitoliteStub
+
WebMock.allow_net_connect!
+
#
# JS driver
#
@@ -28,16 +25,17 @@ require 'capybara/poltergeist'
Capybara.javascript_driver = :poltergeist
Spinach.hooks.on_tag("javascript") do
::Capybara.current_driver = ::Capybara.javascript_driver
+ ::Capybara.default_wait_time = 5
end
-Capybara.default_wait_time = 10
DatabaseCleaner.strategy = :truncation
Spinach.hooks.before_scenario do
- TestEnv.init
-
- DatabaseCleaner.start
+ # Use tmp dir for FS manipulations
+ Gitlab.config.gitolite.stub(repos_path: Rails.root.join('tmp', 'test-git-base-path'))
+ FileUtils.rm_rf Gitlab.config.gitolite.repos_path
+ FileUtils.mkdir_p Gitlab.config.gitolite.repos_path
end
Spinach.hooks.after_scenario do
@@ -48,4 +46,6 @@ Spinach.hooks.before_run do
RSpec::Mocks::setup self
include FactoryGirl::Syntax::Methods
+
+ stub_gitolite!
end
diff --git a/features/teams/team.feature b/features/teams/team.feature
deleted file mode 100644
index ac34ed76..00000000
--- a/features/teams/team.feature
+++ /dev/null
@@ -1,65 +0,0 @@
-Feature: UserTeams
- Background:
- Given I sign in as a user
- And I own project "Shop"
- And project "Shop" has push event
-
- Scenario: I should see teams info block
- When I have teams with my membership
- And I visit dashboard page
- Then I should see dashboard page with teams information block
-
- Scenario: I should can create new team
- When I have teams with my membership
- And I visit dashboard page
- When I click to "New team" link
- And I submit form with new team info
- Then I should be redirected to new team page
- Then I should see newly created team
-
- Scenario: I should see team dashboard list
- When I have teams with projects and members
- When I visit team page
- Then I should see projects list
-
- Scenario: I should see team issues list
- Given I have team with projects and members
- And project from team has issues assigned to me
- When I visit team issues page
- Then I should see issues from this team assigned to me
-
- Scenario: I should see teams members issues list
- Given I have team with projects and members
- Given project from team has issues assigned to teams members
- When I visit team issues page
- Then I should see issues from this team assigned to teams members
-
- Scenario: I should see team merge requests list
- Given I have team with projects and members
- Given project from team has merge requests assigned to me
- When I visit team merge requests page
- Then I should see merge requests from this team assigned to me
-
- Scenario: I should see teams members merge requests list
- Given I have team with projects and members
- Given project from team has merge requests assigned to team members
- When I visit team merge requests page
- Then I should see merge requests from this team assigned to me
-
- @javascript
- Scenario: I should add user to projects in Team
- Given I have team with projects and members
- Given I have new user "John"
- When I visit team people page
- When I click link "New Team Member"
- And I select user "John" from list with role "Reporter"
- Then I should see user "John" in team list
-
- Scenario: I should assign my team to my own project
- Given I have team with projects and members
- And I have my own project without teams
- And I visit my team page
- When I click on link "Assign Project"
- Then I should see form with my own project in available projects list
- When I submit form with selected project and max access
- Then I should see my own project in team projects list
diff --git a/lib/api.rb b/lib/api.rb
index d241f9b7..f58b82ff 100644
--- a/lib/api.rb
+++ b/lib/api.rb
@@ -8,23 +8,10 @@ module Gitlab
rack_response({'message' => '404 Not found'}.to_json, 404)
end
- rescue_from :all do |exception|
- # lifted from https://github.com/rails/rails/blob/master/actionpack/lib/action_dispatch/middleware/debug_exceptions.rb#L60
- # why is this not wrapped in something reusable?
- trace = exception.backtrace
-
- message = "\n#{exception.class} (#{exception.message}):\n"
- message << exception.annoted_source_code.to_s if exception.respond_to?(:annoted_source_code)
- message << " " << trace.join("\n ")
-
- API.logger.add Logger::FATAL, message
- rack_response({'message' => '500 Internal Server Error'}, 500)
- end
-
format :json
+ error_format :json
helpers APIHelpers
-
- mount Groups
+
mount Users
mount Projects
mount Issues
@@ -32,7 +19,5 @@ module Gitlab
mount Session
mount MergeRequests
mount Notes
- mount Internal
- mount SystemHooks
end
end
diff --git a/lib/api/entities.rb b/lib/api/entities.rb
index 3fe4abc3..92245a9f 100644
--- a/lib/api/entities.rb
+++ b/lib/api/entities.rb
@@ -2,23 +2,15 @@ module Gitlab
module Entities
class User < Grape::Entity
expose :id, :username, :email, :name, :bio, :skype, :linkedin, :twitter,
- :dark_scheme, :theme_id, :state, :created_at, :extern_uid, :provider
- end
-
- class UserSafe < Grape::Entity
- expose :name
+ :dark_scheme, :theme_id, :blocked, :created_at
end
class UserBasic < Grape::Entity
- expose :id, :username, :email, :name, :state, :created_at
+ expose :id, :username, :email, :name, :blocked, :created_at
end
- class UserLogin < User
+ class UserLogin < UserBasic
expose :private_token
- expose :is_admin?, as: :is_admin
- expose :can_create_group?, as: :can_create_group
- expose :can_create_project?, as: :can_create_project
- expose :can_create_team?, as: :can_create_team
end
class Hook < Grape::Entity
@@ -26,35 +18,20 @@ module Gitlab
end
class Project < Grape::Entity
- expose :id, :name, :description, :default_branch
+ expose :id, :name, :description, :path, :default_branch
expose :owner, using: Entities::UserBasic
- expose :public
- expose :path, :path_with_namespace
+ expose :private_flag, as: :private
expose :issues_enabled, :merge_requests_enabled, :wall_enabled, :wiki_enabled, :created_at
- expose :namespace
end
class ProjectMember < UserBasic
- expose :project_access, as: :access_level do |user, options|
+ expose :project_access, :as => :access_level do |user, options|
options[:project].users_projects.find_by_user_id(user.id).project_access
end
end
- class Group < Grape::Entity
- expose :id, :name, :path, :owner_id
- end
-
- class GroupDetail < Group
- expose :projects, using: Entities::Project
- end
-
class RepoObject < Grape::Entity
expose :name, :commit
- expose :protected do |repo, options|
- if options[:project]
- options[:project].protected_branch? repo.name
- end
- end
end
class RepoCommit < Grape::Entity
@@ -70,7 +47,7 @@ module Gitlab
class Milestone < Grape::Entity
expose :id
expose (:project_id) {|milestone| milestone.project.id}
- expose :title, :description, :due_date, :state, :updated_at, :created_at
+ expose :title, :description, :due_date, :closed, :updated_at, :created_at
end
class Issue < Grape::Entity
@@ -80,7 +57,7 @@ module Gitlab
expose :label_list, as: :labels
expose :milestone, using: Entities::Milestone
expose :assignee, :author, using: Entities::UserBasic
- expose :state, :updated_at, :created_at
+ expose :closed, :updated_at, :created_at
end
class SSHKey < Grape::Entity
@@ -88,14 +65,13 @@ module Gitlab
end
class MergeRequest < Grape::Entity
- expose :id, :target_branch, :source_branch, :project_id, :title, :state
+ expose :id, :target_branch, :source_branch, :project_id, :title, :closed, :merged
expose :author, :assignee, using: Entities::UserBasic
end
class Note < Grape::Entity
expose :id
expose :note, as: :body
- expose :attachment_identifier, as: :attachment
expose :author, using: Entities::UserBasic
expose :created_at
end
diff --git a/lib/api/groups.rb b/lib/api/groups.rb
deleted file mode 100644
index 52fa8eff..00000000
--- a/lib/api/groups.rb
+++ /dev/null
@@ -1,76 +0,0 @@
-module Gitlab
- # groups API
- class Groups < Grape::API
- before { authenticate! }
-
- resource :groups do
- # Get a groups list
- #
- # Example Request:
- # GET /groups
- get do
- if current_user.admin
- @groups = paginate Group
- else
- @groups = paginate current_user.groups
- end
- present @groups, with: Entities::Group
- end
-
- # Create group. Available only for admin
- #
- # Parameters:
- # name (required) - The name of the group
- # path (required) - The path of the group
- # Example Request:
- # POST /groups
- post do
- authenticated_as_admin!
- required_attributes! [:name, :path]
-
- attrs = attributes_for_keys [:name, :path]
- @group = Group.new(attrs)
- @group.owner = current_user
-
- if @group.save
- present @group, with: Entities::Group
- else
- not_found!
- end
- end
-
- # Get a single group, with containing projects
- #
- # Parameters:
- # id (required) - The ID of a group
- # Example Request:
- # GET /groups/:id
- get ":id" do
- @group = Group.find(params[:id])
- if current_user.admin or current_user.groups.include? @group
- present @group, with: Entities::GroupDetail
- else
- not_found!
- end
- end
-
- # Transfer a project to the Group namespace
- #
- # Parameters:
- # id - group id
- # project_id - project id
- # Example Request:
- # POST /groups/:id/projects/:project_id
- post ":id/projects/:project_id" do
- authenticated_as_admin!
- @group = Group.find(params[:id])
- project = Project.find(params[:project_id])
- if project.transfer(@group)
- present @group
- else
- not_found!
- end
- end
- end
- end
-end
diff --git a/lib/api/helpers.rb b/lib/api/helpers.rb
index f12fb5fd..6bd8111c 100644
--- a/lib/api/helpers.rb
+++ b/lib/api/helpers.rb
@@ -41,17 +41,6 @@ module Gitlab
abilities.allowed?(object, action, subject)
end
- # Checks the occurrences of required attributes, each attribute must be present in the params hash
- # or a Bad Request error is invoked.
- #
- # Parameters:
- # keys (required) - A hash consisting of keys that must be present
- def required_attributes!(keys)
- keys.each do |key|
- bad_request!(key) unless params[key].present?
- end
- end
-
def attributes_for_keys(keys)
attrs = {}
keys.each do |key|
@@ -66,12 +55,6 @@ module Gitlab
render_api_error!('403 Forbidden', 403)
end
- def bad_request!(attribute)
- message = ["400 (Bad request)"]
- message << "\"" + attribute.to_s + "\" not given"
- render_api_error!(message.join(' '), 400)
- end
-
def not_found!(resource = nil)
message = ["404"]
message << resource if resource
diff --git a/lib/api/internal.rb b/lib/api/internal.rb
deleted file mode 100644
index 81451638..00000000
--- a/lib/api/internal.rb
+++ /dev/null
@@ -1,68 +0,0 @@
-module Gitlab
- # Internal access API
- class Internal < Grape::API
- namespace 'internal' do
- #
- # Check if ssh key has access to project code
- #
- # Params:
- # key_id - SSH Key id
- # project - project path with namespace
- # action - git action (git-upload-pack or git-receive-pack)
- # ref - branch name
- #
- get "/allowed" do
- # Check for *.wiki repositories.
- # Strip out the .wiki from the pathname before finding the
- # project. This applies the correct project permissions to
- # the wiki repository as well.
- project_path = params[:project]
- project_path.gsub!(/\.wiki/,'') if project_path =~ /\.wiki/
-
- key = Key.find(params[:key_id])
- project = Project.find_with_namespace(project_path)
- git_cmd = params[:action]
-
-
- if key.is_deploy_key
- project == key.project && git_cmd == 'git-upload-pack'
- else
- user = key.user
-
- return false if user.blocked?
-
- action = case git_cmd
- when 'git-upload-pack'
- then :download_code
- when 'git-receive-pack'
- then
- if project.protected_branch?(params[:ref])
- :push_code_to_protected_branches
- else
- :push_code
- end
- end
-
- user.can?(action, project)
- end
- end
-
- #
- # Discover user by ssh key
- #
- get "/discover" do
- key = Key.find(params[:key_id])
- present key.user, with: Entities::UserSafe
- end
-
- get "/check" do
- {
- api_version: Gitlab::API.version,
- gitlab_version: Gitlab::VERSION,
- gitlab_rev: Gitlab::REVISION,
- }
- end
- end
- end
-end
-
diff --git a/lib/api/issues.rb b/lib/api/issues.rb
index 500a8551..3be55881 100644
--- a/lib/api/issues.rb
+++ b/lib/api/issues.rb
@@ -48,7 +48,6 @@ module Gitlab
# Example Request:
# POST /projects/:id/issues
post ":id/issues" do
- required_attributes! [:title]
attrs = attributes_for_keys [:title, :description, :assignee_id, :milestone_id]
attrs[:label_list] = params[:labels] if params[:labels].present?
@issue = user_project.issues.new attrs
@@ -70,16 +69,15 @@ module Gitlab
# assignee_id (optional) - The ID of a user to assign issue
# milestone_id (optional) - The ID of a milestone to assign issue
# labels (optional) - The labels of an issue
- # state (optional) - The state of an issue (close|reopen)
+ # closed (optional) - The state of an issue (0 = false, 1 = true)
# Example Request:
# PUT /projects/:id/issues/:issue_id
put ":id/issues/:issue_id" do
@issue = user_project.issues.find(params[:issue_id])
authorize! :modify_issue, @issue
- attrs = attributes_for_keys [:title, :description, :assignee_id, :milestone_id, :state_event]
+ attrs = attributes_for_keys [:title, :description, :assignee_id, :milestone_id, :closed]
attrs[:label_list] = params[:labels] if params[:labels].present?
- IssueObserver.current_user = current_user
if @issue.update_attributes attrs
present @issue, with: Entities::Issue
else
diff --git a/lib/api/merge_requests.rb b/lib/api/merge_requests.rb
index d5595d5f..470cd1e1 100644
--- a/lib/api/merge_requests.rb
+++ b/lib/api/merge_requests.rb
@@ -4,16 +4,6 @@ module Gitlab
before { authenticate! }
resource :projects do
- helpers do
- def handle_merge_request_errors!(errors)
- if errors[:project_access].any?
- error!(errors[:project_access], 422)
- elsif errors[:branch_conflict].any?
- error!(errors[:branch_conflict], 422)
- end
- not_found!
- end
- end
# List merge requests
#
@@ -61,7 +51,6 @@ module Gitlab
#
post ":id/merge_requests" do
authorize! :write_merge_request, user_project
- required_attributes! [:source_branch, :target_branch, :title]
attrs = attributes_for_keys [:source_branch, :target_branch, :assignee_id, :title]
merge_request = user_project.merge_requests.new(attrs)
@@ -71,7 +60,7 @@ module Gitlab
merge_request.reload_code
present merge_request, with: Entities::MergeRequest
else
- handle_merge_request_errors! merge_request.errors
+ not_found!
end
end
@@ -84,24 +73,22 @@ module Gitlab
# target_branch - The target branch
# assignee_id - Assignee user ID
# title - Title of MR
- # state_event - Status of MR. (close|reopen|merge)
+ # closed - Status of MR. true - closed
# Example:
# PUT /projects/:id/merge_request/:merge_request_id
#
put ":id/merge_request/:merge_request_id" do
- attrs = attributes_for_keys [:source_branch, :target_branch, :assignee_id, :title, :state_event]
+ attrs = attributes_for_keys [:source_branch, :target_branch, :assignee_id, :title, :closed]
merge_request = user_project.merge_requests.find(params[:merge_request_id])
authorize! :modify_merge_request, merge_request
- MergeRequestObserver.current_user = current_user
-
if merge_request.update_attributes attrs
merge_request.reload_code
merge_request.mark_as_unchecked
present merge_request, with: Entities::MergeRequest
else
- handle_merge_request_errors! merge_request.errors
+ not_found!
end
end
@@ -115,8 +102,6 @@ module Gitlab
# POST /projects/:id/merge_request/:merge_request_id/comments
#
post ":id/merge_request/:merge_request_id/comments" do
- required_attributes! [:note]
-
merge_request = user_project.merge_requests.find(params[:merge_request_id])
note = merge_request.notes.new(note: params[:note], project_id: user_project.id)
note.author = current_user
diff --git a/lib/api/milestones.rb b/lib/api/milestones.rb
index 1adeefec..6aca9d01 100644
--- a/lib/api/milestones.rb
+++ b/lib/api/milestones.rb
@@ -41,7 +41,6 @@ module Gitlab
# POST /projects/:id/milestones
post ":id/milestones" do
authorize! :admin_milestone, user_project
- required_attributes! [:title]
attrs = attributes_for_keys [:title, :description, :due_date]
@milestone = user_project.milestones.new attrs
@@ -60,14 +59,14 @@ module Gitlab
# title (optional) - The title of a milestone
# description (optional) - The description of a milestone
# due_date (optional) - The due date of a milestone
- # state (optional) - The status of the milestone (close|activate)
+ # closed (optional) - The status of the milestone
# Example Request:
# PUT /projects/:id/milestones/:milestone_id
put ":id/milestones/:milestone_id" do
authorize! :admin_milestone, user_project
@milestone = user_project.milestones.find(params[:milestone_id])
- attrs = attributes_for_keys [:title, :description, :due_date, :state_event]
+ attrs = attributes_for_keys [:title, :description, :due_date, :closed]
if @milestone.update_attributes attrs
present @milestone, with: Entities::Milestone
else
diff --git a/lib/api/notes.rb b/lib/api/notes.rb
index 450faae5..4875ac4c 100644
--- a/lib/api/notes.rb
+++ b/lib/api/notes.rb
@@ -3,7 +3,7 @@ module Gitlab
class Notes < Grape::API
before { authenticate! }
- NOTEABLE_TYPES = [Issue, MergeRequest, Snippet]
+ NOTEABLE_TYPES = [Issue, Snippet]
resource :projects do
# Get a list of project wall notes
@@ -13,11 +13,7 @@ module Gitlab
# Example Request:
# GET /projects/:id/notes
get ":id/notes" do
- @notes = user_project.notes.common
-
- # Get recent notes if recent = true
- @notes = @notes.order('id DESC') if params[:recent]
-
+ @notes = user_project.common_notes
present paginate(@notes), with: Entities::Note
end
@@ -29,7 +25,7 @@ module Gitlab
# Example Request:
# GET /projects/:id/notes/:note_id
get ":id/notes/:note_id" do
- @note = user_project.notes.common.find(params[:note_id])
+ @note = user_project.common_notes.find(params[:note_id])
present @note, with: Entities::Note
end
@@ -41,16 +37,12 @@ module Gitlab
# Example Request:
# POST /projects/:id/notes
post ":id/notes" do
- required_attributes! [:body]
-
@note = user_project.notes.new(note: params[:body])
@note.author = current_user
if @note.save
present @note, with: Entities::Note
else
- # :note is exposed as :body, but :note is set on error
- bad_request!(:note) if @note.errors[:note].any?
not_found!
end
end
@@ -97,8 +89,6 @@ module Gitlab
# POST /projects/:id/issues/:noteable_id/notes
# POST /projects/:id/snippets/:noteable_id/notes
post ":id/#{noteables_str}/:#{noteable_id_str}/notes" do
- required_attributes! [:body]
-
@noteable = user_project.send(:"#{noteables_str}").find(params[:"#{noteable_id_str}"])
@note = @noteable.notes.new(note: params[:body])
@note.author = current_user
diff --git a/lib/api/projects.rb b/lib/api/projects.rb
index ce94c34b..64b65f16 100644
--- a/lib/api/projects.rb
+++ b/lib/api/projects.rb
@@ -4,21 +4,12 @@ module Gitlab
before { authenticate! }
resource :projects do
- helpers do
- def handle_project_member_errors(errors)
- if errors[:project_access].any?
- error!(errors[:project_access], 422)
- end
- not_found!
- end
- end
-
# Get a projects list for authenticated user
#
# Example Request:
# GET /projects
get do
- @projects = paginate current_user.authorized_projects
+ @projects = paginate current_user.projects
present @projects, with: Entities::Project
end
@@ -36,52 +27,16 @@ module Gitlab
#
# Parameters:
# name (required) - name for new project
+ # path (optional) - path for new project, uses project name if not set
# description (optional) - short project description
# default_branch (optional) - 'master' by default
# issues_enabled (optional) - enabled by default
# wall_enabled (optional) - enabled by default
# merge_requests_enabled (optional) - enabled by default
# wiki_enabled (optional) - enabled by default
- # namespace_id (optional) - defaults to user namespace
# Example Request
# POST /projects
post do
- required_attributes! [:name]
- attrs = attributes_for_keys [:name,
- :description,
- :default_branch,
- :issues_enabled,
- :wall_enabled,
- :merge_requests_enabled,
- :wiki_enabled,
- :namespace_id]
- @project = ::Projects::CreateContext.new(current_user, attrs).execute
- if @project.saved?
- present @project, with: Entities::Project
- else
- if @project.errors[:limit_reached].present?
- error!(@project.errors[:limit_reached], 403)
- end
- not_found!
- end
- end
-
- # Create new project for a specified user. Only available to admin users.
- #
- # Parameters:
- # user_id (required) - The ID of a user
- # name (required) - name for new project
- # description (optional) - short project description
- # default_branch (optional) - 'master' by default
- # issues_enabled (optional) - enabled by default
- # wall_enabled (optional) - enabled by default
- # merge_requests_enabled (optional) - enabled by default
- # wiki_enabled (optional) - enabled by default
- # Example Request
- # POST /projects/user/:user_id
- post "user/:user_id" do
- authenticated_as_admin!
- user = User.find(params[:user_id])
attrs = attributes_for_keys [:name,
:description,
:default_branch,
@@ -89,7 +44,7 @@ module Gitlab
:wall_enabled,
:merge_requests_enabled,
:wiki_enabled]
- @project = ::Projects::CreateContext.new(user, attrs).execute
+ @project = Project.create_by_user(attrs, current_user)
if @project.saved?
present @project, with: Entities::Project
else
@@ -97,7 +52,6 @@ module Gitlab
end
end
-
# Get a project team members
#
# Parameters:
@@ -136,22 +90,16 @@ module Gitlab
# POST /projects/:id/members
post ":id/members" do
authorize! :admin_project, user_project
- required_attributes! [:user_id, :access_level]
+ users_project = user_project.users_projects.new(
+ user_id: params[:user_id],
+ project_access: params[:access_level]
+ )
- # either the user is already a team member or a new one
- team_member = user_project.team_member_by_id(params[:user_id])
- if team_member.nil?
- team_member = user_project.users_projects.new(
- user_id: params[:user_id],
- project_access: params[:access_level]
- )
- end
-
- if team_member.save
- @member = team_member.user
+ if users_project.save
+ @member = users_project.user
present @member, with: Entities::ProjectMember, project: user_project
else
- handle_project_member_errors team_member.errors
+ not_found!
end
end
@@ -165,16 +113,13 @@ module Gitlab
# PUT /projects/:id/members/:user_id
put ":id/members/:user_id" do
authorize! :admin_project, user_project
- required_attributes! [:access_level]
+ users_project = 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])
- @member = team_member.user
+ if users_project.update_attributes(project_access: params[:access_level])
+ @member = users_project.user
present @member, with: Entities::ProjectMember, project: user_project
else
- handle_project_member_errors team_member.errors
+ not_found!
end
end
@@ -187,12 +132,8 @@ module Gitlab
# 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])
- unless team_member.nil?
- team_member.destroy
- else
- {message: "Access revoked", id: params[:user_id].to_i}
- end
+ users_project = user_project.users_projects.find_by_user_id params[:user_id]
+ users_project.destroy
end
# Get project hooks
@@ -215,7 +156,6 @@ module Gitlab
# Example Request:
# GET /projects/:id/hooks/:hook_id
get ":id/hooks/:hook_id" do
- authorize! :admin_project, user_project
@hook = user_project.hooks.find(params[:hook_id])
present @hook, with: Entities::Hook
end
@@ -230,16 +170,11 @@ module Gitlab
# POST /projects/:id/hooks
post ":id/hooks" do
authorize! :admin_project, user_project
- required_attributes! [:url]
-
@hook = user_project.hooks.new({"url" => params[:url]})
if @hook.save
present @hook, with: Entities::Hook
else
- if @hook.errors[:url].present?
- error!("Invalid url given", 422)
- end
- not_found!
+ error!({'message' => '404 Not found'}, 404)
end
end
@@ -254,36 +189,27 @@ module Gitlab
put ":id/hooks/:hook_id" do
@hook = user_project.hooks.find(params[:hook_id])
authorize! :admin_project, user_project
- required_attributes! [:url]
attrs = attributes_for_keys [:url]
+
if @hook.update_attributes attrs
present @hook, with: Entities::Hook
else
- if @hook.errors[:url].present?
- error!("Invalid url given", 422)
- end
not_found!
end
end
- # Deletes project hook. This is an idempotent function.
+ # Delete project hook
#
# Parameters:
# id (required) - The ID of a project
# hook_id (required) - The ID of hook to delete
# Example Request:
- # DELETE /projects/:id/hooks/:hook_id
+ # DELETE /projects/:id/hooks
delete ":id/hooks" do
authorize! :admin_project, user_project
- required_attributes! [:hook_id]
-
- begin
- @hook = ProjectHook.find(params[:hook_id])
- @hook.destroy
- rescue
- # ProjectHook can raise Error if hook_id not found
- end
+ @hook = user_project.hooks.find(params[:hook_id])
+ @hook.destroy
end
# Get a project repository branches
@@ -293,7 +219,7 @@ module Gitlab
# Example Request:
# GET /projects/:id/repository/branches
get ":id/repository/branches" do
- present user_project.repo.heads.sort_by(&:name), with: Entities::RepoObject, project: user_project
+ present user_project.repo.heads.sort_by(&:name), with: Entities::RepoObject
end
# Get a single branch
@@ -305,46 +231,7 @@ module Gitlab
# GET /projects/:id/repository/branches/:branch
get ":id/repository/branches/:branch" do
@branch = user_project.repo.heads.find { |item| item.name == params[:branch] }
- not_found!("Branch does not exist") if @branch.nil?
- present @branch, with: Entities::RepoObject, project: user_project
- end
-
- # Protect a single branch
- #
- # Parameters:
- # id (required) - The ID of a project
- # branch (required) - The name of the branch
- # Example Request:
- # PUT /projects/:id/repository/branches/:branch/protect
- put ":id/repository/branches/:branch/protect" do
- @branch = user_project.repo.heads.find { |item| item.name == params[:branch] }
- not_found! unless @branch
- protected = user_project.protected_branches.find_by_name(@branch.name)
-
- unless protected
- user_project.protected_branches.create(name: @branch.name)
- end
-
- present @branch, with: Entities::RepoObject, project: user_project
- end
-
- # Unprotect a single branch
- #
- # Parameters:
- # id (required) - The ID of a project
- # branch (required) - The name of the branch
- # Example Request:
- # PUT /projects/:id/repository/branches/:branch/unprotect
- put ":id/repository/branches/:branch/unprotect" do
- @branch = user_project.repo.heads.find { |item| item.name == params[:branch] }
- not_found! unless @branch
- protected = user_project.protected_branches.find_by_name(@branch.name)
-
- if protected
- protected.destroy
- end
-
- present @branch, with: Entities::RepoObject, project: user_project
+ present @branch, with: Entities::RepoObject
end
# Get a project repository tags
@@ -361,18 +248,18 @@ module Gitlab
#
# Parameters:
# id (required) - The ID of a project
- # ref_name (optional) - The name of a repository branch or tag, if not given the default branch is used
+ # ref_name (optional) - The name of a repository branch or tag
# Example Request:
# GET /projects/:id/repository/commits
get ":id/repository/commits" do
authorize! :download_code, user_project
page = params[:page] || 0
- per_page = (params[:per_page] || 20).to_i
+ per_page = params[:per_page] || 20
ref = params[:ref_name] || user_project.try(:default_branch) || 'master'
- commits = user_project.repository.commits(ref, nil, per_page, page * per_page)
- present commits, with: Entities::RepoCommit
+ commits = user_project.commits(ref, nil, per_page, page * per_page)
+ present CommitDecorator.decorate(commits), with: Entities::RepoCommit
end
# Get a project snippets
@@ -409,7 +296,6 @@ module Gitlab
# POST /projects/:id/snippets
post ":id/snippets" do
authorize! :write_snippet, user_project
- required_attributes! [:title, :file_name, :code]
attrs = attributes_for_keys [:title, :file_name]
attrs[:expires_at] = params[:lifetime] if params[:lifetime].present?
@@ -458,12 +344,10 @@ module Gitlab
# Example Request:
# DELETE /projects/:id/snippets/:snippet_id
delete ":id/snippets/:snippet_id" do
- begin
- @snippet = user_project.snippets.find(params[:snippet_id])
- authorize! :modify_snippet, user_project
- @snippet.destroy
- rescue
- end
+ @snippet = user_project.snippets.find(params[:snippet_id])
+ authorize! :modify_snippet, @snippet
+
+ @snippet.destroy
end
# Get a raw project snippet
@@ -489,63 +373,19 @@ module Gitlab
# GET /projects/:id/repository/commits/:sha/blob
get ":id/repository/commits/:sha/blob" do
authorize! :download_code, user_project
- required_attributes! [:filepath]
ref = params[:sha]
- commit = user_project.repository.commit ref
+ commit = user_project.commit ref
not_found! "Commit" unless commit
- tree = Tree.new commit.tree, ref, params[:filepath]
+ tree = Tree.new commit.tree, user_project, ref, params[:filepath]
not_found! "File" unless tree.try(:tree)
content_type tree.mime_type
present tree.data
end
- # Get a specific project's keys
- #
- # Example Request:
- # GET /projects/:id/keys
- get ":id/keys" do
- present user_project.deploy_keys, with: Entities::SSHKey
- end
-
- # Get single key owned by currently authenticated user
- #
- # Example Request:
- # GET /projects/:id/keys/:id
- get ":id/keys/:key_id" do
- key = user_project.deploy_keys.find params[:key_id]
- present key, with: Entities::SSHKey
- end
-
- # Add new ssh key to currently authenticated user
- #
- # Parameters:
- # key (required) - New SSH Key
- # title (required) - New SSH Key's title
- # Example Request:
- # POST /projects/:id/keys
- post ":id/keys" do
- attrs = attributes_for_keys [:title, :key]
- key = user_project.deploy_keys.new attrs
- if key.save
- present key, with: Entities::SSHKey
- else
- not_found!
- end
- end
-
- # Delete existed ssh key of currently authenticated user
- #
- # Example Request:
- # DELETE /projects/:id/keys/:id
- delete ":id/keys/:key_id" do
- key = user_project.deploy_keys.find params[:key_id]
- key.delete
- end
-
end
end
end
diff --git a/lib/api/system_hooks.rb b/lib/api/system_hooks.rb
deleted file mode 100644
index da0b005d..00000000
--- a/lib/api/system_hooks.rb
+++ /dev/null
@@ -1,70 +0,0 @@
-module Gitlab
- # Hooks API
- class SystemHooks < Grape::API
- before {
- authenticate!
- authenticated_as_admin!
- }
-
- resource :hooks do
- # Get the list of system hooks
- #
- # Example Request:
- # GET /hooks
- get do
- @hooks = SystemHook.all
- present @hooks, with: Entities::Hook
- end
-
- # Create new system hook
- #
- # Parameters:
- # url (required) - url for system hook
- # Example Request
- # POST /hooks
- post do
- attrs = attributes_for_keys [:url]
- required_attributes! [:url]
- @hook = SystemHook.new attrs
- if @hook.save
- present @hook, with: Entities::Hook
- else
- not_found!
- end
- end
-
- # Test a hook
- #
- # Example Request
- # GET /hooks/:id
- get ":id" do
- @hook = SystemHook.find(params[:id])
- data = {
- event_name: "project_create",
- name: "Ruby",
- path: "ruby",
- project_id: 1,
- owner_name: "Someone",
- owner_email: "example@gitlabhq.com"
- }
- @hook.execute(data)
- data
- end
-
- # Delete a hook. This is an idempotent function.
- #
- # Parameters:
- # id (required) - ID of the hook
- # Example Request:
- # DELETE /hooks/:id
- delete ":id" do
- begin
- @hook = SystemHook.find(params[:id])
- @hook.destroy
- rescue
- # SystemHook raises an Error if no hook with id found
- end
- end
- end
- end
-end
\ No newline at end of file
diff --git a/lib/api/users.rb b/lib/api/users.rb
index 125a8624..140c20f6 100644
--- a/lib/api/users.rb
+++ b/lib/api/users.rb
@@ -9,9 +9,7 @@ module Gitlab
# Example Request:
# GET /users
get do
- @users = User.scoped
- @users = @users.active if params[:active].present?
- @users = @users.search(params[:search]) if params[:search].present?
+ @users = paginate User
present @users, with: Entities::User
end
@@ -36,16 +34,11 @@ module Gitlab
# linkedin - Linkedin
# twitter - Twitter account
# projects_limit - Number of projects user can create
- # extern_uid - External authentication provider UID
- # provider - External provider
- # bio - Bio
# Example Request:
# POST /users
post do
authenticated_as_admin!
- required_attributes! [:email, :password, :name, :username]
-
- attrs = attributes_for_keys [:email, :name, :password, :skype, :linkedin, :twitter, :projects_limit, :username, :extern_uid, :provider, :bio]
+ attrs = attributes_for_keys [:email, :name, :password, :skype, :linkedin, :twitter, :projects_limit, :username]
user = User.new attrs, as: :admin
if user.save
present user, with: Entities::User
@@ -53,70 +46,6 @@ module Gitlab
not_found!
end
end
-
- # Update user. Available only for admin
- #
- # Parameters:
- # email - Email
- # name - Name
- # password - Password
- # skype - Skype ID
- # linkedin - Linkedin
- # twitter - Twitter account
- # projects_limit - Limit projects each user can create
- # extern_uid - External authentication provider UID
- # provider - External provider
- # bio - Bio
- # Example Request:
- # PUT /users/:id
- put ":id" do
- authenticated_as_admin!
-
- attrs = attributes_for_keys [:email, :name, :password, :skype, :linkedin, :twitter, :projects_limit, :username, :extern_uid, :provider, :bio]
- user = User.find(params[:id])
- not_found!("User not found") unless user
-
- if user.update_attributes(attrs)
- present user, with: Entities::User
- else
- not_found!
- end
- end
-
- # Add ssh key to a specified user. Only available to admin users.
- #
- # Parameters:
- # id (required) - The ID of a user
- # key (required) - New SSH Key
- # title (required) - New SSH Key's title
- # Example Request:
- # POST /users/:id/keys
- post ":id/keys" do
- authenticated_as_admin!
- user = User.find(params[:id])
- attrs = attributes_for_keys [:title, :key]
- key = user.keys.new attrs
- if key.save
- present key, with: Entities::SSHKey
- else
- not_found!
- end
- end
-
- # Delete user. Available only for admin
- #
- # Example Request:
- # DELETE /users/:id
- delete ":id" do
- authenticated_as_admin!
- user = User.find_by_id(params[:id])
-
- if user
- user.destroy
- else
- not_found!
- end
- end
end
resource :user do
@@ -125,7 +54,7 @@ module Gitlab
# Example Request:
# GET /user
get do
- present @current_user, with: Entities::UserLogin
+ present @current_user, with: Entities::User
end
# Get currently authenticated user's keys
@@ -153,8 +82,6 @@ module Gitlab
# Example Request:
# POST /user/keys
post "keys" do
- required_attributes! [:title, :key]
-
attrs = attributes_for_keys [:title, :key]
key = current_user.keys.new attrs
if key.save
@@ -164,18 +91,15 @@ module Gitlab
end
end
- # Delete existing ssh key of currently authenticated user
+ # Delete existed ssh key of currently authenticated user
#
# Parameters:
# id (required) - SSH Key ID
# Example Request:
# DELETE /user/keys/:id
delete "keys/:id" do
- begin
- key = current_user.keys.find params[:id]
- key.delete
- rescue
- end
+ key = current_user.keys.find params[:id]
+ key.delete
end
end
end
diff --git a/lib/event_filter.rb b/lib/event_filter.rb
index 9b4b8c38..14ab0193 100644
--- a/lib/event_filter.rb
+++ b/lib/event_filter.rb
@@ -37,15 +37,15 @@ class EventFilter
filter = params.dup
actions = []
- actions << Event::PUSHED if filter.include? 'push'
- actions << Event::MERGED if filter.include? 'merged'
+ actions << Event::Pushed if filter.include? 'push'
+ actions << Event::Merged if filter.include? 'merged'
if filter.include? 'team'
- actions << Event::JOINED
- actions << Event::LEFT
+ actions << Event::Joined
+ actions << Event::Left
end
- actions << Event::COMMENTED if filter.include? 'comments'
+ actions << Event::Commented if filter.include? 'comments'
events = events.where(action: actions)
end
diff --git a/lib/extracts_path.rb b/lib/extracts_path.rb
index 2e3ab1b2..b60dfd03 100644
--- a/lib/extracts_path.rb
+++ b/lib/extracts_path.rb
@@ -8,7 +8,7 @@ module ExtractsPath
included do
if respond_to?(:before_filter)
- before_filter :assign_ref_vars
+ before_filter :assign_ref_vars, only: [:show]
end
end
@@ -33,9 +33,6 @@ module ExtractsPath
# extract_ref("v2.0.0/README.md")
# # => ['v2.0.0', 'README.md']
#
- # extract_ref('master/app/models/project.rb')
- # # => ['master', 'app/models/project.rb']
- #
# extract_ref('issues/1234/app/models/project.rb')
# # => ['issues/1234', 'app/models/project.rb']
#
@@ -45,12 +42,12 @@ module ExtractsPath
#
# Returns an Array where the first value is the tree-ish and the second is the
# path
- def extract_ref(id)
+ def extract_ref(input)
pair = ['', '']
return pair unless @project
- if id.match(/^([[:alnum:]]{40})(.+)/)
+ if input.match(/^([[:alnum:]]{40})(.+)/)
# If the ref appears to be a SHA, we're done, just split the string
pair = $~.captures
else
@@ -58,9 +55,10 @@ module ExtractsPath
# branches and tags
# Append a trailing slash if we only get a ref and no file path
+ id = input
id += '/' unless id.ends_with?('/')
- valid_refs = @project.repository.ref_names
+ valid_refs = @project.ref_names
valid_refs.select! { |v| id.start_with?("#{v}/") }
if valid_refs.length != 1
@@ -85,8 +83,8 @@ module ExtractsPath
# - @id - A string representing the joined ref and path
# - @ref - A string representing the ref (e.g., the branch, tag, or commit SHA)
# - @path - A string representing the filesystem path
- # - @commit - A Commit representing the commit from the given ref
- # - @tree - A Tree representing the tree at the given ref/path
+ # - @commit - A CommitDecorator representing the commit from the given ref
+ # - @tree - A TreeDecorator representing the tree at the given ref/path
#
# If the :id parameter appears to be requesting a specific response format,
# that will be handled as well.
@@ -94,18 +92,23 @@ module ExtractsPath
# Automatically renders `not_found!` if a valid tree path could not be
# resolved (e.g., when a user inserts an invalid path or ref).
def assign_ref_vars
- @id = params[:id]
+ # Handle formats embedded in the id
+ if params[:id].ends_with?('.atom')
+ params[:id].gsub!(/\.atom$/, '')
+ request.format = :atom
+ end
- @ref, @path = extract_ref(@id)
+ @ref, @path = extract_ref(params[:id])
- # It is used "@project.repository.commits(@ref, @path, 1, 0)",
- # because "@project.repository.commit(@ref)" returns wrong commit when @ref is tag name.
- @commit = @project.repository.commits(@ref, @path, 1, 0).first
+ @id = File.join(@ref, @path)
- @tree = Tree.new(@commit.tree, @ref, @path)
+ @commit = CommitDecorator.decorate(@project.commit(@ref))
+
+ @tree = Tree.new(@commit.tree, @project, @ref, @path)
+ @tree = TreeDecorator.new(@tree)
raise InvalidPathError if @tree.invalid?
- rescue RuntimeError, NoMethodError, InvalidPathError
+ rescue NoMethodError, InvalidPathError
not_found!
end
end
diff --git a/lib/gitlab/auth.rb b/lib/gitlab/auth.rb
index 0fee33db..8c45c935 100644
--- a/lib/gitlab/auth.rb
+++ b/lib/gitlab/auth.rb
@@ -20,9 +20,8 @@ module Gitlab
def create_from_omniauth(auth, ldap = false)
provider = auth.provider
uid = auth.info.uid || auth.uid
- uid = uid.to_s.force_encoding("utf-8")
- name = auth.info.name.to_s.force_encoding("utf-8")
- email = auth.info.email.to_s.downcase unless auth.info.email.nil?
+ name = auth.info.name.force_encoding("utf-8")
+ email = auth.info.email.downcase unless auth.info.email.nil?
ldap_prefix = ldap ? '(LDAP) ' : ''
raise OmniAuth::Error, "#{ldap_prefix}#{provider} does not provide an email"\
@@ -41,12 +40,10 @@ module Gitlab
password_confirmation: password,
projects_limit: Gitlab.config.gitlab.default_projects_limit,
}, as: :admin)
- @user.save!
-
if Gitlab.config.omniauth['block_auto_created_users'] && !ldap
- @user.block
+ @user.blocked = true
end
-
+ @user.save!
@user
end
diff --git a/lib/gitlab/backend/gitolite.rb b/lib/gitlab/backend/gitolite.rb
new file mode 100644
index 00000000..3b8a2090
--- /dev/null
+++ b/lib/gitlab/backend/gitolite.rb
@@ -0,0 +1,56 @@
+require_relative 'gitolite_config'
+
+module Gitlab
+ class Gitolite
+ class AccessDenied < StandardError; end
+
+ def config
+ Gitlab::GitoliteConfig.new
+ end
+
+ def set_key key_id, key_content, projects
+ config.apply do |config|
+ config.write_key(key_id, key_content)
+ config.update_projects(projects)
+ end
+ end
+
+ def remove_key key_id, projects
+ config.apply do |config|
+ config.rm_key(key_id)
+ config.update_projects(projects)
+ end
+ end
+
+ def update_repository project
+ config.update_project!(project)
+ end
+
+ def move_repository(old_repo, project)
+ config.apply do |config|
+ config.clean_repo(old_repo)
+ config.update_project(project)
+ end
+ end
+
+ def remove_repository project
+ config.destroy_project!(project)
+ end
+
+ def url_to_repo path
+ Gitlab.config.gitolite.ssh_path_prefix + "#{path}.git"
+ end
+
+ def enable_automerge
+ config.admin_all_repo!
+ end
+
+ def update_repositories projects
+ config.apply do |config|
+ config.update_projects(projects)
+ end
+ end
+
+ alias_method :create_repository, :update_repository
+ end
+end
diff --git a/lib/gitlab/backend/gitolite_config.rb b/lib/gitlab/backend/gitolite_config.rb
new file mode 100644
index 00000000..a2bc4ca8
--- /dev/null
+++ b/lib/gitlab/backend/gitolite_config.rb
@@ -0,0 +1,213 @@
+require 'gitolite'
+require 'timeout'
+require 'fileutils'
+
+module Gitlab
+ class GitoliteConfig
+ class PullError < StandardError; end
+ class PushError < StandardError; end
+
+ attr_reader :config_tmp_dir, :ga_repo, :conf
+
+ def config_tmp_dir
+ @config_tmp_dir ||= Rails.root.join('tmp',"gitlabhq-gitolite-#{Time.now.to_i}")
+ end
+
+ def ga_repo
+ @ga_repo ||= ::Gitolite::GitoliteAdmin.new(
+ File.join(config_tmp_dir,'gitolite'),
+ conf: Gitlab.config.gitolite.config_file
+ )
+ end
+
+ def apply
+ Timeout::timeout(30) do
+ File.open(Rails.root.join('tmp', "gitlabhq-gitolite.lock"), "w+") do |f|
+ begin
+ # Set exclusive lock
+ # to prevent race condition
+ f.flock(File::LOCK_EX)
+
+ # Pull gitolite-admin repo
+ # in tmp dir before do any changes
+ pull(config_tmp_dir)
+
+ # Build ga_repo object and @conf
+ # to access gitolite-admin configuration
+ @conf = ga_repo.config
+
+ # Do any changes
+ # in gitolite-admin
+ # config here
+ yield(self)
+
+ # Save changes in
+ # gitolite-admin repo
+ # before push it
+ ga_repo.save
+
+ # Push gitolite-admin repo
+ # to apply all changes
+ push(config_tmp_dir)
+ ensure
+ # Remove tmp dir
+ # removing the gitolite folder first is important to avoid
+ # NFS issues.
+ FileUtils.rm_rf(File.join(config_tmp_dir, 'gitolite'))
+
+ # Remove parent tmp dir
+ FileUtils.rm_rf(config_tmp_dir)
+
+ # Unlock so other task can access
+ # gitolite configuration
+ f.flock(File::LOCK_UN)
+ end
+ end
+ end
+ rescue PullError => ex
+ log("Pull error -> " + ex.message)
+ raise Gitolite::AccessDenied, ex.message
+
+ rescue PushError => ex
+ log("Push error -> " + " " + ex.message)
+ raise Gitolite::AccessDenied, ex.message
+
+ rescue Exception => ex
+ log(ex.class.name + " " + ex.message)
+ raise Gitolite::AccessDenied.new("gitolite timeout")
+ end
+
+ def log message
+ Gitlab::GitLogger.error(message)
+ end
+
+ def destroy_project(project)
+ FileUtils.rm_rf(project.path_to_repo)
+ conf.rm_repo(project.path_with_namespace)
+ end
+
+ def clean_repo repo_name
+ conf.rm_repo(repo_name)
+ end
+
+ def destroy_project!(project)
+ apply do |config|
+ config.destroy_project(project)
+ end
+ end
+
+ def write_key(id, key)
+ File.open(File.join(config_tmp_dir, 'gitolite/keydir',"#{id}.pub"), 'w') do |f|
+ f.write(key.gsub(/\n/,''))
+ end
+ end
+
+ def rm_key(user)
+ key_path = File.join(config_tmp_dir, 'gitolite/keydir', "#{user}.pub")
+ ga_key = ::Gitolite::SSHKey.from_file(key_path)
+ ga_repo.rm_key(ga_key)
+ end
+
+ # update or create
+ def update_project(project)
+ repo = update_project_config(project, conf)
+ conf.add_repo(repo, true)
+ end
+
+ def update_project!( project)
+ apply do |config|
+ config.update_project(project)
+ end
+ end
+
+ # Updates many projects and uses project.path_with_namespace as the repo path
+ # An order of magnitude faster than update_project
+ def update_projects(projects)
+ projects.each do |project|
+ repo = update_project_config(project, conf)
+ conf.add_repo(repo, true)
+ end
+ end
+
+ def update_project_config(project, conf)
+ repo_name = project.path_with_namespace
+
+ repo = if conf.has_repo?(repo_name)
+ conf.get_repo(repo_name)
+ else
+ ::Gitolite::Config::Repo.new(repo_name)
+ end
+
+ name_readers = project.repository_readers
+ name_writers = project.repository_writers
+ name_masters = project.repository_masters
+
+ pr_br = project.protected_branches.map(&:name).join("$ ")
+
+ repo.clean_permissions
+
+ # Deny access to protected branches for writers
+ unless name_writers.blank? || pr_br.blank?
+ repo.add_permission("-", pr_br.strip + "$ ", name_writers)
+ end
+
+ # Add read permissions
+ repo.add_permission("R", "", name_readers) unless name_readers.blank?
+
+ # Add write permissions
+ repo.add_permission("RW+", "", name_writers) unless name_writers.blank?
+ repo.add_permission("RW+", "", name_masters) unless name_masters.blank?
+
+ # Add sharedRepository config
+ repo.set_git_config("core.sharedRepository", "0660")
+
+ repo
+ end
+
+ # Enable access to all repos for gitolite admin.
+ # We use it for accept merge request feature
+ def admin_all_repo
+ owner_name = Gitlab.config.gitolite.admin_key
+
+ # @ALL repos premission for gitolite owner
+ repo_name = "@all"
+ repo = if conf.has_repo?(repo_name)
+ conf.get_repo(repo_name)
+ else
+ ::Gitolite::Config::Repo.new(repo_name)
+ end
+
+ repo.add_permission("RW+", "", owner_name)
+ conf.add_repo(repo, true)
+ end
+
+ def admin_all_repo!
+ apply { |config| config.admin_all_repo }
+ end
+
+ private
+
+ def pull tmp_dir
+ Dir.mkdir tmp_dir
+ `git clone #{Gitlab.config.gitolite.admin_uri} #{tmp_dir}/gitolite`
+
+ unless File.exists?(File.join(tmp_dir, 'gitolite', 'conf', 'gitolite.conf'))
+ raise PullError, "unable to clone gitolite-admin repo"
+ end
+ end
+
+ def push tmp_dir
+ Dir.chdir(File.join(tmp_dir, "gitolite"))
+ raise "Git add failed." unless system('git add -A')
+ system('git commit -m "GitLab"') # git commit returns 0 on success, and 1 if there is nothing to commit
+ raise "Git commit failed." unless [0,1].include? $?.exitstatus
+
+ if system('git push')
+ Dir.chdir(Rails.root)
+ else
+ raise PushError, "unable to push gitolite-admin repo"
+ end
+ end
+ end
+end
+
diff --git a/lib/gitlab/backend/grack_auth.rb b/lib/gitlab/backend/grack_auth.rb
index abbee613..7c31117f 100644
--- a/lib/gitlab/backend/grack_auth.rb
+++ b/lib/gitlab/backend/grack_auth.rb
@@ -1,40 +1,30 @@
-require_relative 'shell_env'
-
module Grack
class Auth < Rack::Auth::Basic
attr_accessor :user, :project
- def call(env)
- @env = env
- @request = Rack::Request.new(env)
- @auth = Request.new(env)
+ def valid?
+ # Authentication with username and password
+ login, password = @auth.credentials
+
+ self.user = User.find_by_email(login) || User.find_by_username(login)
+
+ return false unless user.try(:valid_password?, password)
+
+ email = user.email
+
+ # Set GL_USER env variable
+ ENV['GL_USER'] = email
+ # Pass Gitolite update hook
+ ENV['GL_BYPASS_UPDATE_HOOK'] = "true"
# Need this patch due to the rails mount
@env['PATH_INFO'] = @request.path
@env['SCRIPT_NAME'] = ""
- return render_not_found unless project
- return unauthorized unless project.public || @auth.provided?
- return bad_request if @auth.provided? && !@auth.basic?
-
- if valid?
- if @auth.provided?
- @env['REMOTE_USER'] = @auth.username
- end
- return @app.call(env)
- else
- unauthorized
- end
- end
-
- def valid?
- if @auth.provided?
- # Authentication with username and password
- login, password = @auth.credentials
- self.user = User.find_by_email(login) || User.find_by_username(login)
- return false unless user.try(:valid_password?, password)
-
- Gitlab::ShellEnv.set_env(user)
+ # Find project by PATH_INFO from env
+ if m = /^\/([\w\.\/-]+)\.git/.match(@request.path_info).to_a
+ self.project = Project.find_with_namespace(m.last)
+ return false unless project
end
# Git upload and receive
@@ -48,12 +38,12 @@ module Grack
end
def validate_get_request
- project.public || can?(user, :download_code, project)
+ can?(user, :download_code, project)
end
def validate_post_request
if @request.path_info.end_with?('git-upload-pack')
- project.public || can?(user, :download_code, project)
+ can?(user, :download_code, project)
elsif @request.path_info.end_with?('git-receive-pack')
action = if project.protected_branch?(current_ref)
:push_code_to_protected_branches
@@ -79,23 +69,7 @@ module Grack
end
# Need to reset seek point
@request.body.rewind
- /refs\/heads\/([\w\.-]+)/.match(input).to_a.last
- end
-
- def project
- unless instance_variable_defined? :@project
- # Find project by PATH_INFO from env
- if m = /^\/([\w\.\/-]+)\.git/.match(@request.path_info).to_a
- @project = Project.find_with_namespace(m.last)
- end
- end
- return @project
- end
-
- PLAIN_TYPE = {"Content-Type" => "text/plain"}
-
- def render_not_found
- [404, PLAIN_TYPE, ["Not Found"]]
+ /refs\/heads\/([\w\.-]+)/.match(input).to_a.first
end
protected
diff --git a/lib/gitlab/backend/shell.rb b/lib/gitlab/backend/shell.rb
deleted file mode 100644
index bae87977..00000000
--- a/lib/gitlab/backend/shell.rb
+++ /dev/null
@@ -1,136 +0,0 @@
-module Gitlab
- class Shell
- class AccessDenied < StandardError; end
-
- # Init new repository
- #
- # name - project path with namespace
- #
- # Ex.
- # add_repository("gitlab/gitlab-ci")
- #
- def add_repository(name)
- system("#{gitlab_shell_user_home}/gitlab-shell/bin/gitlab-projects add-project #{name}.git")
- end
-
- # Import repository
- #
- # name - project path with namespace
- #
- # Ex.
- # import_repository("gitlab/gitlab-ci", "https://github.com/randx/six.git")
- #
- def import_repository(name, url)
- system("#{gitlab_shell_user_home}/gitlab-shell/bin/gitlab-projects import-project #{name}.git #{url}")
- end
-
- # Move repository
- #
- # path - project path with namespace
- # new_path - new project path with namespace
- #
- # Ex.
- # mv_repository("gitlab/gitlab-ci", "randx/gitlab-ci-new.git")
- #
- def mv_repository(path, new_path)
- system("#{gitlab_shell_user_home}/gitlab-shell/bin/gitlab-projects mv-project #{path}.git #{new_path}.git")
- end
-
- # Remove repository from file system
- #
- # name - project path with namespace
- #
- # Ex.
- # remove_repository("gitlab/gitlab-ci")
- #
- def remove_repository(name)
- system("#{gitlab_shell_user_home}/gitlab-shell/bin/gitlab-projects rm-project #{name}.git")
- end
-
- # Add new key to gitlab-shell
- #
- # Ex.
- # add_key("key-42", "sha-rsa ...")
- #
- def add_key(key_id, key_content)
- system("#{gitlab_shell_user_home}/gitlab-shell/bin/gitlab-keys add-key #{key_id} \"#{key_content}\"")
- end
-
- # Remove ssh key from gitlab shell
- #
- # Ex.
- # remove_key("key-342", "sha-rsa ...")
- #
- def remove_key(key_id, key_content)
- system("#{gitlab_shell_user_home}/gitlab-shell/bin/gitlab-keys rm-key #{key_id} \"#{key_content}\"")
- end
-
- # Add empty directory for storing repositories
- #
- # Ex.
- # add_namespace("gitlab")
- #
- def add_namespace(name)
- FileUtils.mkdir(full_path(name), mode: 0770) unless exists?(name)
- end
-
- # Remove directory from repositories storage
- # Every repository inside this directory will be removed too
- #
- # Ex.
- # rm_namespace("gitlab")
- #
- def rm_namespace(name)
- FileUtils.rm_r(full_path(name), force: true)
- end
-
- # Move namespace directory inside repositories storage
- #
- # Ex.
- # mv_namespace("gitlab", "gitlabhq")
- #
- def mv_namespace(old_name, new_name)
- return false if exists?(new_name) || !exists?(old_name)
-
- FileUtils.mv(full_path(old_name), full_path(new_name))
- end
-
- # Remove GitLab Satellites for provided path (namespace or repo dir)
- #
- # Ex.
- # rm_satellites("gitlab")
- #
- # rm_satellites("gitlab/gitlab-ci.git")
- #
- def rm_satellites(path)
- raise ArgumentError.new("Path can't be blank") if path.blank?
-
- satellites_path = File.join(Gitlab.config.satellites.path, path)
- FileUtils.rm_r(satellites_path, force: true)
- end
-
- def url_to_repo path
- Gitlab.config.gitlab_shell.ssh_path_prefix + "#{path}.git"
- end
-
- protected
-
- def gitlab_shell_user_home
- File.expand_path("~#{Gitlab.config.gitlab_shell.ssh_user}")
- end
-
- def repos_path
- Gitlab.config.gitlab_shell.repos_path
- end
-
- def full_path(dir_name)
- raise ArgumentError.new("Directory name can't be blank") if dir_name.blank?
-
- File.join(repos_path, dir_name)
- end
-
- def exists?(dir_name)
- File.exists?(full_path(dir_name))
- end
- end
-end
diff --git a/lib/gitlab/backend/shell_adapter.rb b/lib/gitlab/backend/shell_adapter.rb
deleted file mode 100644
index f247f459..00000000
--- a/lib/gitlab/backend/shell_adapter.rb
+++ /dev/null
@@ -1,12 +0,0 @@
-# == GitLab Shell mixin
-#
-# Provide a shortcut to Gitlab::Shell instance by gitlab_shell
-#
-module Gitlab
- module ShellAdapter
- def gitlab_shell
- Gitlab::Shell.new
- end
- end
-end
-
diff --git a/lib/gitlab/backend/shell_env.rb b/lib/gitlab/backend/shell_env.rb
deleted file mode 100644
index 15721875..00000000
--- a/lib/gitlab/backend/shell_env.rb
+++ /dev/null
@@ -1,17 +0,0 @@
-module Gitlab
- # This module provide 2 methods
- # to set specific ENV variabled for GitLab Shell
- module ShellEnv
- extend self
-
- def set_env(user)
- # Set GL_ID env variable
- ENV['GL_ID'] = "user-#{user.id}"
- end
-
- def reset_env
- # Reset GL_ID env variable
- ENV['GL_ID'] = nil
- end
- end
-end
diff --git a/lib/gitlab/git/blame.rb b/lib/gitlab/git/blame.rb
deleted file mode 100644
index d6e988b6..00000000
--- a/lib/gitlab/git/blame.rb
+++ /dev/null
@@ -1,22 +0,0 @@
-module Gitlab
- module Git
- class Blame
-
- attr_accessor :repository, :sha, :path
-
- def initialize(repository, sha, path)
- @repository, @sha, @path = repository, sha, path
-
- end
-
- def each
- raw_blame = Grit::Blob.blame(repository.repo, sha, path)
-
- raw_blame.each do |commit, lines|
- commit = Gitlab::Git::Commit.new(commit)
- yield(commit, lines)
- end
- end
- end
- end
-end
diff --git a/lib/gitlab/git/commit.rb b/lib/gitlab/git/commit.rb
deleted file mode 100644
index 35991a38..00000000
--- a/lib/gitlab/git/commit.rb
+++ /dev/null
@@ -1,153 +0,0 @@
-# Gitlab::Git::Commit is a wrapper around native Grit::Commit object
-# We dont want to use grit objects inside app/
-# It helps us easily migrate to rugged in future
-module Gitlab
- module Git
- class Commit
- attr_accessor :raw_commit, :head, :refs
-
- delegate :message, :authored_date, :committed_date, :parents, :sha,
- :date, :committer, :author, :diffs, :tree, :id, :stats, :to_patch,
- to: :raw_commit
-
- class << self
- def find_or_first(repo, commit_id = nil, root_ref)
- commit = if commit_id
- repo.commit(commit_id)
- else
- repo.commits(root_ref).first
- end
-
- Commit.new(commit) if commit
- end
-
- def fresh_commits(repo, n = 10)
- commits = repo.heads.map do |h|
- repo.commits(h.name, n).map { |c| Commit.new(c, h) }
- end.flatten.uniq { |c| c.id }
-
- commits.sort! do |x, y|
- y.committed_date <=> x.committed_date
- end
-
- commits[0...n]
- end
-
- def commits_with_refs(repo, n = 20)
- commits = repo.branches.map { |ref| Commit.new(ref.commit, ref) }
-
- commits.sort! do |x, y|
- y.committed_date <=> x.committed_date
- end
-
- commits[0..n]
- end
-
- def commits_since(repo, date)
- commits = repo.heads.map do |h|
- repo.log(h.name, nil, since: date).each { |c| Commit.new(c, h) }
- end.flatten.uniq { |c| c.id }
-
- commits.sort! do |x, y|
- y.committed_date <=> x.committed_date
- end
-
- commits
- end
-
- def commits(repo, ref, path = nil, limit = nil, offset = nil)
- if path
- repo.log(ref, path, max_count: limit, skip: offset)
- elsif limit && offset
- repo.commits(ref, limit, offset)
- else
- repo.commits(ref)
- end.map{ |c| Commit.new(c) }
- end
-
- def commits_between(repo, from, to)
- repo.commits_between(from, to).map { |c| Commit.new(c) }
- end
- end
-
- def initialize(raw_commit, head = nil)
- raise "Nil as raw commit passed" unless raw_commit
-
- @raw_commit = raw_commit
- @head = head
- end
-
- def short_id(length = 10)
- id.to_s[0..length]
- end
-
- def safe_message
- @safe_message ||= message
- end
-
- def created_at
- committed_date
- end
-
- def author_email
- author.email
- end
-
- def author_name
- author.name
- end
-
- # Was this commit committed by a different person than the original author?
- def different_committer?
- author_name != committer_name || author_email != committer_email
- end
-
- def committer_name
- committer.name
- end
-
- def committer_email
- committer.email
- end
-
- def prev_commit
- @prev_commit ||= if parents.present?
- Commit.new(parents.first)
- else
- nil
- end
- end
-
- def prev_commit_id
- prev_commit.try :id
- end
-
- # Shows the diff between the commit's parent and the commit.
- #
- # Cuts out the header and stats from #to_patch and returns only the diff.
- def to_diff
- # see Grit::Commit#show
- patch = to_patch
-
- # discard lines before the diff
- lines = patch.split("\n")
- while !lines.first.start_with?("diff --git") do
- lines.shift
- end
- lines.pop if lines.last =~ /^[\d.]+$/ # Git version
- lines.pop if lines.last == "-- " # end of diff
- lines.join("\n")
- end
-
- def has_zero_stats?
- stats.total.zero?
- rescue
- true
- end
-
- def no_commit_message
- "--no commit message"
- end
- end
- end
-end
diff --git a/lib/gitlab/git/compare.rb b/lib/gitlab/git/compare.rb
deleted file mode 100644
index 1fa43062..00000000
--- a/lib/gitlab/git/compare.rb
+++ /dev/null
@@ -1,37 +0,0 @@
-module Gitlab
- module Git
- class Compare
- attr_accessor :commits, :commit, :diffs, :same
-
- def initialize(repository, from, to)
- @commits, @diffs = [], []
- @commit = nil
- @same = false
-
- return unless from && to
-
- first = repository.commit(to.try(:strip))
- last = repository.commit(from.try(:strip))
-
- return unless first && last
-
- if first.id == last.id
- @same = true
- return
- end
-
- @commit = Commit.new(first)
-
- @commits = repository.commits_between(last.id, first.id)
- @commits = @commits.map { |c| Commit.new(c) }
-
- @diffs = if @commits.size > 100
- []
- else
- repository.repo.diff(last.id, first.id) rescue []
- end
- end
- end
- end
-end
-
diff --git a/lib/gitlab/git/repository.rb b/lib/gitlab/git/repository.rb
deleted file mode 100644
index 30344a3d..00000000
--- a/lib/gitlab/git/repository.rb
+++ /dev/null
@@ -1,185 +0,0 @@
-# Gitlab::Git::Gitlab::Git::Commit is a wrapper around native Grit::Repository object
-# We dont want to use grit objects inside app/
-# It helps us easily migrate to rugged in future
-module Gitlab
- module Git
- class Repository
- include Gitlab::Popen
-
- class NoRepository < StandardError; end
-
- # Repository directory name with namespace direcotry
- # Examples:
- # gitlab/gitolite
- # diaspora
- #
- attr_accessor :path_with_namespace
-
- # Grit repo object
- attr_accessor :repo
-
- # Default branch in the repository
- attr_accessor :root_ref
-
- def initialize(path_with_namespace, root_ref = 'master')
- @root_ref = root_ref || "master"
- @path_with_namespace = path_with_namespace
-
- # Init grit repo object
- repo
- end
-
- def raw
- repo
- end
-
- def path_to_repo
- @path_to_repo ||= File.join(repos_path, "#{path_with_namespace}.git")
- end
-
- def repos_path
- Gitlab.config.gitlab_shell.repos_path
- end
-
- def repo
- @repo ||= Grit::Repo.new(path_to_repo)
- rescue Grit::NoSuchPathError
- raise NoRepository.new('no repository for such path')
- end
-
- def commit(commit_id = nil)
- Gitlab::Git::Commit.find_or_first(repo, commit_id, root_ref)
- end
-
- def fresh_commits(n = 10)
- Gitlab::Git::Commit.fresh_commits(repo, n)
- end
-
- def commits_with_refs(n = 20)
- Gitlab::Git::Commit.commits_with_refs(repo, n)
- end
-
- def commits_since(date)
- Gitlab::Git::Commit.commits_since(repo, date)
- end
-
- def commits(ref, path = nil, limit = nil, offset = nil)
- Gitlab::Git::Commit.commits(repo, ref, path, limit, offset)
- end
-
- def last_commit_for(ref, path = nil)
- commits(ref, path, 1).first
- end
-
- def commits_between(from, to)
- Gitlab::Git::Commit.commits_between(repo, from, to)
- end
-
- # Returns an Array of branch names
- # sorted by name ASC
- def branch_names
- branches.map(&:name)
- end
-
- # Returns an Array of Branches
- def branches
- repo.branches.sort_by(&:name)
- end
-
- # Returns an Array of tag names
- def tag_names
- repo.tags.collect(&:name).sort.reverse
- end
-
- # Returns an Array of Tags
- def tags
- repo.tags.sort_by(&:name).reverse
- end
-
- # Returns an Array of branch and tag names
- def ref_names
- [branch_names + tag_names].flatten
- end
-
- def heads
- @heads ||= repo.heads
- end
-
- def tree(fcommit, path = nil)
- fcommit = commit if fcommit == :head
- tree = fcommit.tree
- path ? (tree / path) : tree
- end
-
- def has_commits?
- !!commit
- rescue Grit::NoSuchPathError
- false
- end
-
- def empty?
- !has_commits?
- end
-
- # Discovers the default branch based on the repository's available branches
- #
- # - If no branches are present, returns nil
- # - If one branch is present, returns its name
- # - If two or more branches are present, returns the one that has a name
- # matching root_ref (default_branch or 'master' if default_branch is nil)
- def discover_default_branch
- if branch_names.length == 0
- nil
- elsif branch_names.length == 1
- branch_names.first
- else
- branch_names.select { |v| v == root_ref }.first
- end
- end
-
- # Archive Project to .tar.gz
- #
- # Already packed repo archives stored at
- # app_root/tmp/repositories/project_name/project_name-commit-id.tag.gz
- #
- def archive_repo(ref)
- ref = ref || self.root_ref
- commit = self.commit(ref)
- return nil unless commit
-
- # Build file path
- file_name = self.path_with_namespace.gsub("/","_") + "-" + commit.id.to_s + ".tar.gz"
- storage_path = Rails.root.join("tmp", "repositories")
- file_path = File.join(storage_path, self.path_with_namespace, file_name)
-
- # Put files into a directory before archiving
- prefix = File.basename(self.path_with_namespace) + "/"
-
- # Create file if not exists
- unless File.exists?(file_path)
- FileUtils.mkdir_p File.dirname(file_path)
- file = self.repo.archive_to_file(ref, prefix, file_path)
- end
-
- file_path
- end
-
- # Return repo size in megabytes
- # Cached in redis
- def size
- Rails.cache.fetch(cache_key(:size)) do
- size = popen('du -s', path_to_repo).first.strip.to_i
- (size.to_f / 1024).round(2)
- end
- end
-
- def expire_cache
- Rails.cache.delete(cache_key(:size))
- end
-
- def cache_key(type)
- "#{type}:#{path_with_namespace}"
- end
- end
- end
-end
diff --git a/lib/gitlab/graph/commit.rb b/lib/gitlab/graph/commit.rb
new file mode 100644
index 00000000..3d82c344
--- /dev/null
+++ b/lib/gitlab/graph/commit.rb
@@ -0,0 +1,48 @@
+require "grit"
+
+module Gitlab
+ module Graph
+ class Commit
+ include ActionView::Helpers::TagHelper
+
+ attr_accessor :time, :space, :refs
+
+ def initialize(commit)
+ @_commit = commit
+ @time = -1
+ @space = 0
+ end
+
+ def method_missing(m, *args, &block)
+ @_commit.send(m, *args, &block)
+ end
+
+ def to_graph_hash
+ h = {}
+ h[:parents] = self.parents.collect do |p|
+ [p.id,0,0]
+ end
+ h[:author] = author.name
+ h[:time] = time
+ h[:space] = space
+ h[:refs] = refs.collect{|r|r.name}.join(" ") unless refs.nil?
+ h[:id] = sha
+ h[:date] = date
+ h[:message] = message
+ h[:login] = author.email
+ h
+ end
+
+ def add_refs(ref_cache, repo)
+ if ref_cache.empty?
+ repo.refs.each do |ref|
+ ref_cache[ref.commit.id] ||= []
+ ref_cache[ref.commit.id] << ref
+ end
+ end
+ @refs = ref_cache[@_commit.id] if ref_cache.include?(@_commit.id)
+ @refs ||= []
+ end
+ end
+ end
+end
diff --git a/lib/gitlab/graph/json_builder.rb b/lib/gitlab/graph/json_builder.rb
new file mode 100644
index 00000000..a5914363
--- /dev/null
+++ b/lib/gitlab/graph/json_builder.rb
@@ -0,0 +1,171 @@
+require "grit"
+
+module Gitlab
+ module Graph
+ class JsonBuilder
+ attr_accessor :days, :commits, :ref_cache, :repo
+
+ def self.max_count
+ @max_count ||= 650
+ end
+
+ def initialize project
+ @project = project
+ @repo = project.repo
+ @ref_cache = {}
+
+ @commits = collect_commits
+ @days = index_commits
+ end
+
+ def to_json(*args)
+ {
+ days: @days.compact.map { |d| [d.day, d.strftime("%b")] },
+ commits: @commits.map(&:to_graph_hash)
+ }.to_json(*args)
+ end
+
+ protected
+
+ # Get commits from repository
+ #
+ def collect_commits
+ @commits = Grit::Commit.find_all(repo, nil, {max_count: self.class.max_count}).dup
+
+ # Decorate with app/models/commit.rb
+ @commits.map! { |commit| ::Commit.new(commit) }
+
+ # Decorate with lib/gitlab/graph/commit.rb
+ @commits.map! { |commit| Gitlab::Graph::Commit.new(commit) }
+
+ # add refs to each commit
+ @commits.each { |commit| commit.add_refs(ref_cache, repo) }
+
+ @commits
+ end
+
+ # Method is adding time and space on the
+ # list of commits. As well as returns date list
+ # corelated with time set on commits.
+ #
+ # @param [Array] comits to index
+ #
+ # @return [Array] list of commit dates corelated with time on commits
+ def index_commits
+ days, heads = [], []
+ map = {}
+
+ commits.reverse.each_with_index do |c,i|
+ c.time = i
+ days[i] = c.committed_date
+ map[c.id] = c
+ heads += c.refs unless c.refs.nil?
+ end
+
+ heads.select!{|h| h.is_a? Grit::Head or h.is_a? Grit::Remote}
+ # sort heads so the master is top and current branches are closer
+ heads.sort! do |a,b|
+ if a.name == "master"
+ -1
+ elsif b.name == "master"
+ 1
+ else
+ b.commit.committed_date <=> a.commit.committed_date
+ end
+ end
+
+ @_reserved = {}
+ days.each_index do |i|
+ @_reserved[i] = []
+ end
+
+ heads.each do |h|
+ if map.include? h.commit.id then
+ place_chain(map[h.commit.id], map)
+ end
+ end
+
+ days
+ end
+
+ # Add space mark on commit and its parents
+ #
+ # @param [Graph::Commit] the commit object.
+ # @param [Hash] map of commits
+ def place_chain(commit, map, parent_time = nil)
+ leaves = take_left_leaves(commit, map)
+ if leaves.empty?
+ return
+ end
+ space = find_free_space(leaves.last.time..leaves.first.time)
+ leaves.each{|l| l.space = space}
+ # and mark it as reserved
+ min_time = leaves.last.time
+ parents = leaves.last.parents.collect
+ parents.each do |p|
+ if map.include? p.id
+ parent = map[p.id]
+ if parent.time < min_time
+ min_time = parent.time
+ end
+ end
+ end
+ if parent_time.nil?
+ max_time = leaves.first.time
+ else
+ max_time = parent_time - 1
+ end
+ mark_reserved(min_time..max_time, space)
+
+ # Visit branching chains
+ leaves.each do |l|
+ parents = l.parents.collect.select{|p| map.include? p.id and map[p.id].space == 0}
+ for p in parents
+ place_chain(map[p.id], map, l.time)
+ end
+ end
+ end
+
+ def mark_reserved(time_range, space)
+ for day in time_range
+ @_reserved[day].push(space)
+ end
+ end
+
+ def find_free_space(time_range)
+ reserved = []
+ for day in time_range
+ reserved += @_reserved[day]
+ end
+ space = 1
+ while reserved.include? space do
+ space += 1
+ end
+ space
+ end
+
+ # Takes most left subtree branch of commits
+ # which don't have space mark yet.
+ #
+ # @param [Graph::Commit] the commit object.
+ # @param [Hash] map of commits
+ #
+ # @return [Array] list of branch commits
+ def take_left_leaves(commit, map)
+ leaves = []
+ leaves.push(commit) if commit.space.zero?
+
+ while true
+ parent = commit.parents.collect.select do |p|
+ map.include? p.id and map[p.id].space == 0
+ end
+
+ return leaves if parent.count.zero?
+
+ commit = map[parent.first.id]
+ leaves.push(commit)
+ end
+ end
+ end
+ end
+end
diff --git a/lib/gitlab/markdown.rb b/lib/gitlab/markdown.rb
index ad6ba3e8..859184b6 100644
--- a/lib/gitlab/markdown.rb
+++ b/lib/gitlab/markdown.rb
@@ -17,7 +17,7 @@ module Gitlab
# Examples
#
# >> gfm("Hey @david, can you fix this?")
- # => "Hey @david, can you fix this?"
+ # => "Hey @david, can you fix this?"
#
# >> gfm("Commit 35d5f7c closes #1234")
# => "Commit 35d5f7c closes #1234"
@@ -25,7 +25,21 @@ module Gitlab
# >> gfm(":trollface:")
# => "
module Markdown
- include IssuesHelper
+ REFERENCE_PATTERN = %r{
+ (?\W)? # Prefix
+ ( # Reference
+ @(?[a-zA-Z][a-zA-Z0-9_\-\.]*) # User name
+ |\#(?\d+) # Issue ID
+ |!(?\d+) # MR ID
+ |\$(?\d+) # Snippet ID
+ |(?[\h]{6,40}) # Commit ID
+ )
+ (?\W)? # Suffix
+ }x.freeze
+
+ TYPES = [:user, :issue, :merge_request, :snippet, :commit].freeze
+
+ EMOJI_PATTERN = %r{(:(\S+):)}.freeze
attr_reader :html_options
@@ -47,11 +61,12 @@ module Gitlab
# Extract pre blocks so they are not altered
# from http://github.github.com/github-flavored-markdown/
- text.gsub!(%r{
\n"
- end
-
- it "should leave ref-like href of 'manual' links untouched" do
- markdown("why not [inspect !#{merge_request.id}](http://example.tld/#!#{merge_request.id})").should == "
\n"
- end
-
- it "should leave ref-like src of images untouched" do
- markdown("screen shot: ").should == "
screen shot:
\n"
- end
-
- it "should generate absolute urls for refs" do
- markdown("##{issue.id}").should include(project_issue_url(project, issue))
- end
-
- it "should generate absolute urls for emoji" do
- markdown(":smile:").should include("src=\"#{url_to_image("emoji/smile")}")
- end
- end
-
- describe "#render_wiki_content" do
- before do
- @wiki = stub('WikiPage')
- @wiki.stub(:content).and_return('wiki content')
- end
-
- it "should use Gitlab Flavored Markdown for markdown files" do
- @wiki.stub(:format).and_return(:markdown)
-
- helper.should_receive(:markdown).with('wiki content')
-
- helper.render_wiki_content(@wiki)
- end
-
- it "should use the Gollum renderer for all other file types" do
- @wiki.stub(:format).and_return(:rdoc)
- formatted_content_stub = stub('formatted_content')
- formatted_content_stub.should_receive(:html_safe)
- @wiki.stub(:formatted_content).and_return(formatted_content_stub)
-
- helper.render_wiki_content(@wiki)
- end
end
end
diff --git a/spec/helpers/issues_helper_spec.rb b/spec/helpers/issues_helper_spec.rb
deleted file mode 100644
index a1f23073..00000000
--- a/spec/helpers/issues_helper_spec.rb
+++ /dev/null
@@ -1,106 +0,0 @@
-require "spec_helper"
-
-describe IssuesHelper do
- let(:project) { create :project }
- let(:issue) { create :issue, project: project }
- let(:ext_project) { create :redmine_project }
-
- describe :title_for_issue do
- it "should return issue title if used internal tracker" do
- @project = project
- title_for_issue(issue.id).should eq issue.title
- end
-
- it "should always return empty string if used external tracker" do
- @project = ext_project
- title_for_issue(rand(100)).should eq ""
- end
-
- it "should always return empty string if project nil" do
- @project = nil
-
- title_for_issue(rand(100)).should eq ""
- end
- end
-
- describe :url_for_project_issues do
- let(:project_url) { Gitlab.config.issues_tracker.redmine.project_url}
- let(:ext_expected) do
- project_url.gsub(':project_id', ext_project.id.to_s)
- .gsub(':issues_tracker_id', ext_project.issues_tracker_id.to_s)
- end
- let(:int_expected) { polymorphic_path([project]) }
-
- it "should return internal path if used internal tracker" do
- @project = project
- url_for_project_issues.should match(int_expected)
- end
-
- it "should return path to external tracker" do
- @project = ext_project
-
- url_for_project_issues.should match(ext_expected)
- end
-
- it "should return empty string if project nil" do
- @project = nil
-
- url_for_project_issues.should eq ""
- end
- end
-
- describe :url_for_issue do
- let(:issue_id) { 3 }
- let(:issues_url) { Gitlab.config.issues_tracker.redmine.issues_url}
- let(:ext_expected) do
- issues_url.gsub(':id', issue_id.to_s)
- .gsub(':project_id', ext_project.id.to_s)
- .gsub(':issues_tracker_id', ext_project.issues_tracker_id.to_s)
- end
- let(:int_expected) { polymorphic_path([project, issue]) }
-
- it "should return internal path if used internal tracker" do
- @project = project
- url_for_issue(issue.id).should match(int_expected)
- end
-
- it "should return path to external tracker" do
- @project = ext_project
-
- url_for_issue(issue_id).should match(ext_expected)
- end
-
- it "should return empty string if project nil" do
- @project = nil
-
- url_for_issue(issue.id).should eq ""
- end
- end
-
- describe :url_for_new_issue do
- let(:issues_url) { Gitlab.config.issues_tracker.redmine.new_issue_url}
- let(:ext_expected) do
- issues_url.gsub(':project_id', ext_project.id.to_s)
- .gsub(':issues_tracker_id', ext_project.issues_tracker_id.to_s)
- end
- let(:int_expected) { new_project_issue_path(project) }
-
- it "should return internal path if used internal tracker" do
- @project = project
- url_for_new_issue.should match(int_expected)
- end
-
- it "should return path to external tracker" do
- @project = ext_project
-
- url_for_new_issue.should match(ext_expected)
- end
-
- it "should return empty string if project nil" do
- @project = nil
-
- url_for_new_issue.should eq ""
- end
- end
-
-end
diff --git a/spec/helpers/notifications_helper_spec.rb b/spec/helpers/notifications_helper_spec.rb
deleted file mode 100644
index f97959ee..00000000
--- a/spec/helpers/notifications_helper_spec.rb
+++ /dev/null
@@ -1,15 +0,0 @@
-require 'spec_helper'
-
-# Specs in this file have access to a helper object that includes
-# the NotificationsHelper. For example:
-#
-# describe NotificationsHelper do
-# describe "string concat" do
-# it "concats two strings with spaces" do
-# helper.concat_strings("this","that").should == "this that"
-# end
-# end
-# end
-describe NotificationsHelper do
- pending "add some examples to (or delete) #{__FILE__}"
-end
diff --git a/spec/lib/extracts_path_spec.rb b/spec/lib/extracts_path_spec.rb
index aac72c63..cf422017 100644
--- a/spec/lib/extracts_path_spec.rb
+++ b/spec/lib/extracts_path_spec.rb
@@ -7,8 +7,7 @@ describe ExtractsPath do
before do
@project = project
- project.stub(repository: stub(ref_names: ['master', 'foo/bar/baz', 'v1.0.0', 'v2.0.0']))
- project.stub(path_with_namespace: 'gitlab/gitlab-ci')
+ project.stub(:ref_names).and_return(['master', 'foo/bar/baz', 'v1.0.0', 'v2.0.0'])
end
describe '#extract_ref' do
diff --git a/spec/lib/git/commit_spec.rb b/spec/lib/git/commit_spec.rb
deleted file mode 100644
index 475bc359..00000000
--- a/spec/lib/git/commit_spec.rb
+++ /dev/null
@@ -1,49 +0,0 @@
-require "spec_helper"
-
-describe Gitlab::Git::Commit do
- let(:commit) { create(:project_with_code).repository.commit }
-
- describe "Commit info" do
- before do
- @committer = double(
- email: 'mike@smith.com',
- name: 'Mike Smith'
- )
-
- @author = double(
- email: 'john@smith.com',
- name: 'John Smith'
- )
-
- @raw_commit = double(
- id: "bcf03b5de6abcf03b5de6c",
- author: @author,
- committer: @committer,
- committed_date: Date.yesterday,
- message: 'Refactoring specs'
- )
-
- @commit = Gitlab::Git::Commit.new(@raw_commit)
- end
-
- it { @commit.short_id.should == "bcf03b5de6a" }
- it { @commit.safe_message.should == @raw_commit.message }
- it { @commit.created_at.should == @raw_commit.committed_date }
- it { @commit.author_email.should == @author.email }
- it { @commit.author_name.should == @author.name }
- it { @commit.committer_name.should == @committer.name }
- it { @commit.committer_email.should == @committer.email }
- it { @commit.different_committer?.should be_true }
- end
-
- describe "Class methods" do
- subject { Gitlab::Git::Commit }
-
- it { should respond_to(:find_or_first) }
- it { should respond_to(:fresh_commits) }
- it { should respond_to(:commits_with_refs) }
- it { should respond_to(:commits_since) }
- it { should respond_to(:commits_between) }
- it { should respond_to(:commits) }
- end
-end
diff --git a/spec/lib/git/repository_spec.rb b/spec/lib/git/repository_spec.rb
deleted file mode 100644
index b2b6f196..00000000
--- a/spec/lib/git/repository_spec.rb
+++ /dev/null
@@ -1,104 +0,0 @@
-require "spec_helper"
-
-describe Gitlab::Git::Repository do
- let(:repository) { Gitlab::Git::Repository.new('gitlabhq', 'master') }
-
- describe "Respond to" do
- subject { repository }
-
- it { should respond_to(:repo) }
- it { should respond_to(:tree) }
- it { should respond_to(:root_ref) }
- it { should respond_to(:tags) }
- it { should respond_to(:commit) }
- it { should respond_to(:commits) }
- it { should respond_to(:commits_between) }
- it { should respond_to(:commits_with_refs) }
- it { should respond_to(:commits_since) }
- it { should respond_to(:commits_between) }
- end
-
-
- describe "#discover_default_branch" do
- let(:master) { 'master' }
- let(:stable) { 'stable' }
-
- it "returns 'master' when master exists" do
- repository.should_receive(:branch_names).at_least(:once).and_return([stable, master])
- repository.discover_default_branch.should == 'master'
- end
-
- it "returns non-master when master exists but default branch is set to something else" do
- repository.root_ref = 'stable'
- repository.should_receive(:branch_names).at_least(:once).and_return([stable, master])
- repository.discover_default_branch.should == 'stable'
- end
-
- it "returns a non-master branch when only one exists" do
- repository.should_receive(:branch_names).at_least(:once).and_return([stable])
- repository.discover_default_branch.should == 'stable'
- end
-
- it "returns nil when no branch exists" do
- repository.should_receive(:branch_names).at_least(:once).and_return([])
- repository.discover_default_branch.should be_nil
- end
- end
-
- describe :commit do
- it "should return first head commit if without params" do
- repository.commit.id.should == repository.repo.commits.first.id
- end
-
- it "should return valid commit" do
- repository.commit(ValidCommit::ID).should be_valid_commit
- end
-
- it "should return nil" do
- repository.commit("+123_4532530XYZ").should be_nil
- end
- end
-
- describe :tree do
- before do
- @commit = repository.commit(ValidCommit::ID)
- end
-
- it "should raise error w/o arguments" do
- lambda { repository.tree }.should raise_error
- end
-
- it "should return root tree for commit" do
- tree = repository.tree(@commit)
- tree.contents.size.should == ValidCommit::FILES_COUNT
- tree.contents.map(&:name).should == ValidCommit::FILES
- end
-
- it "should return root tree for commit with correct path" do
- tree = repository.tree(@commit, ValidCommit::C_FILE_PATH)
- tree.contents.map(&:name).should == ValidCommit::C_FILES
- end
-
- it "should return root tree for commit with incorrect path" do
- repository.tree(@commit, "invalid_path").should be_nil
- end
- end
-
- describe "fresh commits" do
- it { repository.fresh_commits(3).count.should == 3 }
- it { repository.fresh_commits.first.id.should == "bcf03b5de6c33f3869ef70d68cf06e679d1d7f9a" }
- it { repository.fresh_commits.last.id.should == "f403da73f5e62794a0447aca879360494b08f678" }
- end
-
- describe "commits_between" do
- subject do
- commits = repository.commits_between("3a4b4fb4cde7809f033822a171b9feae19d41fff",
- "8470d70da67355c9c009e4401746b1d5410af2e3")
- commits.map { |c| c.id }
- end
-
- it { should have(3).elements }
- it { should include("f0f14c8eaba69ebddd766498a9d0b0e79becd633") }
- it { should_not include("bcf03b5de6c33f3869ef70d68cf06e679d1d7f9a") }
- end
-end
diff --git a/spec/lib/gitolite_config_spec.rb b/spec/lib/gitolite_config_spec.rb
new file mode 100644
index 00000000..c3ce0db5
--- /dev/null
+++ b/spec/lib/gitolite_config_spec.rb
@@ -0,0 +1,16 @@
+require 'spec_helper'
+
+describe Gitlab::GitoliteConfig do
+ let(:gitolite) { Gitlab::GitoliteConfig.new }
+
+ it { should respond_to :write_key }
+ it { should respond_to :rm_key }
+ it { should respond_to :update_project }
+ it { should respond_to :update_project! }
+ it { should respond_to :update_projects }
+ it { should respond_to :destroy_project }
+ it { should respond_to :destroy_project! }
+ it { should respond_to :apply }
+ it { should respond_to :admin_all_repo }
+ it { should respond_to :admin_all_repo! }
+end
diff --git a/spec/lib/gitolite_spec.rb b/spec/lib/gitolite_spec.rb
new file mode 100644
index 00000000..8075b99e
--- /dev/null
+++ b/spec/lib/gitolite_spec.rb
@@ -0,0 +1,25 @@
+require 'spec_helper'
+
+describe Gitlab::Gitolite do
+ let(:project) { double('Project', path: 'diaspora') }
+ let(:gitolite_config) { double('Gitlab::GitoliteConfig') }
+ let(:gitolite) { Gitlab::Gitolite.new }
+
+ before do
+ gitolite.stub(config: gitolite_config)
+ end
+
+ it { should respond_to :set_key }
+ it { should respond_to :remove_key }
+
+ it { should respond_to :update_repository }
+ it { should respond_to :create_repository }
+ it { should respond_to :remove_repository }
+
+ it { gitolite.url_to_repo('diaspora').should == Gitlab.config.gitolite.ssh_path_prefix + "diaspora.git" }
+
+ it "should call config update" do
+ gitolite_config.should_receive(:update_project!)
+ gitolite.update_repository project
+ end
+end
diff --git a/spec/lib/popen_spec.rb b/spec/lib/popen_spec.rb
deleted file mode 100644
index 4791be41..00000000
--- a/spec/lib/popen_spec.rb
+++ /dev/null
@@ -1,29 +0,0 @@
-require 'spec_helper'
-
-describe 'Gitlab::Popen', no_db: true do
- let (:path) { Rails.root.join('tmp').to_s }
-
- before do
- @klass = Class.new(Object)
- @klass.send(:include, Gitlab::Popen)
- end
-
- context 'zero status' do
- before do
- @output, @status = @klass.new.popen('ls', path)
- end
-
- it { @status.should be_zero }
- it { @output.should include('cache') }
- end
-
- context 'non-zero status' do
- before do
- @output, @status = @klass.new.popen('cat NOTHING', path)
- end
-
- it { @status.should == 1 }
- it { @output.should include('No such file or directory') }
- end
-end
-
diff --git a/spec/lib/project_mover_spec.rb b/spec/lib/project_mover_spec.rb
new file mode 100644
index 00000000..2362bc26
--- /dev/null
+++ b/spec/lib/project_mover_spec.rb
@@ -0,0 +1,65 @@
+require 'spec_helper'
+
+describe Gitlab::ProjectMover do
+ let(:base_path) { Rails.root.join('tmp', 'rspec-sandbox') }
+
+ before do
+ FileUtils.rm_rf base_path if File.exists? base_path
+
+ Gitlab.config.gitolite.stub(repos_path: base_path)
+
+ @project = create(:project)
+ end
+
+ after do
+ FileUtils.rm_rf base_path
+ end
+
+ it "should move project to subdir" do
+ mk_dir base_path, '', @project.path
+ mover = Gitlab::ProjectMover.new(@project, '', 'opensource')
+
+ mover.execute.should be_true
+ moved?('opensource', @project.path).should be_true
+ end
+
+ it "should move project from one subdir to another" do
+ mk_dir base_path, 'vsizov', @project.path
+ mover = Gitlab::ProjectMover.new(@project, 'vsizov', 'randx')
+
+ mover.execute.should be_true
+ moved?('randx', @project.path).should be_true
+ end
+
+ it "should move project from subdir to base" do
+ mk_dir base_path, 'vsizov', @project.path
+ mover = Gitlab::ProjectMover.new(@project, 'vsizov', '')
+
+ mover.execute.should be_true
+ moved?('', @project.path).should be_true
+ end
+
+ it "should raise if destination exists" do
+ mk_dir base_path, '', @project.path
+ mk_dir base_path, 'vsizov', @project.path
+ mover = Gitlab::ProjectMover.new(@project, 'vsizov', '')
+
+ expect { mover.execute }.to raise_error(Gitlab::ProjectMover::ProjectMoveError)
+ end
+
+ it "should raise if move failed" do
+ mk_dir base_path
+ mover = Gitlab::ProjectMover.new(@project, 'vsizov', '')
+
+ expect { mover.execute }.to raise_error(Gitlab::ProjectMover::ProjectMoveError)
+ end
+
+
+ def mk_dir base_path, namespace = '', project_path = ''
+ FileUtils.mkdir_p File.join(base_path, namespace, project_path + ".git")
+ end
+
+ def moved? namespace, path
+ File.exists?(File.join(base_path, namespace, path + '.git'))
+ end
+end
diff --git a/spec/lib/shell_spec.rb b/spec/lib/shell_spec.rb
deleted file mode 100644
index 3c04f4bb..00000000
--- a/spec/lib/shell_spec.rb
+++ /dev/null
@@ -1,17 +0,0 @@
-require 'spec_helper'
-
-describe Gitlab::Shell do
- let(:project) { double('Project', id: 7, path: 'diaspora') }
- let(:gitlab_shell) { Gitlab::Shell.new }
-
- before do
- Project.stub(find: project)
- end
-
- it { should respond_to :add_key }
- it { should respond_to :remove_key }
- it { should respond_to :add_repository }
- it { should respond_to :remove_repository }
-
- it { gitlab_shell.url_to_repo('diaspora').should == Gitlab.config.gitlab_shell.ssh_path_prefix + "diaspora.git" }
-end
diff --git a/spec/lib/votes_spec.rb b/spec/lib/votes_spec.rb
deleted file mode 100644
index b49ed15b..00000000
--- a/spec/lib/votes_spec.rb
+++ /dev/null
@@ -1,132 +0,0 @@
-require 'spec_helper'
-
-describe MergeRequest do
- let(:merge_request) { FactoryGirl.create(:merge_request_with_diffs) }
-
- describe "#upvotes" do
- it "with no notes has a 0/0 score" do
- merge_request.upvotes.should == 0
- end
-
- it "should recognize non-+1 notes" do
- merge_request.notes << create(:note, note: "No +1 here")
- merge_request.should have(1).note
- merge_request.notes.first.upvote?.should be_false
- merge_request.upvotes.should == 0
- end
-
- it "should recognize a single +1 note" do
- merge_request.notes << create(:note, note: "+1 This is awesome")
- merge_request.upvotes.should == 1
- end
-
- it "should recognize multiple +1 notes" do
- merge_request.notes << create(:note, note: "+1 This is awesome")
- merge_request.notes << create(:note, note: "+1 I want this")
- merge_request.upvotes.should == 2
- end
- end
-
- describe "#downvotes" do
- it "with no notes has a 0/0 score" do
- merge_request.downvotes.should == 0
- end
-
- it "should recognize non--1 notes" do
- merge_request.notes << create(:note, note: "Almost got a -1")
- merge_request.should have(1).note
- merge_request.notes.first.downvote?.should be_false
- merge_request.downvotes.should == 0
- end
-
- it "should recognize a single -1 note" do
- merge_request.notes << create(:note, note: "-1 This is bad")
- merge_request.downvotes.should == 1
- end
-
- it "should recognize multiple -1 notes" do
- merge_request.notes << create(:note, note: "-1 This is bad")
- merge_request.notes << create(:note, note: "-1 Away with this")
- merge_request.downvotes.should == 2
- end
- end
-
- describe "#votes_count" do
- it "with no notes has a 0/0 score" do
- merge_request.votes_count.should == 0
- end
-
- it "should recognize non notes" do
- merge_request.notes << create(:note, note: "No +1 here")
- merge_request.should have(1).note
- merge_request.votes_count.should == 0
- end
-
- it "should recognize a single +1 note" do
- merge_request.notes << create(:note, note: "+1 This is awesome")
- merge_request.votes_count.should == 1
- end
-
- it "should recognize a single -1 note" do
- merge_request.notes << create(:note, note: "-1 This is bad")
- merge_request.votes_count.should == 1
- end
-
- it "should recognize multiple notes" do
- merge_request.notes << create(:note, note: "+1 This is awesome")
- merge_request.notes << create(:note, note: "-1 This is bad")
- merge_request.notes << create(:note, note: "+1 I want this")
- merge_request.votes_count.should == 3
- end
- end
-
- describe "#upvotes_in_percent" do
- it "with no notes has a 0% score" do
- merge_request.upvotes_in_percent.should == 0
- end
-
- it "should count a single 1 note as 100%" do
- merge_request.notes << create(:note, note: "+1 This is awesome")
- merge_request.upvotes_in_percent.should == 100
- end
-
- it "should count multiple +1 notes as 100%" do
- merge_request.notes << create(:note, note: "+1 This is awesome")
- merge_request.notes << create(:note, note: "+1 I want this")
- merge_request.upvotes_in_percent.should == 100
- end
-
- it "should count fractions for multiple +1 and -1 notes correctly" do
- merge_request.notes << create(:note, note: "+1 This is awesome")
- merge_request.notes << create(:note, note: "+1 I want this")
- merge_request.notes << create(:note, note: "-1 This is bad")
- merge_request.notes << create(:note, note: "+1 me too")
- merge_request.upvotes_in_percent.should == 75
- end
- end
-
- describe "#downvotes_in_percent" do
- it "with no notes has a 0% score" do
- merge_request.downvotes_in_percent.should == 0
- end
-
- it "should count a single -1 note as 100%" do
- merge_request.notes << create(:note, note: "-1 This is bad")
- merge_request.downvotes_in_percent.should == 100
- end
-
- it "should count multiple -1 notes as 100%" do
- merge_request.notes << create(:note, note: "-1 This is bad")
- merge_request.notes << create(:note, note: "-1 Away with this")
- merge_request.downvotes_in_percent.should == 100
- end
-
- it "should count fractions for multiple +1 and -1 notes correctly" do
- merge_request.notes << create(:note, note: "+1 This is awesome")
- merge_request.notes << create(:note, note: "+1 I want this")
- merge_request.notes << create(:note, note: "-1 This is bad")
- merge_request.notes << create(:note, note: "+1 me too")
- merge_request.downvotes_in_percent.should == 25
- end
- end
-end
diff --git a/spec/lib/wiki_to_gollum_migrator_spec.rb b/spec/lib/wiki_to_gollum_migrator_spec.rb
deleted file mode 100644
index f9b9c78e..00000000
--- a/spec/lib/wiki_to_gollum_migrator_spec.rb
+++ /dev/null
@@ -1,219 +0,0 @@
-require "spec_helper"
-
-describe WikiToGollumMigrator do
-
- def create_wiki_for(project)
- 3.times { @pages[project.id] << create_page(project) }
- end
-
- def create_revisions_for(project)
- @pages[project.id].each do |page|
- create_revision(page)
- end
- end
-
- def create_page(project)
- page = project.wikis.new(title: "Page #{rand(1000)}", content: "Content")
- page.user = project.owner
- page.slug = page.title.parameterize
- page.save!
- page
- end
-
- def create_revision(page)
- revision = page.dup
- revision.content = "Updated Content"
- revision.save!
- end
-
- def create_temp_repo(path)
- FileUtils.mkdir_p path
- command = "git init --quiet --bare #{path};"
- system(command)
- end
-
- before do
- @repo_path = "#{Rails.root}/tmp/test-git-base-path"
- @projects = []
- @pages = Hash.new {|h,k| h[k] = Array.new }
-
- @projects << create(:project)
- @projects << create(:project)
-
- @projects.each do |project|
- create_wiki_for project
- create_revisions_for project
- end
-
- @project_without_wiki = create(:project)
- end
-
- context "Before the migration" do
- it "has two projects with valid wikis" do
- @projects.each do |project|
- pages = project.wikis.group(:slug).all
- pages.count.should == 3
- end
- end
-
- it "has two revision for each page" do
- @projects.each do |project|
- @pages[project.id].each do |page|
- revisions = project.wikis.where(slug: page.slug)
- revisions.count.should == 2
- end
- end
- end
- end
-
- describe "#initialize" do
- it "finds all projects that have existing wiki pages" do
- Project.count.should == 3
- subject.projects.count.should == 2
- end
- end
-
- context "#migrate!" do
- before do
- Gitlab::Shell.any_instance.stub(:add_repository) do |path|
- create_temp_repo("#{@repo_path}/#{path}.git")
- end
-
- subject.stub(:log).as_null_object
-
- subject.migrate!
- end
-
- it "creates a new Gollum Wiki for each project" do
- @projects.each do |project|
- wiki_path = project.path_with_namespace + ".wiki.git"
- full_path = @repo_path + "/" + wiki_path
- File.exist?(full_path).should be_true
- File.directory?(full_path).should be_true
- end
- end
-
- it "creates a gollum page for each unique Wiki page" do
- @projects.each do |project|
- wiki = GollumWiki.new(project, nil)
- wiki.pages.count.should == 3
- end
- end
-
- it "creates a new revision for each old revision of the page" do
- @projects.each do |project|
- wiki = GollumWiki.new(project, nil)
- wiki.pages.each do |page|
- page.versions.count.should == 2
- end
- end
- end
-
- context "wikis with pages that have titles that do not match the slugs" do
- before do
- project = @projects.last
- @page = project.wikis.new(title: "test page", content: "Invalid Page")
- @page.slug = "totally-incorrect-slug"
- @page.user = project.owner
- @page.save!
-
- create_revision(@page)
-
- subject.rollback!
- subject.migrate!
- end
-
- it "has a page with a title differing the slug" do
- @page.slug.should_not == @page.title.parameterize
- end
-
- it "creates a new revision for each old revision of the page" do
- @projects.each do |project|
- wiki = GollumWiki.new(project, nil)
- wiki.pages.each do |page|
- page.versions.count.should == 2
- end
- end
- end
- end
-
- context "changing wiki title from index to home" do
- before do
- @project = @projects.last
- @page = @project.wikis.new(title: "Index", content: "Home Page")
- @page.slug = "index"
- @page.user = @project.owner
- @page.save!
-
- create_revision(@page)
-
- subject.rollback!
- end
-
- it "creates a page called Home" do
- subject.migrate!
- wiki = GollumWiki.new(@project, nil)
- page = wiki.find_page("home")
- page.should be_present
- end
-
- context "when a page called Home already exists" do
- before do
- @index_page = @project.wikis.new(title: "Index", content: "Index Page")
- @index_page.slug = "index"
- @index_page.user = @project.owner
- @index_page.save!
-
- create_revision(@index_page)
-
- @home_page = @project.wikis.new(title: "Home", content: "Home Page")
- @home_page.slug = "home"
- @home_page.user = @project.owner
- @home_page.save!
-
- create_revision(@home_page)
- subject.migrate!
- end
-
- it "creates the index page" do
- wiki = GollumWiki.new(@project, nil)
- page = wiki.find_page("index")
- page.should be_present
- end
-
- it "creates the home page" do
- wiki = GollumWiki.new(@project, nil)
- page = wiki.find_page("home")
- page.should be_present
- end
- end
- end
- end
-
- context "#rollback!" do
- before do
- Gitlab::Shell.any_instance.stub(:add_repository) do |path|
- create_temp_repo("#{@repo_path}/#{path}.git")
- end
-
- Gitlab::Shell.any_instance.stub(:remove_repository) do |path|
- FileUtils.rm_rf "#{@repo_path}/#{path}.git"
- end
-
- subject.stub(:log).as_null_object
-
- subject.migrate!
- subject.rollback!
- end
-
- it "destroys all of the wiki repositories that were created during migrate!" do
- @projects.each do |project|
- wiki_path = project.path_with_namespace + ".wiki.git"
- full_path = @repo_path + "/" + wiki_path
- File.exist?(full_path).should be_false
- end
- end
- end
-
-
-end
diff --git a/spec/mailers/notify_spec.rb b/spec/mailers/notify_spec.rb
index 84ce7e86..58698eec 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
@@ -32,7 +32,6 @@ describe Notify do
end
it 'contains the new user\'s password' do
- Gitlab.config.gitlab.stub(:signup_enabled).and_return(false)
should have_body_text /#{new_user.password}/
end
@@ -41,57 +40,6 @@ describe Notify do
end
end
-
- describe 'for users that signed up, the email' do
- let(:example_site_path) { root_path }
- let(:new_user) { create(:user, email: 'newguy@example.com', password: "securePassword") }
-
- subject { Notify.new_user_email(new_user.id, new_user.password) }
-
- it 'is sent to the new user' do
- should deliver_to new_user.email
- end
-
- it 'has the correct subject' do
- should have_subject /^gitlab \| Account was created for you$/i
- end
-
- it 'contains the new user\'s login name' do
- should have_body_text /#{new_user.email}/
- end
-
- it 'should not contain the new user\'s password' do
- Gitlab.config.gitlab.stub(:signup_enabled).and_return(true)
- should_not have_body_text /#{new_user.password}/
- end
-
- it 'includes a link to the site' do
- should have_body_text /#{example_site_path}/
- end
- end
-
- describe 'user added ssh key' do
- let(:key) { create(:personal_key) }
-
- subject { Notify.new_ssh_key_email(key.id) }
-
- it 'is sent to the new user' do
- should deliver_to key.user.email
- end
-
- it 'has the correct subject' do
- should have_subject /^gitlab \| SSH key was added to your account$/i
- end
-
- it 'contains the new ssh key title' do
- should have_body_text /#{key.title}/
- end
-
- it 'includes a link to ssh keys page' do
- should have_body_text /#{keys_path}/
- end
- end
-
context 'for a project' do
describe 'items that are assignable, the email' do
let(:assignee) { create(:user, email: 'assignee@example.com') }
@@ -107,12 +55,12 @@ describe Notify do
let(:issue) { create(:issue, assignee: assignee, project: project ) }
describe 'that are new' do
- subject { Notify.new_issue_email(issue.assignee_id, issue.id) }
+ subject { Notify.new_issue_email(issue.id) }
it_behaves_like 'an assignee email'
it 'has the correct subject' do
- should have_subject /#{project.name} \| new issue ##{issue.id} \| #{issue.title}/
+ should have_subject /new issue ##{issue.id} \| #{issue.title} \| #{project.name}/
end
it 'contains a link to the new issue' do
@@ -172,7 +120,7 @@ describe Notify do
let(:merge_request) { create(:merge_request, assignee: assignee, project: project) }
describe 'that are new' do
- subject { Notify.new_merge_request_email(merge_request.assignee_id, merge_request.id) }
+ subject { Notify.new_merge_request_email(merge_request.id) }
it_behaves_like 'an assignee email'
@@ -243,7 +191,7 @@ describe Notify do
let(:note) { create(:note, project: project, author: note_author) }
before :each do
- Note.stub(:find).with(note.id).and_return(note)
+ Note.stub(:find).with(note.id).and_return(note)
end
shared_examples 'a note email' do
@@ -261,7 +209,7 @@ describe Notify do
end
describe 'on a project wall' do
- let(:note_on_the_wall_path) { project_wall_path(project, anchor: "note_#{note.id}") }
+ let(:note_on_the_wall_path) { wall_project_path(project, anchor: "note_#{note.id}") }
subject { Notify.note_wall_email(recipient.id, note.id) }
@@ -277,8 +225,14 @@ describe Notify do
end
describe 'on a commit' do
- let(:commit) { project.repository.commit }
-
+ let(:commit) do
+ mock(:commit).tap do |commit|
+ commit.stub(:id).and_return('fauxsha1')
+ commit.stub(:project).and_return(project)
+ commit.stub(:short_id).and_return('fauxsha1')
+ commit.stub(:safe_message).and_return('some message')
+ end
+ end
before(:each) { note.stub(:noteable).and_return(commit) }
subject { Notify.note_commit_email(recipient.id, note.id) }
@@ -290,7 +244,7 @@ describe Notify do
end
it 'contains a link to the commit' do
- should have_body_text commit.short_id
+ should have_body_text /fauxsha1/
end
end
diff --git a/spec/models/commit_spec.rb b/spec/models/commit_spec.rb
index 6cf777be..e4bc1936 100644
--- a/spec/models/commit_spec.rb
+++ b/spec/models/commit_spec.rb
@@ -1,50 +1,37 @@
require 'spec_helper'
describe Commit do
- let(:commit) { create(:project_with_code).repository.commit }
+ let(:commit) { create(:project).commit }
+ describe CommitDecorator do
+ let(:decorator) { CommitDecorator.new(commit) }
- describe '#title' do
- it "returns no_commit_message when safe_message is blank" do
- commit.stub(:safe_message).and_return('')
- commit.title.should == "--no commit message"
+ describe '#title' do
+ it "returns no_commit_message when safe_message is blank" do
+ decorator.stub(:safe_message).and_return('')
+ decorator.title.should == "--no commit message"
+ end
+
+ it "truncates a message without a newline at 70 characters" do
+ message = commit.safe_message * 10
+
+ decorator.stub(:safe_message).and_return(message)
+ decorator.title.should == "#{message[0..69]}…"
+ end
+
+ it "truncates a message with a newline before 80 characters at the newline" do
+ message = commit.safe_message.split(" ").first
+
+ decorator.stub(:safe_message).and_return(message + "\n" + message)
+ decorator.title.should == message
+ end
+
+ it "truncates a message with a newline after 80 characters at 70 characters" do
+ message = (commit.safe_message * 10) + "\n"
+
+ decorator.stub(:safe_message).and_return(message)
+ decorator.title.should == "#{message[0..69]}…"
+ end
end
-
- it "truncates a message without a newline at 70 characters" do
- message = commit.safe_message * 10
-
- commit.stub(:safe_message).and_return(message)
- commit.title.should == "#{message[0..69]}…"
- end
-
- it "truncates a message with a newline before 80 characters at the newline" do
- message = commit.safe_message.split(" ").first
-
- commit.stub(:safe_message).and_return(message + "\n" + message)
- commit.title.should == message
- end
-
- it "truncates a message with a newline after 80 characters at 70 characters" do
- message = (commit.safe_message * 10) + "\n"
-
- commit.stub(:safe_message).and_return(message)
- commit.title.should == "#{message[0..69]}…"
- end
- end
-
- describe "delegation" do
- subject { commit }
-
- it { should respond_to(:message) }
- it { should respond_to(:authored_date) }
- it { should respond_to(:committed_date) }
- it { should respond_to(:parents) }
- it { should respond_to(:date) }
- it { should respond_to(:committer) }
- it { should respond_to(:author) }
- it { should respond_to(:diffs) }
- it { should respond_to(:tree) }
- it { should respond_to(:id) }
- it { should respond_to(:to_patch) }
end
end
diff --git a/spec/models/event_spec.rb b/spec/models/event_spec.rb
index 85bdf08a..82b46b68 100644
--- a/spec/models/event_spec.rb
+++ b/spec/models/event_spec.rb
@@ -52,7 +52,7 @@ describe Event do
@event = Event.create(
project: project,
- action: Event::PUSHED,
+ action: Event::Pushed,
data: data,
author_id: @user.id
)
@@ -72,7 +72,6 @@ describe Event do
before {
Event.should_receive :create
- observer.stub(notification: stub.as_null_object)
}
describe "Joined project team" do
diff --git a/spec/models/gitlab_ci_service_spec.rb b/spec/models/gitlab_ci_service_spec.rb
deleted file mode 100644
index b86588af..00000000
--- a/spec/models/gitlab_ci_service_spec.rb
+++ /dev/null
@@ -1,46 +0,0 @@
-# == Schema Information
-#
-# Table name: services
-#
-# id :integer not null, primary key
-# type :string(255)
-# title :string(255)
-# token :string(255)
-# project_id :integer not null
-# created_at :datetime not null
-# updated_at :datetime not null
-# active :boolean default(FALSE), not null
-# project_url :string(255)
-#
-
-require 'spec_helper'
-
-describe GitlabCiService do
- describe "Associations" do
- it { should belong_to :project }
- it { should have_one :service_hook }
- end
-
- describe "Mass assignment" do
- it { should_not allow_mass_assignment_of(:project_id) }
- end
-
- describe 'commits methods' do
- before do
- @service = GitlabCiService.new
- @service.stub(
- service_hook: true,
- project_url: 'http://ci.gitlab.org/projects/2',
- token: 'verySecret'
- )
- end
-
- describe :commit_status_path do
- it { @service.commit_status_path("2ab7834c").should == "http://ci.gitlab.org/projects/2/builds/2ab7834c/status.json?token=verySecret"}
- end
-
- describe :build_page do
- it { @service.build_page("2ab7834c").should == "http://ci.gitlab.org/projects/2/builds/2ab7834c"}
- end
- end
-end
diff --git a/spec/models/gollum_wiki_spec.rb b/spec/models/gollum_wiki_spec.rb
deleted file mode 100644
index aa850dfd..00000000
--- a/spec/models/gollum_wiki_spec.rb
+++ /dev/null
@@ -1,196 +0,0 @@
-require "spec_helper"
-
-describe GollumWiki do
-
- def create_temp_repo(path)
- FileUtils.mkdir_p path
- command = "git init --quiet #{path};"
- system(command)
- end
-
- def remove_temp_repo(path)
- FileUtils.rm_rf path
- end
-
- def commit_details
- commit = {name: user.name, email: user.email, message: "test commit"}
- end
-
- def create_page(name, content)
- subject.wiki.write_page(name, :markdown, content, commit_details)
- end
-
- def destroy_page(page)
- subject.wiki.delete_page(page, commit_details)
- end
-
- let(:project) { create(:project) }
- let(:repository) { project.repository }
- let(:user) { project.owner }
- let(:gitlab_shell) { Gitlab::Shell.new }
-
- subject { GollumWiki.new(project, user) }
-
- before do
- create_temp_repo(subject.send(:path_to_repo))
- end
-
- describe "#path_with_namespace" do
- it "returns the project path with namespace with the .wiki extension" do
- subject.path_with_namespace.should == project.path_with_namespace + ".wiki"
- end
- end
-
- describe "#url_to_repo" do
- it "returns the correct ssh url to the repo" do
- subject.url_to_repo.should == gitlab_shell.url_to_repo(subject.path_with_namespace)
- end
- end
-
- describe "#ssh_url_to_repo" do
- it "equals #url_to_repo" do
- subject.ssh_url_to_repo.should == subject.url_to_repo
- end
- end
-
- describe "#http_url_to_repo" do
- it "provides the full http url to the repo" do
- gitlab_url = Gitlab.config.gitlab.url
- repo_http_url = "#{gitlab_url}/#{subject.path_with_namespace}.git"
- subject.http_url_to_repo.should == repo_http_url
- end
- end
-
- describe "#wiki" do
- it "contains a Gollum::Wiki instance" do
- subject.wiki.should be_a Gollum::Wiki
- end
-
- before do
- Gitlab::Shell.any_instance.stub(:add_repository) do
- create_temp_repo("#{Rails.root}/tmp/test-git-base-path/non-existant.wiki.git")
- end
- project.stub(:path_with_namespace).and_return("non-existant")
- end
-
- it "creates a new wiki repo if one does not yet exist" do
- wiki = GollumWiki.new(project, user)
- wiki.create_page("index", "test content").should_not == false
-
- FileUtils.rm_rf wiki.send(:path_to_repo)
- end
-
- it "raises CouldNotCreateWikiError if it can't create the wiki repository" do
- GollumWiki.any_instance.stub(:init_repo).and_return(false)
- expect { GollumWiki.new(project, user).wiki }.to raise_exception(GollumWiki::CouldNotCreateWikiError)
- end
- end
-
- describe "#pages" do
- before do
- create_page("index", "This is an awesome new Gollum Wiki")
- @pages = subject.pages
- end
-
- after do
- destroy_page(@pages.first.page)
- end
-
- it "returns an array of WikiPage instances" do
- @pages.first.should be_a WikiPage
- end
-
- it "returns the correct number of pages" do
- @pages.count.should == 1
- end
- end
-
- describe "#find_page" do
- before do
- create_page("index page", "This is an awesome Gollum Wiki")
- end
-
- after do
- destroy_page(subject.pages.first.page)
- end
-
- it "returns the latest version of the page if it exists" do
- page = subject.find_page("index page")
- page.title.should == "index page"
- end
-
- it "returns nil if the page does not exist" do
- subject.find_page("non-existant").should == nil
- end
-
- it "can find a page by slug" do
- page = subject.find_page("index-page")
- page.title.should == "index page"
- end
-
- it "returns a WikiPage instance" do
- page = subject.find_page("index page")
- page.should be_a WikiPage
- end
- end
-
- describe "#create_page" do
- after do
- destroy_page(subject.pages.first.page)
- end
-
- it "creates a new wiki page" do
- subject.create_page("test page", "this is content").should_not == false
- subject.pages.count.should == 1
- end
-
- it "returns false when a duplicate page exists" do
- subject.create_page("test page", "content")
- subject.create_page("test page", "content").should == false
- end
-
- it "stores an error message when a duplicate page exists" do
- 2.times { subject.create_page("test page", "content") }
- subject.error_message.should =~ /Duplicate page:/
- end
-
- it "sets the correct commit message" do
- subject.create_page("test page", "some content", :markdown, "commit message")
- subject.pages.first.page.version.message.should == "commit message"
- end
- end
-
- describe "#update_page" do
- before do
- create_page("update-page", "some content")
- @gollum_page = subject.wiki.paged("update-page")
- subject.update_page(@gollum_page, "some other content", :markdown, "updated page")
- @page = subject.pages.first.page
- end
-
- after do
- destroy_page(@page)
- end
-
- it "updates the content of the page" do
- @page.raw_data.should == "some other content"
- end
-
- it "sets the correct commit message" do
- @page.version.message.should == "updated page"
- end
- end
-
- describe "#delete_page" do
- before do
- create_page("index", "some content")
- @page = subject.wiki.paged("index")
- end
-
- it "deletes the page" do
- subject.delete_page(@page)
- subject.pages.count.should == 0
- end
- end
-
-end
diff --git a/spec/models/group_spec.rb b/spec/models/group_spec.rb
index 5d4674e3..108bc303 100644
--- a/spec/models/group_spec.rb
+++ b/spec/models/group_spec.rb
@@ -2,14 +2,13 @@
#
# Table name: namespaces
#
-# id :integer not null, primary key
-# name :string(255) not null
-# path :string(255) not null
-# owner_id :integer not null
-# created_at :datetime not null
-# updated_at :datetime not null
-# type :string(255)
-# description :string(255) default(""), not null
+# id :integer not null, primary key
+# name :string(255) not null
+# path :string(255) not null
+# owner_id :integer not null
+# created_at :datetime not null
+# updated_at :datetime not null
+# type :string(255)
#
require 'spec_helper'
diff --git a/spec/models/issue_spec.rb b/spec/models/issue_spec.rb
index 1bc794dc..4c52a094 100644
--- a/spec/models/issue_spec.rb
+++ b/spec/models/issue_spec.rb
@@ -9,11 +9,11 @@
# project_id :integer
# created_at :datetime not null
# updated_at :datetime not null
+# closed :boolean default(FALSE), not null
# position :integer default(0)
# branch_name :string(255)
# description :text
# milestone_id :integer
-# state :string(255)
#
require 'spec_helper'
@@ -28,8 +28,13 @@ describe Issue do
it { should_not allow_mass_assignment_of(:project_id) }
end
+ describe "Validation" do
+ it { should ensure_length_of(:description).is_within(0..2000) }
+ end
+
describe 'modules' do
- it { should include_module(Issuable) }
+ it { should include_module(IssueCommonality) }
+ it { should include_module(Votes) }
end
subject { create(:issue) }
@@ -44,15 +49,34 @@ describe Issue do
end
end
- describe '#is_being_reassigned?' do
- it 'returnes issues assigned to user' do
- user = create :user
+ describe '#is_being_closed?' do
+ it 'returns true if the closed attribute has changed and is now true' do
+ subject.closed = true
+ subject.is_being_closed?.should be_true
+ end
+ it 'returns false if the closed attribute has changed and is now false' do
+ issue = create(:closed_issue)
+ issue.closed = false
+ issue.is_being_closed?.should be_false
+ end
+ it 'returns false if the closed attribute has not changed' do
+ subject.is_being_closed?.should be_false
+ end
+ end
- 2.times do
- issue = create :issue, assignee: user
- end
- Issue.open_for(user).count.should eq 2
+ describe '#is_being_reopened?' do
+ it 'returns true if the closed attribute has changed and is now false' do
+ issue = create(:closed_issue)
+ issue.closed = false
+ issue.is_being_reopened?.should be_true
+ end
+ it 'returns false if the closed attribute has changed and is now true' do
+ subject.closed = true
+ subject.is_being_reopened?.should be_false
+ end
+ it 'returns false if the closed attribute has not changed' do
+ subject.is_being_reopened?.should be_false
end
end
end
diff --git a/spec/models/key_spec.rb b/spec/models/key_spec.rb
index a9ab2f05..6d2310df 100644
--- a/spec/models/key_spec.rb
+++ b/spec/models/key_spec.rb
@@ -46,9 +46,9 @@ describe Key do
key.should_not be_valid
end
- it "does not accept the same key for another project" do
+ it "does accept the same key for another project" do
key = build(:key, project_id: 0)
- key.should_not be_valid
+ key.should be_valid
end
end
@@ -73,12 +73,8 @@ describe Key do
build(:key, user: user).should be_valid
end
- it "rejects the unfingerprintable key (contains space in middle)" do
+ it "rejects the unfingerprintable key" do
build(:key_with_a_space_in_the_middle).should_not be_valid
end
-
- it "rejects the unfingerprintable key (not a key)" do
- build(:invalid_key).should_not be_valid
- end
end
end
diff --git a/spec/models/merge_request_spec.rb b/spec/models/merge_request_spec.rb
index c64c053b..a0849401 100644
--- a/spec/models/merge_request_spec.rb
+++ b/spec/models/merge_request_spec.rb
@@ -9,13 +9,14 @@
# author_id :integer
# assignee_id :integer
# title :string(255)
+# closed :boolean default(FALSE), not null
# created_at :datetime not null
# updated_at :datetime not null
# st_commits :text(2147483647)
# st_diffs :text(2147483647)
+# merged :boolean default(FALSE), not null
+# state :integer default(1), not null
# milestone_id :integer
-# state :string(255)
-# merge_status :string(255)
#
require 'spec_helper'
@@ -31,25 +32,16 @@ describe MergeRequest do
it { should_not allow_mass_assignment_of(:project_id) }
end
- describe "Respond to" do
- it { should respond_to(:unchecked?) }
- it { should respond_to(:can_be_merged?) }
- it { should respond_to(:cannot_be_merged?) }
- end
-
describe 'modules' do
- it { should include_module(Issuable) }
- end
-
- describe "#mr_and_commit_notes" do
-
+ it { should include_module(IssueCommonality) }
+ it { should include_module(Votes) }
end
describe "#mr_and_commit_notes" do
let!(:merge_request) { create(:merge_request) }
before do
- merge_request.stub(:commits) { [merge_request.project.repository.commit] }
+ merge_request.stub(:commits) { [merge_request.project.commit] }
create(:note, commit_id: merge_request.commits.first.id, noteable_type: 'Commit')
create(:note, noteable: merge_request)
end
@@ -71,4 +63,35 @@ describe MergeRequest do
subject.is_being_reassigned?.should be_false
end
end
+
+ describe '#is_being_closed?' do
+ it 'returns true if the closed attribute has changed and is now true' do
+ subject.closed = true
+ subject.is_being_closed?.should be_true
+ end
+ it 'returns false if the closed attribute has changed and is now false' do
+ merge_request = create(:closed_merge_request)
+ merge_request.closed = false
+ merge_request.is_being_closed?.should be_false
+ end
+ it 'returns false if the closed attribute has not changed' do
+ subject.is_being_closed?.should be_false
+ end
+ end
+
+
+ describe '#is_being_reopened?' do
+ it 'returns true if the closed attribute has changed and is now false' do
+ merge_request = create(:closed_merge_request)
+ merge_request.closed = false
+ merge_request.is_being_reopened?.should be_true
+ end
+ it 'returns false if the closed attribute has changed and is now true' do
+ subject.closed = true
+ subject.is_being_reopened?.should be_false
+ end
+ it 'returns false if the closed attribute has not changed' do
+ subject.is_being_reopened?.should be_false
+ end
+ end
end
diff --git a/spec/models/milestone_spec.rb b/spec/models/milestone_spec.rb
index f74fea01..431985d0 100644
--- a/spec/models/milestone_spec.rb
+++ b/spec/models/milestone_spec.rb
@@ -7,9 +7,9 @@
# project_id :integer not null
# description :text
# due_date :date
+# closed :boolean default(FALSE), not null
# created_at :datetime not null
# updated_at :datetime not null
-# state :string(255)
#
require 'spec_helper'
@@ -27,6 +27,7 @@ describe Milestone do
describe "Validation" do
it { should validate_presence_of(:title) }
it { should validate_presence_of(:project) }
+ it { should ensure_inclusion_of(:closed).in_array([true, false]) }
end
let(:milestone) { create(:milestone) }
@@ -39,8 +40,7 @@ describe Milestone do
end
it "should count closed issues" do
- IssueObserver.current_user = issue.author
- issue.close
+ issue.update_attributes(closed: true)
milestone.issues << issue
milestone.percent_complete.should == 100
end
@@ -62,82 +62,4 @@ describe Milestone do
milestone.expires_at.should be_present
end
end
-
- describe :expired? do
- context "expired" do
- before do
- milestone.stub(due_date: Date.today.prev_year)
- end
-
- it { milestone.expired?.should be_true }
- end
-
- context "not expired" do
- before do
- milestone.stub(due_date: Date.today.next_year)
- end
-
- it { milestone.expired?.should be_false }
- end
- end
-
- describe :percent_complete do
- before do
- milestone.stub(
- closed_items_count: 3,
- total_items_count: 4
- )
- end
-
- it { milestone.percent_complete.should == 75 }
- end
-
- describe :items_count do
- before do
- milestone.issues << create(:issue)
- milestone.issues << create(:closed_issue)
- milestone.merge_requests << create(:merge_request)
- end
-
- it { milestone.closed_items_count.should == 1 }
- it { milestone.open_items_count.should == 2 }
- it { milestone.total_items_count.should == 3 }
- it { milestone.is_empty?.should be_false }
- end
-
- describe :can_be_closed? do
- it { milestone.can_be_closed?.should be_true }
- end
-
- describe :is_empty? do
- before do
- issue = create :closed_issue, milestone: milestone
- merge_request = create :merge_request, milestone: milestone
- end
-
- it 'Should return total count of issues and merge requests assigned to milestone' do
- milestone.total_items_count.should eq 2
- end
- end
-
- describe :can_be_closed? do
- before do
- milestone = create :milestone
- create :closed_issue, milestone: milestone
-
- issue = create :issue
- end
-
- it 'should be true if milestone active and all nestied issues closed' do
- milestone.can_be_closed?.should be_true
- end
-
- it 'should be false if milestone active and not all nestied issues closed' do
- issue.milestone = milestone
- issue.save
-
- milestone.can_be_closed?.should be_false
- end
- end
-
end
diff --git a/spec/models/namespace_spec.rb b/spec/models/namespace_spec.rb
index b40a0795..d0de4a7b 100644
--- a/spec/models/namespace_spec.rb
+++ b/spec/models/namespace_spec.rb
@@ -2,14 +2,13 @@
#
# Table name: namespaces
#
-# id :integer not null, primary key
-# name :string(255) not null
-# path :string(255) not null
-# owner_id :integer not null
-# created_at :datetime not null
-# updated_at :datetime not null
-# type :string(255)
-# description :string(255) default(""), not null
+# id :integer not null, primary key
+# name :string(255) not null
+# path :string(255) not null
+# owner_id :integer not null
+# created_at :datetime not null
+# updated_at :datetime not null
+# type :string(255)
#
require 'spec_helper'
@@ -60,7 +59,7 @@ describe Namespace do
end
it "should raise error when dirtory exists" do
- expect { @namespace.move_dir }.to raise_error("namespace directory cannot be moved")
+ expect { @namespace.move_dir }.to raise_error("Already exists")
end
it "should move dir if path changed" do
diff --git a/spec/models/note_spec.rb b/spec/models/note_spec.rb
index 52e24a78..61aaf645 100644
--- a/spec/models/note_spec.rb
+++ b/spec/models/note_spec.rb
@@ -4,6 +4,7 @@
#
# id :integer not null, primary key
# note :text
+# noteable_id :string(255)
# noteable_type :string(255)
# author_id :integer
# created_at :datetime not null
@@ -11,8 +12,6 @@
# project_id :integer
# attachment :string(255)
# line_code :string(255)
-# commit_id :string(255)
-# noteable_id :integer
#
require 'spec_helper'
@@ -34,112 +33,89 @@ describe Note do
it { should validate_presence_of(:project) }
end
+ describe "Scopes" do
+ it "should have a today named scope that returns ..." do
+ Note.today.where_values.should == ["created_at >= '#{Date.today}'"]
+ end
+ end
+
describe "Voting score" do
let(:project) { create(:project) }
it "recognizes a neutral note" do
- note = create(:votable_note, note: "This is not a +1 note")
+ note = create(:note, note: "This is not a +1 note")
note.should_not be_upvote
note.should_not be_downvote
end
it "recognizes a neutral emoji note" do
- note = build(:votable_note, note: "I would :+1: this, but I don't want to")
+ note = build(:note, note: "I would :+1: this, but I don't want to")
note.should_not be_upvote
note.should_not be_downvote
end
it "recognizes a +1 note" do
- note = create(:votable_note, note: "+1 for this")
+ note = create(:note, note: "+1 for this")
note.should be_upvote
end
it "recognizes a +1 emoji as a vote" do
- note = build(:votable_note, note: ":+1: for this")
+ note = build(:note, note: ":+1: for this")
note.should be_upvote
end
it "recognizes a -1 note" do
- note = create(:votable_note, note: "-1 for this")
+ note = create(:note, note: "-1 for this")
note.should be_downvote
end
it "recognizes a -1 emoji as a vote" do
- note = build(:votable_note, note: ":-1: for this")
+ note = build(:note, note: ":-1: for this")
note.should be_downvote
end
end
let(:project) { create(:project) }
- let(:commit) { project.repository.commit }
+ let(:commit) { project.commit }
describe "Commit notes" do
- let!(:note) { create(:note_on_commit, note: "+1 from me") }
- let!(:commit) { note.noteable }
+ before do
+ @note = create(:note,
+ commit_id: commit.id,
+ noteable_type: "Commit")
+ end
it "should be accessible through #noteable" do
- note.commit_id.should == commit.id
- note.noteable.should be_a(Commit)
- note.noteable.should == commit
+ @note.commit_id.should == commit.id
+ @note.noteable.should be_a(Commit)
+ @note.noteable.should == commit
end
it "should save a valid note" do
- note.commit_id.should == commit.id
- note.noteable == commit
+ @note.commit_id.should == commit.id
+ @note.noteable == commit
end
it "should be recognized by #for_commit?" do
- note.should be_for_commit
- end
-
- it "should not be votable" do
- note.should_not be_votable
+ @note.should be_for_commit
end
end
- describe "Commit diff line notes" do
- let!(:note) { create(:note_on_commit_diff, note: "+1 from me") }
- let!(:commit) { note.noteable }
+ describe "Pre-line commit notes" do
+ before do
+ @note = create(:note,
+ commit_id: commit.id,
+ noteable_type: "Commit",
+ line_code: "0_16_1")
+ end
it "should save a valid note" do
- note.commit_id.should == commit.id
- note.noteable.id.should == commit.id
+ @note.commit_id.should == commit.id
+ @note.noteable.id.should == commit.id
end
it "should be recognized by #for_diff_line?" do
- note.should be_for_diff_line
- end
-
- it "should be recognized by #for_commit_diff_line?" do
- note.should be_for_commit_diff_line
- end
-
- it "should not be votable" do
- note.should_not be_votable
- end
- end
-
- describe "Issue notes" do
- let!(:note) { create(:note_on_issue, note: "+1 from me") }
-
- it "should not be votable" do
- note.should be_votable
- end
- end
-
- describe "Merge request notes" do
- let!(:note) { create(:note_on_merge_request, note: "+1 from me") }
-
- it "should not be votable" do
- note.should be_votable
- end
- end
-
- describe "Merge request diff line notes" do
- let!(:note) { create(:note_on_merge_request_diff, note: "+1 from me") }
-
- it "should not be votable" do
- note.should_not be_votable
+ @note.should be_for_diff_line
end
end
diff --git a/spec/models/project_hooks_spec.rb b/spec/models/project_hooks_spec.rb
new file mode 100644
index 00000000..df6a3831
--- /dev/null
+++ b/spec/models/project_hooks_spec.rb
@@ -0,0 +1,123 @@
+require 'spec_helper'
+
+describe Project, "Hooks" do
+ let(:project) { create(:project) }
+ before do
+ @key = create(:key, user: project.owner)
+ @user = @key.user
+ @key_id = @key.identifier
+ end
+
+ describe "Post Receive Event" do
+ it "should create push event" do
+ oldrev, newrev, ref = '00000000000000000000000000000000', 'newrev', 'refs/heads/master'
+ data = project.post_receive_data(oldrev, newrev, ref, @user)
+
+ project.observe_push(data)
+ event = Event.last
+
+ event.should_not be_nil
+ event.project.should == project
+ event.action.should == Event::Pushed
+ event.data.should == data
+ end
+ end
+
+ describe "Project hooks" do
+ context "with no web hooks" do
+ it "raises no errors" do
+ lambda {
+ project.execute_hooks({})
+ }.should_not raise_error
+ end
+ end
+
+ context "with web hooks" do
+ before do
+ @project_hook = create(:project_hook)
+ @project_hook_2 = create(:project_hook)
+ project.hooks << [@project_hook, @project_hook_2]
+ end
+
+ it "executes multiple web hook" do
+ @project_hook.should_receive(:execute).once
+ @project_hook_2.should_receive(:execute).once
+
+ project.trigger_post_receive('oldrev', 'newrev', 'refs/heads/master', @user)
+ end
+ end
+
+ context "does not execute web hooks" do
+ before do
+ @project_hook = create(:project_hook)
+ project.hooks << [@project_hook]
+ end
+
+ it "when pushing a branch for the first time" do
+ @project_hook.should_not_receive(:execute)
+ project.trigger_post_receive('00000000000000000000000000000000', 'newrev', 'refs/heads/master', @user)
+ end
+
+ it "when pushing tags" do
+ @project_hook.should_not_receive(:execute)
+ project.trigger_post_receive('oldrev', 'newrev', 'refs/tags/v1.0.0', @user)
+ end
+ end
+
+ context "when pushing new branches" do
+
+ end
+
+ context "when gathering commit data" do
+ before do
+ @oldrev, @newrev, @ref = project.fresh_commits(2).last.sha, project.fresh_commits(2).first.sha, 'refs/heads/master'
+ @commit = project.fresh_commits(2).first
+
+ # Fill nil/empty attributes
+ project.description = "This is a description"
+
+ @data = project.post_receive_data(@oldrev, @newrev, @ref, @user)
+ end
+
+ subject { @data }
+
+ it { should include(before: @oldrev) }
+ it { should include(after: @newrev) }
+ it { should include(ref: @ref) }
+ it { should include(user_id: project.owner.id) }
+ it { should include(user_name: project.owner.name) }
+
+ context "with repository data" do
+ subject { @data[:repository] }
+
+ it { should include(name: project.name) }
+ it { should include(url: project.web_url) }
+ it { should include(description: project.description) }
+ it { should include(homepage: project.web_url) }
+ end
+
+ context "with commits" do
+ subject { @data[:commits] }
+
+ it { should be_an(Array) }
+ it { should have(1).element }
+
+ context "the commit" do
+ subject { @data[:commits].first }
+
+ it { should include(id: @commit.id) }
+ it { should include(message: @commit.safe_message) }
+ it { should include(timestamp: @commit.date.xmlschema) }
+ it { should include(url: "#{Gitlab.config.gitlab.url}/#{project.code}/commit/#{@commit.id}") }
+
+ context "with a author" do
+ subject { @data[:commits].first[:author] }
+
+ it { should include(name: @commit.author_name) }
+ it { should include(email: @commit.author_email) }
+ end
+ end
+ end
+ end
+ end
+end
diff --git a/spec/models/project_security_spec.rb b/spec/models/project_security_spec.rb
index 1f2bd7a5..92c6bce0 100644
--- a/spec/models/project_security_spec.rb
+++ b/spec/models/project_security_spec.rb
@@ -8,7 +8,7 @@ describe Project do
@u1 = create(:user)
@u2 = create(:user)
@u3 = create(:user)
- @u4 = @p1.owner
+ @u4 = @p1.chief
@abilities = Six.new
@abilities << Ability
diff --git a/spec/models/project_spec.rb b/spec/models/project_spec.rb
index cbc7f278..83a76976 100644
--- a/spec/models/project_spec.rb
+++ b/spec/models/project_spec.rb
@@ -8,17 +8,14 @@
# description :text
# created_at :datetime not null
# updated_at :datetime not null
-# creator_id :integer
+# private_flag :boolean default(TRUE), not null
+# owner_id :integer
# default_branch :string(255)
# issues_enabled :boolean default(TRUE), not null
# wall_enabled :boolean default(TRUE), not null
# merge_requests_enabled :boolean default(TRUE), not null
# wiki_enabled :boolean default(TRUE), not null
# namespace_id :integer
-# public :boolean default(FALSE), not null
-# issues_tracker :string(255) default("gitlab"), not null
-# issues_tracker_id :string(255)
-# snippets_enabled :boolean default(TRUE), not null
#
require 'spec_helper'
@@ -27,7 +24,7 @@ describe Project do
describe "Associations" do
it { should belong_to(:group) }
it { should belong_to(:namespace) }
- it { should belong_to(:creator).class_name('User') }
+ it { should belong_to(:owner).class_name('User') }
it { should have_many(:users) }
it { should have_many(:events).dependent(:destroy) }
it { should have_many(:merge_requests).dependent(:destroy) }
@@ -44,7 +41,8 @@ describe Project do
describe "Mass assignment" do
it { should_not allow_mass_assignment_of(:namespace_id) }
- it { should_not allow_mass_assignment_of(:creator_id) }
+ it { should_not allow_mass_assignment_of(:owner_id) }
+ it { should_not allow_mass_assignment_of(:private_flag) }
end
describe "Validation" do
@@ -57,37 +55,105 @@ describe Project do
it { should validate_presence_of(:path) }
it { should validate_uniqueness_of(:path) }
it { should ensure_length_of(:path).is_within(0..255) }
+ # TODO: Formats
+
it { should ensure_length_of(:description).is_within(0..2000) }
- it { should validate_presence_of(:creator) }
+
+ # TODO: Formats
+
+ it { should validate_presence_of(:owner) }
it { should ensure_inclusion_of(:issues_enabled).in_array([true, false]) }
it { should ensure_inclusion_of(:wall_enabled).in_array([true, false]) }
it { should ensure_inclusion_of(:merge_requests_enabled).in_array([true, false]) }
it { should ensure_inclusion_of(:wiki_enabled).in_array([true, false]) }
- it { should ensure_length_of(:issues_tracker_id).is_within(0..255) }
it "should not allow new projects beyond user limits" do
- project.stub(:creator).and_return(double(can_create_project?: false, projects_limit: 1))
+ project.stub(:owner).and_return(double(can_create_project?: false, projects_limit: 1))
project.should_not be_valid
- project.errors[:limit_reached].first.should match(/Your own projects limit is 1/)
+ project.errors[:base].first.should match(/Your own projects limit is 1/)
+ end
+
+ it "should not allow 'gitolite-admin' as repo name" do
+ should allow_value("blah").for(:path)
+ should_not allow_value("gitolite-admin").for(:path)
end
end
describe "Respond to" do
+ it { should respond_to(:public?) }
+ it { should respond_to(:private?) }
it { should respond_to(:url_to_repo) }
+ it { should respond_to(:path_to_repo) }
+ it { should respond_to(:valid_repo?) }
it { should respond_to(:repo_exists?) }
+
+ # Repository Role
+ it { should respond_to(:tree) }
+ it { should respond_to(:root_ref) }
+ it { should respond_to(:repo) }
+ it { should respond_to(:tags) }
+ it { should respond_to(:commit) }
+ it { should respond_to(:commits) }
+ it { should respond_to(:commits_between) }
+ it { should respond_to(:commits_with_refs) }
+ it { should respond_to(:commits_since) }
+ it { should respond_to(:commits_between) }
it { should respond_to(:satellite) }
+ it { should respond_to(:update_repository) }
+ it { should respond_to(:destroy_repository) }
+ it { should respond_to(:archive_repo) }
+
+ # Authority Role
+ it { should respond_to(:add_access) }
+ it { should respond_to(:reset_access) }
+ it { should respond_to(:repository_writers) }
+ it { should respond_to(:repository_masters) }
+ it { should respond_to(:repository_readers) }
+ it { should respond_to(:allow_read_for?) }
+ it { should respond_to(:guest_access_for?) }
+ it { should respond_to(:report_access_for?) }
+ it { should respond_to(:dev_access_for?) }
+ it { should respond_to(:master_access_for?) }
+
+ # Team Role
+ it { should respond_to(:team_member_by_name_or_email) }
+ it { should respond_to(:team_member_by_id) }
+ it { should respond_to(:add_user_to_team) }
+ it { should respond_to(:add_users_to_team) }
+ it { should respond_to(:add_user_id_to_team) }
+ it { should respond_to(:add_users_ids_to_team) }
+
+ # Project Push Role
+ it { should respond_to(:observe_push) }
it { should respond_to(:update_merge_requests) }
it { should respond_to(:execute_hooks) }
+ it { should respond_to(:post_receive_data) }
+ it { should respond_to(:trigger_post_receive) }
+
+ # Namespaced Project Role
it { should respond_to(:transfer) }
it { should respond_to(:name_with_namespace) }
it { should respond_to(:namespace_owner) }
- it { should respond_to(:owner) }
+ it { should respond_to(:chief) }
it { should respond_to(:path_with_namespace) }
end
+ describe 'modules' do
+ it { should include_module(Repository) }
+ it { should include_module(PushObserver) }
+ it { should include_module(Authority) }
+ it { should include_module(Team) }
+ it { should include_module(NamespacedProject) }
+ end
+
it "should return valid url to repo" do
project = Project.new(path: "somewhere")
- project.url_to_repo.should == Gitlab.config.gitlab_shell.ssh_path_prefix + "somewhere.git"
+ project.url_to_repo.should == Gitlab.config.gitolite.ssh_path_prefix + "somewhere.git"
+ end
+
+ it "should return path to repo" do
+ project = Project.new(path: "somewhere")
+ project.path_to_repo.should == Rails.root.join("tmp", "repositories", "somewhere")
end
it "returns the full web URL for this repo" do
@@ -119,10 +185,13 @@ 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, project: project)
+ @merge_request = create(:merge_request,
+ project: project,
+ merged: false,
+ closed: false)
@key = create(:key, user_id: project.owner.id)
end
@@ -131,7 +200,8 @@ describe Project do
@merge_request.last_commit.id.should == "bcf03b5de6c33f3869ef70d68cf06e679d1d7f9a"
project.update_merge_requests("8716fc78f3c65bbf7bcf7b574febd583bc5d2812", "bcf03b5de6c33f3869ef70d68cf06e679d1d7f9a", "refs/heads/stable", @key.user)
@merge_request.reload
- @merge_request.merged?.should be_true
+ @merge_request.merged.should be_true
+ @merge_request.closed.should be_true
end
it "should update merge request commits with new one if pushed to source branch" do
@@ -141,117 +211,4 @@ describe Project do
@merge_request.last_commit.id.should == "bcf03b5de6c33f3869ef70d68cf06e679d1d7f9a"
end
end
-
-
- describe :find_with_namespace do
- context 'with namespace' do
- before do
- @group = create :group, name: 'gitlab'
- @project = create(:project, name: 'gitlab-ci', namespace: @group)
- end
-
- it { Project.find_with_namespace('gitlab/gitlab-ci').should == @project }
- it { Project.find_with_namespace('gitlab-ci').should be_nil }
- end
-
- context 'w/o namespace' do
- before do
- @project = create(:project, name: 'gitlab-ci')
- end
-
- it { Project.find_with_namespace('gitlab-ci').should == @project }
- it { Project.find_with_namespace('gitlab/gitlab-ci').should be_nil }
- end
- end
-
- describe :to_param do
- context 'with namespace' do
- before do
- @group = create :group, name: 'gitlab'
- @project = create(:project, name: 'gitlab-ci', namespace: @group)
- end
-
- it { @project.to_param.should == "gitlab/gitlab-ci" }
- end
-
- context 'w/o namespace' do
- before do
- @project = create(:project, name: 'gitlab-ci')
- end
-
- it { @project.to_param.should == "gitlab-ci" }
- end
- end
-
- describe :repository do
- let(:project) { create(:project) }
-
- it "should return valid repo" do
- project.repository.should be_kind_of(Repository)
- end
- end
-
- describe :issue_exists? do
- let(:project) { create(:project) }
- let(:existed_issue) { create(:issue, project: project) }
- let(:not_existed_issue) { create(:issue) }
- let(:ext_project) { create(:redmine_project) }
-
- it "should be true or if used internal tracker and issue exists" do
- project.issue_exists?(existed_issue.id).should be_true
- end
-
- it "should be false or if used internal tracker and issue not exists" do
- project.issue_exists?(not_existed_issue.id).should be_false
- end
-
- it "should always be true if used other tracker" do
- ext_project.issue_exists?(rand(100)).should be_true
- end
- end
-
- describe :used_default_issues_tracker? do
- let(:project) { create(:project) }
- let(:ext_project) { create(:redmine_project) }
-
- it "should be true if used internal tracker" do
- project.used_default_issues_tracker?.should be_true
- end
-
- it "should be false if used other tracker" do
- ext_project.used_default_issues_tracker?.should be_false
- end
- end
-
- describe :can_have_issues_tracker_id? do
- let(:project) { create(:project) }
- let(:ext_project) { create(:redmine_project) }
-
- it "should be true for projects with external issues tracker if issues enabled" do
- ext_project.can_have_issues_tracker_id?.should be_true
- end
-
- it "should be false for projects with internal issue tracker if issues enabled" do
- project.can_have_issues_tracker_id?.should be_false
- end
-
- it "should be always false if issues disbled" do
- project.issues_enabled = false
- ext_project.issues_enabled = false
-
- project.can_have_issues_tracker_id?.should be_false
- ext_project.can_have_issues_tracker_id?.should be_false
- end
- end
-
- describe :open_branches do
- let(:project) { create(:project_with_code) }
-
- before do
- project.protected_branches.create(name: 'master')
- end
-
- it { project.open_branches.map(&:name).should include('bootstrap') }
- it { project.open_branches.map(&:name).should_not include('master') }
- end
end
diff --git a/spec/models/project_team_spec.rb b/spec/models/project_team_spec.rb
deleted file mode 100644
index 3e3543e8..00000000
--- a/spec/models/project_team_spec.rb
+++ /dev/null
@@ -1,15 +0,0 @@
-require "spec_helper"
-
-describe ProjectTeam do
- let(:team) { create(:project).team }
-
- describe "Respond to" do
- subject { team }
-
- it { should respond_to(:developers) }
- it { should respond_to(:masters) }
- it { should respond_to(:reporters) }
- it { should respond_to(:guests) }
- end
-end
-
diff --git a/spec/models/protected_branch_spec.rb b/spec/models/protected_branch_spec.rb
index 6e830393..7340ce50 100644
--- a/spec/models/protected_branch_spec.rb
+++ b/spec/models/protected_branch_spec.rb
@@ -24,4 +24,28 @@ describe ProtectedBranch do
it { should validate_presence_of(:project) }
it { should validate_presence_of(:name) }
end
+
+ describe 'Callbacks' do
+ let(:branch) { build(:protected_branch) }
+
+ it 'call update_repository after save' do
+ branch.should_receive(:update_repository)
+ branch.save
+ end
+
+ it 'call update_repository after destroy' do
+ branch.save
+ branch.should_receive(:update_repository)
+ branch.destroy
+ end
+ end
+
+ describe '#commit' do
+ let(:branch) { create(:protected_branch) }
+
+ it 'commits itself to its project' do
+ branch.project.should_receive(:commit).with(branch.name)
+ branch.commit
+ end
+ end
end
diff --git a/spec/models/snippet_spec.rb b/spec/models/snippet_spec.rb
index e4d19348..b474d88c 100644
--- a/spec/models/snippet_spec.rb
+++ b/spec/models/snippet_spec.rb
@@ -38,5 +38,6 @@ describe Snippet do
it { should ensure_length_of(:title).is_within(0..255) }
it { should validate_presence_of(:content) }
+ it { should ensure_length_of(:content).is_within(0..10_000) }
end
end
diff --git a/spec/models/system_hook_spec.rb b/spec/models/system_hook_spec.rb
index a9ed6a5f..9d03b56c 100644
--- a/spec/models/system_hook_spec.rb
+++ b/spec/models/system_hook_spec.rb
@@ -23,40 +23,53 @@ describe SystemHook do
end
it "project_create hook" do
- project = create(:project)
+ with_resque do
+ project = create(:project)
+ end
WebMock.should have_requested(:post, @system_hook.url).with(body: /project_create/).once
end
it "project_destroy hook" do
project = create(:project)
- project.destroy
+ with_resque do
+ project.destroy
+ end
WebMock.should have_requested(:post, @system_hook.url).with(body: /project_destroy/).once
end
it "user_create hook" do
- create(:user)
+ with_resque do
+ create(:user)
+ end
WebMock.should have_requested(:post, @system_hook.url).with(body: /user_create/).once
end
it "user_destroy hook" do
user = create(:user)
- user.destroy
+ with_resque do
+ user.destroy
+ end
WebMock.should have_requested(:post, @system_hook.url).with(body: /user_destroy/).once
end
it "project_create hook" do
user = create(:user)
project = create(:project)
- project.team << [user, :master]
+ with_resque do
+ project.users << user
+ end
WebMock.should have_requested(:post, @system_hook.url).with(body: /user_add_to_team/).once
end
it "project_destroy hook" do
user = create(:user)
project = create(:project)
- project.team << [user, :master]
- project.users_projects.clear
+ project.users << user
+ with_resque do
+ project.users_projects.clear
+ end
WebMock.should have_requested(:post, @system_hook.url).with(body: /user_remove_from_team/).once
end
end
+
end
diff --git a/spec/models/user_spec.rb b/spec/models/user_spec.rb
index 4e276dea..d09484f8 100644
--- a/spec/models/user_spec.rb
+++ b/spec/models/user_spec.rb
@@ -22,18 +22,15 @@
# linkedin :string(255) default(""), not null
# twitter :string(255) default(""), not null
# authentication_token :string(255)
+# dark_scheme :boolean default(FALSE), not null
# theme_id :integer default(1), not null
# bio :string(255)
+# blocked :boolean default(FALSE), not null
# failed_attempts :integer default(0)
# locked_at :datetime
# extern_uid :string(255)
# provider :string(255)
# username :string(255)
-# can_create_group :boolean default(TRUE), not null
-# can_create_team :boolean default(TRUE), not null
-# state :string(255)
-# color_scheme_id :integer default(1), not null
-# notification_level :integer default(1), not null
#
require 'spec_helper'
@@ -42,6 +39,7 @@ describe User do
describe "Associations" do
it { should have_one(:namespace) }
it { should have_many(:users_projects).dependent(:destroy) }
+ it { should have_many(:projects) }
it { should have_many(:groups) }
it { should have_many(:keys).dependent(:destroy) }
it { should have_many(:events).class_name('Event').dependent(:destroy) }
@@ -68,12 +66,34 @@ describe User do
it { should ensure_length_of(:bio).is_within(0..255) }
end
+ describe 'modules' do
+ it { should include_module(Account) }
+ end
+
describe "Respond to" do
it { should respond_to(:is_admin?) }
+ it { should respond_to(:identifier) }
it { should respond_to(:name) }
it { should respond_to(:private_token) }
end
+ describe '#identifier' do
+ it "should return valid identifier" do
+ user = build(:user, email: "test@mail.com")
+ user.identifier.should == "test_mail_com"
+ end
+
+ it "should return identifier without + sign" do
+ user = build(:user, email: "test+foo@mail.com")
+ user.identifier.should == "test_foo_mail_com"
+ end
+
+ it "should conform to Gitolite's required identifier pattern" do
+ user = build(:user, email: "_test@example.com")
+ user.identifier.should == 'test_example_com'
+ end
+ end
+
describe '#generate_password' do
it "should execute callback when force_random_password specified" do
user = build(:user, force_random_password: true)
@@ -99,83 +119,4 @@ describe User do
user.authentication_token.should_not be_blank
end
end
-
- describe 'projects' do
- before do
- ActiveRecord::Base.observers.enable(:user_observer)
- @user = create :user
- @project = create :project, namespace: @user.namespace
- end
-
- it { @user.authorized_projects.should include(@project) }
- it { @user.owned_projects.should include(@project) }
- it { @user.personal_projects.should include(@project) }
- end
-
- describe 'groups' do
- before do
- ActiveRecord::Base.observers.enable(:user_observer)
- @user = create :user
- @group = create :group, owner: @user
- end
-
- it { @user.several_namespaces?.should be_true }
- it { @user.namespaces.should == [@user.namespace, @group] }
- it { @user.authorized_groups.should == [@group] }
- it { @user.owned_groups.should == [@group] }
- end
-
- describe 'namespaced' do
- before do
- ActiveRecord::Base.observers.enable(:user_observer)
- @user = create :user
- @project = create :project, namespace: @user.namespace
- end
-
- it { @user.several_namespaces?.should be_false }
- it { @user.namespaces.should == [@user.namespace] }
- end
-
- describe 'blocking user' do
- let(:user) { create(:user, name: 'John Smith') }
-
- it "should block user" do
- user.block
- user.blocked?.should be_true
- end
- end
-
- describe 'filter' do
- before do
- User.delete_all
- @user = create :user
- @admin = create :user, admin: true
- @blocked = create :user, state: :blocked
- end
-
- it { User.filter("admins").should == [@admin] }
- it { User.filter("blocked").should == [@blocked] }
- it { User.filter("wop").should == [@user, @admin, @blocked] }
- it { User.filter(nil).should == [@user, @admin] }
- end
-
- describe :not_in_project do
- before do
- User.delete_all
- @user = create :user
- @project = create :project
- end
-
- it { User.not_in_project(@project).should == [@user, @project.owner] }
- end
-
- describe 'normal user' do
- let(:user) { create(:user, name: 'John Smith') }
-
- it { user.is_admin?.should be_false }
- it { user.require_ssh_key?.should be_true }
- it { user.can_create_group?.should be_true }
- it { user.can_create_project?.should be_true }
- it { user.first_name.should == 'John' }
- end
end
diff --git a/spec/models/user_team_project_relationship_spec.rb b/spec/models/user_team_project_relationship_spec.rb
deleted file mode 100644
index 86150cf3..00000000
--- a/spec/models/user_team_project_relationship_spec.rb
+++ /dev/null
@@ -1,17 +0,0 @@
-# == Schema Information
-#
-# Table name: user_team_project_relationships
-#
-# id :integer not null, primary key
-# project_id :integer
-# user_team_id :integer
-# greatest_access :integer
-# created_at :datetime not null
-# updated_at :datetime not null
-#
-
-require 'spec_helper'
-
-describe UserTeamProjectRelationship do
- pending "add some examples to (or delete) #{__FILE__}"
-end
diff --git a/spec/models/user_team_spec.rb b/spec/models/user_team_spec.rb
deleted file mode 100644
index d330bbf3..00000000
--- a/spec/models/user_team_spec.rb
+++ /dev/null
@@ -1,37 +0,0 @@
-# == Schema Information
-#
-# Table name: user_teams
-#
-# id :integer not null, primary key
-# name :string(255)
-# path :string(255)
-# owner_id :integer
-# created_at :datetime not null
-# updated_at :datetime not null
-# description :string(255) default(""), not null
-#
-
-require 'spec_helper'
-
-describe UserTeam do
- let(:team) { FactoryGirl.create :user_team }
-
- context ".add_member" do
- let(:user) { FactoryGirl.create :user }
-
- it "should work" do
- team.add_member(user, UsersProject::DEVELOPER, false)
- team.members.should include(user)
- end
- end
-
- context ".remove_member" do
- let(:user) { FactoryGirl.create :user }
- before { team.add_member(user, UsersProject::DEVELOPER, false) }
-
- it "should work" do
- team.remove_member(user)
- team.members.should_not include(user)
- end
- end
-end
diff --git a/spec/models/user_team_user_relationship_spec.rb b/spec/models/user_team_user_relationship_spec.rb
deleted file mode 100644
index 981ad1e8..00000000
--- a/spec/models/user_team_user_relationship_spec.rb
+++ /dev/null
@@ -1,18 +0,0 @@
-# == Schema Information
-#
-# Table name: user_team_user_relationships
-#
-# id :integer not null, primary key
-# user_id :integer
-# user_team_id :integer
-# group_admin :boolean
-# permission :integer
-# created_at :datetime not null
-# updated_at :datetime not null
-#
-
-require 'spec_helper'
-
-describe UserTeamUserRelationship do
- pending "add some examples to (or delete) #{__FILE__}"
-end
diff --git a/spec/models/users_project_spec.rb b/spec/models/users_project_spec.rb
index e8f5b647..1f896324 100644
--- a/spec/models/users_project_spec.rb
+++ b/spec/models/users_project_spec.rb
@@ -29,7 +29,6 @@ describe UsersProject do
it { should validate_uniqueness_of(:user_id).scoped_to(:project_id).with_message(/already exists/) }
it { should validate_presence_of(:project) }
- it { should ensure_inclusion_of(:project_access).in_array(UsersProject.access_roles.values) }
end
describe "Delegate methods" do
@@ -48,10 +47,10 @@ describe UsersProject do
@user_1 = create :user
@user_2 = create :user
- @project_1.team << [ @user_1, :developer ]
- @project_2.team << [ @user_2, :reporter ]
+ @project_1.add_access @user_1, :write
+ @project_2.add_access @user_2, :read
- @status = @project_2.team.import(@project_1)
+ @status = UsersProject.import_team(@project_1, @project_2)
end
it { @status.should be_true }
@@ -69,45 +68,4 @@ describe UsersProject do
it { @project_1.users.should_not include(@user_2) }
end
end
-
- describe :add_users_into_projects do
- before do
- @project_1 = create :project
- @project_2 = create :project
-
- @user_1 = create :user
- @user_2 = create :user
-
- UsersProject.add_users_into_projects(
- [@project_1.id, @project_2.id],
- [@user_1.id, @user_2.id],
- UsersProject::MASTER
- )
- end
-
- it { @project_1.users.should include(@user_1) }
- it { @project_1.users.should include(@user_2) }
-
-
- it { @project_2.users.should include(@user_1) }
- it { @project_2.users.should include(@user_2) }
- end
-
- describe :truncate_teams do
- before do
- @project_1 = create :project
- @project_2 = create :project
-
- @user_1 = create :user
- @user_2 = create :user
-
- @project_1.team << [ @user_1, :developer]
- @project_2.team << [ @user_2, :reporter]
-
- UsersProject.truncate_teams([@project_1.id, @project_2.id])
- end
-
- it { @project_1.users.should be_empty }
- it { @project_2.users.should be_empty }
- end
end
diff --git a/spec/models/wiki_page_spec.rb b/spec/models/wiki_page_spec.rb
deleted file mode 100644
index 67f2a6da..00000000
--- a/spec/models/wiki_page_spec.rb
+++ /dev/null
@@ -1,164 +0,0 @@
-require "spec_helper"
-
-describe WikiPage do
-
- def create_temp_repo(path)
- FileUtils.mkdir_p path
- command = "git init --quiet #{path};"
- system(command)
- end
-
- def remove_temp_repo(path)
- FileUtils.rm_rf path
- end
-
- def commit_details
- commit = {name: user.name, email: user.email, message: "test commit"}
- end
-
- def create_page(name, content)
- wiki.wiki.write_page(name, :markdown, content, commit_details)
- end
-
- def destroy_page(title)
- page = wiki.wiki.paged(title)
- wiki.wiki.delete_page(page, commit_details)
- end
-
- let(:project) { create(:project) }
- let(:repository) { project.repository }
- let(:user) { project.owner }
- let(:wiki) { GollumWiki.new(project, user) }
-
- subject { WikiPage.new(wiki) }
-
- before do
- create_temp_repo(wiki.send(:path_to_repo))
- end
-
- describe "#initialize" do
- context "when initialized with an existing gollum page" do
- before do
- create_page("test page", "test content")
- @page = wiki.wiki.paged("test page")
- @wiki_page = WikiPage.new(wiki, @page, true)
- end
-
- it "sets the slug attribute" do
- @wiki_page.slug.should == "test-page"
- end
-
- it "sets the title attribute" do
- @wiki_page.title.should == "test page"
- end
-
- it "sets the formatted content attribute" do
- @wiki_page.content.should == "test content"
- end
-
- it "sets the format attribute" do
- @wiki_page.format.should == :markdown
- end
-
- it "sets the message attribute" do
- @wiki_page.message.should == "test commit"
- end
-
- it "sets the version attribute" do
- @wiki_page.version.should be_a Commit
- end
- end
- end
-
- describe "validations" do
- before do
- subject.attributes = {title: 'title', content: 'content'}
- end
-
- it "validates presence of title" do
- subject.attributes.delete(:title)
- subject.valid?.should be_false
- end
-
- it "validates presence of content" do
- subject.attributes.delete(:content)
- subject.valid?.should be_false
- end
- end
-
- before do
- @wiki_attr = {title: "Index", content: "Home Page", format: "markdown"}
- end
-
- describe "#create" do
- after do
- destroy_page("Index")
- end
-
- context "with valid attributes" do
- it "saves the wiki page" do
- subject.create(@wiki_attr)
- wiki.find_page("Index").should_not be_nil
- end
-
- it "returns true" do
- subject.create(@wiki_attr).should == true
- end
- end
- end
-
- describe "#update" do
- before do
- create_page("Update", "content")
- @page = wiki.find_page("Update")
- end
-
- after do
- destroy_page("Update")
- end
-
- context "with valid attributes" do
- it "updates the content of the page" do
- @page.update("new content")
- @page = wiki.find_page("Update")
- end
-
- it "returns true" do
- @page.update("more content").should be_true
- end
- end
- end
-
- describe "#destroy" do
- before do
- create_page("Delete Page", "content")
- @page = wiki.find_page("Delete Page")
- end
-
- it "should delete the page" do
- @page.delete
- wiki.pages.should be_empty
- end
-
- it "should return true" do
- @page.delete.should == true
- end
- end
-
- describe "#versions" do
- before do
- create_page("Update", "content")
- @page = wiki.find_page("Update")
- end
-
- after do
- destroy_page("Update")
- end
-
- it "returns an array of all commits for the page" do
- 3.times { |i| @page.update("content #{i}") }
- @page.versions.count.should == 4
- end
- end
-
-end
diff --git a/spec/observers/activity_observer_spec.rb b/spec/observers/activity_observer_spec.rb
index 3d503027..6af5d070 100644
--- a/spec/observers/activity_observer_spec.rb
+++ b/spec/observers/activity_observer_spec.rb
@@ -17,7 +17,7 @@ describe ActivityObserver do
end
it_should_be_valid_event
- it { @event.action.should == Event::CREATED }
+ it { @event.action.should == Event::Created }
it { @event.target.should == @merge_request }
end
@@ -30,7 +30,7 @@ describe ActivityObserver do
end
it_should_be_valid_event
- it { @event.action.should == Event::CREATED }
+ it { @event.action.should == Event::Created }
it { @event.target.should == @issue }
end
@@ -44,7 +44,7 @@ describe ActivityObserver do
end
it_should_be_valid_event
- it { @event.action.should == Event::COMMENTED }
+ it { @event.action.should == Event::Commented }
it { @event.target.should == @note }
end
end
diff --git a/spec/observers/issue_observer_spec.rb b/spec/observers/issue_observer_spec.rb
index 539c6550..bbffbd34 100644
--- a/spec/observers/issue_observer_spec.rb
+++ b/spec/observers/issue_observer_spec.rb
@@ -1,19 +1,12 @@
require 'spec_helper'
describe IssueObserver do
- let(:some_user) { create :user }
- let(:assignee) { create :user }
- let(:author) { create :user }
- let(:mock_issue) { double(:issue, id: 42, assignee: assignee, author: author) }
- let(:assigned_issue) { create(:issue, assignee: assignee, author: author) }
- let(:unassigned_issue) { create(:issue, author: author) }
- let(:closed_assigned_issue) { create(:closed_issue, assignee: assignee, author: author) }
- let(:closed_unassigned_issue) { create(:closed_issue, author: author) }
-
-
- before { subject.stub(:current_user).and_return(some_user) }
- before { subject.stub(notification: mock('NotificationService').as_null_object) }
+ let(:some_user) { double(:user, id: 1) }
+ let(:assignee) { double(:user, id: 2) }
+ let(:author) { double(:user, id: 3) }
+ let(:issue) { double(:issue, id: 42, assignee: assignee, author: author) }
+ before(:each) { subject.stub(:current_user).and_return(some_user) }
subject { IssueObserver.instance }
@@ -27,57 +20,26 @@ describe IssueObserver do
end
end
- it 'trigger notification to send emails' do
- subject.should_receive(:notification)
+ it 'sends an email to the assignee' do
+ Notify.should_receive(:new_issue_email).with(issue.id).
+ and_return(double(deliver: true))
- subject.after_create(mock_issue)
- end
- end
-
- context '#after_close' do
- context 'a status "closed"' do
- it 'note is created if the issue is being closed' do
- Note.should_receive(:create_status_change_note).with(assigned_issue, some_user, 'closed')
-
- assigned_issue.close
- end
-
- it 'trigger notification to send emails' do
- subject.should_receive(:notification)
-
- assigned_issue.close
- end
-
- it 'creates a note' do
- Note.should_receive(:create_status_change_note).with(unassigned_issue, some_user, 'closed')
- unassigned_issue.close
- end
+ subject.after_create(issue)
end
- context 'a status "reopened"' do
- it 'note is created if the issue is being reopened' do
- Note.should_receive(:create_status_change_note).with(closed_assigned_issue, some_user, 'reopened')
+ it 'does not send an email to the assignee if assignee created the issue' do
+ subject.stub(:current_user).and_return(assignee)
+ Notify.should_not_receive(:new_issue_email)
- closed_assigned_issue.reopen
- end
-
- it 'trigger notification to send emails' do
- subject.should_receive(:notification)
-
- closed_assigned_issue.reopen
- end
-
- it 'create a note' do
- Note.should_receive(:create_status_change_note).with(closed_unassigned_issue, some_user, 'reopened')
-
- closed_unassigned_issue.reopen
- end
+ subject.after_create(issue)
end
end
context '#after_update' do
before(:each) do
- mock_issue.stub(:is_being_reassigned?).and_return(false)
+ issue.stub(:is_being_reassigned?).and_return(false)
+ issue.stub(:is_being_closed?).and_return(false)
+ issue.stub(:is_being_reopened?).and_return(false)
end
it 'is called when an issue is changed' do
@@ -90,19 +52,147 @@ describe IssueObserver do
end
end
- context 'notification' do
- it 'triggered if the issue is being reassigned' do
- mock_issue.should_receive(:is_being_reassigned?).and_return(true)
- subject.should_receive(:notification)
+ context 'a reassigned email' do
+ it 'is sent if the issue is being reassigned' do
+ issue.should_receive(:is_being_reassigned?).and_return(true)
+ subject.should_receive(:send_reassigned_email).with(issue)
- subject.after_update(mock_issue)
+ subject.after_update(issue)
end
- it 'is not triggered if the issue is not being reassigned' do
- mock_issue.should_receive(:is_being_reassigned?).and_return(false)
- subject.should_not_receive(:notification)
+ it 'is not sent if the issue is not being reassigned' do
+ issue.should_receive(:is_being_reassigned?).and_return(false)
+ subject.should_not_receive(:send_reassigned_email)
- subject.after_update(mock_issue)
+ subject.after_update(issue)
+ end
+ end
+
+ context 'a status "closed"' do
+ it 'note is created if the issue is being closed' do
+ issue.should_receive(:is_being_closed?).and_return(true)
+ Note.should_receive(:create_status_change_note).with(issue, some_user, 'closed')
+
+ subject.after_update(issue)
+ end
+
+ it 'note is not created if the issue is not being closed' do
+ issue.should_receive(:is_being_closed?).and_return(false)
+ Note.should_not_receive(:create_status_change_note).with(issue, some_user, 'closed')
+
+ subject.after_update(issue)
+ end
+
+ it 'notification is delivered if the issue being closed' do
+ issue.stub(:is_being_closed?).and_return(true)
+ Notify.should_receive(:issue_status_changed_email).twice.and_return(stub(deliver: true))
+ Note.should_receive(:create_status_change_note).with(issue, some_user, 'closed')
+
+ subject.after_update(issue)
+ end
+
+ it 'notification is not delivered if the issue not being closed' do
+ issue.stub(:is_being_closed?).and_return(false)
+ Notify.should_not_receive(:issue_status_changed_email)
+ Note.should_not_receive(:create_status_change_note).with(issue, some_user, 'closed')
+
+ subject.after_update(issue)
+ end
+
+ it 'notification is delivered only to author if the issue being closed' do
+ issue_without_assignee = double(:issue, id: 42, author: author, assignee: nil)
+ issue_without_assignee.stub(:is_being_reassigned?).and_return(false)
+ issue_without_assignee.stub(:is_being_closed?).and_return(true)
+ issue_without_assignee.stub(:is_being_reopened?).and_return(false)
+ Notify.should_receive(:issue_status_changed_email).once.and_return(stub(deliver: true))
+ Note.should_receive(:create_status_change_note).with(issue_without_assignee, some_user, 'closed')
+
+ subject.after_update(issue_without_assignee)
+ end
+ end
+
+ context 'a status "reopened"' do
+ it 'note is created if the issue is being reopened' do
+ issue.should_receive(:is_being_reopened?).and_return(true)
+ Note.should_receive(:create_status_change_note).with(issue, some_user, 'reopened')
+
+ subject.after_update(issue)
+ end
+
+ it 'note is not created if the issue is not being reopened' do
+ issue.should_receive(:is_being_reopened?).and_return(false)
+ Note.should_not_receive(:create_status_change_note).with(issue, some_user, 'reopened')
+
+ subject.after_update(issue)
+ end
+
+ it 'notification is delivered if the issue being reopened' do
+ issue.stub(:is_being_reopened?).and_return(true)
+ Notify.should_receive(:issue_status_changed_email).twice.and_return(stub(deliver: true))
+ Note.should_receive(:create_status_change_note).with(issue, some_user, 'reopened')
+
+ subject.after_update(issue)
+ end
+
+ it 'notification is not delivered if the issue not being reopened' do
+ issue.stub(:is_being_reopened?).and_return(false)
+ Notify.should_not_receive(:issue_status_changed_email)
+ Note.should_not_receive(:create_status_change_note).with(issue, some_user, 'reopened')
+
+ subject.after_update(issue)
+ end
+
+ it 'notification is delivered only to author if the issue being reopened' do
+ issue_without_assignee = double(:issue, id: 42, author: author, assignee: nil)
+ issue_without_assignee.stub(:is_being_reassigned?).and_return(false)
+ issue_without_assignee.stub(:is_being_closed?).and_return(false)
+ issue_without_assignee.stub(:is_being_reopened?).and_return(true)
+ Notify.should_receive(:issue_status_changed_email).once.and_return(stub(deliver: true))
+ Note.should_receive(:create_status_change_note).with(issue_without_assignee, some_user, 'reopened')
+
+ subject.after_update(issue_without_assignee)
+ end
+ end
+ end
+
+ describe '#send_reassigned_email' do
+ let(:previous_assignee) { double(:user, id: 3) }
+
+ before(:each) do
+ issue.stub(:assignee_id).and_return(assignee.id)
+ issue.stub(:assignee_id_was).and_return(previous_assignee.id)
+ end
+
+ def it_sends_a_reassigned_email_to(recipient)
+ Notify.should_receive(:reassigned_issue_email).with(recipient, issue.id, previous_assignee.id).
+ and_return(double(deliver: true))
+ end
+
+ def it_does_not_send_a_reassigned_email_to(recipient)
+ Notify.should_not_receive(:reassigned_issue_email).with(recipient, issue.id, previous_assignee.id)
+ end
+
+ it 'sends a reassigned email to the previous and current assignees' do
+ it_sends_a_reassigned_email_to assignee.id
+ it_sends_a_reassigned_email_to previous_assignee.id
+
+ subject.send(:send_reassigned_email, issue)
+ end
+
+ context 'does not send an email to the user who made the reassignment' do
+ it 'if the user is the assignee' do
+ subject.stub(:current_user).and_return(assignee)
+ it_sends_a_reassigned_email_to previous_assignee.id
+ it_does_not_send_a_reassigned_email_to assignee.id
+
+ subject.send(:send_reassigned_email, issue)
+ end
+ it 'if the user is the previous assignee' do
+ subject.stub(:current_user).and_return(previous_assignee)
+ it_sends_a_reassigned_email_to assignee.id
+ it_does_not_send_a_reassigned_email_to previous_assignee.id
+
+ subject.send(:send_reassigned_email, issue)
end
end
end
diff --git a/spec/observers/key_observer_spec.rb b/spec/observers/key_observer_spec.rb
index 452844cb..7f2a76a3 100644
--- a/spec/observers/key_observer_spec.rb
+++ b/spec/observers/key_observer_spec.rb
@@ -1,22 +1,33 @@
require 'spec_helper'
describe KeyObserver do
- before do
- @key = create(:personal_key)
+ before do
+ @key = double('Key',
+ identifier: 'admin_654654',
+ key: '== a vaild ssh key',
+ projects: [],
+ is_deploy_key: false
+ )
+
+ @gitolite = double('Gitlab::Gitolite',
+ set_key: true,
+ remove_key: true
+ )
@observer = KeyObserver.instance
+ @observer.stub(:git_host => @gitolite)
end
context :after_save do
it do
- GitlabShellWorker.should_receive(:perform_async).with(:add_key, @key.shell_id, @key.key)
+ @gitolite.should_receive(:set_key).with(@key.identifier, @key.key, @key.projects)
@observer.after_save(@key)
end
end
- context :after_destroy do
+ context :after_destroy do
it do
- GitlabShellWorker.should_receive(:perform_async).with(:remove_key, @key.shell_id, @key.key)
+ @gitolite.should_receive(:remove_key).with(@key.identifier, @key.projects)
@observer.after_destroy(@key)
end
end
diff --git a/spec/observers/merge_request_observer_spec.rb b/spec/observers/merge_request_observer_spec.rb
index 2593da72..6b15be96 100644
--- a/spec/observers/merge_request_observer_spec.rb
+++ b/spec/observers/merge_request_observer_spec.rb
@@ -1,17 +1,12 @@
require 'spec_helper'
describe MergeRequestObserver do
- let(:some_user) { create :user }
- let(:assignee) { create :user }
- let(:author) { create :user }
- let(:mr_mock) { double(:merge_request, id: 42, assignee: assignee, author: author) }
- let(:assigned_mr) { create(:merge_request, assignee: assignee, author: author) }
- let(:unassigned_mr) { create(:merge_request, author: author) }
- let(:closed_assigned_mr) { create(:closed_merge_request, assignee: assignee, author: author) }
- let(:closed_unassigned_mr) { create(:closed_merge_request, author: author) }
+ let(:some_user) { double(:user, id: 1) }
+ let(:assignee) { double(:user, id: 2) }
+ let(:author) { double(:user, id: 3) }
+ let(:mr) { double(:merge_request, id: 42, assignee: assignee, author: author) }
- before { subject.stub(:current_user).and_return(some_user) }
- before { subject.stub(notification: mock('NotificationService').as_null_object) }
+ before(:each) { subject.stub(:current_user).and_return(some_user) }
subject { MergeRequestObserver.instance }
@@ -19,18 +14,32 @@ describe MergeRequestObserver do
it 'is called when a merge request is created' do
subject.should_receive(:after_create)
- create(:merge_request, project: create(:project))
+
+ MergeRequest.observers.enable :merge_request_observer do
+ create(:merge_request, project: create(:project))
+ end
end
- it 'trigger notification service' do
- subject.should_receive(:notification)
- subject.after_create(mr_mock)
+ it 'sends an email to the assignee' do
+ Notify.should_receive(:new_merge_request_email).with(mr.id).
+ and_return(double(deliver: true))
+
+ subject.after_create(mr)
+ end
+
+ it 'does not send an email to the assignee if assignee created the merge request' do
+ subject.stub(:current_user).and_return(assignee)
+ Notify.should_not_receive(:new_merge_request_email)
+
+ subject.after_create(mr)
end
end
context '#after_update' do
before(:each) do
- mr_mock.stub(:is_being_reassigned?).and_return(false)
+ mr.stub(:is_being_reassigned?).and_return(false)
+ mr.stub(:is_being_closed?).and_return(false)
+ mr.stub(:is_being_reopened?).and_return(false)
end
it 'is called when a merge request is changed' do
@@ -43,51 +52,141 @@ describe MergeRequestObserver do
end
end
- context 'a notification' do
+ context 'a reassigned email' do
it 'is sent if the merge request is being reassigned' do
- mr_mock.should_receive(:is_being_reassigned?).and_return(true)
- subject.should_receive(:notification)
+ mr.should_receive(:is_being_reassigned?).and_return(true)
+ subject.should_receive(:send_reassigned_email).with(mr)
- subject.after_update(mr_mock)
+ subject.after_update(mr)
end
it 'is not sent if the merge request is not being reassigned' do
- mr_mock.should_receive(:is_being_reassigned?).and_return(false)
- subject.should_not_receive(:notification)
+ mr.should_receive(:is_being_reassigned?).and_return(false)
+ subject.should_not_receive(:send_reassigned_email)
- subject.after_update(mr_mock)
+ subject.after_update(mr)
end
end
- end
- 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, some_user, 'closed')
+ mr.should_receive(:is_being_closed?).and_return(true)
+ Note.should_receive(:create_status_change_note).with(mr, some_user, 'closed')
- assigned_mr.close
+ subject.after_update(mr)
+ end
+
+ it 'note is not created if the merge request is not being closed' do
+ mr.should_receive(:is_being_closed?).and_return(false)
+ Note.should_not_receive(:create_status_change_note).with(mr, some_user, 'closed')
+
+ subject.after_update(mr)
+ end
+
+ it 'notification is delivered if the merge request being closed' do
+ mr.stub(:is_being_closed?).and_return(true)
+ Note.should_receive(:create_status_change_note).with(mr, some_user, 'closed')
+
+ subject.after_update(mr)
+ end
+
+ it 'notification is not delivered if the merge request not being closed' do
+ mr.stub(:is_being_closed?).and_return(false)
+ Note.should_not_receive(:create_status_change_note).with(mr, some_user, 'closed')
+
+ subject.after_update(mr)
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, some_user, 'closed')
+ mr_without_assignee = double(:merge_request, id: 42, author: author, assignee: nil)
+ mr_without_assignee.stub(:is_being_reassigned?).and_return(false)
+ mr_without_assignee.stub(:is_being_closed?).and_return(true)
+ mr_without_assignee.stub(:is_being_reopened?).and_return(false)
+ Note.should_receive(:create_status_change_note).with(mr_without_assignee, some_user, 'closed')
- unassigned_mr.close
+ subject.after_update(mr_without_assignee)
+ end
+ end
+
+ context 'a status "reopened"' do
+ it 'note is created if the merge request is being reopened' do
+ mr.should_receive(:is_being_reopened?).and_return(true)
+ Note.should_receive(:create_status_change_note).with(mr, some_user, 'reopened')
+
+ subject.after_update(mr)
+ end
+
+ it 'note is not created if the merge request is not being reopened' do
+ mr.should_receive(:is_being_reopened?).and_return(false)
+ Note.should_not_receive(:create_status_change_note).with(mr, some_user, 'reopened')
+
+ subject.after_update(mr)
+ end
+
+ it 'notification is delivered if the merge request being reopened' do
+ mr.stub(:is_being_reopened?).and_return(true)
+ Note.should_receive(:create_status_change_note).with(mr, some_user, 'reopened')
+
+ subject.after_update(mr)
+ end
+
+ it 'notification is not delivered if the merge request is not being reopened' do
+ mr.stub(:is_being_reopened?).and_return(false)
+ Note.should_not_receive(:create_status_change_note).with(mr, some_user, 'reopened')
+
+ subject.after_update(mr)
+ end
+
+ it 'notification is delivered only to author if the merge request is being reopened' do
+ mr_without_assignee = double(:merge_request, id: 42, author: author, assignee: nil)
+ mr_without_assignee.stub(:is_being_reassigned?).and_return(false)
+ mr_without_assignee.stub(:is_being_closed?).and_return(false)
+ mr_without_assignee.stub(:is_being_reopened?).and_return(true)
+ Note.should_receive(:create_status_change_note).with(mr_without_assignee, some_user, 'reopened')
+
+ subject.after_update(mr_without_assignee)
end
end
end
- 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, some_user, 'reopened')
+ describe '#send_reassigned_email' do
+ let(:previous_assignee) { double(:user, id: 3) }
- closed_assigned_mr.reopen
+ before(:each) do
+ mr.stub(:assignee_id).and_return(assignee.id)
+ mr.stub(:assignee_id_was).and_return(previous_assignee.id)
+ end
+
+ def it_sends_a_reassigned_email_to(recipient)
+ Notify.should_receive(:reassigned_merge_request_email).with(recipient, mr.id, previous_assignee.id).
+ and_return(double(deliver: true))
+ end
+
+ def it_does_not_send_a_reassigned_email_to(recipient)
+ Notify.should_not_receive(:reassigned_merge_request_email).with(recipient, mr.id, previous_assignee.id)
+ end
+
+ it 'sends a reassigned email to the previous and current assignees' do
+ it_sends_a_reassigned_email_to assignee.id
+ it_sends_a_reassigned_email_to previous_assignee.id
+
+ subject.send(:send_reassigned_email, mr)
+ end
+
+ context 'does not send an email to the user who made the reassignment' do
+ it 'if the user is the assignee' do
+ subject.stub(:current_user).and_return(assignee)
+ it_sends_a_reassigned_email_to previous_assignee.id
+ it_does_not_send_a_reassigned_email_to assignee.id
+
+ subject.send(:send_reassigned_email, mr)
end
+ it 'if the user is the previous assignee' do
+ subject.stub(:current_user).and_return(previous_assignee)
+ it_sends_a_reassigned_email_to assignee.id
+ it_does_not_send_a_reassigned_email_to previous_assignee.id
- 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, some_user, 'reopened')
-
- closed_unassigned_mr.reopen
+ subject.send(:send_reassigned_email, mr)
end
end
end
diff --git a/spec/observers/note_observer_spec.rb b/spec/observers/note_observer_spec.rb
index 9ada9270..7dfa9f77 100644
--- a/spec/observers/note_observer_spec.rb
+++ b/spec/observers/note_observer_spec.rb
@@ -2,9 +2,9 @@ require 'spec_helper'
describe NoteObserver do
subject { NoteObserver.instance }
- before { subject.stub(notification: mock('NotificationService').as_null_object) }
let(:team_without_author) { (1..2).map { |n| double :user, id: n } }
+ let(:delivery_success) { double deliver: true }
describe '#after_create' do
let(:note) { double :note }
@@ -18,9 +18,111 @@ describe NoteObserver do
end
it 'sends out notifications' do
- subject.should_receive(:notification)
+ subject.should_receive(:send_notify_mails).with(note)
subject.after_create(note)
end
end
+
+ describe "#send_notify_mails" do
+ let(:note) { double :note, notify: false, notify_author: false }
+
+ it 'notifies team of new note when flagged to notify' do
+ note.stub(:notify).and_return(true)
+ subject.should_receive(:notify_team).with(note)
+
+ subject.after_create(note)
+ end
+
+ it 'does not notify team of new note when not flagged to notify' do
+ subject.should_not_receive(:notify_team).with(note)
+
+ subject.after_create(note)
+ end
+
+ it 'notifies the author of a commit when flagged to notify the author' do
+ note.stub(:notify_author).and_return(true)
+ note.stub(:id).and_return(42)
+ author = double :user, id: 1
+ note.stub(:commit_author).and_return(author)
+ Notify.should_receive(:note_commit_email).and_return(delivery_success)
+
+ subject.after_create(note)
+ end
+
+ it 'does not notify the author of a commit when not flagged to notify the author' do
+ Notify.should_not_receive(:note_commit_email)
+
+ subject.after_create(note)
+ end
+
+ it 'does nothing if no notify flags are set' do
+ subject.after_create(note).should be_nil
+ end
+ end
+
+ describe '#notify_team' do
+ let(:note) { double :note, id: 1 }
+
+ before :each do
+ subject.stub(:team_without_note_author).with(note).and_return(team_without_author)
+ end
+
+ context 'notifies team of a new note on' do
+ it 'a commit' do
+ note.stub(:noteable_type).and_return('Commit')
+ Notify.should_receive(:note_commit_email).twice.and_return(delivery_success)
+
+ subject.send(:notify_team, note)
+ end
+
+ it 'an issue' do
+ note.stub(:noteable_type).and_return('Issue')
+ Notify.should_receive(:note_issue_email).twice.and_return(delivery_success)
+
+ subject.send(:notify_team, note)
+ end
+
+ it 'a wiki page' do
+ note.stub(:noteable_type).and_return('Wiki')
+ Notify.should_receive(:note_wiki_email).twice.and_return(delivery_success)
+
+ subject.send(:notify_team, note)
+ end
+
+ it 'a merge request' do
+ note.stub(:noteable_type).and_return('MergeRequest')
+ Notify.should_receive(:note_merge_request_email).twice.and_return(delivery_success)
+
+ subject.send(:notify_team, note)
+ end
+
+ it 'a wall' do
+ # Note: wall posts have #noteable_type of nil
+ note.stub(:noteable_type).and_return(nil)
+ Notify.should_receive(:note_wall_email).twice.and_return(delivery_success)
+
+ subject.send(:notify_team, note)
+ end
+ end
+
+ it 'does nothing for a new note on a snippet' do
+ note.stub(:noteable_type).and_return('Snippet')
+
+ subject.send(:notify_team, note).should be_nil
+ end
+ end
+
+
+ describe '#team_without_note_author' do
+ let(:author) { double :user, id: 4 }
+
+ let(:users) { team_without_author + [author] }
+ let(:project) { double :project, users: users }
+ let(:note) { double :note, project: project, author: author }
+
+ it 'returns the projects user without the note author included' do
+ subject.send(:team_without_note_author, note).should == team_without_author
+ end
+ end
end
diff --git a/spec/observers/user_observer_spec.rb b/spec/observers/user_observer_spec.rb
index 5b735a8f..4ba0f05d 100644
--- a/spec/observers/user_observer_spec.rb
+++ b/spec/observers/user_observer_spec.rb
@@ -2,24 +2,35 @@ require 'spec_helper'
describe UserObserver do
subject { UserObserver.instance }
- before { subject.stub(notification: mock('NotificationService').as_null_object) }
it 'calls #after_create when new users are created' do
new_user = build(:user)
subject.should_receive(:after_create).with(new_user)
- new_user.save
+
+ User.observers.enable :user_observer do
+ new_user.save
+ end
end
context 'when a new user is created' do
+ let(:user) { double(:user, id: 42,
+ password: 'P@ssword!',
+ name: 'John',
+ email: 'u@mail.local',
+ username: 'root',
+ create_namespace: true) }
+ let(:notification) { double :notification }
+
it 'sends an email' do
- subject.should_receive(:notification)
- create(:user)
+ notification.should_receive(:deliver)
+ Notify.should_receive(:new_user_email).with(user.id, user.password).and_return(notification)
+
+ subject.after_create(user)
end
it 'trigger logger' do
- user = double(:user, id: 42, password: 'P@ssword!', name: 'John', email: 'u@mail.local', extern_uid?: false)
Gitlab::AppLogger.should_receive(:info)
- create(:user)
+ subject.after_create(user)
end
end
end
diff --git a/spec/observers/users_project_observer_spec.rb b/spec/observers/users_project_observer_spec.rb
index c034501e..548f1893 100644
--- a/spec/observers/users_project_observer_spec.rb
+++ b/spec/observers/users_project_observer_spec.rb
@@ -3,63 +3,72 @@ require 'spec_helper'
describe UsersProjectObserver do
let(:user) { create(:user) }
let(:project) { create(:project) }
+ let(:users_project) { create(:users_project,
+ project: project,
+ user: user )}
subject { UsersProjectObserver.instance }
- before { subject.stub(notification: mock('NotificationService').as_null_object) }
describe "#after_commit" do
it "should called when UsersProject created" do
- subject.should_receive(:after_commit)
- create(:users_project)
+ subject.should_receive(:after_commit).once
+ UsersProject.observers.enable :users_project_observer do
+ create(:users_project)
+ end
end
it "should send email to user" do
- subject.should_receive(:notification)
+ Notify.should_receive(:project_access_granted_email).with(users_project.id).and_return(double(deliver: true))
+ subject.after_commit(users_project)
Event.stub(:create => true)
-
- create(:users_project)
end
it "should create new event" do
- Event.should_receive(:create)
+ Event.should_receive(:create).with(
+ project_id: users_project.project.id,
+ action: Event::Joined,
+ author_id: users_project.user.id
+ )
- create(:users_project)
+ subject.after_create(users_project)
end
end
describe "#after_update" do
- before do
- @users_project = create :users_project
- end
-
it "should called when UsersProject updated" do
- subject.should_receive(:after_commit)
- @users_project.update_attribute(:project_access, UsersProject::MASTER)
+ subject.should_receive(:after_commit).once
+ UsersProject.observers.enable :users_project_observer do
+ create(:users_project).update_attribute(:project_access, UsersProject::MASTER)
+ end
end
it "should send email to user" do
- subject.should_receive(:notification)
- @users_project.update_attribute(:project_access, UsersProject::MASTER)
+ Notify.should_receive(:project_access_granted_email).with(users_project.id).and_return(double(deliver: true))
+ subject.after_commit(users_project)
end
-
it "should not called after UsersProject destroyed" do
subject.should_not_receive(:after_commit)
- @users_project.destroy
+ UsersProject.observers.enable :users_project_observer do
+ users_project.destroy
+ end
end
end
describe "#after_destroy" do
- before do
- @users_project = create :users_project
- end
-
it "should called when UsersProject destroyed" do
subject.should_receive(:after_destroy)
- @users_project.destroy
+
+ UsersProject.observers.enable :users_project_observer do
+ create(:users_project).destroy
+ end
end
it "should create new event" do
- Event.should_receive(:create)
- @users_project.destroy
+ Event.should_receive(:create).with(
+ project_id: users_project.project.id,
+ action: Event::Left,
+ author_id: users_project.user.id
+ )
+ subject.after_destroy(users_project)
end
end
end
diff --git a/spec/features/admin/admin_hooks_spec.rb b/spec/requests/admin/admin_hooks_spec.rb
similarity index 97%
rename from spec/features/admin/admin_hooks_spec.rb
rename to spec/requests/admin/admin_hooks_spec.rb
index 102a1b92..bc0586b2 100644
--- a/spec/features/admin/admin_hooks_spec.rb
+++ b/spec/requests/admin/admin_hooks_spec.rb
@@ -12,7 +12,7 @@ describe "Admin::Hooks" do
describe "GET /admin/hooks" do
it "should be ok" do
visit admin_root_path
- within ".main-nav" do
+ within ".main_menu" do
click_on "Hooks"
end
current_path.should == admin_hooks_path
diff --git a/spec/requests/admin/admin_projects_spec.rb b/spec/requests/admin/admin_projects_spec.rb
new file mode 100644
index 00000000..c9ddf1f4
--- /dev/null
+++ b/spec/requests/admin/admin_projects_spec.rb
@@ -0,0 +1,76 @@
+require 'spec_helper'
+
+describe "Admin::Projects" do
+ before do
+ @project = create(:project)
+ login_as :admin
+ end
+
+ describe "GET /admin/projects" do
+ before do
+ visit admin_projects_path
+ end
+
+ it "should be ok" do
+ current_path.should == admin_projects_path
+ end
+
+ it "should have projects list" do
+ page.should have_content(@project.name)
+ end
+ end
+
+ describe "GET /admin/projects/:id" do
+ before do
+ visit admin_projects_path
+ click_link "#{@project.name}"
+ end
+
+ it "should have project info" do
+ page.should have_content(@project.path)
+ page.should have_content(@project.name)
+ end
+ end
+
+ describe "GET /admin/projects/:id/edit" do
+ before do
+ visit admin_projects_path
+ click_link "edit_project_#{@project.id}"
+ end
+
+ it "should have project edit page" do
+ page.should have_content("Edit project")
+ page.should have_button("Save Project")
+ end
+
+ describe "Update project" do
+ before do
+ fill_in "project_name", with: "Big Bang"
+ click_button "Save Project"
+ @project.reload
+ end
+
+ it "should show page with new data" do
+ page.should have_content("Big Bang")
+ end
+
+ it "should change project entry" do
+ @project.name.should == "Big Bang"
+ end
+ end
+ end
+
+ describe "Add new team member" do
+ before do
+ @new_user = create(:user)
+ visit admin_project_path(@project)
+ end
+
+ it "should create new user" do
+ select @new_user.name, from: "user_ids"
+ expect { click_button "Add" }.to change { UsersProject.count }.by(1)
+ page.should have_content @new_user.name
+ current_path.should == admin_project_path(@project)
+ end
+ end
+end
diff --git a/spec/features/admin/admin_users_spec.rb b/spec/requests/admin/admin_users_spec.rb
similarity index 79%
rename from spec/features/admin/admin_users_spec.rb
rename to spec/requests/admin/admin_users_spec.rb
index 22d1ee91..ca134c2d 100644
--- a/spec/features/admin/admin_users_spec.rb
+++ b/spec/requests/admin/admin_users_spec.rb
@@ -41,7 +41,7 @@ describe "Admin::Users" do
end
it "should call send mail" do
- Notify.should_receive(:new_user_email)
+ Notify.should_receive(:new_user_email).and_return(stub(deliver: true))
User.observers.enable :user_observer do
click_button "Save"
@@ -49,26 +49,15 @@ describe "Admin::Users" do
end
it "should send valid email to user with email & password" do
- Gitlab.config.gitlab.stub(:signup_enabled).and_return(false)
User.observers.enable :user_observer do
- click_button "Save"
+ with_resque do
+ click_button "Save"
+ end
user = User.last
email = ActionMailer::Base.deliveries.last
email.subject.should have_content("Account was created")
- email.text_part.body.should have_content(user.email)
- email.text_part.body.should have_content(@password)
- end
- end
-
- it "should send valid email to user with email without password when signup is enabled" do
- Gitlab.config.gitlab.stub(:signup_enabled).and_return(true)
- User.observers.enable :user_observer do
- click_button "Save"
- user = User.last
- email = ActionMailer::Base.deliveries.last
- email.subject.should have_content("Account was created")
- email.text_part.body.should have_content(user.email)
- email.text_part.body.should_not have_content(@password)
+ email.body.should have_content(user.email)
+ email.body.should have_content(@password)
end
end
end
@@ -82,6 +71,7 @@ describe "Admin::Users" do
it "should have user info" do
page.should have_content(@user.email)
page.should have_content(@user.name)
+ page.should have_content(@user.projects_limit)
end
end
diff --git a/spec/features/admin/security_spec.rb b/spec/requests/admin/security_spec.rb
similarity index 100%
rename from spec/features/admin/security_spec.rb
rename to spec/requests/admin/security_spec.rb
diff --git a/spec/requests/api/groups_spec.rb b/spec/requests/api/groups_spec.rb
deleted file mode 100644
index e97ceb2c..00000000
--- a/spec/requests/api/groups_spec.rb
+++ /dev/null
@@ -1,126 +0,0 @@
-require 'spec_helper'
-
-describe Gitlab::API do
- include ApiHelpers
-
- let(:user1) { create(:user) }
- let(:user2) { create(:user) }
- let(:admin) { create(:admin) }
- let!(:group1) { create(:group, owner: user1) }
- let!(:group2) { create(:group, owner: user2) }
-
- describe "GET /groups" do
- context "when unauthenticated" do
- it "should return authentication error" do
- get api("/groups")
- response.status.should == 401
- end
- end
-
- context "when authenticated as user" do
- it "normal user: should return an array of groups of user1" do
- get api("/groups", user1)
- response.status.should == 200
- json_response.should be_an Array
- json_response.length.should == 1
- json_response.first['name'].should == group1.name
- end
- end
-
- context "when authenticated as admin" do
- it "admin: should return an array of all groups" do
- get api("/groups", admin)
- response.status.should == 200
- json_response.should be_an Array
- json_response.length.should == 2
- end
- end
- end
-
- describe "GET /groups/:id" do
- context "when authenticated as user" do
- it "should return one of user1's groups" do
- get api("/groups/#{group1.id}", user1)
- response.status.should == 200
- json_response['name'] == group1.name
- end
-
- it "should not return a non existing group" do
- get api("/groups/1328", user1)
- response.status.should == 404
- end
-
- it "should not return a group not attached to user1" do
- get api("/groups/#{group2.id}", user1)
- response.status.should == 404
- end
- end
-
- context "when authenticated as admin" do
- it "should return any existing group" do
- get api("/groups/#{group2.id}", admin)
- response.status.should == 200
- json_response['name'] == group2.name
- end
-
- it "should not return a non existing group" do
- get api("/groups/1328", admin)
- response.status.should == 404
- end
- end
- end
-
- describe "POST /groups" do
- context "when authenticated as user" do
- it "should not create group" do
- post api("/groups", user1), attributes_for(:group)
- response.status.should == 403
- end
- end
-
- context "when authenticated as admin" do
- it "should create group" do
- post api("/groups", admin), attributes_for(:group)
- response.status.should == 201
- end
-
- it "should not create group, duplicate" do
- post api("/groups", admin), {:name => "Duplicate Test", :path => group2.path}
- response.status.should == 404
- end
-
- it "should return 400 bad request error if name not given" do
- post api("/groups", admin), { :path => group2.path }
- response.status.should == 400
- end
-
- it "should return 400 bad request error if path not given" do
- post api("/groups", admin), { :name => 'test' }
- response.status.should == 400
- end
- end
- end
-
- describe "POST /groups/:id/projects/:project_id" do
- let(:project) { create(:project) }
- before(:each) do
- project.stub!(:transfer).and_return(true)
- Project.stub(:find).and_return(project)
- end
-
-
- context "when authenticated as user" do
- it "should not transfer project to group" do
- post api("/groups/#{group1.id}/projects/#{project.id}", user2)
- response.status.should == 403
- end
- end
-
- context "when authenticated as admin" do
- it "should transfer project to group" do
- project.should_receive(:transfer)
- post api("/groups/#{group1.id}/projects/#{project.id}", admin)
- end
- end
- end
-end
diff --git a/spec/requests/api/internal_spec.rb b/spec/requests/api/internal_spec.rb
deleted file mode 100644
index ba11a41d..00000000
--- a/spec/requests/api/internal_spec.rb
+++ /dev/null
@@ -1,124 +0,0 @@
-require 'spec_helper'
-
-describe Gitlab::API do
- include ApiHelpers
-
- let(:user) { create(:user) }
- let(:key) { create(:key, user: user) }
- let(:project) { create(:project) }
-
- describe "GET /internal/check", no_db: true do
- it do
- get api("/internal/check")
-
- response.status.should == 200
- json_response['api_version'].should == Gitlab::API.version
- end
- end
-
- describe "GET /internal/discover" do
- it do
- get(api("/internal/discover"), key_id: key.id)
-
- response.status.should == 200
-
- json_response['name'].should == user.name
- end
- end
-
- describe "GET /internal/allowed" do
- context "access granted" do
- before do
- project.team << [user, :developer]
- end
-
- context "git pull" do
- it do
- pull(key, project)
-
- response.status.should == 200
- response.body.should == 'true'
- end
- end
-
- context "git push" do
- it do
- push(key, project)
-
- response.status.should == 200
- response.body.should == 'true'
- end
- end
- end
-
- context "access denied" do
- before do
- project.team << [user, :guest]
- end
-
- context "git pull" do
- it do
- pull(key, project)
-
- response.status.should == 200
- response.body.should == 'false'
- end
- end
-
- context "git push" do
- it do
- push(key, project)
-
- response.status.should == 200
- response.body.should == 'false'
- end
- end
- end
-
- context "blocked user" do
- let(:personal_project) { create(:project, namespace: user.namespace) }
-
- before do
- user.block
- end
-
- context "git pull" do
- it do
- pull(key, personal_project)
-
- response.status.should == 200
- response.body.should == 'false'
- end
- end
-
- context "git push" do
- it do
- push(key, personal_project)
-
- response.status.should == 200
- response.body.should == 'false'
- end
- end
- end
- end
-
- def pull(key, project)
- get(
- api("/internal/allowed"),
- ref: 'master',
- key_id: key.id,
- project: project.path_with_namespace,
- action: 'git-upload-pack'
- )
- end
-
- def push(key, project)
- get(
- api("/internal/allowed"),
- ref: 'master',
- key_id: key.id,
- project: project.path_with_namespace,
- action: 'git-receive-pack'
- )
- end
-end
diff --git a/spec/requests/api/issues_spec.rb b/spec/requests/api/issues_spec.rb
index ecf0bdb7..1850ecb9 100644
--- a/spec/requests/api/issues_spec.rb
+++ b/spec/requests/api/issues_spec.rb
@@ -4,9 +4,9 @@ describe Gitlab::API do
include ApiHelpers
let(:user) { create(:user) }
- let!(:project) { create(:project, namespace: user.namespace ) }
+ let!(:project) { create(:project, owner: user) }
let!(:issue) { create(:issue, author: user, assignee: user, project: project) }
- before { project.team << [user, :reporter] }
+ before { project.add_access(user, :read) }
describe "GET /issues" do
context "when unauthenticated" do
@@ -28,7 +28,7 @@ describe Gitlab::API do
describe "GET /projects/:id/issues" do
it "should return project issues" do
- get api("/projects/#{project.id}/issues", user)
+ get api("/projects/#{project.path}/issues", user)
response.status.should == 200
json_response.should be_an Array
json_response.first['title'].should == issue.title
@@ -37,63 +37,37 @@ describe Gitlab::API do
describe "GET /projects/:id/issues/:issue_id" do
it "should return a project issue by id" do
- get api("/projects/#{project.id}/issues/#{issue.id}", user)
+ get api("/projects/#{project.path}/issues/#{issue.id}", user)
response.status.should == 200
json_response['title'].should == issue.title
end
-
- it "should return 404 if issue id not found" do
- get api("/projects/#{project.id}/issues/54321", user)
- response.status.should == 404
- end
end
describe "POST /projects/:id/issues" do
it "should create a new project issue" do
- post api("/projects/#{project.id}/issues", user),
+ post api("/projects/#{project.path}/issues", user),
title: 'new issue', labels: 'label, label2'
response.status.should == 201
json_response['title'].should == 'new issue'
json_response['description'].should be_nil
json_response['labels'].should == ['label', 'label2']
end
-
- it "should return a 400 bad request if title not given" do
- post api("/projects/#{project.id}/issues", user), labels: 'label, label2'
- response.status.should == 400
- end
end
- describe "PUT /projects/:id/issues/:issue_id to update only title" do
+ describe "PUT /projects/:id/issues/:issue_id" do
it "should update a project issue" do
- put api("/projects/#{project.id}/issues/#{issue.id}", user),
- title: 'updated title'
+ put api("/projects/#{project.path}/issues/#{issue.id}", user),
+ title: 'updated title', labels: 'label2', closed: 1
response.status.should == 200
-
json_response['title'].should == 'updated title'
- end
-
- it "should return 404 error if issue id not found" do
- put api("/projects/#{project.id}/issues/44444", user),
- title: 'updated title'
- response.status.should == 404
- end
- end
-
- describe "PUT /projects/:id/issues/:issue_id to update state and label" do
- it "should update a project issue" do
- put api("/projects/#{project.id}/issues/#{issue.id}", user),
- labels: 'label2', state_event: "close"
- response.status.should == 200
-
json_response['labels'].should == ['label2']
- json_response['state'].should eq "closed"
+ json_response['closed'].should be_true
end
end
describe "DELETE /projects/:id/issues/:issue_id" do
it "should delete a project issue" do
- delete api("/projects/#{project.id}/issues/#{issue.id}", user)
+ delete api("/projects/#{project.path}/issues/#{issue.id}", user)
response.status.should == 405
end
end
diff --git a/spec/requests/api/merge_requests_spec.rb b/spec/requests/api/merge_requests_spec.rb
index 25bbd986..43931aed 100644
--- a/spec/requests/api/merge_requests_spec.rb
+++ b/spec/requests/api/merge_requests_spec.rb
@@ -4,21 +4,21 @@ describe Gitlab::API do
include ApiHelpers
let(:user) { create(:user ) }
- let!(:project) { create(:project_with_code, creator_id: user.id) }
+ let!(:project) { create(:project, owner: user) }
let!(:merge_request) { create(:merge_request, author: user, assignee: user, project: project, title: "Test") }
- before { project.team << [user, :reporters] }
+ before { project.add_access(user, :read) }
describe "GET /projects/:id/merge_requests" do
context "when unauthenticated" do
it "should return authentication error" do
- get api("/projects/#{project.id}/merge_requests")
+ get api("/projects/#{project.path}/merge_requests")
response.status.should == 401
end
end
context "when authenticated" do
it "should return an array of merge_requests" do
- get api("/projects/#{project.id}/merge_requests", user)
+ get api("/projects/#{project.path}/merge_requests", user)
response.status.should == 200
json_response.should be_an Array
json_response.first['title'].should == merge_request.title
@@ -28,102 +28,35 @@ describe Gitlab::API do
describe "GET /projects/:id/merge_request/:merge_request_id" do
it "should return merge_request" do
- get api("/projects/#{project.id}/merge_request/#{merge_request.id}", user)
+ get api("/projects/#{project.path}/merge_request/#{merge_request.id}", user)
response.status.should == 200
json_response['title'].should == merge_request.title
end
-
- it "should return a 404 error if merge_request_id not found" do
- get api("/projects/#{project.id}/merge_request/999", user)
- response.status.should == 404
- end
end
describe "POST /projects/:id/merge_requests" do
it "should return merge_request" do
- post api("/projects/#{project.id}/merge_requests", user),
+ post api("/projects/#{project.path}/merge_requests", 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
- 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
- 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
- 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'
- response.status.should == 400
- end
- end
-
- describe "PUT /projects/:id/merge_request/:merge_request_id to close MR" do
- it "should return merge_request" do
- put api("/projects/#{project.id}/merge_request/#{merge_request.id}", user), state_event: "close"
- response.status.should == 200
- json_response['state'].should == 'closed'
- end
- end
-
- describe "PUT /projects/:id/merge_request/:merge_request_id to merge MR" do
- it "should return merge_request" do
- put api("/projects/#{project.id}/merge_request/#{merge_request.id}", user), state_event: "merge"
- response.status.should == 200
- json_response['state'].should == 'merged'
- end
end
describe "PUT /projects/:id/merge_request/:merge_request_id" do
it "should return merge_request" do
- put api("/projects/#{project.id}/merge_request/#{merge_request.id}", user), title: "New title"
+ put api("/projects/#{project.path}/merge_request/#{merge_request.id}", user), title: "New title"
response.status.should == 200
json_response['title'].should == 'New title'
end
-
- 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"
- response.status.should == 422
- end
-
- it "should return merge_request with renamed target_branch" do
- put api("/projects/#{project.id}/merge_request/#{merge_request.id}", user), target_branch: "test"
- response.status.should == 200
- json_response['target_branch'].should == 'test'
- end
end
describe "POST /projects/:id/merge_request/:merge_request_id/comments" do
it "should return comment" do
- post api("/projects/#{project.id}/merge_request/#{merge_request.id}/comments", user), note: "My comment"
+ post api("/projects/#{project.path}/merge_request/#{merge_request.id}/comments", user), note: "My comment"
response.status.should == 201
json_response['note'].should == 'My comment'
end
-
- it "should return 400 if note is missing" do
- post api("/projects/#{project.id}/merge_request/#{merge_request.id}/comments", user)
- response.status.should == 400
- end
-
- it "should return 404 if note is attached to non existent merge request" do
- post api("/projects/#{project.id}/merge_request/111/comments", user), note: "My comment"
- response.status.should == 404
- end
end
end
diff --git a/spec/requests/api/milestones_spec.rb b/spec/requests/api/milestones_spec.rb
index c379e8a5..dc96d46d 100644
--- a/spec/requests/api/milestones_spec.rb
+++ b/spec/requests/api/milestones_spec.rb
@@ -4,87 +4,44 @@ describe Gitlab::API do
include ApiHelpers
let(:user) { create(:user) }
- let!(:project) { create(:project, namespace: user.namespace ) }
+ let!(:project) { create(:project, owner: user) }
let!(:milestone) { create(:milestone, project: project) }
- before { project.team << [user, :developer] }
+ before { project.add_access(user, :read) }
describe "GET /projects/:id/milestones" do
it "should return project milestones" do
- get api("/projects/#{project.id}/milestones", user)
+ get api("/projects/#{project.path}/milestones", user)
response.status.should == 200
json_response.should be_an Array
json_response.first['title'].should == milestone.title
end
-
- it "should return a 401 error if user not authenticated" do
- get api("/projects/#{project.id}/milestones")
- response.status.should == 401
- end
end
describe "GET /projects/:id/milestones/:milestone_id" do
it "should return a project milestone by id" do
- get api("/projects/#{project.id}/milestones/#{milestone.id}", user)
+ get api("/projects/#{project.path}/milestones/#{milestone.id}", user)
response.status.should == 200
json_response['title'].should == milestone.title
end
-
- it "should return 401 error if user not authenticated" do
- get api("/projects/#{project.id}/milestones/#{milestone.id}")
- response.status.should == 401
- end
-
- it "should return a 404 error if milestone id not found" do
- get api("/projects/#{project.id}/milestones/1234", user)
- response.status.should == 404
- end
end
describe "POST /projects/:id/milestones" do
it "should create a new project milestone" do
- post api("/projects/#{project.id}/milestones", user), title: 'new milestone'
+ post api("/projects/#{project.path}/milestones", user),
+ title: 'new milestone'
response.status.should == 201
json_response['title'].should == 'new milestone'
json_response['description'].should be_nil
end
-
- it "should create a new project milestone with description and due date" do
- post api("/projects/#{project.id}/milestones", user),
- title: 'new milestone', description: 'release', due_date: '2013-03-02'
- response.status.should == 201
- json_response['description'].should == 'release'
- json_response['due_date'].should == '2013-03-02'
- end
-
- it "should return a 400 error if title is missing" do
- post api("/projects/#{project.id}/milestones", user)
- response.status.should == 400
- end
end
describe "PUT /projects/:id/milestones/:milestone_id" do
it "should update a project milestone" do
- put api("/projects/#{project.id}/milestones/#{milestone.id}", user),
+ put api("/projects/#{project.path}/milestones/#{milestone.id}", user),
title: 'updated title'
response.status.should == 200
json_response['title'].should == 'updated title'
end
-
- it "should return a 404 error if milestone id not found" do
- put api("/projects/#{project.id}/milestones/1234", user),
- title: 'updated title'
- response.status.should == 404
- end
- end
-
- describe "PUT /projects/:id/milestones/:milestone_id to close milestone" do
- it "should update a project milestone" do
- put api("/projects/#{project.id}/milestones/#{milestone.id}", user),
- state_event: 'close'
- response.status.should == 200
-
- json_response['state'].should == 'closed'
- end
end
end
diff --git a/spec/requests/api/notes_spec.rb b/spec/requests/api/notes_spec.rb
index 90164083..681ba015 100644
--- a/spec/requests/api/notes_spec.rb
+++ b/spec/requests/api/notes_spec.rb
@@ -4,15 +4,13 @@ describe Gitlab::API do
include ApiHelpers
let(:user) { create(:user) }
- let!(:project) { create(:project, namespace: user.namespace ) }
+ let!(:project) { create(:project, owner: user) }
let!(:issue) { create(:issue, project: project, author: user) }
- let!(:merge_request) { create(:merge_request, project: project, author: user) }
let!(:snippet) { create(:snippet, project: project, author: user) }
let!(:issue_note) { create(:note, noteable: issue, project: project, author: user) }
- let!(:merge_request_note) { create(:note, noteable: merge_request, project: project, author: user) }
let!(:snippet_note) { create(:note, noteable: snippet, project: project, author: user) }
let!(:wall_note) { create(:note, project: project, author: user) }
- before { project.team << [user, :reporter] }
+ before { project.add_access(user, :read) }
describe "GET /projects/:id/notes" do
context "when unauthenticated" do
@@ -38,11 +36,6 @@ describe Gitlab::API do
response.status.should == 200
json_response['body'].should == wall_note.note
end
-
- it "should return a 404 error if note not found" do
- get api("/projects/#{project.id}/notes/123", user)
- response.status.should == 404
- end
end
describe "POST /projects/:id/notes" do
@@ -51,16 +44,6 @@ describe Gitlab::API do
response.status.should == 201
json_response['body'].should == 'hi!'
end
-
- it "should return 401 unauthorized error" do
- post api("/projects/#{project.id}/notes")
- response.status.should == 401
- end
-
- it "should return a 400 bad request if body is missing" do
- post api("/projects/#{project.id}/notes", user)
- response.status.should == 400
- end
end
describe "GET /projects/:id/noteable/:noteable_id/notes" do
@@ -71,11 +54,6 @@ describe Gitlab::API do
json_response.should be_an Array
json_response.first['body'].should == issue_note.note
end
-
- it "should return a 404 error when issue id not found" do
- get api("/projects/#{project.id}/issues/123/notes", user)
- response.status.should == 404
- end
end
context "when noteable is a Snippet" do
@@ -85,25 +63,6 @@ describe Gitlab::API do
json_response.should be_an Array
json_response.first['body'].should == snippet_note.note
end
-
- it "should return a 404 error when snippet id not found" do
- get api("/projects/#{project.id}/snippets/42/notes", user)
- response.status.should == 404
- end
- end
-
- context "when noteable is a Merge Request" do
- it "should return an array of merge_requests notes" do
- get api("/projects/#{project.id}/merge_requests/#{merge_request.id}/notes", user)
- response.status.should == 200
- json_response.should be_an Array
- json_response.first['body'].should == merge_request_note.note
- end
-
- it "should return a 404 error if merge request id not found" do
- get api("/projects/#{project.id}/merge_requests/4444/notes", user)
- response.status.should == 404
- end
end
end
@@ -114,11 +73,6 @@ describe Gitlab::API do
response.status.should == 200
json_response['body'].should == issue_note.note
end
-
- it "should return a 404 error if issue note not found" do
- get api("/projects/#{project.id}/issues/#{issue.id}/notes/123", user)
- response.status.should == 404
- end
end
context "when noteable is a Snippet" do
@@ -127,11 +81,6 @@ describe Gitlab::API do
response.status.should == 200
json_response['body'].should == snippet_note.note
end
-
- it "should return a 404 error if snippet note not found" do
- get api("/projects/#{project.id}/snippets/#{snippet.id}/notes/123", user)
- response.status.should == 404
- end
end
end
@@ -143,16 +92,6 @@ describe Gitlab::API do
json_response['body'].should == 'hi!'
json_response['author']['email'].should == user.email
end
-
- it "should return a 400 bad request error if body not given" do
- post api("/projects/#{project.id}/issues/#{issue.id}/notes", user)
- response.status.should == 400
- end
-
- it "should return a 401 unauthorized error if user not authenticated" do
- post api("/projects/#{project.id}/issues/#{issue.id}/notes"), body: 'hi!'
- response.status.should == 401
- end
end
context "when noteable is a Snippet" do
@@ -162,16 +101,6 @@ describe Gitlab::API do
json_response['body'].should == 'hi!'
json_response['author']['email'].should == user.email
end
-
- it "should return a 400 bad request error if body not given" do
- post api("/projects/#{project.id}/snippets/#{snippet.id}/notes", user)
- response.status.should == 400
- end
-
- it "should return a 401 unauthorized error if user not authenticated" do
- post api("/projects/#{project.id}/snippets/#{snippet.id}/notes"), body: 'hi!'
- response.status.should == 401
- end
end
end
end
diff --git a/spec/requests/api/projects_spec.rb b/spec/requests/api/projects_spec.rb
index aca3919a..a3965164 100644
--- a/spec/requests/api/projects_spec.rb
+++ b/spec/requests/api/projects_spec.rb
@@ -6,15 +6,12 @@ describe Gitlab::API do
let(:user) { create(:user) }
let(:user2) { create(:user) }
let(:user3) { create(:user) }
- let(:admin) { create(:admin) }
- let!(:project) { create(:project_with_code, creator_id: user.id) }
let!(:hook) { create(:project_hook, project: project, url: "http://example.com") }
+ let!(:project) { create(:project, owner: user ) }
let!(:snippet) { create(: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) }
- let(:key) { create(:key, project: project) }
-
- before { project.team << [user, :reporter] }
+ before { project.add_access(user, :read) }
describe "GET /projects" do
context "when unauthenticated" do
@@ -36,20 +33,6 @@ describe Gitlab::API do
end
describe "POST /projects" do
- context "maximum number of projects reached" do
- before do
- (1..user2.projects_limit).each do |project|
- post api("/projects", user2), name: "foo#{project}"
- end
- end
-
- it "should not create new project" do
- expect {
- post api("/projects", user2), name: 'foo'
- }.to change {Project.count}.by(0)
- end
- end
-
it "should create new project without path" do
expect { post api("/projects", user), name: 'foo' }.to change {Project.count}.by(1)
end
@@ -58,33 +41,14 @@ describe Gitlab::API do
expect { post api("/projects", user) }.to_not change {Project.count}
end
- it "should return a 400 error if name not given" do
- post api("/projects", user)
- response.status.should == 400
- end
-
- it "should create last project before reaching project limit" do
- (1..user2.projects_limit-1).each { |p| post api("/projects", user2), name: "foo#{p}" }
- post api("/projects", user2), name: "foo"
- response.status.should == 201
- end
-
it "should respond with 201 on success" do
post api("/projects", user), name: 'foo'
response.status.should == 201
end
- it "should respond with 400 if name is not given" do
+ it "should respond with 404 on failure" do
post api("/projects", user)
- response.status.should == 400
- end
-
- it "should return a 403 error if project limit reached" do
- (1..user.projects_limit).each do |p|
- post api("/projects", user), name: "foo#{p}"
- end
- post api("/projects", user), name: 'bar'
- response.status.should == 403
+ response.status.should == 404
end
it "should assign attributes to project" do
@@ -100,47 +64,6 @@ describe Gitlab::API do
post api("/projects", user), project
project.each_pair do |k,v|
- next if k == :path
- json_response[k.to_s].should == v
- end
- end
- end
-
- describe "POST /projects/user/:id" do
- before { admin }
-
- it "should create new project without path" do
- expect { post api("/projects/user/#{user.id}", admin), name: 'foo' }.to change {Project.count}.by(1)
- end
-
- it "should not create new project without name" do
- expect { post api("/projects/user/#{user.id}", admin) }.to_not change {Project.count}
- end
-
- it "should respond with 201 on success" do
- post api("/projects/user/#{user.id}", admin), name: 'foo'
- response.status.should == 201
- end
-
- it "should respond with 404 on failure" do
- post api("/projects/user/#{user.id}", admin)
- response.status.should == 404
- end
-
- it "should assign attributes to project" do
- project = attributes_for(:project, {
- description: Faker::Lorem.sentence,
- default_branch: 'stable',
- issues_enabled: false,
- wall_enabled: false,
- merge_requests_enabled: false,
- wiki_enabled: false
- })
-
- post api("/projects/user/#{user.id}", admin), project
-
- project.each_pair do |k,v|
- next if k == :path
json_response[k.to_s].should == v
end
end
@@ -155,7 +78,7 @@ describe Gitlab::API do
end
it "should return a project by path name" do
- get api("/projects/#{project.id}", user)
+ get api("/projects/#{project.path}", user)
response.status.should == 200
json_response['name'].should == project.name
end
@@ -165,17 +88,11 @@ describe Gitlab::API do
response.status.should == 404
json_response['message'].should == '404 Not Found'
end
-
- it "should return a 404 error if user is not a member" do
- other_user = create(:user)
- get api("/projects/#{project.id}", other_user)
- response.status.should == 404
- end
end
describe "GET /projects/:id/repository/branches" do
it "should return an array of project branches" do
- get api("/projects/#{project.id}/repository/branches", user)
+ get api("/projects/#{project.path}/repository/branches", user)
response.status.should == 200
json_response.should be_an Array
json_response.first['name'].should == project.repo.heads.sort_by(&:name).first.name
@@ -184,67 +101,17 @@ describe Gitlab::API do
describe "GET /projects/:id/repository/branches/:branch" do
it "should return the branch information for a single branch" do
- get api("/projects/#{project.id}/repository/branches/new_design", user)
+ get api("/projects/#{project.path}/repository/branches/new_design", user)
response.status.should == 200
json_response['name'].should == 'new_design'
json_response['commit']['id'].should == '621491c677087aa243f165eab467bfdfbee00be1'
- json_response['protected'].should == false
- end
-
- it "should return a 404 error if branch is not available" do
- get api("/projects/#{project.id}/repository/branches/unknown", user)
- response.status.should == 404
- end
- end
-
- describe "PUT /projects/:id/repository/branches/:branch/protect" do
- it "should protect a single branch" do
- put api("/projects/#{project.id}/repository/branches/new_design/protect", user)
- response.status.should == 200
-
- json_response['name'].should == 'new_design'
- json_response['commit']['id'].should == '621491c677087aa243f165eab467bfdfbee00be1'
- json_response['protected'].should == true
- end
-
- it "should return a 404 error if branch not found" do
- put api("/projects/#{project.id}/repository/branches/unknown/protect", user)
- response.status.should == 404
- end
-
- it "should return success when protect branch again" do
- put api("/projects/#{project.id}/repository/branches/new_design/protect", user)
- put api("/projects/#{project.id}/repository/branches/new_design/protect", user)
- response.status.should == 200
- end
- end
-
- describe "PUT /projects/:id/repository/branches/:branch/unprotect" do
- it "should unprotect a single branch" do
- put api("/projects/#{project.id}/repository/branches/new_design/unprotect", user)
- response.status.should == 200
-
- json_response['name'].should == 'new_design'
- json_response['commit']['id'].should == '621491c677087aa243f165eab467bfdfbee00be1'
- json_response['protected'].should == false
- end
-
- it "should return success when unprotect branch" do
- put api("/projects/#{project.id}/repository/branches/unknown/unprotect", user)
- response.status.should == 404
- end
-
- it "should return success when unprotect branch again" do
- put api("/projects/#{project.id}/repository/branches/new_design/unprotect", user)
- put api("/projects/#{project.id}/repository/branches/new_design/unprotect", user)
- response.status.should == 200
end
end
describe "GET /projects/:id/members" do
it "should return project team members" do
- get api("/projects/#{project.id}/members", user)
+ get api("/projects/#{project.path}/members", user)
response.status.should == 200
json_response.should be_an Array
json_response.count.should == 2
@@ -252,37 +119,27 @@ describe Gitlab::API do
end
it "finds team members with query string" do
- get api("/projects/#{project.id}/members", user), query: user.username
+ get api("/projects/#{project.path}/members", user), query: user.username
response.status.should == 200
json_response.should be_an Array
json_response.count.should == 1
json_response.first['email'].should == user.email
end
-
- it "should return a 404 error if id not found" do
- get api("/projects/9999/members", user)
- response.status.should == 404
- end
end
describe "GET /projects/:id/members/:user_id" do
it "should return project team member" do
- get api("/projects/#{project.id}/members/#{user.id}", user)
+ get api("/projects/#{project.path}/members/#{user.id}", user)
response.status.should == 200
json_response['email'].should == user.email
json_response['access_level'].should == UsersProject::MASTER
end
-
- it "should return a 404 error if user id not found" do
- get api("/projects/#{project.id}/members/1234", user)
- response.status.should == 404
- end
end
describe "POST /projects/:id/members" do
it "should add user to project team" do
expect {
- post api("/projects/#{project.id}/members", user), user_id: user2.id,
+ post api("/projects/#{project.path}/members", user), user_id: user2.id,
access_level: UsersProject::DEVELOPER
}.to change { UsersProject.count }.by(1)
@@ -290,210 +147,76 @@ describe Gitlab::API do
json_response['email'].should == user2.email
json_response['access_level'].should == UsersProject::DEVELOPER
end
-
- it "should return a 201 status if user is already project member" do
- post api("/projects/#{project.id}/members", user), user_id: user2.id,
- access_level: UsersProject::DEVELOPER
- expect {
- post api("/projects/#{project.id}/members", user), user_id: user2.id,
- access_level: UsersProject::DEVELOPER
- }.not_to change { UsersProject.count }.by(1)
-
- response.status.should == 201
- json_response['email'].should == user2.email
- json_response['access_level'].should == UsersProject::DEVELOPER
- end
-
- it "should return a 400 error when user id is not given" do
- post api("/projects/#{project.id}/members", user), access_level: UsersProject::MASTER
- response.status.should == 400
- end
-
- it "should return a 400 error when access level is not given" do
- post api("/projects/#{project.id}/members", user), user_id: user2.id
- response.status.should == 400
- end
-
- it "should return a 422 error when access level is not known" do
- post api("/projects/#{project.id}/members", user), user_id: user2.id, access_level: 1234
- response.status.should == 422
- end
end
describe "PUT /projects/:id/members/:user_id" do
it "should update project team member" do
- put api("/projects/#{project.id}/members/#{user3.id}", user), access_level: UsersProject::MASTER
+ put api("/projects/#{project.path}/members/#{user3.id}", user), access_level: UsersProject::MASTER
response.status.should == 200
json_response['email'].should == user3.email
json_response['access_level'].should == UsersProject::MASTER
end
-
- it "should return a 404 error if user_id is not found" do
- put api("/projects/#{project.id}/members/1234", user), access_level: UsersProject::MASTER
- response.status.should == 404
- end
-
- it "should return a 400 error when access level is not given" do
- put api("/projects/#{project.id}/members/#{user3.id}", user)
- response.status.should == 400
- end
-
- it "should return a 422 error when access level is not known" do
- put api("/projects/#{project.id}/members/#{user3.id}", user), access_level: 123
- response.status.should == 422
- end
end
describe "DELETE /projects/:id/members/:user_id" do
it "should remove user from project team" do
expect {
- delete api("/projects/#{project.id}/members/#{user3.id}", user)
+ delete api("/projects/#{project.path}/members/#{user3.id}", user)
}.to change { UsersProject.count }.by(-1)
end
-
- it "should return 200 if team member is not part of a project" do
- delete api("/projects/#{project.id}/members/#{user3.id}", user)
- expect {
- delete api("/projects/#{project.id}/members/#{user3.id}", user)
- }.to_not change { UsersProject.count }.by(1)
- end
-
- it "should return 200 if team member already removed" do
- delete api("/projects/#{project.id}/members/#{user3.id}", user)
- 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)
- }.to change { UsersProject.count }.by(0)
- response.status.should == 200
- json_response['message'].should == "Access revoked"
- json_response['id'].should == 1000000
- end
end
describe "GET /projects/:id/hooks" do
- context "authorized user" do
- it "should return project hooks" do
- get api("/projects/#{project.id}/hooks", user)
- response.status.should == 200
+ it "should return project hooks" do
+ get api("/projects/#{project.path}/hooks", user)
- json_response.should be_an Array
- json_response.count.should == 1
- json_response.first['url'].should == "http://example.com"
- end
- end
+ response.status.should == 200
- context "unauthorized user" do
- it "should not access project hooks" do
- get api("/projects/#{project.id}/hooks", user3)
- response.status.should == 403
- end
+ json_response.should be_an Array
+ json_response.count.should == 1
+ json_response.first['url'].should == "http://example.com"
end
end
describe "GET /projects/:id/hooks/:hook_id" do
- context "authorized user" do
- it "should return a project hook" do
- get api("/projects/#{project.id}/hooks/#{hook.id}", user)
- response.status.should == 200
- json_response['url'].should == hook.url
- end
-
- it "should return a 404 error if hook id is not available" do
- get api("/projects/#{project.id}/hooks/1234", user)
- response.status.should == 404
- end
- end
-
- context "unauthorized user" do
- it "should not access an existing hook" do
- get api("/projects/#{project.id}/hooks/#{hook.id}", user3)
- response.status.should == 403
- end
- end
-
- it "should return a 404 error if hook id is not available" do
- get api("/projects/#{project.id}/hooks/1234", user)
- response.status.should == 404
+ it "should return a project hook" do
+ get api("/projects/#{project.path}/hooks/#{hook.id}", user)
+ response.status.should == 200
+ json_response['url'].should == hook.url
end
end
describe "POST /projects/:id/hooks" do
it "should add hook to project" do
expect {
- post api("/projects/#{project.id}/hooks", user),
- url: "http://example.com"
+ post api("/projects/#{project.path}/hooks", user),
+ "url" => "http://example.com"
}.to change {project.hooks.count}.by(1)
- response.status.should == 201
- end
-
- it "should return a 400 error if url not given" do
- post api("/projects/#{project.id}/hooks", user)
- response.status.should == 400
- end
-
- it "should return a 422 error if url not valid" do
- post api("/projects/#{project.id}/hooks", user), "url" => "ftp://example.com"
- response.status.should == 422
end
end
describe "PUT /projects/:id/hooks/:hook_id" do
it "should update an existing project hook" do
- put api("/projects/#{project.id}/hooks/#{hook.id}", user),
+ put api("/projects/#{project.path}/hooks/#{hook.id}", user),
url: 'http://example.org'
response.status.should == 200
json_response['url'].should == 'http://example.org'
end
-
- it "should return 404 error if hook id not found" do
- put api("/projects/#{project.id}/hooks/1234", user), url: 'http://example.org'
- response.status.should == 404
- end
-
- it "should return 400 error if url is not given" do
- put api("/projects/#{project.id}/hooks/#{hook.id}", user)
- response.status.should == 400
- end
-
- it "should return a 422 error if url is not valid" do
- put api("/projects/#{project.id}/hooks/#{hook.id}", user), url: 'ftp://example.com'
- response.status.should == 422
- end
end
+
describe "DELETE /projects/:id/hooks" do
it "should delete hook from project" do
expect {
- delete api("/projects/#{project.id}/hooks", user), hook_id: hook.id
+ delete api("/projects/#{project.path}/hooks", user),
+ hook_id: hook.id
}.to change {project.hooks.count}.by(-1)
- response.status.should == 200
- end
-
- it "should return success when deleting hook" do
- delete api("/projects/#{project.id}/hooks", user), hook_id: hook.id
- response.status.should == 200
- end
-
- it "should return success when deleting non existent hook" do
- delete api("/projects/#{project.id}/hooks", user), hook_id: 42
- response.status.should == 200
- end
-
- it "should return a 400 error if hook id not given" do
- delete api("/projects/#{project.id}/hooks", user)
- response.status.should == 400
end
end
describe "GET /projects/:id/repository/tags" do
it "should return an array of project tags" do
- get api("/projects/#{project.id}/repository/tags", user)
+ get api("/projects/#{project.path}/repository/tags", user)
response.status.should == 200
json_response.should be_an Array
json_response.first['name'].should == project.repo.tags.sort_by(&:name).reverse.first.name
@@ -502,20 +225,20 @@ describe Gitlab::API do
describe "GET /projects/:id/repository/commits" do
context "authorized user" do
- before { project.team << [user2, :reporter] }
+ before { project.add_access(user2, :read) }
it "should return project commits" do
- get api("/projects/#{project.id}/repository/commits", user)
+ get api("/projects/#{project.path}/repository/commits", user)
response.status.should == 200
json_response.should be_an Array
- json_response.first['id'].should == project.repository.commit.id
+ json_response.first['id'].should == project.commit.id
end
end
context "unauthorized user" do
it "should not return project commits" do
- get api("/projects/#{project.id}/repository/commits")
+ get api("/projects/#{project.path}/repository/commits")
response.status.should == 401
end
end
@@ -523,7 +246,7 @@ describe Gitlab::API do
describe "GET /projects/:id/snippets" do
it "should return an array of project snippets" do
- get api("/projects/#{project.id}/snippets", user)
+ get api("/projects/#{project.path}/snippets", user)
response.status.should == 200
json_response.should be_an Array
json_response.first['title'].should == snippet.title
@@ -532,160 +255,59 @@ describe Gitlab::API do
describe "GET /projects/:id/snippets/:snippet_id" do
it "should return a project snippet" do
- get api("/projects/#{project.id}/snippets/#{snippet.id}", user)
+ get api("/projects/#{project.path}/snippets/#{snippet.id}", user)
response.status.should == 200
json_response['title'].should == snippet.title
end
-
- it "should return a 404 error if snippet id not found" do
- get api("/projects/#{project.id}/snippets/1234", user)
- response.status.should == 404
- end
end
describe "POST /projects/:id/snippets" do
it "should create a new project snippet" do
- post api("/projects/#{project.id}/snippets", user),
+ post api("/projects/#{project.path}/snippets", user),
title: 'api test', file_name: 'sample.rb', code: 'test'
response.status.should == 201
json_response['title'].should == 'api test'
end
-
- it "should return a 400 error if title is not given" do
- post api("/projects/#{project.id}/snippets", user),
- file_name: 'sample.rb', code: 'test'
- response.status.should == 400
- end
-
- it "should return a 400 error if file_name not given" do
- post api("/projects/#{project.id}/snippets", user),
- title: 'api test', code: 'test'
- response.status.should == 400
- end
-
- it "should return a 400 error if code not given" do
- post api("/projects/#{project.id}/snippets", user),
- title: 'api test', file_name: 'sample.rb'
- response.status.should == 400
- end
end
describe "PUT /projects/:id/snippets/:shippet_id" do
it "should update an existing project snippet" do
- put api("/projects/#{project.id}/snippets/#{snippet.id}", user),
+ put api("/projects/#{project.path}/snippets/#{snippet.id}", user),
code: 'updated code'
response.status.should == 200
json_response['title'].should == 'example'
snippet.reload.content.should == 'updated code'
end
-
- it "should update an existing project snippet with new title" do
- put api("/projects/#{project.id}/snippets/#{snippet.id}", user),
- title: 'other api test'
- response.status.should == 200
- json_response['title'].should == 'other api test'
- end
end
describe "DELETE /projects/:id/snippets/:snippet_id" do
it "should delete existing project snippet" do
expect {
- delete api("/projects/#{project.id}/snippets/#{snippet.id}", user)
+ delete api("/projects/#{project.path}/snippets/#{snippet.id}", user)
}.to change { Snippet.count }.by(-1)
- response.status.should == 200
- end
-
- it "should return success when deleting unknown snippet id" do
- delete api("/projects/#{project.id}/snippets/1234", user)
- response.status.should == 200
end
end
describe "GET /projects/:id/snippets/:snippet_id/raw" do
it "should get a raw project snippet" do
- get api("/projects/#{project.id}/snippets/#{snippet.id}/raw", user)
+ get api("/projects/#{project.path}/snippets/#{snippet.id}/raw", user)
response.status.should == 200
end
-
- it "should return a 404 error if raw project snippet not found" do
- get api("/projects/#{project.id}/snippets/5555/raw", user)
- response.status.should == 404
- end
end
- describe "GET /projects/:id/repository/commits/:sha/blob" do
+ describe "GET /projects/:id/:sha/blob" do
it "should get the raw file contents" do
- get api("/projects/#{project.id}/repository/commits/master/blob?filepath=README.md", user)
+ get api("/projects/#{project.path}/repository/commits/master/blob?filepath=README.md", user)
response.status.should == 200
end
it "should return 404 for invalid branch_name" do
- get api("/projects/#{project.id}/repository/commits/invalid_branch_name/blob?filepath=README.md", user)
+ get api("/projects/#{project.path}/repository/commits/invalid_branch_name/blob?filepath=README.md", user)
response.status.should == 404
end
it "should return 404 for invalid file" do
- get api("/projects/#{project.id}/repository/commits/master/blob?filepath=README.invalid", user)
- response.status.should == 404
- end
-
- it "should return a 400 error if filepath is missing" do
- get api("/projects/#{project.id}/repository/commits/master/blob", user)
- response.status.should == 400
- end
- end
-
- describe "GET /projects/:id/keys" do
- it "should return array of ssh keys" do
- project.deploy_keys << key
- project.save
- get api("/projects/#{project.id}/keys", user)
- response.status.should == 200
- json_response.should be_an Array
- json_response.first['title'].should == key.title
- end
- end
-
- describe "GET /projects/:id/keys/:key_id" do
- it "should return a single key" do
- project.deploy_keys << key
- project.save
- get api("/projects/#{project.id}/keys/#{key.id}", user)
- response.status.should == 200
- json_response['title'].should == key.title
- end
-
- it "should return 404 Not Found with invalid ID" do
- get api("/projects/#{project.id}/keys/404", user)
- response.status.should == 404
- end
- end
-
- describe "POST /projects/:id/keys" do
- it "should not create an invalid ssh key" do
- post api("/projects/#{project.id}/keys", user), { title: "invalid key" }
- response.status.should == 404
- end
-
- it "should create new ssh key" do
- key_attrs = attributes_for :key
- expect {
- post api("/projects/#{project.id}/keys", user), key_attrs
- }.to change{ project.deploy_keys.count }.by(1)
- end
- end
-
- describe "DELETE /projects/:id/keys/:key_id" do
- it "should delete existing key" do
- project.deploy_keys << key
- project.save
- expect {
- delete api("/projects/#{project.id}/keys/#{key.id}", user)
- }.to change{ project.deploy_keys.count }.by(-1)
- end
-
- it "should return 404 Not Found with invalid ID" do
- delete api("/projects/#{project.id}/keys/404", user)
+ get api("/projects/#{project.path}/repository/commits/master/blob?filepath=README.invalid", user)
response.status.should == 404
end
end
diff --git a/spec/requests/api/session_spec.rb b/spec/requests/api/session_spec.rb
index 4a37312b..afae8be8 100644
--- a/spec/requests/api/session_spec.rb
+++ b/spec/requests/api/session_spec.rb
@@ -13,10 +13,6 @@ describe Gitlab::API do
json_response['email'].should == user.email
json_response['private_token'].should == user.private_token
- json_response['is_admin'].should == user.is_admin?
- json_response['can_create_team'].should == user.can_create_team?
- json_response['can_create_project'].should == user.can_create_project?
- json_response['can_create_group'].should == user.can_create_group?
end
end
@@ -39,15 +35,5 @@ describe Gitlab::API do
json_response['private_token'].should be_nil
end
end
-
- context "when empty name" do
- it "should return authentication error" do
- post api("/session"), password: user.password
- response.status.should == 401
-
- json_response['email'].should be_nil
- json_response['private_token'].should be_nil
- end
- end
end
end
diff --git a/spec/requests/api/system_hooks_spec.rb b/spec/requests/api/system_hooks_spec.rb
deleted file mode 100644
index fe1b324c..00000000
--- a/spec/requests/api/system_hooks_spec.rb
+++ /dev/null
@@ -1,81 +0,0 @@
-require 'spec_helper'
-
-describe Gitlab::API do
- include ApiHelpers
-
- let(:user) { create(:user) }
- let(:admin) { create(:admin) }
- let!(:hook) { create(:system_hook, url: "http://example.com") }
-
- before { stub_request(:post, hook.url) }
-
- describe "GET /hooks" do
- context "when no user" do
- it "should return authentication error" do
- get api("/hooks")
- response.status.should == 401
- end
- end
-
- context "when not an admin" do
- it "should return forbidden error" do
- get api("/hooks", user)
- response.status.should == 403
- end
- end
-
- context "when authenticated as admin" do
- it "should return an array of hooks" do
- get api("/hooks", admin)
- response.status.should == 200
- json_response.should be_an Array
- json_response.first['url'].should == hook.url
- end
- end
- end
-
- describe "POST /hooks" do
- it "should create new hook" do
- expect {
- post api("/hooks", admin), url: 'http://example.com'
- }.to change { SystemHook.count }.by(1)
- end
-
- it "should respond with 400 if url not given" do
- post api("/hooks", admin)
- response.status.should == 400
- end
-
- it "should not create new hook without url" do
- expect {
- post api("/hooks", admin)
- }.to_not change { SystemHook.count }
- end
- end
-
- describe "GET /hooks/:id" do
- it "should return hook by id" do
- get api("/hooks/#{hook.id}", admin)
- response.status.should == 200
- json_response['event_name'].should == 'project_create'
- end
-
- it "should return 404 on failure" do
- get api("/hooks/404", admin)
- response.status.should == 404
- end
- end
-
- describe "DELETE /hooks/:id" do
- it "should delete a hook" do
- expect {
- delete api("/hooks/#{hook.id}", admin)
- }.to change { SystemHook.count }.by(-1)
- end
-
- it "should return success if hook id not found" do
- delete api("/hooks/12345", admin)
- response.status.should == 200
- end
- end
-end
\ No newline at end of file
diff --git a/spec/requests/api/users_spec.rb b/spec/requests/api/users_spec.rb
index b4688dd2..4cfb4884 100644
--- a/spec/requests/api/users_spec.rb
+++ b/spec/requests/api/users_spec.rb
@@ -31,182 +31,26 @@ describe Gitlab::API do
response.status.should == 200
json_response['email'].should == user.email
end
-
- it "should return a 401 if unauthenticated" do
- get api("/users/9998")
- response.status.should == 401
- end
-
- it "should return a 404 error if user id not found" do
- get api("/users/9999", user)
- response.status.should == 404
- end
end
describe "POST /users" do
before{ admin }
+ it "should not create invalid user" do
+ post api("/users", admin), { email: "invalid email" }
+ response.status.should == 404
+ end
+
it "should create user" do
expect {
post api("/users", admin), attributes_for(:user, projects_limit: 3)
}.to change { User.count }.by(1)
end
- it "should return 201 Created on success" do
- post api("/users", admin), attributes_for(:user, projects_limit: 3)
- response.status.should == 201
- end
-
- it "should not create user with invalid email" do
- post api("/users", admin), { email: "invalid email", password: 'password' }
- response.status.should == 400
- end
-
- it "should return 400 error if password not given" do
- post api("/users", admin), { email: 'test@example.com' }
- response.status.should == 400
- end
-
- it "should return 400 error if email not given" do
- post api("/users", admin), { password: 'pass1234' }
- response.status.should == 400
- end
-
it "shouldn't available for non admin users" do
post api("/users", user), attributes_for(:user)
response.status.should == 403
end
-
- context "with existing user" do
- before { post api("/users", admin), { email: 'test@example.com', password: 'password', username: 'test' } }
-
- it "should not create user with same email" do
- expect {
- post api("/users", admin), { email: 'test@example.com', password: 'password' }
- }.to change { User.count }.by(0)
- end
-
- it "should return 409 conflict error if user with email exists" do
- post api("/users", admin), { email: 'test@example.com', password: 'password' }
- end
-
- it "should return 409 conflict error if same username exists" do
- post api("/users", admin), { email: 'foo@example.com', password: 'pass', username: 'test' }
- end
- end
- end
-
- describe "GET /users/sign_up" do
- context 'enabled' do
- before do
- Gitlab.config.gitlab.stub(:signup_enabled).and_return(true)
- end
-
- it "should return sign up page if signup is enabled" do
- get "/users/sign_up"
- response.status.should == 200
- end
- end
-
- context 'disabled' do
- before do
- Gitlab.config.gitlab.stub(:signup_enabled).and_return(false)
- end
-
- it "should redirect to sign in page if signup is disabled" do
- get "/users/sign_up"
- response.status.should == 302
- response.should redirect_to(new_user_session_path)
- end
- end
- end
-
- describe "PUT /users/:id" do
- before { admin }
-
- it "should update user with new bio" do
- put api("/users/#{user.id}", admin), {bio: 'new test bio'}
- response.status.should == 200
- json_response['bio'].should == 'new test bio'
- user.reload.bio.should == 'new test bio'
- end
-
- it "should not allow invalid update" do
- put api("/users/#{user.id}", admin), {email: 'invalid email'}
- response.status.should == 404
- user.reload.email.should_not == 'invalid email'
- end
-
- it "shouldn't available for non admin users" do
- put api("/users/#{user.id}", user), attributes_for(:user)
- response.status.should == 403
- end
-
- it "should return 404 for non-existing user" do
- put api("/users/999999", admin), {bio: 'update should fail'}
- response.status.should == 404
- end
-
- context "with existing user" do
- before {
- post api("/users", admin), { email: 'test@example.com', password: 'password', username: 'test', name: 'test' }
- post api("/users", admin), { email: 'foo@bar.com', password: 'password', username: 'john', name: 'john' }
- @user_id = User.all.last.id
- }
-
-# it "should return 409 conflict error if email address exists" do
-# put api("/users/#{@user_id}", admin), { email: 'test@example.com' }
-# response.status.should == 409
-# end
-#
-# it "should return 409 conflict error if username taken" do
-# @user_id = User.all.last.id
-# put api("/users/#{@user_id}", admin), { username: 'test' }
-# response.status.should == 409
-# end
- end
- end
-
- describe "POST /users/:id/keys" do
- before { admin }
-
- it "should not create invalid ssh key" do
- post api("/users/#{user.id}/keys", admin), { title: "invalid key" }
- response.status.should == 404
- end
-
- it "should create ssh key" do
- key_attrs = attributes_for :key
- expect {
- post api("/users/#{user.id}/keys", admin), key_attrs
- }.to change{ user.keys.count }.by(1)
- end
- end
-
- describe "DELETE /users/:id" do
- before { admin }
-
- it "should delete user" do
- delete api("/users/#{user.id}", admin)
- response.status.should == 200
- expect { User.find(user.id) }.to raise_error ActiveRecord::RecordNotFound
- json_response['email'].should == user.email
- end
-
- it "should not delete for unauthenticated user" do
- delete api("/users/#{user.id}")
- response.status.should == 401
- end
-
- it "shouldn't available for non admin users" do
- delete api("/users/#{user.id}", user)
- response.status.should == 403
- end
-
- it "should return 404 for non-existing user" do
- delete api("/users/999999", admin)
- response.status.should == 404
- end
end
describe "GET /user" do
@@ -214,15 +58,6 @@ describe Gitlab::API do
get api("/user", user)
response.status.should == 200
json_response['email'].should == user.email
- json_response['is_admin'].should == user.is_admin?
- json_response['can_create_team'].should == user.can_create_team?
- json_response['can_create_project'].should == user.can_create_project?
- json_response['can_create_group'].should == user.can_create_group?
- end
-
- it "should return 401 error if user is unauthenticated" do
- get api("/user")
- response.status.should == 401
end
end
@@ -259,38 +94,19 @@ describe Gitlab::API do
get api("/user/keys/42", user)
response.status.should == 404
end
-
- it "should return 404 error if admin accesses user's ssh key" do
- user.keys << key
- user.save
- admin
- get api("/user/keys/#{key.id}", admin)
- response.status.should == 404
- end
end
describe "POST /user/keys" do
+ it "should not create invalid ssh key" do
+ post api("/user/keys", user), { title: "invalid key" }
+ response.status.should == 404
+ end
+
it "should create ssh key" do
key_attrs = attributes_for :key
expect {
post api("/user/keys", user), key_attrs
}.to change{ user.keys.count }.by(1)
- response.status.should == 201
- end
-
- it "should return a 401 error if unauthorized" do
- post api("/user/keys"), title: 'some title', key: 'some key'
- response.status.should == 401
- end
-
- it "should not create ssh key without key" do
- post api("/user/keys", user), title: 'title'
- response.status.should == 400
- end
-
- it "should not create ssh key without title" do
- post api("/user/keys", user), key: "somekey"
- response.status.should == 400
end
end
@@ -301,19 +117,11 @@ describe Gitlab::API do
expect {
delete api("/user/keys/#{key.id}", user)
}.to change{user.keys.count}.by(-1)
- response.status.should == 200
end
- it "should return success if key ID not found" do
+ it "should return 404 Not Found within invalid ID" do
delete api("/user/keys/42", user)
- response.status.should == 200
- end
-
- it "should return 401 error if unauthorized" do
- user.keys << key
- user.save
- delete api("/user/keys/#{key.id}")
- response.status.should == 401
+ response.status.should == 404
end
end
end
diff --git a/spec/features/atom/dashboard_issues_spec.rb b/spec/requests/atom/dashboard_issues_spec.rb
similarity index 93%
rename from spec/features/atom/dashboard_issues_spec.rb
rename to spec/requests/atom/dashboard_issues_spec.rb
index 6f5d51d1..8ce64cd4 100644
--- a/spec/features/atom/dashboard_issues_spec.rb
+++ b/spec/requests/atom/dashboard_issues_spec.rb
@@ -10,7 +10,7 @@ describe "Dashboard Issues Feed" do
describe "atom feed" do
it "should render atom feed via private token" do
- visit issues_dashboard_path(:atom, private_token: user.private_token)
+ visit dashboard_issues_path(:atom, private_token: user.private_token)
page.response_headers['Content-Type'].should have_content("application/atom+xml")
page.body.should have_selector("title", text: "#{user.name} issues")
diff --git a/spec/features/atom/dashboard_spec.rb b/spec/requests/atom/dashboard_spec.rb
similarity index 100%
rename from spec/features/atom/dashboard_spec.rb
rename to spec/requests/atom/dashboard_spec.rb
diff --git a/spec/features/atom/issues_spec.rb b/spec/requests/atom/issues_spec.rb
similarity index 91%
rename from spec/features/atom/issues_spec.rb
rename to spec/requests/atom/issues_spec.rb
index 0488c1f2..29f88f3f 100644
--- a/spec/features/atom/issues_spec.rb
+++ b/spec/requests/atom/issues_spec.rb
@@ -3,10 +3,10 @@ require 'spec_helper'
describe "Issues Feed" do
describe "GET /issues" do
let!(:user) { create(:user) }
- let!(:project) { create(:project, namespace: user.namespace) }
+ let!(:project) { create(:project, owner: user) }
let!(:issue) { create(:issue, author: user, project: project) }
- before { project.team << [user, :developer] }
+ before { project.add_access(user, :read, :write) }
context "when authenticated" do
it "should render atom feed" do
diff --git a/spec/features/gitlab_flavored_markdown_spec.rb b/spec/requests/gitlab_flavored_markdown_spec.rb
similarity index 75%
rename from spec/features/gitlab_flavored_markdown_spec.rb
rename to spec/requests/gitlab_flavored_markdown_spec.rb
index 653ff865..98319f81 100644
--- a/spec/features/gitlab_flavored_markdown_spec.rb
+++ b/spec/requests/gitlab_flavored_markdown_spec.rb
@@ -1,12 +1,12 @@
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, project: project) }
let(:fred) do
u = create(:user, name: "fred")
- project.team << [u, :master]
+ project.users << u
u
end
@@ -33,11 +33,11 @@ describe "Gitlab Flavored Markdown" do
project.repo.gc_auto
end
- let(:commit) { project.repository.commits(@branch_name).first }
+ let(:commit) { project.commits(@branch_name).first }
before do
login_as :user
- project.team << [@user, :developer]
+ project.add_access(@user, :read, :write)
end
describe "for commits" do
@@ -67,14 +67,13 @@ describe "Gitlab Flavored Markdown" do
end
end
- # @wip
- #it "should render title in refs#blame" do
- #visit project_blame_path(project, File.join(@branch_name, @test_file))
+ it "should render title in refs#blame" do
+ visit project_blame_path(project, File.join(@branch_name, @test_file))
- #within(".blame_commit") do
- #page.should have_link("##{issue.id}")
- #end
- #end
+ within(".blame_commit") do
+ page.should have_link("##{issue.id}")
+ end
+ end
it "should render title in repositories#branches" do
visit branches_project_repository_path(project)
@@ -169,32 +168,55 @@ describe "Gitlab Flavored Markdown" do
describe "for notes" do
it "should render in commits#show", js: true do
visit project_commit_path(project, commit)
- within ".new_note.js-main-target-form" do
- fill_in "note_note", with: "see ##{issue.id}"
- click_button "Add Comment"
- end
+ fill_in "note_note", with: "see ##{issue.id}"
+ click_button "Add Comment"
page.should have_link("##{issue.id}")
end
it "should render in issue#show", js: true do
visit project_issue_path(project, issue)
- within ".new_note.js-main-target-form" do
- fill_in "note_note", with: "see ##{issue.id}"
- click_button "Add Comment"
- end
+ fill_in "note_note", with: "see ##{issue.id}"
+ click_button "Add Comment"
page.should have_link("##{issue.id}")
end
it "should render in merge_request#show", js: true do
visit project_merge_request_path(project, merge_request)
- within ".new_note.js-main-target-form" do
- fill_in "note_note", with: "see ##{issue.id}"
- click_button "Add Comment"
- end
+ fill_in "note_note", with: "see ##{issue.id}"
+ click_button "Add Comment"
+
+ page.should have_link("##{issue.id}")
+ end
+
+ it "should render in projects#wall", js: true do
+ visit wall_project_path(project)
+ fill_in "note_note", with: "see ##{issue.id}"
+ click_button "Add Comment"
page.should have_link("##{issue.id}")
end
end
+
+
+ describe "for wikis" do
+ before do
+ visit project_wiki_path(project, :index)
+ fill_in "Title", with: "Circumvent ##{issue.id}"
+ fill_in "Content", with: "# Other pages\n\n* [Foo](foo)\n* [Bar](bar)\n\nAlso look at ##{issue.id} :-)"
+ click_on "Save"
+ end
+
+ it "should NOT render title in wikis#show" do
+ within(".content h3") do # page title
+ page.should have_content("Circumvent ##{issue.id}")
+ page.should_not have_link("##{issue.id}")
+ end
+ end
+
+ it "should render content in wikis#show" do
+ page.should have_link("##{issue.id}")
+ end
+ end
end
diff --git a/spec/features/issues_spec.rb b/spec/requests/issues_spec.rb
similarity index 96%
rename from spec/features/issues_spec.rb
rename to spec/requests/issues_spec.rb
index 6fff59f0..08141085 100644
--- a/spec/features/issues_spec.rb
+++ b/spec/requests/issues_spec.rb
@@ -7,7 +7,8 @@ describe "Issues" do
login_as :user
user2 = create(:user)
- project.team << [[@user, user2], :developer]
+ project.add_access(@user, :read, :write)
+ project.add_access(user2, :read, :write)
end
describe "Edit issue" do
@@ -58,7 +59,8 @@ describe "Issues" do
it "should be able to search on different statuses" do
issue = Issue.first # with title 'foobar'
- issue.close
+ issue.closed = true
+ issue.save
visit project_issues_path(project)
click_link 'Closed'
diff --git a/spec/features/projects_deploy_keys_spec.rb b/spec/requests/projects_deploy_keys_spec.rb
similarity index 97%
rename from spec/features/projects_deploy_keys_spec.rb
rename to spec/requests/projects_deploy_keys_spec.rb
index 25b1da9e..35323f55 100644
--- a/spec/features/projects_deploy_keys_spec.rb
+++ b/spec/requests/projects_deploy_keys_spec.rb
@@ -5,7 +5,7 @@ describe "Projects", "DeployKeys" do
before do
login_as :user
- project.team << [@user, :master]
+ project.add_access(@user, :read, :write, :admin)
end
describe "GET /keys" do
diff --git a/spec/requests/projects_spec.rb b/spec/requests/projects_spec.rb
new file mode 100644
index 00000000..e097f080
--- /dev/null
+++ b/spec/requests/projects_spec.rb
@@ -0,0 +1,70 @@
+require 'spec_helper'
+
+describe "Projects" do
+ before { login_as :user }
+
+ describe "GET /projects/show" do
+ before do
+ @project = create(:project, owner: @user)
+ @project.add_access(@user, :read)
+
+ visit project_path(@project)
+ end
+
+ it "should be correct path" do
+ current_path.should == project_path(@project)
+ end
+ end
+
+ describe "GET /projects/:id/edit" do
+ before do
+ @project = create(:project)
+ @project.add_access(@user, :admin, :read)
+
+ visit edit_project_path(@project)
+ end
+
+ it "should be correct path" do
+ current_path.should == edit_project_path(@project)
+ end
+
+ it "should have labels for new project" do
+ page.should have_content("Project name is")
+ page.should have_content("Advanced settings:")
+ page.should have_content("Features:")
+ end
+ end
+
+ describe "PUT /projects/:id" do
+ before do
+ @project = create(:project, owner: @user)
+ @project.add_access(@user, :admin, :read)
+
+ visit edit_project_path(@project)
+
+ fill_in 'project_name', with: 'Awesome'
+ click_button "Save"
+ @project = @project.reload
+ end
+
+ it "should be correct path" do
+ current_path.should == edit_project_path(@project)
+ end
+
+ it "should show project" do
+ page.should have_content("Awesome")
+ end
+ end
+
+ describe "DELETE /projects/:id" do
+ before do
+ @project = create(:project, owner: @user)
+ @project.add_access(@user, :read, :admin)
+ visit edit_project_path(@project)
+ end
+
+ it "should be correct path" do
+ expect { click_link "Remove" }.to change {Project.count}.by(-1)
+ end
+ end
+end
diff --git a/spec/features/search_spec.rb b/spec/requests/search_spec.rb
similarity index 60%
rename from spec/features/search_spec.rb
rename to spec/requests/search_spec.rb
index 5ce4cae3..17cc0d39 100644
--- a/spec/features/search_spec.rb
+++ b/spec/requests/search_spec.rb
@@ -4,13 +4,10 @@ describe "Search" do
before do
login_as :user
@project = create(:project)
- @project.team << [@user, :reporter]
+ @project.add_access(@user, :read)
visit search_path
-
- within '.search-holder' do
- fill_in "search", with: @project.name[0..3]
- click_button "Search"
- end
+ fill_in "search", with: @project.name[0..3]
+ click_button "Search"
end
it "should show project in search results" do
diff --git a/spec/features/security/profile_access_spec.rb b/spec/requests/security/profile_access_spec.rb
similarity index 100%
rename from spec/features/security/profile_access_spec.rb
rename to spec/requests/security/profile_access_spec.rb
diff --git a/spec/features/security/project_access_spec.rb b/spec/requests/security/project_access_spec.rb
similarity index 79%
rename from spec/features/security/project_access_spec.rb
rename to spec/requests/security/project_access_spec.rb
index cfbb8f13..060a276b 100644
--- a/spec/features/security/project_access_spec.rb
+++ b/spec/requests/security/project_access_spec.rb
@@ -14,7 +14,7 @@ describe "Application access" do
end
describe "Project" do
- let(:project) { create(:project_with_code) }
+ let(:project) { create(:project) }
let(:master) { create(:user) }
let(:guest) { create(:user) }
@@ -22,10 +22,10 @@ describe "Application access" do
before do
# full access
- project.team << [master, :master]
+ project.users_projects.create(user: master, project_access: UsersProject::MASTER)
# readonly
- project.team << [reporter, :reporter]
+ project.users_projects.create(user: reporter, project_access: UsersProject::REPORTER)
end
describe "GET /project_code" do
@@ -33,40 +33,40 @@ describe "Application access" do
it { should be_allowed_for master }
it { should be_allowed_for reporter }
- it { should be_allowed_for :admin }
+ it { should be_denied_for :admin }
it { should be_denied_for guest }
it { should be_denied_for :user }
it { should be_denied_for :visitor }
end
describe "GET /project_code/tree/master" do
- subject { project_tree_path(project, project.repository.root_ref) }
+ subject { project_tree_path(project, project.root_ref) }
it { should be_allowed_for master }
it { should be_allowed_for reporter }
- it { should be_allowed_for :admin }
+ it { should be_denied_for :admin }
it { should be_denied_for guest }
it { should be_denied_for :user }
it { should be_denied_for :visitor }
end
describe "GET /project_code/commits/master" do
- subject { project_commits_path(project, project.repository.root_ref, limit: 1) }
+ subject { project_commits_path(project, project.root_ref, limit: 1) }
it { should be_allowed_for master }
it { should be_allowed_for reporter }
- it { should be_allowed_for :admin }
+ it { should be_denied_for :admin }
it { should be_denied_for guest }
it { should be_denied_for :user }
it { should be_denied_for :visitor }
end
describe "GET /project_code/commit/:sha" do
- subject { project_commit_path(project, project.repository.commit) }
+ subject { project_commit_path(project, project.commit) }
it { should be_allowed_for master }
it { should be_allowed_for reporter }
- it { should be_allowed_for :admin }
+ it { should be_denied_for :admin }
it { should be_denied_for guest }
it { should be_denied_for :user }
it { should be_denied_for :visitor }
@@ -77,7 +77,7 @@ describe "Application access" do
it { should be_allowed_for master }
it { should be_allowed_for reporter }
- it { should be_allowed_for :admin }
+ it { should be_denied_for :admin }
it { should be_denied_for guest }
it { should be_denied_for :user }
it { should be_denied_for :visitor }
@@ -88,18 +88,18 @@ describe "Application access" do
it { should be_allowed_for master }
it { should be_allowed_for reporter }
- it { should be_allowed_for :admin }
+ it { should be_denied_for :admin }
it { should be_denied_for guest }
it { should be_denied_for :user }
it { should be_denied_for :visitor }
end
describe "GET /project_code/wall" do
- subject { project_wall_path(project) }
+ subject { wall_project_path(project) }
it { should be_allowed_for master }
it { should be_allowed_for reporter }
- it { should be_allowed_for :admin }
+ it { should be_denied_for :admin }
it { should be_denied_for guest }
it { should be_denied_for :user }
it { should be_denied_for :visitor }
@@ -107,14 +107,14 @@ describe "Application access" do
describe "GET /project_code/blob" do
before do
- commit = project.repository.commit
+ commit = project.commit
path = commit.tree.contents.select { |i| i.is_a?(Grit::Blob)}.first.name
@blob_path = project_blob_path(project, File.join(commit.id, path))
end
it { @blob_path.should be_allowed_for master }
it { @blob_path.should be_allowed_for reporter }
- it { @blob_path.should be_allowed_for :admin }
+ it { @blob_path.should be_denied_for :admin }
it { @blob_path.should be_denied_for guest }
it { @blob_path.should be_denied_for :user }
it { @blob_path.should be_denied_for :visitor }
@@ -125,7 +125,7 @@ describe "Application access" do
it { should be_allowed_for master }
it { should be_denied_for reporter }
- it { should be_allowed_for :admin }
+ it { should be_denied_for :admin }
it { should be_denied_for guest }
it { should be_denied_for :user }
it { should be_denied_for :visitor }
@@ -136,7 +136,7 @@ describe "Application access" do
it { should be_allowed_for master }
it { should be_denied_for reporter }
- it { should be_allowed_for :admin }
+ it { should be_denied_for :admin }
it { should be_denied_for guest }
it { should be_denied_for :user }
it { should be_denied_for :visitor }
@@ -147,7 +147,7 @@ describe "Application access" do
it { should be_allowed_for master }
it { should be_allowed_for reporter }
- it { should be_allowed_for :admin }
+ it { should be_denied_for :admin }
it { should be_denied_for guest }
it { should be_denied_for :user }
it { should be_denied_for :visitor }
@@ -158,7 +158,7 @@ describe "Application access" do
it { should be_allowed_for master }
it { should be_allowed_for reporter }
- it { should be_allowed_for :admin }
+ it { should be_denied_for :admin }
it { should be_denied_for guest }
it { should be_denied_for :user }
it { should be_denied_for :visitor }
@@ -169,7 +169,7 @@ describe "Application access" do
it { should be_allowed_for master }
it { should be_allowed_for reporter }
- it { should be_allowed_for :admin }
+ it { should be_denied_for :admin }
it { should be_denied_for guest }
it { should be_denied_for :user }
it { should be_denied_for :visitor }
@@ -180,7 +180,7 @@ describe "Application access" do
it { should be_allowed_for master }
it { should be_allowed_for reporter }
- it { should be_allowed_for :admin }
+ it { should be_denied_for :admin }
it { should be_denied_for guest }
it { should be_denied_for :user }
it { should be_denied_for :visitor }
@@ -196,7 +196,7 @@ describe "Application access" do
it { should be_allowed_for master }
it { should be_allowed_for reporter }
- it { should be_allowed_for :admin }
+ it { should be_denied_for :admin }
it { should be_denied_for guest }
it { should be_denied_for :user }
it { should be_denied_for :visitor }
@@ -212,7 +212,7 @@ describe "Application access" do
it { should be_allowed_for master }
it { should be_allowed_for reporter }
- it { should be_allowed_for :admin }
+ it { should be_denied_for :admin }
it { should be_denied_for guest }
it { should be_denied_for :user }
it { should be_denied_for :visitor }
@@ -223,7 +223,18 @@ describe "Application access" do
it { should be_allowed_for master }
it { should be_allowed_for reporter }
- it { should be_allowed_for :admin }
+ it { should be_denied_for :admin }
+ it { should be_denied_for guest }
+ it { should be_denied_for :user }
+ it { should be_denied_for :visitor }
+ end
+
+ describe "GET /project_code/files" do
+ subject { files_project_path(project) }
+
+ it { should be_allowed_for master }
+ it { should be_allowed_for reporter }
+ it { should be_denied_for :admin }
it { should be_denied_for guest }
it { should be_denied_for :user }
it { should be_denied_for :visitor }
diff --git a/spec/features/snippets_spec.rb b/spec/requests/snippets_spec.rb
similarity index 95%
rename from spec/features/snippets_spec.rb
rename to spec/requests/snippets_spec.rb
index 1a0f6eae..b231b940 100644
--- a/spec/features/snippets_spec.rb
+++ b/spec/requests/snippets_spec.rb
@@ -5,7 +5,7 @@ describe "Snippets" do
before do
login_as :user
- project.team << [@user, :developer]
+ project.add_access(@user, :read, :write)
end
describe "GET /snippets" do
@@ -26,7 +26,7 @@ describe "Snippets" do
before do
# admin access to remove snippet
@user.users_projects.destroy_all
- project.team << [@user, :master]
+ project.add_access(@user, :read, :write, :admin)
visit edit_project_snippet_path(project, @snippet)
end
@@ -72,7 +72,7 @@ describe "Snippets" do
author: @user,
project: project)
visit project_snippet_path(project, @snippet)
- click_link "Edit Snippet"
+ click_link "Edit"
end
it "should open edit page" do
diff --git a/spec/roles/account_role_spec.rb b/spec/roles/account_role_spec.rb
new file mode 100644
index 00000000..4b214551
--- /dev/null
+++ b/spec/roles/account_role_spec.rb
@@ -0,0 +1,44 @@
+require 'spec_helper'
+
+describe User, "Account" do
+ describe 'normal user' do
+ let(:user) { create(:user, name: 'John Smith') }
+
+ it { user.is_admin?.should be_false }
+ it { user.require_ssh_key?.should be_true }
+ it { user.can_create_group?.should be_false }
+ it { user.can_create_project?.should be_true }
+ it { user.first_name.should == 'John' }
+ end
+
+ describe 'blocking user' do
+ let(:user) { create(:user, name: 'John Smith') }
+
+ it "should block user" do
+ user.block
+ user.blocked.should be_true
+ end
+ end
+
+ describe 'projects' do
+ before do
+ ActiveRecord::Base.observers.enable(:user_observer)
+ @user = create :user
+ @project = create :project, namespace: @user.namespace
+ end
+
+ it { @user.authorized_projects.should include(@project) }
+ it { @user.my_own_projects.should include(@project) }
+ end
+
+ describe 'namespaced' do
+ before do
+ ActiveRecord::Base.observers.enable(:user_observer)
+ @user = create :user
+ @project = create :project, namespace: @user.namespace
+ end
+
+ it { @user.several_namespaces?.should be_false }
+ it { @user.namespaces.should == [@user.namespace] }
+ end
+end
diff --git a/spec/models/concerns/issuable_spec.rb b/spec/roles/issue_commonality_spec.rb
similarity index 94%
rename from spec/models/concerns/issuable_spec.rb
rename to spec/roles/issue_commonality_spec.rb
index 551e1753..11f278de 100644
--- a/spec/models/concerns/issuable_spec.rb
+++ b/spec/roles/issue_commonality_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe Issue, "Issuable" do
+describe Issue, "IssueCommonality" do
let(:issue) { create(:issue) }
describe "Associations" do
@@ -15,6 +15,7 @@ describe Issue, "Issuable" do
it { should validate_presence_of(:author) }
it { should validate_presence_of(:title) }
it { should ensure_length_of(:title).is_at_least(0).is_at_most(255) }
+ it { should ensure_inclusion_of(:closed).in_array([true, false]) }
end
describe "Scope" do
diff --git a/spec/roles/repository_spec.rb b/spec/roles/repository_spec.rb
new file mode 100644
index 00000000..e1d01cbf
--- /dev/null
+++ b/spec/roles/repository_spec.rb
@@ -0,0 +1,159 @@
+require 'spec_helper'
+
+describe Project, "Repository" do
+ let(:project) { create(:project) }
+
+ describe "#empty_repo?" do
+ it "should return true if the repo doesn't exist" do
+ project.stub(repo_exists?: false, has_commits?: true)
+ project.should be_empty_repo
+ end
+
+ it "should return true if the repo has commits" do
+ project.stub(repo_exists?: true, has_commits?: false)
+ project.should be_empty_repo
+ end
+
+ it "should return false if the repo exists and has commits" do
+ project.stub(repo_exists?: true, has_commits?: true)
+ project.should_not be_empty_repo
+ end
+ end
+
+ describe "#discover_default_branch" do
+ let(:master) { 'master' }
+ let(:stable) { 'stable' }
+
+ it "returns 'master' when master exists" do
+ project.should_receive(:branch_names).at_least(:once).and_return([stable, master])
+ project.discover_default_branch.should == 'master'
+ end
+
+ it "returns non-master when master exists but default branch is set to something else" do
+ project.default_branch = 'stable'
+ project.should_receive(:branch_names).at_least(:once).and_return([stable, master])
+ project.discover_default_branch.should == 'stable'
+ end
+
+ it "returns a non-master branch when only one exists" do
+ project.should_receive(:branch_names).at_least(:once).and_return([stable])
+ project.discover_default_branch.should == 'stable'
+ end
+
+ it "returns nil when no branch exists" do
+ project.should_receive(:branch_names).at_least(:once).and_return([])
+ project.discover_default_branch.should be_nil
+ end
+ end
+
+ describe "#root_ref" do
+ it "returns default_branch when set" do
+ project.default_branch = 'stable'
+ project.root_ref.should == 'stable'
+ end
+
+ it "returns 'master' when default_branch is nil" do
+ project.default_branch = nil
+ project.root_ref.should == 'master'
+ end
+ end
+
+ describe "#root_ref?" do
+ it "returns true when branch is root_ref" do
+ project.default_branch = 'stable'
+ project.root_ref?('stable').should be_true
+ end
+
+ it "returns false when branch is not root_ref" do
+ project.default_branch = nil
+ project.root_ref?('stable').should be_false
+ end
+ end
+
+ describe :repo do
+ it "should return valid repo" do
+ project.repo.should be_kind_of(Grit::Repo)
+ end
+
+ it "should return nil" do
+ lambda { Project.new(path: "invalid").repo }.should raise_error(Grit::NoSuchPathError)
+ end
+
+ it "should return nil" do
+ lambda { Project.new.repo }.should raise_error(TypeError)
+ end
+ end
+
+ describe :commit do
+ it "should return first head commit if without params" do
+ project.commit.id.should == project.repo.commits.first.id
+ end
+
+ it "should return valid commit" do
+ project.commit(ValidCommit::ID).should be_valid_commit
+ end
+
+ it "should return nil" do
+ project.commit("+123_4532530XYZ").should be_nil
+ end
+ end
+
+ describe :tree do
+ before do
+ @commit = project.commit(ValidCommit::ID)
+ end
+
+ it "should raise error w/o arguments" do
+ lambda { project.tree }.should raise_error
+ end
+
+ it "should return root tree for commit" do
+ tree = project.tree(@commit)
+ tree.contents.size.should == ValidCommit::FILES_COUNT
+ tree.contents.map(&:name).should == ValidCommit::FILES
+ end
+
+ it "should return root tree for commit with correct path" do
+ tree = project.tree(@commit, ValidCommit::C_FILE_PATH)
+ tree.contents.map(&:name).should == ValidCommit::C_FILES
+ end
+
+ it "should return root tree for commit with incorrect path" do
+ project.tree(@commit, "invalid_path").should be_nil
+ end
+ end
+
+ describe "fresh commits" do
+ let(:project) { create(:project) }
+
+ it { project.fresh_commits(3).count.should == 3 }
+ it { project.fresh_commits.first.id.should == "bcf03b5de6c33f3869ef70d68cf06e679d1d7f9a" }
+ it { project.fresh_commits.last.id.should == "f403da73f5e62794a0447aca879360494b08f678" }
+ end
+
+ describe "commits_between" do
+ let(:project) { create(:project) }
+
+ subject do
+ commits = project.commits_between("3a4b4fb4cde7809f033822a171b9feae19d41fff",
+ "8470d70da67355c9c009e4401746b1d5410af2e3")
+ commits.map { |c| c.id }
+ end
+
+ it { should have(3).elements }
+ it { should include("f0f14c8eaba69ebddd766498a9d0b0e79becd633") }
+ it { should_not include("bcf03b5de6c33f3869ef70d68cf06e679d1d7f9a") }
+ end
+
+ describe :valid_repo? do
+ it "should be valid repo" do
+ project = create(:project)
+ project.valid_repo?.should be_true
+ end
+
+ it "should be invalid repo" do
+ project = Project.new(name: "ok_name", path: "/INVALID_PATH/", path: "NEOK")
+ project.valid_repo?.should be_false
+ end
+ end
+end
diff --git a/spec/roles/votes_spec.rb b/spec/roles/votes_spec.rb
new file mode 100644
index 00000000..98666022
--- /dev/null
+++ b/spec/roles/votes_spec.rb
@@ -0,0 +1,132 @@
+require 'spec_helper'
+
+describe Issue do
+ let(:issue) { create(:issue) }
+
+ describe "#upvotes" do
+ it "with no notes has a 0/0 score" do
+ issue.upvotes.should == 0
+ end
+
+ it "should recognize non-+1 notes" do
+ issue.notes << create(:note, note: "No +1 here")
+ issue.should have(1).note
+ issue.notes.first.upvote?.should be_false
+ issue.upvotes.should == 0
+ end
+
+ it "should recognize a single +1 note" do
+ issue.notes << create(:note, note: "+1 This is awesome")
+ issue.upvotes.should == 1
+ end
+
+ it "should recognize multiple +1 notes" do
+ issue.notes << create(:note, note: "+1 This is awesome")
+ issue.notes << create(:note, note: "+1 I want this")
+ issue.upvotes.should == 2
+ end
+ end
+
+ describe "#downvotes" do
+ it "with no notes has a 0/0 score" do
+ issue.downvotes.should == 0
+ end
+
+ it "should recognize non--1 notes" do
+ issue.notes << create(:note, note: "Almost got a -1")
+ issue.should have(1).note
+ issue.notes.first.downvote?.should be_false
+ issue.downvotes.should == 0
+ end
+
+ it "should recognize a single -1 note" do
+ issue.notes << create(:note, note: "-1 This is bad")
+ issue.downvotes.should == 1
+ end
+
+ it "should recognize multiple -1 notes" do
+ issue.notes << create(:note, note: "-1 This is bad")
+ issue.notes << create(:note, note: "-1 Away with this")
+ issue.downvotes.should == 2
+ end
+ end
+
+ describe "#votes_count" do
+ it "with no notes has a 0/0 score" do
+ issue.votes_count.should == 0
+ end
+
+ it "should recognize non notes" do
+ issue.notes << create(:note, note: "No +1 here")
+ issue.should have(1).note
+ issue.votes_count.should == 0
+ end
+
+ it "should recognize a single +1 note" do
+ issue.notes << create(:note, note: "+1 This is awesome")
+ issue.votes_count.should == 1
+ end
+
+ it "should recognize a single -1 note" do
+ issue.notes << create(:note, note: "-1 This is bad")
+ issue.votes_count.should == 1
+ end
+
+ it "should recognize multiple notes" do
+ issue.notes << create(:note, note: "+1 This is awesome")
+ issue.notes << create(:note, note: "-1 This is bad")
+ issue.notes << create(:note, note: "+1 I want this")
+ issue.votes_count.should == 3
+ end
+ end
+
+ describe "#upvotes_in_percent" do
+ it "with no notes has a 0% score" do
+ issue.upvotes_in_percent.should == 0
+ end
+
+ it "should count a single 1 note as 100%" do
+ issue.notes << create(:note, note: "+1 This is awesome")
+ issue.upvotes_in_percent.should == 100
+ end
+
+ it "should count multiple +1 notes as 100%" do
+ issue.notes << create(:note, note: "+1 This is awesome")
+ issue.notes << create(:note, note: "+1 I want this")
+ issue.upvotes_in_percent.should == 100
+ end
+
+ it "should count fractions for multiple +1 and -1 notes correctly" do
+ issue.notes << create(:note, note: "+1 This is awesome")
+ issue.notes << create(:note, note: "+1 I want this")
+ issue.notes << create(:note, note: "-1 This is bad")
+ issue.notes << create(:note, note: "+1 me too")
+ issue.upvotes_in_percent.should == 75
+ end
+ end
+
+ describe "#downvotes_in_percent" do
+ it "with no notes has a 0% score" do
+ issue.downvotes_in_percent.should == 0
+ end
+
+ it "should count a single -1 note as 100%" do
+ issue.notes << create(:note, note: "-1 This is bad")
+ issue.downvotes_in_percent.should == 100
+ end
+
+ it "should count multiple -1 notes as 100%" do
+ issue.notes << create(:note, note: "-1 This is bad")
+ issue.notes << create(:note, note: "-1 Away with this")
+ issue.downvotes_in_percent.should == 100
+ end
+
+ it "should count fractions for multiple +1 and -1 notes correctly" do
+ issue.notes << create(:note, note: "+1 This is awesome")
+ issue.notes << create(:note, note: "+1 I want this")
+ issue.notes << create(:note, note: "-1 This is bad")
+ issue.notes << create(:note, note: "+1 me too")
+ issue.downvotes_in_percent.should == 25
+ end
+ end
+end
diff --git a/spec/routing/admin_routing_spec.rb b/spec/routing/admin_routing_spec.rb
index b6509fcb..fb26bf98 100644
--- a/spec/routing/admin_routing_spec.rb
+++ b/spec/routing/admin_routing_spec.rb
@@ -66,29 +66,49 @@ end
# PUT /admin/projects/:id(.:format) admin/projects#update {:id=>/[^\/]+/}
# DELETE /admin/projects/:id(.:format) admin/projects#destroy {:id=>/[^\/]+/}
describe Admin::ProjectsController, "routing" do
+ it "to #team" do
+ get("/admin/projects/gitlab/team").should route_to('admin/projects#team', id: 'gitlab')
+ end
+
+ it "to #team_update" do
+ put("/admin/projects/gitlab/team_update").should route_to('admin/projects#team_update', id: 'gitlab')
+ end
+
it "to #index" do
get("/admin/projects").should route_to('admin/projects#index')
end
+ it "to #edit" do
+ get("/admin/projects/gitlab/edit").should route_to('admin/projects#edit', id: 'gitlab')
+ end
+
it "to #show" do
get("/admin/projects/gitlab").should route_to('admin/projects#show', id: 'gitlab')
end
-end
-
-# edit_admin_project_member GET /admin/projects/:project_id/members/:id/edit(.:format) admin/projects/members#edit {:id=>/[^\/]+/, :project_id=>/[^\/]+/}
-# admin_project_member PUT /admin/projects/:project_id/members/:id(.:format) admin/projects/members#update {:id=>/[^\/]+/, :project_id=>/[^\/]+/}
-# DELETE /admin/projects/:project_id/members/:id(.:format) admin/projects/members#destroy {:id=>/[^\/]+/, :project_id=>/[^\/]+/}
-describe Admin::Projects::MembersController, "routing" do
- it "to #edit" do
- get("/admin/projects/test/members/1/edit").should route_to('admin/projects/members#edit', project_id: 'test', id: '1')
- end
it "to #update" do
- put("/admin/projects/test/members/1").should route_to('admin/projects/members#update', project_id: 'test', id: '1')
+ put("/admin/projects/gitlab").should route_to('admin/projects#update', id: 'gitlab')
end
it "to #destroy" do
- delete("/admin/projects/test/members/1").should route_to('admin/projects/members#destroy', project_id: 'test', id: '1')
+ delete("/admin/projects/gitlab").should route_to('admin/projects#destroy', id: 'gitlab')
+ end
+end
+
+# edit_admin_team_member GET /admin/team_members/:id/edit(.:format) admin/team_members#edit
+# admin_team_member PUT /admin/team_members/:id(.:format) admin/team_members#update
+# DELETE /admin/team_members/:id(.:format) admin/team_members#destroy
+describe Admin::TeamMembersController, "routing" do
+ it "to #edit" do
+ get("/admin/team_members/1/edit").should route_to('admin/team_members#edit', id: '1')
+ end
+
+ it "to #update" do
+ put("/admin/team_members/1").should route_to('admin/team_members#update', id: '1')
+ end
+
+ it "to #destroy" do
+ delete("/admin/team_members/1").should route_to('admin/team_members#destroy', id: '1')
end
end
diff --git a/spec/routing/notifications_routing_spec.rb b/spec/routing/notifications_routing_spec.rb
deleted file mode 100644
index 6880d281..00000000
--- a/spec/routing/notifications_routing_spec.rb
+++ /dev/null
@@ -1,13 +0,0 @@
-require "spec_helper"
-
-describe NotificationsController do
- describe "routing" do
- it "routes to #show" do
- get("/profile/notifications").should route_to("notifications#show")
- end
-
- it "routes to #update" do
- put("/profile/notifications").should route_to("notifications#update")
- end
- end
-end
diff --git a/spec/routing/project_routing_spec.rb b/spec/routing/project_routing_spec.rb
index 41533f8b..09e11588 100644
--- a/spec/routing/project_routing_spec.rb
+++ b/spec/routing/project_routing_spec.rb
@@ -56,6 +56,7 @@ end
# projects POST /projects(.:format) projects#create
# new_project GET /projects/new(.:format) projects#new
# wall_project GET /:id/wall(.:format) projects#wall
+# graph_project GET /:id/graph(.:format) projects#graph
# files_project GET /:id/files(.:format) projects#files
# edit_project GET /:id/edit(.:format) projects#edit
# project GET /:id(.:format) projects#show
@@ -71,7 +72,15 @@ describe ProjectsController, "routing" do
end
it "to #wall" do
- get("/gitlabhq/wall").should route_to('walls#show', project_id: 'gitlabhq')
+ get("/gitlabhq/wall").should route_to('projects#wall', id: 'gitlabhq')
+ end
+
+ it "to #graph" do
+ get("/gitlabhq/graph").should route_to('projects#graph', id: 'gitlabhq')
+ end
+
+ it "to #files" do
+ get("/gitlabhq/files").should route_to('projects#files', id: 'gitlabhq')
end
it "to #edit" do
@@ -182,18 +191,17 @@ describe ProtectedBranchesController, "routing" do
end
end
-# switch_project_refs GET /:project_id/refs/switch(.:format) refs#switch
-# logs_tree_project_ref GET /:project_id/refs/:id/logs_tree(.:format) refs#logs_tree
-# logs_file_project_ref GET /:project_id/refs/:id/logs_tree/:path(.:format) refs#logs_tree
+# switch_project_refs GET /:project_id/switch(.:format) refs#switch
+# logs_tree_project_ref GET /:project_id/:id/logs_tree(.:format) refs#logs_tree
+# logs_file_project_ref GET /:project_id/:id/logs_tree/:path(.:format) refs#logs_tree
describe RefsController, "routing" do
it "to #switch" do
- get("/gitlabhq/refs/switch").should route_to('refs#switch', project_id: 'gitlabhq')
+ get("/gitlabhq/switch").should route_to('refs#switch', project_id: 'gitlabhq')
end
it "to #logs_tree" do
- get("/gitlabhq/refs/stable/logs_tree").should route_to('refs#logs_tree', project_id: 'gitlabhq', id: 'stable')
- get("/gitlabhq/refs/stable/logs_tree/foo/bar/baz").should route_to('refs#logs_tree', project_id: 'gitlabhq', id: 'stable', path: 'foo/bar/baz')
- get("/gitlab/gitlabhq/refs/stable/logs_tree/files.scss").should route_to('refs#logs_tree', project_id: 'gitlab/gitlabhq', id: 'stable', path: 'files.scss')
+ get("/gitlabhq/stable/logs_tree").should route_to('refs#logs_tree', project_id: 'gitlabhq', id: 'stable')
+ get("/gitlabhq/stable/logs_tree/foo/bar/baz").should route_to('refs#logs_tree', project_id: 'gitlabhq', id: 'stable', path: 'foo/bar/baz')
end
end
@@ -293,10 +301,6 @@ describe CommitsController, "routing" do
let(:actions) { [:show] }
let(:controller) { 'commits' }
end
-
- it "to #show" do
- get("/gitlab/gitlabhq/commits/master.atom").should route_to('commits#show', project_id: 'gitlab/gitlabhq', id: "master", format: "atom")
- end
end
# project_team_members GET /:project_id/team_members(.:format) team_members#index
@@ -381,7 +385,6 @@ end
describe BlameController, "routing" do
it "to #show" do
get("/gitlabhq/blame/master/app/models/project.rb").should route_to('blame#show', project_id: 'gitlabhq', id: 'master/app/models/project.rb')
- get("/gitlab/gitlabhq/blame/master/files.scss").should route_to('blame#show', project_id: 'gitlab/gitlabhq', id: 'master/files.scss')
end
end
@@ -389,8 +392,6 @@ end
describe BlobController, "routing" do
it "to #show" do
get("/gitlabhq/blob/master/app/models/project.rb").should route_to('blob#show', project_id: 'gitlabhq', id: 'master/app/models/project.rb')
- get("/gitlabhq/blob/master/app/models/compare.rb").should route_to('blob#show', project_id: 'gitlabhq', id: 'master/app/models/compare.rb')
- get("/gitlab/gitlabhq/blob/master/files.scss").should route_to('blob#show', project_id: 'gitlab/gitlabhq', id: 'master/files.scss')
end
end
@@ -398,7 +399,6 @@ end
describe TreeController, "routing" do
it "to #show" do
get("/gitlabhq/tree/master/app/models/project.rb").should route_to('tree#show', project_id: 'gitlabhq', id: 'master/app/models/project.rb')
- get("/gitlab/gitlabhq/tree/master/files.scss").should route_to('tree#show', project_id: 'gitlab/gitlabhq', id: 'master/files.scss')
end
end
@@ -419,10 +419,3 @@ describe CompareController, "routing" do
get("/gitlabhq/compare/issue/1234...stable").should route_to('compare#show', project_id: 'gitlabhq', from: 'issue/1234', to: 'stable')
end
end
-
-describe GraphController, "routing" do
- it "to #show" do
- get("/gitlabhq/graph/master").should route_to('graph#show', project_id: 'gitlabhq', id: 'master')
- get("/gitlabhq/graph/master.json").should route_to('graph#show', project_id: 'gitlabhq', id: 'master', format: "json")
- end
-end
diff --git a/spec/routing/routing_spec.rb b/spec/routing/routing_spec.rb
index 5ad8165e..57fd70e7 100644
--- a/spec/routing/routing_spec.rb
+++ b/spec/routing/routing_spec.rb
@@ -146,14 +146,14 @@ describe KeysController, "routing" do
end
end
-# dashboard GET /dashboard(.:format) dashboard#show
+# dashboard GET /dashboard(.:format) dashboard#index
# dashboard_issues GET /dashboard/issues(.:format) dashboard#issues
# dashboard_merge_requests GET /dashboard/merge_requests(.:format) dashboard#merge_requests
-# root / dashboard#show
+# root / dashboard#index
describe DashboardController, "routing" do
it "to #index" do
- get("/dashboard").should route_to('dashboard#show')
- get("/").should route_to('dashboard#show')
+ get("/dashboard").should route_to('dashboard#index')
+ get("/").should route_to('dashboard#index')
end
it "to #issues" do
diff --git a/spec/services/git_push_service_spec.rb b/spec/services/git_push_service_spec.rb
deleted file mode 100644
index 286a8cda..00000000
--- a/spec/services/git_push_service_spec.rb
+++ /dev/null
@@ -1,111 +0,0 @@
-require 'spec_helper'
-
-describe GitPushService do
- let (:user) { create :user }
- let (:project) { create :project_with_code }
- let (:service) { GitPushService.new }
-
- before do
- @oldrev = 'b98a310def241a6fd9c9a9a3e7934c48e498fe81'
- @newrev = 'b19a04f53caeebf4fe5ec2327cb83e9253dc91bb'
- @ref = 'refs/heads/master'
- end
-
- describe "Git Push Data" do
- before do
- service.execute(project, user, @oldrev, @newrev, @ref)
- @push_data = service.push_data
- @commit = project.repository.commit(@newrev)
- end
-
- subject { @push_data }
-
- it { should include(before: @oldrev) }
- it { should include(after: @newrev) }
- it { should include(ref: @ref) }
- it { should include(user_id: user.id) }
- it { should include(user_name: user.name) }
-
- context "with repository data" do
- subject { @push_data[:repository] }
-
- it { should include(name: project.name) }
- it { should include(url: project.url_to_repo) }
- it { should include(description: project.description) }
- it { should include(homepage: project.web_url) }
- end
-
- context "with commits" do
- subject { @push_data[:commits] }
-
- it { should be_an(Array) }
- it { should have(1).element }
-
- context "the commit" do
- subject { @push_data[:commits].first }
-
- it { should include(id: @commit.id) }
- it { should include(message: @commit.safe_message) }
- it { should include(timestamp: @commit.date.xmlschema) }
- it { should include(url: "#{Gitlab.config.gitlab.url}/#{project.code}/commit/#{@commit.id}") }
-
- context "with a author" do
- subject { @push_data[:commits].first[:author] }
-
- it { should include(name: @commit.author_name) }
- it { should include(email: @commit.author_email) }
- end
- end
- end
- end
-
- describe "Push Event" do
- before do
- service.execute(project, user, @oldrev, @newrev, @ref)
- @event = Event.last
- end
-
- it { @event.should_not be_nil }
- it { @event.project.should == project }
- it { @event.action.should == Event::PUSHED }
- it { @event.data.should == service.push_data }
- end
-
- describe "Web Hooks" do
- context "with web hooks" do
- before do
- @project_hook = create(:project_hook)
- @project_hook_2 = create(:project_hook)
- project.hooks << [@project_hook, @project_hook_2]
-
- stub_request(:post, @project_hook.url)
- stub_request(:post, @project_hook_2.url)
- end
-
- it "executes multiple web hook" do
- @project_hook.should_receive(:async_execute).once
- @project_hook_2.should_receive(:async_execute).once
-
- service.execute(project, user, @oldrev, @newrev, @ref)
- end
- end
-
- context "does not execute web hooks" do
- before do
- @project_hook = create(:project_hook)
- project.hooks << [@project_hook]
- end
-
- it "when pushing a branch for the first time" do
- @project_hook.should_not_receive(:execute)
- service.execute(project, user, '00000000000000000000000000000000', 'newrev', 'refs/heads/master')
- end
-
- it "when pushing tags" do
- @project_hook.should_not_receive(:execute)
- service.execute(project, user, 'newrev', 'newrev', 'refs/tags/v1.0.0')
- end
- end
- end
-end
-
diff --git a/spec/services/notification_service_spec.rb b/spec/services/notification_service_spec.rb
deleted file mode 100644
index fa47a635..00000000
--- a/spec/services/notification_service_spec.rb
+++ /dev/null
@@ -1,247 +0,0 @@
-require 'spec_helper'
-
-describe NotificationService do
- # Disable observers to prevent factory trigger notification service
- before(:all) { ActiveRecord::Base.observers.disable :all }
- after(:all) { ActiveRecord::Base.observers.enable :all }
-
- let(:notification) { NotificationService.new }
-
- describe 'Keys' do
- describe :new_key do
- let(:key) { create(:personal_key) }
-
- it { notification.new_key(key).should be_true }
-
- it 'should sent email to key owner' do
- Notify.should_receive(:new_ssh_key_email).with(key.id)
- notification.new_key(key)
- end
- end
- end
-
- describe 'Notes' do
- context 'issue note' do
- let(:issue) { create(:issue, assignee: create(:user)) }
- let(:note) { create(:note_on_issue, noteable: issue, project_id: issue.project_id) }
-
- before do
- build_team(note.project)
- end
-
- describe :new_note do
- it do
- should_email(@u_watcher.id)
- should_email(note.noteable.author_id)
- should_email(note.noteable.assignee_id)
- should_not_email(note.author_id)
- should_not_email(@u_participating.id)
- should_not_email(@u_disabled.id)
- notification.new_note(note)
- end
-
- def should_email(user_id)
- Notify.should_receive(:note_issue_email).with(user_id, note.id)
- end
-
- def should_not_email(user_id)
- Notify.should_not_receive(:note_issue_email).with(user_id, note.id)
- end
- end
- end
-
- context 'commit note' do
- let(:note) { create :note_on_commit }
-
- before do
- build_team(note.project)
- end
-
- describe :new_note do
- it do
- should_email(@u_watcher.id)
- should_not_email(note.author_id)
- should_not_email(@u_participating.id)
- should_not_email(@u_disabled.id)
- notification.new_note(note)
- end
-
- it do
- create(:note_on_commit,
- author: @u_participating,
- project_id: note.project_id,
- commit_id: note.commit_id)
-
- should_email(@u_watcher.id)
- should_email(@u_participating.id)
- should_not_email(note.author_id)
- should_not_email(@u_disabled.id)
- notification.new_note(note)
- end
-
- def should_email(user_id)
- Notify.should_receive(:note_commit_email).with(user_id, note.id)
- end
-
- def should_not_email(user_id)
- Notify.should_not_receive(:note_commit_email).with(user_id, note.id)
- end
- end
- end
- end
-
- describe 'Issues' do
- let(:issue) { create :issue, assignee: create(:user) }
-
- before do
- build_team(issue.project)
- end
-
- describe :new_issue do
- it do
- should_email(issue.assignee_id)
- should_email(@u_watcher.id)
- should_not_email(@u_participating.id)
- should_not_email(@u_disabled.id)
- notification.new_issue(issue, @u_disabled)
- end
-
- def should_email(user_id)
- Notify.should_receive(:new_issue_email).with(user_id, issue.id)
- end
-
- def should_not_email(user_id)
- Notify.should_not_receive(:new_issue_email).with(user_id, issue.id)
- end
- end
-
- describe :reassigned_issue do
- it 'should email new assignee' do
- should_email(issue.assignee_id)
- should_email(@u_watcher.id)
- should_not_email(@u_participating.id)
- should_not_email(@u_disabled.id)
-
- notification.reassigned_issue(issue, @u_disabled)
- end
-
- def should_email(user_id)
- Notify.should_receive(:reassigned_issue_email).with(user_id, issue.id, issue.assignee_id)
- end
-
- def should_not_email(user_id)
- Notify.should_not_receive(:reassigned_issue_email).with(user_id, issue.id, issue.assignee_id)
- end
- end
-
- describe :close_issue do
- it 'should sent email to issue assignee and issue author' do
- should_email(issue.assignee_id)
- should_email(issue.author_id)
- should_email(@u_watcher.id)
- should_not_email(@u_participating.id)
- should_not_email(@u_disabled.id)
-
- notification.close_issue(issue, @u_disabled)
- end
-
- def should_email(user_id)
- Notify.should_receive(:closed_issue_email).with(user_id, issue.id, @u_disabled.id)
- end
-
- def should_not_email(user_id)
- Notify.should_not_receive(:closed_issue_email).with(user_id, issue.id, @u_disabled.id)
- end
- end
- end
-
- describe 'Merge Requests' do
- let(:merge_request) { create :merge_request, assignee: create(:user) }
-
- before do
- build_team(merge_request.project)
- end
-
- describe :new_merge_request do
- it do
- should_email(merge_request.assignee_id)
- should_email(@u_watcher.id)
- should_not_email(@u_participating.id)
- should_not_email(@u_disabled.id)
- notification.new_merge_request(merge_request, @u_disabled)
- end
-
- def should_email(user_id)
- Notify.should_receive(:new_merge_request_email).with(user_id, merge_request.id)
- end
-
- def should_not_email(user_id)
- Notify.should_not_receive(:new_merge_request_email).with(user_id, merge_request.id)
- end
- end
-
- describe :reassigned_merge_request do
- it do
- should_email(merge_request.assignee_id)
- should_email(@u_watcher.id)
- should_not_email(@u_participating.id)
- should_not_email(@u_disabled.id)
- notification.reassigned_merge_request(merge_request, merge_request.author)
- end
-
- def should_email(user_id)
- Notify.should_receive(:reassigned_merge_request_email).with(user_id, merge_request.id, merge_request.assignee_id)
- end
-
- def should_not_email(user_id)
- Notify.should_not_receive(:reassigned_merge_request_email).with(user_id, merge_request.id, merge_request.assignee_id)
- end
- end
-
- describe :closed_merge_request do
- it do
- should_email(merge_request.assignee_id)
- should_email(@u_watcher.id)
- should_not_email(@u_participating.id)
- should_not_email(@u_disabled.id)
- notification.close_mr(merge_request, @u_disabled)
- end
-
- def should_email(user_id)
- Notify.should_receive(:closed_merge_request_email).with(user_id, merge_request.id, @u_disabled.id)
- end
-
- def should_not_email(user_id)
- Notify.should_not_receive(:closed_merge_request_email).with(user_id, merge_request.id, @u_disabled.id)
- end
- end
-
- describe :merged_merge_request do
- it do
- should_email(merge_request.assignee_id)
- should_email(@u_watcher.id)
- should_not_email(@u_participating.id)
- should_not_email(@u_disabled.id)
- notification.merge_mr(merge_request)
- end
-
- def should_email(user_id)
- Notify.should_receive(:merged_merge_request_email).with(user_id, merge_request.id)
- end
-
- def should_not_email(user_id)
- Notify.should_not_receive(:merged_merge_request_email).with(user_id, merge_request.id)
- end
- end
- end
-
- def build_team(project)
- @u_watcher = create(:user, notification_level: Notification::N_WATCH)
- @u_participating = create(:user, notification_level: Notification::N_PARTICIPATING)
- @u_disabled = create(:user, notification_level: Notification::N_DISABLED)
-
- project.team << [@u_watcher, :master]
- project.team << [@u_participating, :master]
- project.team << [@u_disabled, :master]
- end
-end
diff --git a/spec/services/project_transfer_service_spec.rb b/spec/services/project_transfer_service_spec.rb
deleted file mode 100644
index dea0b0b2..00000000
--- a/spec/services/project_transfer_service_spec.rb
+++ /dev/null
@@ -1,47 +0,0 @@
-require 'spec_helper'
-
-describe ProjectTransferService do
- context 'namespace -> namespace' do
- let(:user) { create(:user) }
- let(:group) { create(:group) }
- let(:project) { create(:project, namespace: user.namespace) }
-
- before do
- @result = service.transfer(project, group)
- end
-
- it { @result.should be_true }
- it { project.namespace.should == group }
- end
-
- context 'namespace -> no namespace' do
- let(:user) { create(:user) }
- let(:project) { create(:project, namespace: user.namespace) }
-
- before do
- @result = service.transfer(project, nil)
- end
-
- it { @result.should be_true }
- it { project.namespace.should == nil }
- end
-
- context 'no namespace -> namespace' do
- let(:project) { create(:project) }
- let(:user) { create(:user) }
-
- before do
- @result = service.transfer(project, user.namespace)
- end
-
- it { @result.should be_true }
- it { project.namespace.should == user.namespace }
- end
-
- def service
- service = ProjectTransferService.new
- service.gitlab_shell.stub(mv_repository: true)
- service
- end
-end
-
diff --git a/spec/services/system_hooks_service_spec.rb b/spec/services/system_hooks_service_spec.rb
deleted file mode 100644
index 7f1590f5..00000000
--- a/spec/services/system_hooks_service_spec.rb
+++ /dev/null
@@ -1,41 +0,0 @@
-require 'spec_helper'
-
-describe SystemHooksService do
- let (:user) { create :user }
- let (:project) { create :project }
- let (:users_project) { create :users_project }
-
- context 'it should build event data' do
- it 'should build event data for user' do
- SystemHooksService.build_event_data(user, :create).should include(:event_name, :name, :created_at, :email)
- end
-
- it 'should build event data for project' do
- SystemHooksService.build_event_data(project, :create).should include(:event_name, :name, :created_at, :path, :project_id, :owner_name, :owner_email)
- end
-
- it 'should build event data for users project' do
- SystemHooksService.build_event_data(users_project, :create).should include(:event_name, :created_at, :project_name, :project_path, :project_id, :user_name, :user_email, :project_access)
- end
- end
-
- context 'it should build event names' do
- it 'should build event names for user' do
- SystemHooksService.build_event_name(user, :create).should eq "user_create"
-
- SystemHooksService.build_event_name(user, :destroy).should eq "user_destroy"
- end
-
- it 'should build event names for project' do
- SystemHooksService.build_event_name(project, :create).should eq "project_create"
-
- SystemHooksService.build_event_name(project, :destroy).should eq "project_destroy"
- end
-
- it 'should build event names for users project' do
- SystemHooksService.build_event_name(users_project, :create).should eq "user_add_to_team"
-
- SystemHooksService.build_event_name(users_project, :destroy).should eq "user_remove_from_team"
- end
- end
-end
diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb
index 8a01c930..9f066c0e 100644
--- a/spec/spec_helper.rb
+++ b/spec/spec_helper.rb
@@ -1,58 +1,49 @@
-require 'rubygems'
-require 'spork'
-
-Spork.prefork do
- require 'simplecov' unless ENV['CI']
-
- if ENV['TRAVIS']
- require 'coveralls'
- Coveralls.wear!
- end
-
- # This file is copied to spec/ when you run 'rails generate rspec:install'
- ENV["RAILS_ENV"] ||= 'test'
- require File.expand_path("../../config/environment", __FILE__)
- require 'rspec/rails'
- require 'capybara/rails'
- require 'capybara/rspec'
- require 'webmock/rspec'
- require 'email_spec'
- require 'sidekiq/testing/inline'
- require 'capybara/poltergeist'
-
- # Loading more in this block will cause your tests to run faster. However,
-
- # if you change any configuration or code from libraries loaded here, you'll
- # need to restart spork for it take effect.
- Capybara.javascript_driver = :poltergeist
- Capybara.default_wait_time = 10
-
- # Requires supporting ruby files with custom matchers and macros, etc,
- # in spec/support/ and its subdirectories.
- Dir[Rails.root.join("spec/support/**/*.rb")].each {|f| require f}
-
- WebMock.disable_net_connect!(allow_localhost: true)
-
- RSpec.configure do |config|
- config.mock_with :rspec
-
- config.include LoginHelpers, type: :feature
- config.include LoginHelpers, type: :request
- config.include FactoryGirl::Syntax::Methods
- config.include Devise::TestHelpers, type: :controller
-
- # If you're not using ActiveRecord, or you'd prefer not to run each of your
- # examples within a transaction, remove the following line or assign false
- # instead of true.
- config.use_transactional_fixtures = false
-
- config.before do
- TestEnv.init
- end
- end
+unless ENV['CI']
+ require 'simplecov'
+ SimpleCov.start 'rails'
end
-Spork.each_run do
- # This code will be run each time you run your specs.
+# This file is copied to spec/ when you run 'rails generate rspec:install'
+ENV["RAILS_ENV"] ||= 'test'
+require File.expand_path("../../config/environment", __FILE__)
+require 'rspec/rails'
+require 'capybara/rails'
+require 'capybara/rspec'
+require 'webmock/rspec'
+require 'email_spec'
+# Requires supporting ruby files with custom matchers and macros, etc,
+# in spec/support/ and its subdirectories.
+Dir[Rails.root.join("spec/support/**/*.rb")].each {|f| require f}
+
+require 'capybara/poltergeist'
+Capybara.javascript_driver = :poltergeist
+
+WebMock.disable_net_connect!(allow_localhost: true)
+
+RSpec.configure do |config|
+ config.mock_with :rspec
+
+ config.include LoginHelpers, type: :request
+ config.include GitoliteStub
+ config.include FactoryGirl::Syntax::Methods
+ config.include Devise::TestHelpers, type: :controller
+
+ # If you're not using ActiveRecord, or you'd prefer not to run each of your
+ # examples within a transaction, remove the following line or assign false
+ # instead of true.
+ config.use_transactional_fixtures = false
+
+ config.before do
+ stub_gitolite!
+
+ # !!! Observers disabled by default in tests
+ ActiveRecord::Base.observers.disable(:all)
+ # ActiveRecord::Base.observers.enable(:all)
+
+ # Use tmp dir for FS manipulations
+ Gitlab.config.gitolite.stub(repos_path: Rails.root.join('tmp', 'test-git-base-path'))
+ FileUtils.rm_rf Gitlab.config.gitolite.repos_path
+ FileUtils.mkdir_p Gitlab.config.gitolite.repos_path
+ end
end
diff --git a/spec/support/db_cleaner.rb b/spec/support/db_cleaner.rb
index 8c9c74f1..f1e072aa 100644
--- a/spec/support/db_cleaner.rb
+++ b/spec/support/db_cleaner.rb
@@ -9,14 +9,10 @@ RSpec.configure do |config|
DatabaseCleaner.strategy = :transaction
end
- unless example.metadata[:no_db]
- DatabaseCleaner.start
- end
+ DatabaseCleaner.start
end
config.after do
- unless example.metadata[:no_db]
- DatabaseCleaner.clean
- end
+ DatabaseCleaner.clean
end
end
diff --git a/spec/support/gitolite_stub.rb b/spec/support/gitolite_stub.rb
new file mode 100644
index 00000000..574bb5a1
--- /dev/null
+++ b/spec/support/gitolite_stub.rb
@@ -0,0 +1,21 @@
+module GitoliteStub
+ def stub_gitolite!
+ stub_gitlab_gitolite
+ stub_gitolite_admin
+ end
+
+ def stub_gitolite_admin
+ gitolite_admin = double('Gitolite::GitoliteAdmin')
+ gitolite_admin.as_null_object
+
+ Gitolite::GitoliteAdmin.stub(new: gitolite_admin)
+ end
+
+ def stub_gitlab_gitolite
+ gitolite_config = double('Gitlab::GitoliteConfig')
+ gitolite_config.stub(apply: ->() { yield(self) })
+ gitolite_config.as_null_object
+
+ Gitlab::GitoliteConfig.stub(new: gitolite_config)
+ end
+end
diff --git a/spec/support/login_helpers.rb b/spec/support/login_helpers.rb
index d423ccf8..4579c971 100644
--- a/spec/support/login_helpers.rb
+++ b/spec/support/login_helpers.rb
@@ -12,7 +12,7 @@ module LoginHelpers
# user - User instance to login with
def login_with(user)
visit new_user_session_path
- fill_in "user_login", with: user.email
+ fill_in "user_email", with: user.email
fill_in "user_password", with: "123456"
click_button "Sign in"
end
diff --git a/spec/support/select2_helper.rb b/spec/support/select2_helper.rb
deleted file mode 100644
index 20dd9bf4..00000000
--- a/spec/support/select2_helper.rb
+++ /dev/null
@@ -1,25 +0,0 @@
-# Select2 ajax programatic helper
-# It allows you to select value from select2
-#
-# Params
-# value - real value of selected item
-# opts - options containing css selector
-#
-# Usage:
-#
-# select2(2, from: '#user_ids')
-#
-
-module Select2Helper
- def select2(value, options={})
- raise "Must pass a hash containing 'from'" if not options.is_a?(Hash) or not options.has_key?(:from)
-
- selector = options[:from]
-
- if options[:multiple]
- page.execute_script("$('#{selector}').select2('val', ['#{value}']);")
- else
- page.execute_script("$('#{selector}').select2('val', '#{value}');")
- end
- end
-end
diff --git a/spec/support/stubbed_repository.rb b/spec/support/stubbed_repository.rb
new file mode 100644
index 00000000..5bf3ea46
--- /dev/null
+++ b/spec/support/stubbed_repository.rb
@@ -0,0 +1,31 @@
+# Stubs out all Git repository access done by models so that specs can run
+# against fake repositories without Grit complaining that they don't exist.
+module StubbedRepository
+ def path_to_repo
+ if new_record? || path == 'newproject'
+ # There are a couple Project specs and features that expect the Project's
+ # path to be in the returned path, so let's patronize them.
+ Rails.root.join('tmp', 'repositories', path)
+ else
+ # For everything else, just give it the path to one of our real seeded
+ # repos.
+ Rails.root.join('tmp', 'repositories', 'gitlabhq')
+ end
+ end
+
+ def satellite
+ FakeSatellite.new
+ end
+
+ class FakeSatellite
+ def exists?
+ true
+ end
+
+ def create
+ true
+ end
+ end
+end
+
+Project.send(:include, StubbedRepository)
diff --git a/spec/support/test_env.rb b/spec/support/test_env.rb
deleted file mode 100644
index 370094d3..00000000
--- a/spec/support/test_env.rb
+++ /dev/null
@@ -1,63 +0,0 @@
-module TestEnv
- extend self
-
- # Test environment
- #
- # all repositories and namespaces stored at
- # RAILS_APP/tmp/test-git-base-path
- #
- # Next shell methods are stubbed and return true
- # - mv_repository
- # - remove_repository
- # - add_key
- # - remove_key
- #
- def init
- # Use tmp dir for FS manipulations
- repos_path = Rails.root.join('tmp', 'test-git-base-path')
- Gitlab.config.gitlab_shell.stub(repos_path: repos_path)
-
- GollumWiki.any_instance.stub(:init_repo) do |path|
- create_temp_repo(File.join(repos_path, "#{path}.git"))
- end
-
- Gitlab::Shell.any_instance.stub(
- add_repository: true,
- mv_repository: true,
- remove_repository: true,
- add_key: true,
- remove_key: true
- )
-
- Gitlab::Satellite::Satellite.any_instance.stub(
- exists?: true,
- destroy: true,
- create: true
- )
-
- MergeRequest.any_instance.stub(
- check_if_can_be_merged: true
- )
-
- Repository.any_instance.stub(
- size: 12.45
- )
-
- # Remove tmp/test-git-base-path
- FileUtils.rm_rf Gitlab.config.gitlab_shell.repos_path
-
- # Recreate tmp/test-git-base-path
- FileUtils.mkdir_p Gitlab.config.gitlab_shell.repos_path
-
- # Symlink tmp/repositories/gitlabhq to tmp/test-git-base-path/gitlabhq
- seed_repo = Rails.root.join('tmp', 'repositories', 'gitlabhq')
- target_repo = File.join(repos_path, 'gitlabhq.git')
- system("ln -s #{seed_repo} #{target_repo}")
- end
-
- def create_temp_repo(path)
- FileUtils.mkdir_p path
- command = "git init --quiet --bare #{path};"
- system(command)
- end
-end
diff --git a/spec/tasks/gitlab/backup_rake_spec.rb b/spec/tasks/gitlab/backup_rake_spec.rb
index babbf291..b17521e0 100644
--- a/spec/tasks/gitlab/backup_rake_spec.rb
+++ b/spec/tasks/gitlab/backup_rake_spec.rb
@@ -3,7 +3,6 @@ require 'rake'
describe 'gitlab:app namespace rake task' do
before :all do
- Rake.application.rake_require "tasks/gitlab/task_helpers"
Rake.application.rake_require "tasks/gitlab/backup"
# empty task as env is already loaded
Rake::Task.define_task :environment
diff --git a/spec/workers/post_receive_spec.rb b/spec/workers/post_receive_spec.rb
index 46e86dbe..26b461c3 100644
--- a/spec/workers/post_receive_spec.rb
+++ b/spec/workers/post_receive_spec.rb
@@ -4,26 +4,27 @@ describe PostReceive do
context "as a resque worker" do
it "reponds to #perform" do
- PostReceive.new.should respond_to(:perform)
+ PostReceive.should respond_to(:perform)
end
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 }
+ let(:key_id) { key.identifier }
it "fetches the correct project" do
Project.should_receive(:find_with_namespace).with(project.path_with_namespace).and_return(project)
- PostReceive.new.perform(pwd(project), 'sha-old', 'sha-new', 'refs/heads/master', key_id)
+ PostReceive.perform(pwd(project), 'sha-old', 'sha-new', 'refs/heads/master', key_id)
end
it "does not run if the author is not in the project" do
- Key.stub(find_by_id: nil)
+ Key.stub(find_by_identifier: nil)
+ project.should_not_receive(:observe_push)
project.should_not_receive(:execute_hooks)
- PostReceive.new.perform(pwd(project), 'sha-old', 'sha-new', 'refs/heads/master', key_id).should be_false
+ PostReceive.perform(pwd(project), 'sha-old', 'sha-new', 'refs/heads/master', key_id).should be_false
end
it "asks the project to trigger all hooks" do
@@ -31,12 +32,13 @@ describe PostReceive do
project.should_receive(:execute_hooks)
project.should_receive(:execute_services)
project.should_receive(:update_merge_requests)
+ project.should_receive(:observe_push)
- PostReceive.new.perform(pwd(project), 'sha-old', 'sha-new', 'refs/heads/master', key_id)
+ PostReceive.perform(pwd(project), 'sha-old', 'sha-new', 'refs/heads/master', key_id)
end
end
def pwd(project)
- File.join(Gitlab.config.gitlab_shell.repos_path, project.path_with_namespace)
+ File.join(Gitlab.config.gitolite.repos_path, project.path_with_namespace)
end
end
diff --git a/vendor/assets/javascripts/ace-src-noconflict/ace.js b/vendor/assets/javascripts/ace-src-noconflict/ace.js
index 8bd2d9a6..11b4bbb8 100644
--- a/vendor/assets/javascripts/ace-src-noconflict/ace.js
+++ b/vendor/assets/javascripts/ace-src-noconflict/ace.js
@@ -4800,7 +4800,7 @@ var SearchHighlight = require("./search_highlight").SearchHighlight;
/**
* new EditSession(text, mode)
* - text (Document | String): If `text` is a `Document`, it associates the `EditSession` with it. Otherwise, a new `Document` is created, with the initial text
- * - mode (TextMode): The initial language mode to use for the document
+ * - mode (TextMode): The inital language mode to use for the document
*
* Sets up a new `EditSession` and associates it with the given `Document` and `TextMode`.
*
@@ -10068,7 +10068,7 @@ ace.define('ace/token_iterator', ['require', 'exports', 'module' ], function(req
* - initialRow (Number): The row to start the tokenizing at
* - initialColumn (Number): The column to start the tokenizing at
*
- * Creates a new token iterator object. The initial token index is set to the provided row and column coordinates.
+ * Creates a new token iterator object. The inital token index is set to the provided row and column coordinates.
*
**/
var TokenIterator = function(session, initialRow, initialColumn) {
@@ -11946,7 +11946,7 @@ var VirtualRenderer = function(container, theme) {
this.$horizScroll = horizScroll;
if (horizScrollChanged) {
this.scroller.style.overflowX = horizScroll ? "scroll" : "hidden";
- // when we hide scrollbar scroll event isn't emitted
+ // when we hide scrollbar scroll event isn't emited
// leaving session with wrong scrollLeft value
if (!horizScroll)
this.session.setScrollLeft(0);
@@ -13029,7 +13029,7 @@ var Text = function(parentEl) {
var html = [];
// Get the tokens per line as there might be some lines in between
- // being folded.
+ // beeing folded.
this.$renderLine(html, row, false, row == foldStart ? foldLine : false);
// don't use setInnerHtml since we are working with an empty DIV
@@ -14529,7 +14529,7 @@ var Editor = require("./editor").Editor;
* - dir (Number): The direction of lines to select: -1 for up, 1 for down
* - skip (Boolean): If `true`, removes the active selection range
*
- * Finds the next occurrence of text in an active selection and adds it to the selections.
+ * Finds the next occurence of text in an active selection and adds it to the selections.
**/
this.selectMore = function(dir, skip) {
var session = this.session;
@@ -15878,4 +15878,4 @@ ace.define("text!ace/theme/textmate.css", [], ".ace-tm .ace_editor {\n" +
ace[key] = a[key];
});
})();
-
+
\ No newline at end of file
diff --git a/vendor/assets/javascripts/ace-src-noconflict/mode-coldfusion.js b/vendor/assets/javascripts/ace-src-noconflict/mode-coldfusion.js
index aea42145..1b41d001 100644
--- a/vendor/assets/javascripts/ace-src-noconflict/mode-coldfusion.js
+++ b/vendor/assets/javascripts/ace-src-noconflict/mode-coldfusion.js
@@ -1170,7 +1170,7 @@ var JavaScriptHighlightRules = function() {
}
],
// regular expressions are only allowed after certain tokens. This
- // makes sure we don't mix up regexps with the division operator
+ // makes sure we don't mix up regexps with the divison operator
"regex_allowed": [
DocCommentHighlightRules.getStartRule("doc-start"),
{
diff --git a/vendor/assets/javascripts/ace-src-noconflict/mode-groovy.js b/vendor/assets/javascripts/ace-src-noconflict/mode-groovy.js
index 80d153d8..ad7bdf58 100644
--- a/vendor/assets/javascripts/ace-src-noconflict/mode-groovy.js
+++ b/vendor/assets/javascripts/ace-src-noconflict/mode-groovy.js
@@ -337,7 +337,7 @@ var JavaScriptHighlightRules = function() {
}
],
// regular expressions are only allowed after certain tokens. This
- // makes sure we don't mix up regexps with the division operator
+ // makes sure we don't mix up regexps with the divison operator
"regex_allowed": [
DocCommentHighlightRules.getStartRule("doc-start"),
{
diff --git a/vendor/assets/javascripts/ace-src-noconflict/mode-html.js b/vendor/assets/javascripts/ace-src-noconflict/mode-html.js
index 5ec11f14..0ea36845 100644
--- a/vendor/assets/javascripts/ace-src-noconflict/mode-html.js
+++ b/vendor/assets/javascripts/ace-src-noconflict/mode-html.js
@@ -389,7 +389,7 @@ var JavaScriptHighlightRules = function() {
}
],
// regular expressions are only allowed after certain tokens. This
- // makes sure we don't mix up regexps with the division operator
+ // makes sure we don't mix up regexps with the divison operator
"regex_allowed": [
DocCommentHighlightRules.getStartRule("doc-start"),
{
diff --git a/vendor/assets/javascripts/ace-src-noconflict/mode-jade.js b/vendor/assets/javascripts/ace-src-noconflict/mode-jade.js
index 32aafd17..c01a3598 100644
--- a/vendor/assets/javascripts/ace-src-noconflict/mode-jade.js
+++ b/vendor/assets/javascripts/ace-src-noconflict/mode-jade.js
@@ -659,7 +659,7 @@ var JavaScriptHighlightRules = function() {
}
],
// regular expressions are only allowed after certain tokens. This
- // makes sure we don't mix up regexps with the division operator
+ // makes sure we don't mix up regexps with the divison operator
"regex_allowed": [
DocCommentHighlightRules.getStartRule("doc-start"),
{
diff --git a/vendor/assets/javascripts/ace-src-noconflict/mode-java.js b/vendor/assets/javascripts/ace-src-noconflict/mode-java.js
index c05bf0f9..23f9e603 100644
--- a/vendor/assets/javascripts/ace-src-noconflict/mode-java.js
+++ b/vendor/assets/javascripts/ace-src-noconflict/mode-java.js
@@ -338,7 +338,7 @@ var JavaScriptHighlightRules = function() {
}
],
// regular expressions are only allowed after certain tokens. This
- // makes sure we don't mix up regexps with the division operator
+ // makes sure we don't mix up regexps with the divison operator
"regex_allowed": [
DocCommentHighlightRules.getStartRule("doc-start"),
{
diff --git a/vendor/assets/javascripts/ace-src-noconflict/mode-javascript.js b/vendor/assets/javascripts/ace-src-noconflict/mode-javascript.js
index 90cf57eb..d266bffb 100644
--- a/vendor/assets/javascripts/ace-src-noconflict/mode-javascript.js
+++ b/vendor/assets/javascripts/ace-src-noconflict/mode-javascript.js
@@ -342,7 +342,7 @@ var JavaScriptHighlightRules = function() {
}
],
// regular expressions are only allowed after certain tokens. This
- // makes sure we don't mix up regexps with the division operator
+ // makes sure we don't mix up regexps with the divison operator
"regex_allowed": [
DocCommentHighlightRules.getStartRule("doc-start"),
{
diff --git a/vendor/assets/javascripts/ace-src-noconflict/mode-jsp.js b/vendor/assets/javascripts/ace-src-noconflict/mode-jsp.js
index e4f4bcff..c96d25e9 100644
--- a/vendor/assets/javascripts/ace-src-noconflict/mode-jsp.js
+++ b/vendor/assets/javascripts/ace-src-noconflict/mode-jsp.js
@@ -597,7 +597,7 @@ var JavaScriptHighlightRules = function() {
}
],
// regular expressions are only allowed after certain tokens. This
- // makes sure we don't mix up regexps with the division operator
+ // makes sure we don't mix up regexps with the divison operator
"regex_allowed": [
DocCommentHighlightRules.getStartRule("doc-start"),
{
diff --git a/vendor/assets/javascripts/ace-src-noconflict/mode-liquid.js b/vendor/assets/javascripts/ace-src-noconflict/mode-liquid.js
index 3886e739..2623396c 100644
--- a/vendor/assets/javascripts/ace-src-noconflict/mode-liquid.js
+++ b/vendor/assets/javascripts/ace-src-noconflict/mode-liquid.js
@@ -641,7 +641,7 @@ var JavaScriptHighlightRules = function() {
}
],
// regular expressions are only allowed after certain tokens. This
- // makes sure we don't mix up regexps with the division operator
+ // makes sure we don't mix up regexps with the divison operator
"regex_allowed": [
DocCommentHighlightRules.getStartRule("doc-start"),
{
diff --git a/vendor/assets/javascripts/ace-src-noconflict/mode-luahtml.js b/vendor/assets/javascripts/ace-src-noconflict/mode-luahtml.js
index d8a1b653..89bc2ec7 100644
--- a/vendor/assets/javascripts/ace-src-noconflict/mode-luahtml.js
+++ b/vendor/assets/javascripts/ace-src-noconflict/mode-luahtml.js
@@ -466,7 +466,7 @@ var JavaScriptHighlightRules = function() {
}
],
// regular expressions are only allowed after certain tokens. This
- // makes sure we don't mix up regexps with the division operator
+ // makes sure we don't mix up regexps with the divison operator
"regex_allowed": [
DocCommentHighlightRules.getStartRule("doc-start"),
{
@@ -2412,4 +2412,4 @@ oop.inherits(LuaHtmlHighlightRules, HtmlHighlightRules);
exports.LuaHtmlHighlightRules = LuaHtmlHighlightRules;
-});
+});
\ No newline at end of file
diff --git a/vendor/assets/javascripts/ace-src-noconflict/mode-luapage.js b/vendor/assets/javascripts/ace-src-noconflict/mode-luapage.js
index 9be136de..8f03866d 100644
--- a/vendor/assets/javascripts/ace-src-noconflict/mode-luapage.js
+++ b/vendor/assets/javascripts/ace-src-noconflict/mode-luapage.js
@@ -382,7 +382,7 @@ var JavaScriptHighlightRules = function() {
}
],
// regular expressions are only allowed after certain tokens. This
- // makes sure we don't mix up regexps with the division operator
+ // makes sure we don't mix up regexps with the divison operator
"regex_allowed": [
DocCommentHighlightRules.getStartRule("doc-start"),
{
@@ -2477,4 +2477,4 @@ oop.inherits(LuaPageHighlightRules, HtmlHighlightRules);
exports.LuaPageHighlightRules = LuaPageHighlightRules;
-});
+});
\ No newline at end of file
diff --git a/vendor/assets/javascripts/ace-src-noconflict/mode-markdown.js b/vendor/assets/javascripts/ace-src-noconflict/mode-markdown.js
index e1c269ee..179376aa 100644
--- a/vendor/assets/javascripts/ace-src-noconflict/mode-markdown.js
+++ b/vendor/assets/javascripts/ace-src-noconflict/mode-markdown.js
@@ -384,7 +384,7 @@ var JavaScriptHighlightRules = function() {
}
],
// regular expressions are only allowed after certain tokens. This
- // makes sure we don't mix up regexps with the division operator
+ // makes sure we don't mix up regexps with the divison operator
"regex_allowed": [
DocCommentHighlightRules.getStartRule("doc-start"),
{
diff --git a/vendor/assets/javascripts/ace-src-noconflict/mode-php.js b/vendor/assets/javascripts/ace-src-noconflict/mode-php.js
index 40710cee..d3deefc6 100644
--- a/vendor/assets/javascripts/ace-src-noconflict/mode-php.js
+++ b/vendor/assets/javascripts/ace-src-noconflict/mode-php.js
@@ -1685,7 +1685,7 @@ var JavaScriptHighlightRules = function() {
}
],
// regular expressions are only allowed after certain tokens. This
- // makes sure we don't mix up regexps with the division operator
+ // makes sure we don't mix up regexps with the divison operator
"regex_allowed": [
DocCommentHighlightRules.getStartRule("doc-start"),
{
diff --git a/vendor/assets/javascripts/ace-src-noconflict/mode-scala.js b/vendor/assets/javascripts/ace-src-noconflict/mode-scala.js
index 87b8e12b..ee8ebb8f 100644
--- a/vendor/assets/javascripts/ace-src-noconflict/mode-scala.js
+++ b/vendor/assets/javascripts/ace-src-noconflict/mode-scala.js
@@ -338,7 +338,7 @@ var JavaScriptHighlightRules = function() {
}
],
// regular expressions are only allowed after certain tokens. This
- // makes sure we don't mix up regexps with the division operator
+ // makes sure we don't mix up regexps with the divison operator
"regex_allowed": [
DocCommentHighlightRules.getStartRule("doc-start"),
{
diff --git a/vendor/assets/javascripts/ace-src-noconflict/mode-svg.js b/vendor/assets/javascripts/ace-src-noconflict/mode-svg.js
index 96b965ba..29c2b17b 100644
--- a/vendor/assets/javascripts/ace-src-noconflict/mode-svg.js
+++ b/vendor/assets/javascripts/ace-src-noconflict/mode-svg.js
@@ -1177,7 +1177,7 @@ var JavaScriptHighlightRules = function() {
}
],
// regular expressions are only allowed after certain tokens. This
- // makes sure we don't mix up regexps with the division operator
+ // makes sure we don't mix up regexps with the divison operator
"regex_allowed": [
DocCommentHighlightRules.getStartRule("doc-start"),
{
diff --git a/vendor/assets/javascripts/ace-src-noconflict/worker-javascript.js b/vendor/assets/javascripts/ace-src-noconflict/worker-javascript.js
index 671d7bec..923bac6f 100644
--- a/vendor/assets/javascripts/ace-src-noconflict/worker-javascript.js
+++ b/vendor/assets/javascripts/ace-src-noconflict/worker-javascript.js
@@ -2912,7 +2912,7 @@ var JSHINT = (function () {
immed : true, // if immediate invocations must be wrapped in parens
iterator : true, // if the `__iterator__` property should be allowed
jquery : true, // if jQuery globals should be predefined
- lastsemic : true, // if semicolons may be omitted for the trailing
+ lastsemic : true, // if semicolons may be ommitted for the trailing
// statements inside of a one-line blocks.
latedef : true, // if the use before definition should not be tolerated
laxbreak : true, // if line breaks should not be checked
@@ -3674,7 +3674,7 @@ var JSHINT = (function () {
line += 1;
// If smarttabs option is used check for spaces followed by tabs only.
- // Otherwise check for any occurrence of mixed tabs and spaces.
+ // Otherwise check for any occurence of mixed tabs and spaces.
if (option.smarttabs)
at = s.search(/ \t/);
else
diff --git a/vendor/assets/javascripts/ace-src-noconflict/worker-xquery.js b/vendor/assets/javascripts/ace-src-noconflict/worker-xquery.js
index 1d8c512e..494066fd 100644
--- a/vendor/assets/javascripts/ace-src-noconflict/worker-xquery.js
+++ b/vendor/assets/javascripts/ace-src-noconflict/worker-xquery.js
@@ -7609,7 +7609,7 @@ org.antlr.runtime.BaseRecognizer.prototype = {
*
* Until then I'll leave this unimplemented. If there is enough clamor
* it would be possible to keep track of the invocation stack using an
- * auxiliary array, but that will definitely be a performance hit.
+ * auxillary array, but that will definitely be a performance hit.
*/
getRuleInvocationStack: function(e, recognizerClassName)
{
diff --git a/vendor/assets/javascripts/branch-graph.js b/vendor/assets/javascripts/branch-graph.js
new file mode 100644
index 00000000..a7e1e152
--- /dev/null
+++ b/vendor/assets/javascripts/branch-graph.js
@@ -0,0 +1,255 @@
+!function(){
+
+ var BranchGraph = function(element, options){
+ this.element = element;
+ this.options = options;
+
+ this.preparedCommits = {};
+ this.mtime = 0;
+ this.mspace = 0;
+ this.parents = {};
+ this.colors = ["#000"];
+
+ this.load();
+ };
+
+ BranchGraph.prototype.load = function(){
+ $.ajax({
+ url: this.options.url,
+ method: 'get',
+ dataType: 'json',
+ success: $.proxy(function(data){
+ $('.loading', this.element).hide();
+ this.prepareData(data.days, data.commits);
+ this.buildGraph();
+ }, this)
+ });
+ };
+
+ BranchGraph.prototype.prepareData = function(days, commits){
+ this.days = days;
+ this.dayCount = days.length;
+ this.commits = commits;
+ this.commitCount = commits.length;
+
+ this.collectParents();
+
+ this.mtime += 4;
+ this.mspace += 10;
+ for (var i = 0; i < this.commitCount; i++) {
+ if (this.commits[i].id in this.parents) {
+ this.commits[i].isParent = true;
+ }
+ this.preparedCommits[this.commits[i].id] = this.commits[i];
+ }
+ this.collectColors();
+ };
+
+ BranchGraph.prototype.collectParents = function(){
+ for (var i = 0; i < this.commitCount; i++) {
+ for (var j = 0, jj = this.commits[i].parents.length; j < jj; j++) {
+ this.parents[this.commits[i].parents[j][0]] = true;
+ }
+ this.mtime = Math.max(this.mtime, this.commits[i].time);
+ this.mspace = Math.max(this.mspace, this.commits[i].space);
+ }
+ };
+
+ BranchGraph.prototype.collectColors = function(){
+ for (var k = 0; k < this.mspace; k++) {
+ this.colors.push(Raphael.getColor());
+ }
+ };
+
+ BranchGraph.prototype.buildGraph = function(){
+ var graphWidth = $(this.element).width()
+ , ch = this.mspace * 20 + 20
+ , cw = Math.max(graphWidth, this.mtime * 20 + 20)
+ , r = Raphael(this.element.get(0), cw, ch)
+ , top = r.set()
+ , cuday = 0
+ , cumonth = ""
+ , offsetX = 20
+ , offsetY = 60
+ , barWidth = Math.max(graphWidth, this.dayCount * 20 + 80);
+
+ this.raphael = r;
+
+ r.rect(0, 0, barWidth, 20).attr({fill: "#222"});
+ r.rect(0, 20, barWidth, 20).attr({fill: "#444"});
+
+ for (mm = 0; mm < this.dayCount; mm++) {
+ if(this.days[mm] != null){
+ if(cuday != this.days[mm][0]){
+ // Dates
+ r.text(offsetX + mm * 20, 31, this.days[mm][0]).attr({
+ font: "12px Monaco, Arial",
+ fill: "#DDD"
+ });
+ cuday = this.days[mm][0];
+ }
+ if(cumonth != this.days[mm][1]){
+ // Months
+ r.text(offsetX + mm * 20, 11, this.days[mm][1]).attr({
+ font: "12px Monaco, Arial",
+ fill: "#EEE"
+ });
+ cumonth = this.days[mm][1];
+ }
+ }
+ }
+
+ for (i = 0; i < this.commitCount; i++) {
+ var x = offsetX + 20 * this.commits[i].time
+ , y = offsetY + 20 * this.commits[i].space;
+ r.circle(x, y, 3).attr({
+ fill: this.colors[this.commits[i].space],
+ stroke: "none"
+ });
+ if (this.commits[i].refs != null && this.commits[i].refs != "") {
+ var longrefs = this.commits[i].refs
+ , shortrefs = this.commits[i].refs;
+ if (shortrefs.length > 15){
+ shortrefs = shortrefs.substr(0,13) + "...";
+ }
+ var t = r.text(x+5, y+8, shortrefs).attr({
+ font: "12px Monaco, Arial",
+ fill: "#666",
+ title: longrefs,
+ cursor: "pointer",
+ rotation: "90"
+ });
+
+ var textbox = t.getBBox();
+ t.translate(textbox.height/-4, textbox.width/2);
+ }
+ var c;
+ for (var j = 0, jj = this.commits[i].parents.length; j < jj; j++) {
+ c = this.preparedCommits[this.commits[i].parents[j][0]];
+ if (c) {
+ var cx = offsetX + 20 * c.time
+ , cy = offsetY + 20 * c.space;
+ if (c.space == this.commits[i].space) {
+ r.path([
+ "M", x, y,
+ "L", x - 20 * (c.time + 1), y
+ ]).attr({
+ stroke: this.colors[c.space],
+ "stroke-width": 2
+ });
+
+ } else if (c.space < this.commits[i].space) {
+ r.path(["M", x - 5, y + .0001, "l-5-2,0,4,5,-2C", x - 5, y, x - 17, y + 2, x - 20, y - 5, "L", cx, y - 5, cx, cy])
+ .attr({
+ stroke: this.colors[this.commits[i].space],
+ "stroke-width": 2
+ });
+ } else {
+ r.path(["M", x - 3, y + 6, "l-4,3,4,2,0,-5L", x - 10, y + 20, "L", x - 10, cy, cx, cy])
+ .attr({
+ stroke: this.colors[c.space],
+ "stroke-width": 2
+ });
+ }
+ }
+ }
+ this.appendAnchor(top, this.commits[i], x, y);
+ }
+ top.toFront();
+ this.element.scrollLeft(cw);
+ this.bindEvents();
+ };
+
+ BranchGraph.prototype.bindEvents = function(){
+ var drag = {}
+ , element = this.element;
+
+ var dragger = function(event){
+ element.scrollLeft(drag.sl - (event.clientX - drag.x));
+ element.scrollTop(drag.st - (event.clientY - drag.y));
+ };
+
+ element.on({
+ mousedown: function (event) {
+ drag = {
+ x: event.clientX,
+ y: event.clientY,
+ st: element.scrollTop(),
+ sl: element.scrollLeft()
+ };
+ $(window).on('mousemove', dragger);
+ }
+ });
+ $(window).on({
+ mouseup: function(){
+ //bars.animate({opacity: 0}, 300);
+ $(window).off('mousemove', dragger);
+ },
+ keydown: function(event){
+ if(event.keyCode == 37){
+ // left
+ element.scrollLeft( element.scrollLeft() - 50);
+ }
+ if(event.keyCode == 38){
+ // top
+ element.scrollTop( element.scrollTop() - 50);
+ }
+ if(event.keyCode == 39){
+ // right
+ element.scrollLeft( element.scrollLeft() + 50);
+ }
+ if(event.keyCode == 40){
+ // bottom
+ element.scrollTop( element.scrollTop() + 50);
+ }
+ }
+ });
+ };
+
+ BranchGraph.prototype.appendAnchor = function(top, c, x, y) {
+ var r = this.raphael
+ , options = this.options
+ , anchor;
+ anchor = r.circle(x, y, 10).attr({
+ fill: "#000",
+ opacity: 0,
+ cursor: "pointer"
+ })
+ .click(function(){
+ window.location = options.commit_url.replace('%s', c.id);
+ })
+ .hover(function(){
+ var text = r.text(100, 100, c.author + "\n \n" + c.id + "\n \n" + c.message).attr({
+ fill: "#fff"
+ });
+ this.popup = r.tooltip(x, y + 5, text, 0);
+ top.push(this.popup.insertBefore(this));
+ }, function(){
+ this.popup && this.popup.remove() && delete this.popup;
+ });
+ top.push(anchor);
+ };
+
+ this.BranchGraph = BranchGraph;
+
+}(this);
+Raphael.fn.tooltip = function (x, y, set, dir, size) {
+ dir = dir == null ? 2 : dir;
+ size = size || 5;
+ x = Math.round(x);
+ y = Math.round(y);
+ var mmax = Math.max
+ , bb = set.getBBox()
+ , w = Math.round(bb.width / 2)
+ , h = Math.round(bb.height / 2)
+ , dx = [0, w + size * 2, 0, -w - size * 2]
+ , dy = [-h * 2 - size * 3, -h - size, 0, -h - size]
+ , p = ["M", x - dx[dir], y - dy[dir], "l", -size, (dir == 2) * -size, -mmax(w - size, 0), 0, "a", size, size, 0, 0, 1, -size, -size,
+ "l", 0, -mmax(h - size, 0), (dir == 3) * -size, -size, (dir == 3) * size, -size, 0, -mmax(h - size, 0), "a", size, size, 0, 0, 1, size, -size,
+ "l", mmax(w - size, 0), 0, size, !dir * -size, size, !dir * size, mmax(w - size, 0), 0, "a", size, size, 0, 0, 1, size, size,
+ "l", 0, mmax(h - size, 0), (dir == 1) * size, size, (dir == 1) * -size, size, 0, mmax(h - size, 0), "a", size, size, 0, 0, 1, -size, size,
+ "l", -mmax(w - size, 0), 0, "z"].join(",")
+ , xy = [{x: x, y: y + size * 2 + h}, {x: x - size * 2 - w, y: y}, {x: x, y: y - size * 2 - h}, {x: x + size * 2 + w, y: y}][dir];
+ set.translate(xy.x - w - bb.x, xy.y - h - bb.y);
+ return this.set(this.path(p).attr({fill: "#234", stroke: "none"}).insertBefore(set.node ? set : set[0]), set);
+};
diff --git a/vendor/assets/javascripts/g.bar-min.js b/vendor/assets/javascripts/g.bar-min.js
index 7620dabd..42f452af 100644
--- a/vendor/assets/javascripts/g.bar-min.js
+++ b/vendor/assets/javascripts/g.bar-min.js
@@ -3,6 +3,5 @@
*
* Copyright (c) 2009 Dmitry Baranovskiy (http://g.raphaeljs.com)
* Licensed under the MIT (http://www.opensource.org/licenses/mit-license.php) license.
- * From: https://github.com/jhurt/g.raphael/blob/master/g.bar.js
*/
-(function(){function c(c,d,e,f,g,h,i,j){var k,l={round:"round",sharp:"sharp",soft:"soft",square:"square"};if(g&&!f||!g&&!e)return i?"":j.path();switch(h=l[h]||"square",f=Math.round(f),e=Math.round(e),c=Math.round(c),d=Math.round(d),h){case"round":if(g)m=~~(e/2),m>f?(m=f,k=["M",c-~~(e/2),d,"l",0,0,"a",~~(e/2),m,0,0,1,e,0,"l",0,0,"z"]):k=["M",c-m,d,"l",0,m-f,"a",m,m,0,1,1,e,0,"l",0,f-m,"z"];else{var m=~~(f/2);m>e?(m=e,k=["M",c+.5,d+.5-~~(f/2),"l",0,0,"a",m,~~(f/2),0,0,1,0,f,"l",0,0,"z"]):k=["M",c+.5,d+.5-m,"l",e-m,0,"a",m,m,0,1,1,0,f,"l",m-e,0,"z"]}break;case"sharp":if(g)n=~~(e/2),k=["M",c+n,d,"l",-e,0,0,-b(f-n,0),n,-a(n,f),n,a(n,f),n,"z"];else{var n=~~(f/2);k=["M",c,d+n,"l",0,-f,b(e-n,0),0,a(n,e),n,-a(n,e),n+(f>2*n),"z"]}break;case"square":k=g?["M",c+~~(e/2),d,"l",1-e,0,0,-f,e-1,0,"z"]:["M",c,d+~~(f/2),"l",0,-f,e,0,0,f,"z"];break;case"soft":g?(m=a(Math.round(e/5),f),k=["M",c-~~(e/2),d,"l",0,m-f,"a",m,m,0,0,1,m,-m,"l",e-2*m,0,"a",m,m,0,0,1,m,m,"l",0,f-m,"z"]):(m=a(e,Math.round(f/5)),k=["M",c+.5,d+.5-~~(f/2),"l",e-m,0,"a",m,m,0,0,1,m,m,"l",0,f-2*m,"a",m,m,0,0,1,-m,m,"l",m-e,0,"z"])}return i?k.join(","):j.path(k)}function d(a,b,d,e,f,g,h){h=h||{};var i=this,j=h.type||"square",k=parseFloat(h.gutter||"20%"),l=a.set(),m=a.set(),n=a.set(),o=a.set(),p=Math.max.apply(Math,g),q=[],r=0,s=h.colors||i.colors,t=g.length;if(Raphael.is(g[0],"array")){p=[],r=t,t=0;for(var u=g.length;u--;)m.push(a.set()),p.push(Math.max.apply(Math,g[u])),t=Math.max(t,g[u].length);if(h.stacked)for(var u=t;u--;){for(var v=0,w=g.length;w--;)v+=+g[w][u]||0;q.push(v)}for(var u=g.length;u--;)if(t>g[u].length)for(var w=t;w--;)g[u].push(0);p=Math.max.apply(Math,h.stacked?q:p)}p=h.to||p;var x=100*(e/(t*(100+k)+k)),y=x*k/100,z=null==h.vgutter?20:h.vgutter,A=[],B=b+y,C=(f-2*z)/p;h.stretch||(y=Math.round(y),x=Math.floor(x)),!h.stacked&&(x/=r||1);for(var u=0;t>u;u++){A=[];for(var w=0;(r||1)>w;w++){var D=Math.round((r?g[w][u]:g[u])*C),E=d+f-z-D,F=c(Math.round(B+x/2),E+D,x,D,!0,j,null,a).attr({stroke:"none",fill:s[r?w:u]});r?m[w].push(F):m.push(F),F.y=E,F.x=Math.round(B+x/2),F.w=x,F.h=D,F.value=r?g[w][u]:g[u],h.stacked?A.push(F):B+=x}if(h.stacked){var G;o.push(G=a.rect(A[0].x-A[0].w/2,d,x,f).attr(i.shim)),G.bars=a.set();for(var H=0,I=A.length;I--;)A[I].toFront();for(var I=0,J=A.length;J>I;I++){var K,F=A[I],D=(H+F.value)*C,L=c(F.x,d+f-z-.5*!!H,x,D,!0,j,1,a);G.bars.push(F),H&&F.attr({path:L}),F.h=D,F.y=d+f-z-.5*!!H-D,n.push(K=a.rect(F.x-F.w/2,F.y,x,F.value*C).attr(i.shim)),K.bar=F,K.value=F.value,H+=F.value}B+=x}B+=y}if(o.toFront(),B=b+y,!h.stacked)for(var u=0;t>u;u++){for(var w=0;(r||1)>w;w++){var K;n.push(K=a.rect(Math.round(B),d+z,x,f-z).attr(i.shim)),K.bar=r?m[w][u]:m[u],K.value=K.bar.value,B+=x}B+=y}return l.label=function(b,c){b=b||[],this.labels=a.set();var e,j=-1/0;if(h.stacked){for(var k=0;t>k;k++)for(var l=0,o=0;(r||1)>o;o++)if(l+=r?g[o][k]:g[k],o==r-1){var q=i.labelise(b[k],l,p);e=a.text(m[o][k].x,d+f-z/2,q).attr(i.txtattr).attr({fill:h.legendcolor||"#000","text-anchor":"start"}).insertBefore(n[k*(r||1)+o]);var s=e.getBBox();j>s.x-7?e.remove():(this.labels.push(e),j=s.x+s.width)}}else for(var k=0;t>k;k++)for(var o=0;(r||1)>o;o++){var q=i.labelise(r?b[o]&&b[o][k]:b[k],r?g[o][k]:g[k],p);e=a.text(m[o][k].x-x/2,c?d+f-z/2:m[o][k].y-10,q).attr(i.txtattr).attr({fill:h.legendcolor||"#000","text-anchor":"start"}).insertBefore(n[k*(r||1)+o]);var s=e.getBBox();e.translate((x-s.width)/2,1),j>s.x-7?e.remove():(this.labels.push(e),j=s.x+s.width)}return this},l.hover=function(a,b){return o.hide(),n.show(),n.mouseover(a).mouseout(b),this},l.hoverColumn=function(a,b){return n.hide(),o.show(),b=b||function(){},o.mouseover(a).mouseout(b),this},l.click=function(a){return o.hide(),n.show(),n.click(a),this},l.each=function(a){if(!Raphael.is(a,"function"))return this;for(var b=n.length;b--;)a.call(n[b]);return this},l.eachColumn=function(a){if(!Raphael.is(a,"function"))return this;for(var b=o.length;b--;)a.call(o[b]);return this},l.clickColumn=function(a){return n.hide(),o.show(),o.click(a),this},l.push(m,n,o),l.bars=m,l.covers=n,l}function e(a,b,d,e,f,g,h){h=h||{};var i=this,j=h.type||"square",k=parseFloat(h.gutter||"20%"),l=a.set(),m=a.set(),n=a.set(),o=a.set(),p=Math.max.apply(Math,g),q=[],r=0,s=h.colors||i.colors,t=g.length;if(Raphael.is(g[0],"array")){p=[],r=t,t=0;for(var u=g.length;u--;)m.push(a.set()),p.push(Math.max.apply(Math,g[u])),t=Math.max(t,g[u].length);if(h.stacked)for(var u=t;u--;){for(var v=0,w=g.length;w--;)v+=+g[w][u]||0;q.push(v)}for(var u=g.length;u--;)if(t>g[u].length)for(var w=t;w--;)g[u].push(0);p=Math.max.apply(Math,h.stacked?q:p)}p=h.to||p;var x=Math.floor(100*(f/(t*(100+k)+k))),y=Math.floor(x*k/100),z=[],A=d+y,B=(e-1)/p;!h.stacked&&(x/=r||1);for(var u=0;t>u;u++){z=[];for(var w=0;(r||1)>w;w++){var C=r?g[w][u]:g[u],D=c(b,A+x/2,Math.round(C*B),x-1,!1,j,null,a).attr({stroke:"none",fill:s[r?w:u]});r?m[w].push(D):m.push(D),D.x=b+Math.round(C*B),D.y=A+x/2,D.w=Math.round(C*B),D.h=x,D.value=+C,h.stacked?z.push(D):A+=x}if(h.stacked){var E=a.rect(b,z[0].y-z[0].h/2,e,x).attr(i.shim);o.push(E),E.bars=a.set();for(var F=0,G=z.length;G--;)z[G].toFront();for(var G=0,H=z.length;H>G;G++){var I,D=z[G],C=Math.round((F+D.value)*B),J=c(b,D.y,C,x-1,!1,j,1,a);E.bars.push(D),F&&D.attr({path:J}),D.w=C,D.x=b+C,n.push(I=a.rect(b+F*B,D.y-D.h/2,D.value*B,x).attr(i.shim)),I.bar=D,F+=D.value}A+=x}A+=y}if(o.toFront(),A=d+y,!h.stacked)for(var u=0;t>u;u++){for(var w=0;(r||1)>w;w++){var I=a.rect(b,A,e,x).attr(i.shim);n.push(I),I.bar=r?m[w][u]:m[u],I.value=I.bar.value,A+=x}A+=y}return l.label=function(c,d){c=c||[],this.labels=a.set();for(var e=0;t>e;e++)for(var f=0;r>f;f++){var o,j=i.labelise(r?c[f]&&c[f][e]:c[e],r?g[f][e]:g[e],p),k=d?m[f][e].x-x/2+3:b+5;this.labels.push(o=a.text(k,m[f][e].y,j).attr(i.txtattr).attr({fill:h.legendcolor||"#000","text-anchor":"start"}).insertBefore(n[0])),b+5>o.getBBox().x?o.attr({x:b+5,"text-anchor":"start"}):m[f][e].label=o}return this},l.hover=function(a,b){return o.hide(),n.show(),b=b||function(){},n.mouseover(a).mouseout(b),this},l.hoverColumn=function(a,b){return n.hide(),o.show(),b=b||function(){},o.mouseover(a).mouseout(b),this},l.each=function(a){if(!Raphael.is(a,"function"))return this;for(var b=n.length;b--;)a.call(n[b]);return this},l.eachColumn=function(a){if(!Raphael.is(a,"function"))return this;for(var b=o.length;b--;)a.call(o[b]);return this},l.click=function(a){return o.hide(),n.show(),n.click(a),this},l.clickColumn=function(a){return n.hide(),o.show(),o.click(a),this},l.push(m,n,o),l.bars=m,l.covers=n,l}var a=Math.min,b=Math.max,f=function(){};f.prototype=Raphael.g,e.prototype=d.prototype=new f,Raphael.fn.hbarchart=function(a,b,c,d,f,g){return new e(this,a,b,c,d,f,g)},Raphael.fn.barchart=function(a,b,c,e,f,g){return new d(this,a,b,c,e,f,g)}})();
\ No newline at end of file
+(function(){var f=Math.min,a=Math.max;function e(o,m,h,p,j,k,l,i){var s,n={round:"round",sharp:"sharp",soft:"soft",square:"square"};if((j&&!p)||(!j&&!h)){return l?"":i.path()}k=n[k]||"square";p=Math.round(p);h=Math.round(h);o=Math.round(o);m=Math.round(m);switch(k){case"round":if(!j){var g=~~(p/2);if(h=2*b?g.attr({path:["M",c,d+b,"a",b,b,0,1,1,0,2*-b,b,b,0,1,1,0,2*b,"m",0,2*-b-e,"a",b+e,b+e,0,1,0,0,2*(b+e),"L",c+b+e,d+h.height/2+e,"l",h.width+2*e,0,0,-h.height-2*e,-h.width-2*e,0,"L",c,d-b-e].join(",")}):(i=Math.sqrt(Math.pow(b+e,2)-Math.pow(h.height/2+e,2)),g.attr({path:["M",c,d+b,"c",-j,0,-b,j-b,-b,-b,0,-j,b-j,-b,b,-b,j,0,b,b-j,b,b,0,j,j-b,b,-b,b,"M",c+i,d-h.height/2-e,"a",b+e,b+e,0,1,0,0,h.height+2*e,"l",b+e-i+h.width+2*e,0,0,-h.height-2*e,"L",c+i,d-h.height/2-e].join(",")})),a=360-a,g.rotate(a,c,d),this.attrs?(this.attr(this.attrs.x?"x":"cx",c+b+e+(k?h.width/2:"text"==this.type?h.width:0)).attr("y",k?d:d-h.height/2),this.rotate(a,c,d),a>90&&270>a&&this.attr(this.attrs.x?"x":"cx",c-b-e-(k?h.width/2:h.width)).rotate(180,c,d)):a>90&&270>a?(this.translate(c-h.x-h.width-b-e,d-h.y-h.height/2),this.rotate(a-180,h.x+h.width+b+e,h.y+h.height/2)):(this.translate(c-h.x+b+e,d-h.y-h.height/2),this.rotate(a,h.x-b-e,h.y+h.height/2)),g.insertBefore(this.node?this:this[0])}},Raphael.el.drop=function(a,b,c){var f,g,h,i,j,d=this.getBBox(),e=this.paper||this[0].paper;if(e){switch(this.type){case"text":case"circle":case"ellipse":f=!0;break;default:f=!1}return a=a||0,b="number"==typeof b?b:f?d.x+d.width/2:d.x,c="number"==typeof c?c:f?d.y+d.height/2:d.y,g=Math.max(d.width,d.height)+Math.min(d.width,d.height),h=e.path(["M",b,c,"l",g,0,"A",.4*g,.4*g,0,1,0,b+.7*g,c-.7*g,"z"]).attr({fill:"#000",stroke:"none"}).rotate(22.5-a,b,c),a=(a+90)*Math.PI/180,i=b+g*Math.sin(a)-(f?0:d.width/2),j=c+g*Math.cos(a)-(f?0:d.height/2),this.attrs?this.attr(this.attrs.x?"x":"cx",i).attr(this.attrs.y?"y":"cy",j):this.translate(i-d.x,j-d.y),h.insertBefore(this.node?this:this[0])}},Raphael.el.flag=function(a,b,c){var d=3,e=this.paper||this[0].paper;if(e){var i,f=e.path().attr({fill:"#000",stroke:"#000"}),g=this.getBBox(),h=g.height/2;switch(this.type){case"text":case"circle":case"ellipse":i=!0;break;default:i=!1}return a=a||0,b="number"==typeof b?b:i?g.x+g.width/2:g.x,c="number"==typeof c?c:i?g.y+g.height/2:g.y,f.attr({path:["M",b,c,"l",h+d,-h-d,g.width+2*d,0,0,g.height+2*d,-g.width-2*d,0,"z"].join(",")}),a=360-a,f.rotate(a,b,c),this.attrs?(this.attr(this.attrs.x?"x":"cx",b+h+d+(i?g.width/2:"text"==this.type?g.width:0)).attr("y",i?c:c-g.height/2),this.rotate(a,b,c),a>90&&270>a&&this.attr(this.attrs.x?"x":"cx",b-h-d-(i?g.width/2:g.width)).rotate(180,b,c)):a>90&&270>a?(this.translate(b-g.x-g.width-h-d,c-g.y-g.height/2),this.rotate(a-180,g.x+g.width+h+d,g.y+g.height/2)):(this.translate(b-g.x+h+d,c-g.y-g.height/2),this.rotate(a,g.x-h-d,g.y+g.height/2)),f.insertBefore(this.node?this:this[0])}},Raphael.el.label=function(){var a=this.getBBox(),b=this.paper||this[0].paper,c=Math.min(20,a.width+10,a.height+10)/2;if(b)return b.rect(a.x-c/2,a.y-c/2,a.width+c,a.height+c,c).attr({stroke:"none",fill:"#000"}).insertBefore(this.node?this:this[0])},Raphael.el.blob=function(a,b,c){var g,h,i,d=this.getBBox(),e=Math.PI/180,f=this.paper||this[0].paper;if(f){switch(this.type){case"text":case"circle":case"ellipse":h=!0;break;default:h=!1}g=f.path().attr({fill:"#000",stroke:"none"}),a=(+a+1?a:45)+90,i=Math.min(d.height,d.width),b="number"==typeof b?b:h?d.x+d.width/2:d.x,c="number"==typeof c?c:h?d.y+d.height/2:d.y;var j=Math.max(d.width+i,25*i/12),k=Math.max(d.height+i,25*i/12),l=b+i*Math.sin((a-22.5)*e),m=c+i*Math.cos((a-22.5)*e),n=b+i*Math.sin((a+22.5)*e),o=c+i*Math.cos((a+22.5)*e),p=(n-l)/2,q=(o-m)/2,r=j/2,s=k/2,t=-Math.sqrt(Math.abs(r*r*s*s-r*r*q*q-s*s*p*p)/(r*r*q*q+s*s*p*p)),u=t*r*q/s+(n+l)/2,v=t*-s*p/r+(o+m)/2;return g.attr({x:u,y:v,path:["M",b,c,"L",n,o,"A",r,s,0,1,1,l,m,"z"].join(",")}),this.translate(u-d.x-d.width/2,v-d.y-d.height/2),g.insertBefore(this.node?this:this[0])}},Raphael.fn.label=function(a,b,c){var d=this.set();return c=this.text(a,b,c).attr(Raphael.g.txtattr),d.push(c.label(),c)},Raphael.fn.popup=function(a,b,c,d,e){var f=this.set();return c=this.text(a,b,c).attr(Raphael.g.txtattr),f.push(c.popup(d,e),c)},Raphael.fn.tag=function(a,b,c,d,e){var f=this.set();return c=this.text(a,b,c).attr(Raphael.g.txtattr),f.push(c.tag(d,e),c)},Raphael.fn.flag=function(a,b,c,d){var e=this.set();return c=this.text(a,b,c).attr(Raphael.g.txtattr),e.push(c.flag(d),c)},Raphael.fn.drop=function(a,b,c,d){var e=this.set();return c=this.text(a,b,c).attr(Raphael.g.txtattr),e.push(c.drop(d),c)},Raphael.fn.blob=function(a,b,c,d){var e=this.set();return c=this.text(a,b,c).attr(Raphael.g.txtattr),e.push(c.blob(d),c)},Raphael.el.lighter=function(a){a=a||2;var b=[this.attrs.fill,this.attrs.stroke];return this.fs=this.fs||[b[0],b[1]],b[0]=Raphael.rgb2hsb(Raphael.getRGB(b[0]).hex),b[1]=Raphael.rgb2hsb(Raphael.getRGB(b[1]).hex),b[0].b=Math.min(b[0].b*a,1),b[0].s=b[0].s/a,b[1].b=Math.min(b[1].b*a,1),b[1].s=b[1].s/a,this.attr({fill:"hsb("+[b[0].h,b[0].s,b[0].b]+")",stroke:"hsb("+[b[1].h,b[1].s,b[1].b]+")"}),this},Raphael.el.darker=function(a){a=a||2;var b=[this.attrs.fill,this.attrs.stroke];return this.fs=this.fs||[b[0],b[1]],b[0]=Raphael.rgb2hsb(Raphael.getRGB(b[0]).hex),b[1]=Raphael.rgb2hsb(Raphael.getRGB(b[1]).hex),b[0].s=Math.min(b[0].s*a,1),b[0].b=b[0].b/a,b[1].s=Math.min(b[1].s*a,1),b[1].b=b[1].b/a,this.attr({fill:"hsb("+[b[0].h,b[0].s,b[0].b]+")",stroke:"hsb("+[b[1].h,b[1].s,b[1].b]+")"}),this},Raphael.el.resetBrightness=function(){return this.fs&&(this.attr({fill:this.fs[0],stroke:this.fs[1]}),delete this.fs),this},function(){var a=["lighter","darker","resetBrightness"],b=["popup","tag","flag","label","drop","blob"];for(var c in b)(function(a){Raphael.st[a]=function(){return Raphael.el[a].apply(this,arguments)}})(b[c]);for(var c in a)(function(a){Raphael.st[a]=function(){for(var b=0;this.length>b;b++)this[b][a].apply(this[b],arguments);return this}})(a[c])}(),Raphael.g={shim:{stroke:"none",fill:"#000","fill-opacity":0},txtattr:{font:"12px Arial, sans-serif",fill:"#fff"},colors:function(){for(var a=[.6,.2,.05,.1333,.75,0],b=[],c=0;10>c;c++)a.length>c?b.push("hsb("+a[c]+",.75, .75)"):b.push("hsb("+a[c-a.length]+", 1, .5)");return b}(),snapEnds:function(a,b,c){function f(a){return.25>Math.abs(a-.5)?~~a+.5:Math.round(a)}var d=a,e=b;if(d==e)return{from:d,to:e,power:0};var g=(e-d)/c,h=~~g,i=h,j=0;if(h){for(;i;)j--,i=~~(g*Math.pow(10,j))/Math.pow(10,j);j++}else{if(0!=g&&isFinite(g))for(;!h;)j=j||1,h=~~(g*Math.pow(10,j))/Math.pow(10,j),j++;else j=1;j&&j--}return e=f(b*Math.pow(10,j))/Math.pow(10,j),b>e&&(e=f((b+.5)*Math.pow(10,j))/Math.pow(10,j)),d=f((a-(j>0?0:.5))*Math.pow(10,j))/Math.pow(10,j),{from:d,to:e,power:j}},axis:function(a,b,c,d,e,f,g,h,i,j,k){j=null==j?2:j,i=i||"t",f=f||10,k=arguments[arguments.length-1];var t,l="|"==i||" "==i?["M",a+.5,b,"l",0,.001]:1==g||3==g?["M",a+.5,b,"l",0,-c]:["M",a,b+.5,"l",c,0],m=this.snapEnds(d,e,f),n=m.from,o=m.to,p=m.power,q=0,r={font:"11px 'Fontin Sans', Fontin-Sans, sans-serif"},s=k.set();t=(o-n)/f;var u=n,v=p>0?p:0;if(z=c/f,1==+g||3==+g){for(var w=b,x=(g-1?1:-1)*(j+3+!!(g-1));w>=b-c;)"-"!=i&&" "!=i&&(l=l.concat(["M",a-("+"==i||"|"==i?j:2*!(g-1)*j),w+.5,"l",2*j+1,0])),s.push(k.text(a+x,w,h&&h[q++]||(Math.round(u)==u?u:+u.toFixed(v))).attr(r).attr({"text-anchor":g-1?"start":"end"})),u+=t,w-=z;Math.round(w+z-(b-c))&&("-"!=i&&" "!=i&&(l=l.concat(["M",a-("+"==i||"|"==i?j:2*!(g-1)*j),b-c+.5,"l",2*j+1,0])),s.push(k.text(a+x,b-c,h&&h[q]||(Math.round(u)==u?u:+u.toFixed(v))).attr(r).attr({"text-anchor":g-1?"start":"end"})))}else{u=n,v=(p>0)*p,x=(g?-1:1)*(j+9+!g);for(var y=a,z=c/f,A=0,B=0;a+c>=y;){"-"!=i&&" "!=i&&(l=l.concat(["M",y+.5,b-("+"==i?j:2*!!g*j),"l",0,2*j+1])),s.push(A=k.text(y,b+x,h&&h[q++]||(Math.round(u)==u?u:+u.toFixed(v))).attr(r));var C=A.getBBox();B>=C.x-5?s.pop(s.length-1).remove():B=C.x+C.width,u+=t,y+=z}Math.round(y-z-a-c)&&("-"!=i&&" "!=i&&(l=l.concat(["M",a+c+.5,b-("+"==i?j:2*!!g*j),"l",0,2*j+1])),s.push(k.text(a+c,b+x,h&&h[q]||(Math.round(u)==u?u:+u.toFixed(v))).attr(r)))}var D=k.path(l);return D.text=s,D.all=k.set([D,s]),D.remove=function(){this.text.remove(),this.constructor.prototype.remove.call(this)},D},labelise:function(a,b,c){return a?(a+"").replace(/(##+(?:\.#+)?)|(%%+(?:\.%+)?)/g,function(a,d,e){return d?(+b).toFixed(d.replace(/^#+\.?/g,"").length):e?(100*b/c).toFixed(e.replace(/^%+\.?/g,"").length)+"%":void 0}):(+b).toFixed(0)}};
\ No newline at end of file
+Raphael.el.popup=function(d,a,b,f){var e=this.paper||this[0].paper,c,g,i,h;if(e){switch(this.type){case "text":case "circle":case "ellipse":g=!0;break;default:g=!1}d=null==d?"up":d;a=a||5;c=this.getBBox();b="number"==typeof b?b:g?c.x+c.width/2:c.x;f="number"==typeof f?f:g?c.y+c.height/2:c.y;i=Math.max(c.width/2-a,0);h=Math.max(c.height/2-a,0);this.translate(b-c.x-(g?c.width/2:0),f-c.y-(g?c.height/2:0));c=this.getBBox();b={up:["M",b,f,"l",-a,-a,-i,0,"a",a,a,0,0,1,-a,-a,"l",0,-c.height,"a",a,a,0,0,
+1,a,-a,"l",2*a+2*i,0,"a",a,a,0,0,1,a,a,"l",0,c.height,"a",a,a,0,0,1,-a,a,"l",-i,0,"z"].join(),down:["M",b,f,"l",a,a,i,0,"a",a,a,0,0,1,a,a,"l",0,c.height,"a",a,a,0,0,1,-a,a,"l",-(2*a+2*i),0,"a",a,a,0,0,1,-a,-a,"l",0,-c.height,"a",a,a,0,0,1,a,-a,"l",i,0,"z"].join(),left:["M",b,f,"l",-a,a,0,h,"a",a,a,0,0,1,-a,a,"l",-c.width,0,"a",a,a,0,0,1,-a,-a,"l",0,-(2*a+2*h),"a",a,a,0,0,1,a,-a,"l",c.width,0,"a",a,a,0,0,1,a,a,"l",0,h,"z"].join(),right:["M",b,f,"l",a,-a,0,-h,"a",a,a,0,0,1,a,-a,"l",c.width,0,"a",a,
+a,0,0,1,a,a,"l",0,2*a+2*h,"a",a,a,0,0,1,-a,a,"l",-c.width,0,"a",a,a,0,0,1,-a,-a,"l",0,-h,"z"].join()};a={up:{x:-!g*(c.width/2),y:2*-a-(g?c.height/2:c.height)},down:{x:-!g*(c.width/2),y:2*a+(g?c.height/2:c.height)},left:{x:2*-a-(g?c.width/2:c.width),y:-!g*(c.height/2)},right:{x:2*a+(g?c.width/2:c.width),y:-!g*(c.height/2)}}[d];this.translate(a.x,a.y);return e.path(b[d]).attr({fill:"#000",stroke:"none"}).insertBefore(this.node?this:this[0])}};
+Raphael.el.tag=function(d,a,b,f){var e=this.paper||this[0].paper;if(e){var e=e.path().attr({fill:"#000",stroke:"#000"}),c=this.getBBox(),g,i,h;switch(this.type){case "text":case "circle":case "ellipse":h=!0;break;default:h=!1}d=d||0;b="number"==typeof b?b:h?c.x+c.width/2:c.x;f="number"==typeof f?f:h?c.y+c.height/2:c.y;a=null==a?5:a;i=0.5522*a;c.height>=2*a?e.attr({path:["M",b,f+a,"a",a,a,0,1,1,0,2*-a,a,a,0,1,1,0,2*a,"m",0,2*-a-3,"a",a+3,a+3,0,1,0,0,2*(a+3),"L",b+a+3,f+c.height/2+3,"l",c.width+6,0,
+0,-c.height-6,-c.width-6,0,"L",b,f-a-3].join()}):(g=Math.sqrt(Math.pow(a+3,2)-Math.pow(c.height/2+3,2)),e.attr({path:["M",b,f+a,"c",-i,0,-a,i-a,-a,-a,0,-i,a-i,-a,a,-a,i,0,a,a-i,a,a,0,i,i-a,a,-a,a,"M",b+g,f-c.height/2-3,"a",a+3,a+3,0,1,0,0,c.height+6,"l",a+3-g+c.width+6,0,0,-c.height-6,"L",b+g,f-c.height/2-3].join()}));d=360-d;e.rotate(d,b,f);this.attrs?(this.attr(this.attrs.x?"x":"cx",b+a+3+(!h?"text"==this.type?c.width:0:c.width/2)).attr("y",h?f:f-c.height/2),this.rotate(d,b,f),90d&&this.attr(this.attrs.x?
+"x":"cx",b-a-3-(!h?c.width:c.width/2)).rotate(180,b,f)):90d?(this.translate(b-c.x-c.width-a-3,f-c.y-c.height/2),this.rotate(d-180,c.x+c.width+a+3,c.y+c.height/2)):(this.translate(b-c.x+a+3,f-c.y-c.height/2),this.rotate(d,c.x-a-3,c.y+c.height/2));return e.insertBefore(this.node?this:this[0])}};
+Raphael.el.drop=function(d,a,b){var f=this.getBBox(),e=this.paper||this[0].paper,c,g;if(e){switch(this.type){case "text":case "circle":case "ellipse":c=!0;break;default:c=!1}d=d||0;a="number"==typeof a?a:c?f.x+f.width/2:f.x;b="number"==typeof b?b:c?f.y+f.height/2:f.y;g=Math.max(f.width,f.height)+Math.min(f.width,f.height);e=e.path(["M",a,b,"l",g,0,"A",0.4*g,0.4*g,0,1,0,a+0.7*g,b-0.7*g,"z"]).attr({fill:"#000",stroke:"none"}).rotate(22.5-d,a,b);d=(d+90)*Math.PI/180;a=a+g*Math.sin(d)-(c?0:f.width/2);
+d=b+g*Math.cos(d)-(c?0:f.height/2);this.attrs?this.attr(this.attrs.x?"x":"cx",a).attr(this.attrs.y?"y":"cy",d):this.translate(a-f.x,d-f.y);return e.insertBefore(this.node?this:this[0])}};
+Raphael.el.flag=function(d,a,b){var f=this.paper||this[0].paper;if(f){var f=f.path().attr({fill:"#000",stroke:"#000"}),e=this.getBBox(),c=e.height/2,g;switch(this.type){case "text":case "circle":case "ellipse":g=!0;break;default:g=!1}d=d||0;a="number"==typeof a?a:g?e.x+e.width/2:e.x;b="number"==typeof b?b:g?e.y+e.height/2:e.y;f.attr({path:["M",a,b,"l",c+3,-c-3,e.width+6,0,0,e.height+6,-e.width-6,0,"z"].join()});d=360-d;f.rotate(d,a,b);this.attrs?(this.attr(this.attrs.x?"x":"cx",a+c+3+(!g?"text"==
+this.type?e.width:0:e.width/2)).attr("y",g?b:b-e.height/2),this.rotate(d,a,b),90d&&this.attr(this.attrs.x?"x":"cx",a-c-3-(!g?e.width:e.width/2)).rotate(180,a,b)):90d?(this.translate(a-e.x-e.width-c-3,b-e.y-e.height/2),this.rotate(d-180,e.x+e.width+c+3,e.y+e.height/2)):(this.translate(a-e.x+c+3,b-e.y-e.height/2),this.rotate(d,e.x-c-3,e.y+e.height/2));return f.insertBefore(this.node?this:this[0])}};
+Raphael.el.label=function(){var d=this.getBBox(),a=this.paper||this[0].paper,b=Math.min(20,d.width+10,d.height+10)/2;if(a)return a.rect(d.x-b/2,d.y-b/2,d.width+b,d.height+b,b).attr({stroke:"none",fill:"#000"}).insertBefore(this.node?this:this[0])};
+Raphael.el.blob=function(d,a,b){var f=this.getBBox(),e=Math.PI/180,c=this.paper||this[0].paper,g,i;if(c){switch(this.type){case "text":case "circle":case "ellipse":g=!0;break;default:g=!1}c=c.path().attr({fill:"#000",stroke:"none"});d=(+d+1?d:45)+90;i=Math.min(f.height,f.width);var a="number"==typeof a?a:g?f.x+f.width/2:f.x,b="number"==typeof b?b:g?f.y+f.height/2:f.y,h=Math.max(f.width+i,25*i/12),j=Math.max(f.height+i,25*i/12);g=a+i*Math.sin((d-22.5)*e);var o=b+i*Math.cos((d-22.5)*e),l=a+i*Math.sin((d+
+22.5)*e),d=b+i*Math.cos((d+22.5)*e),e=(l-g)/2;i=(d-o)/2;var h=h/2,j=j/2,n=-Math.sqrt(Math.abs(h*h*j*j-h*h*i*i-j*j*e*e)/(h*h*i*i+j*j*e*e));i=n*h*i/j+(l+g)/2;e=n*-j*e/h+(d+o)/2;c.attr({x:i,y:e,path:["M",a,b,"L",l,d,"A",h,j,0,1,1,g,o,"z"].join()});this.translate(i-f.x-f.width/2,e-f.y-f.height/2);return c.insertBefore(this.node?this:this[0])}};Raphael.fn.label=function(d,a,b){var f=this.set(),b=this.text(d,a,b).attr(Raphael.g.txtattr);return f.push(b.label(),b)};
+Raphael.fn.popup=function(d,a,b,f,e){var c=this.set(),b=this.text(d,a,b).attr(Raphael.g.txtattr);return c.push(b.popup(f,e),b)};Raphael.fn.tag=function(d,a,b,f,e){var c=this.set(),b=this.text(d,a,b).attr(Raphael.g.txtattr);return c.push(b.tag(f,e),b)};Raphael.fn.flag=function(d,a,b,f){var e=this.set(),b=this.text(d,a,b).attr(Raphael.g.txtattr);return e.push(b.flag(f),b)};Raphael.fn.drop=function(d,a,b,f){var e=this.set(),b=this.text(d,a,b).attr(Raphael.g.txtattr);return e.push(b.drop(f),b)};
+Raphael.fn.blob=function(d,a,b,f){var e=this.set(),b=this.text(d,a,b).attr(Raphael.g.txtattr);return e.push(b.blob(f),b)};Raphael.el.lighter=function(d){var d=d||2,a=[this.attrs.fill,this.attrs.stroke];this.fs=this.fs||[a[0],a[1]];a[0]=Raphael.rgb2hsb(Raphael.getRGB(a[0]).hex);a[1]=Raphael.rgb2hsb(Raphael.getRGB(a[1]).hex);a[0].b=Math.min(a[0].b*d,1);a[0].s/=d;a[1].b=Math.min(a[1].b*d,1);a[1].s/=d;this.attr({fill:"hsb("+[a[0].h,a[0].s,a[0].b]+")",stroke:"hsb("+[a[1].h,a[1].s,a[1].b]+")"});return this};
+Raphael.el.darker=function(d){var d=d||2,a=[this.attrs.fill,this.attrs.stroke];this.fs=this.fs||[a[0],a[1]];a[0]=Raphael.rgb2hsb(Raphael.getRGB(a[0]).hex);a[1]=Raphael.rgb2hsb(Raphael.getRGB(a[1]).hex);a[0].s=Math.min(a[0].s*d,1);a[0].b/=d;a[1].s=Math.min(a[1].s*d,1);a[1].b/=d;this.attr({fill:"hsb("+[a[0].h,a[0].s,a[0].b]+")",stroke:"hsb("+[a[1].h,a[1].s,a[1].b]+")"});return this};Raphael.el.resetBrightness=function(){this.fs&&(this.attr({fill:this.fs[0],stroke:this.fs[1]}),delete this.fs);return this};
+(function(){var d=["lighter","darker","resetBrightness"],a="popup tag flag label drop blob".split(" "),b;for(b in a)(function(a){Raphael.st[a]=function(){return Raphael.el[a].apply(this,arguments)}})(a[b]);for(b in d)(function(a){Raphael.st[a]=function(){for(var b=0;bb;b++)bMath.abs(a-0.5)?~~a+0.5:Math.round(a)}var e=d,c=a;if(e==c)return{from:e,to:c,power:0};var e=(c-e)/b,g=c=~~e,b=0;if(c){for(;g;)b--,g=~~(e*Math.pow(10,b))/Math.pow(10,b);
+b++}else{if(0==e||!isFinite(e))b=1;else for(;!c;)b=b||1,c=~~(e*Math.pow(10,b))/Math.pow(10,b),b++;b&&b--}c=f(a*Math.pow(10,b))/Math.pow(10,b);c=a-b;)"-"!=h&&" "!=h&&(l=l.concat(["M",d-("+"==h||"|"==h?j:2*!(g-1)*j),m+0.5,"l",2*j+1,0])),n.push(o.text(d+p,m,i&&i[u++]||(Math.round(k)==k?k:+k.toFixed(r))).attr(v).attr({"text-anchor":g-1?"start":"end"})),k+=t,m-=s;Math.round(m+s-(a-b))&&("-"!=h&&" "!=h&&(l=l.concat(["M",d-("+"==h||"|"==h?j:2*!(g-1)*j),a-b+0.5,"l",2*j+1,0])),n.push(o.text(d+
+p,a-b,i&&i[u]||(Math.round(k)==k?k:+k.toFixed(r))).attr(v).attr({"text-anchor":g-1?"start":"end"})))}else{for(var k=p,r=(0=q.x-5?n.pop(n.length-1).remove():w=q.x+q.width,k+=t,m+=s;Math.round(m-s-d-b)&&("-"!=h&&" "!=h&&(l=l.concat(["M",d+b+0.5,a-("+"==h?j:2*!!g*j),"l",0,2*j+1])),n.push(o.text(d+
+b,a+p,i&&i[u]||(Math.round(k)==k?k:+k.toFixed(r))).attr(v)))}l=o.path(l);l.text=n;l.all=o.set([l,n]);l.remove=function(){this.text.remove();this.constructor.prototype.remove.call(this)};return l},labelise:function(d,a,b){return d?(d+"").replace(/(##+(?:\.#+)?)|(%%+(?:\.%+)?)/g,function(d,e,c){if(e)return(+a).toFixed(e.replace(/^#+\.?/g,"").length);if(c)return(100*a/b).toFixed(c.replace(/^%+\.?/g,"").length)+"%"}):(+a).toFixed(0)}};
\ No newline at end of file