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/development.md b/doc/development.md
new file mode 100644
index 00000000..b7213adc
--- /dev/null
+++ b/doc/development.md
@@ -0,0 +1,36 @@
+## Development tips:
+
+
+### Installation
+
+Install the Gitlab development in a virtual machine with the [Gitlab Vagrant virtual machine](https://github.com/gitlabhq/gitlab-vagrant-vm). Installing it in a virtual machine makes it much easier to set up all the dependencies for integration testing.
+
+
+### Start application in development mode
+
+#### 1. Via foreman
+
+ bundle exec foreman start -p 3000
+
+#### 2. Manually
+
+ bundle exec rails s
+ bundle exec rake environment resque:work QUEUE=* VVERBOSE=1
+
+
+### Test DB setup & seed
+
+ bundle exec rake db:setup RAILS_ENV=test
+ bundle exec rake db:seed_fu RAILS_ENV=test
+
+
+### Run the Tests
+
+ # All in one
+ bundle exec rake gitlab:test
+
+ # Rspec
+ bundle exec rake spec
+
+ # Spinach
+ bundle exec rake spinach
diff --git a/doc/install/databases.md b/doc/install/databases.md
index fade5d4f..b7beff26 100644
--- a/doc/install/databases.md
+++ b/doc/install/databases.md
@@ -1,51 +1,71 @@
-# Setup Database
+# Databases:
-GitLab supports the following databases:
+GitLab use mysql as default database but you are free to use PostgreSQL or SQLite.
-* MySQL (preferred)
-* PostgreSQL
+## SQLite
+
+ sudo apt-get install -y sqlite3 libsqlite3-dev
## MySQL
- # Install the database packages
sudo apt-get install -y mysql-server mysql-client libmysqlclient-dev
# Login to MySQL
- mysql -u root -p
-
- # Create a user for GitLab. (change $password to a real password)
- mysql> CREATE USER 'gitlab'@'localhost' IDENTIFIED BY '$password';
+ $ mysql -u root -p
# Create the GitLab production database
mysql> CREATE DATABASE IF NOT EXISTS `gitlabhq_production` DEFAULT CHARACTER SET `utf8` COLLATE `utf8_unicode_ci`;
- # Grant the GitLab user necessary permissopns on the table.
+ # Create the MySQL User change $password to a real password
+ mysql> CREATE USER 'gitlab'@'localhost' IDENTIFIED BY '$password';
+
+ # Grant proper permissions to the MySQL User
mysql> GRANT SELECT, INSERT, UPDATE, DELETE, CREATE, DROP, INDEX, ALTER ON `gitlabhq_production`.* TO 'gitlab'@'localhost';
- # Quit the database session
- mysql> \q
-
- # Try connecting to the new database with the new user
- sudo -u git -H mysql -u gitlab -p -D gitlabhq_production
## PostgreSQL
- # Install the database packages
- sudo apt-get install -y postgresql-9.1 libpq-dev
+ sudo apt-get install -y postgresql-9.1 postgresql-server-dev-9.1
- # Login to PostgreSQL
+ # Connect to database server
sudo -u postgres psql -d template1
- # Create a user for GitLab. (change $password to a real password)
- template1=# CREATE USER git WITH PASSWORD '$password';
+ # Add a user called gitlab. Change $password to a real 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
+ # Quit from PostgreSQL server
template1=# \q
- # Try connecting to the new database with the new user
- sudo -u git -H psql -d gitlabhq_production
+ # Try connect to new database
+ sudo -u gitlab psql -d gitlabhq_production
+
+
+
+#### Select the database you want to use
+
+ # SQLite
+ sudo -u gitlab cp config/database.yml.sqlite config/database.yml
+
+ # Mysql
+ sudo -u gitlab cp config/database.yml.mysql config/database.yml
+
+ # PostgreSQL
+ sudo -u gitlab cp config/database.yml.postgresql config/database.yml
+
+ # make sure to update username/password in config/database.yml
+
+#### Install gems
+
+ # mysql
+ sudo -u gitlab -H bundle install --without development test sqlite postgres --deployment
+
+ # or postgres
+ sudo -u gitlab -H bundle install --without development test sqlite mysql --deployment
+
+ # or sqlite
+ sudo -u gitlab -H bundle install --without development test mysql postgres --deployment
diff --git a/doc/install/installation.md b/doc/install/installation.md
index a9ae4b1e..07ed0b0f 100644
--- a/doc/install/installation.md
+++ b/doc/install/installation.md
@@ -1,318 +1,283 @@
-# Important notes
+_This installation guide created for Debian/Ubuntu and properly tested._
-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.
+_Checkout requirements before setup_
-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
-If you find a bug/error in this guide please **submit a pull request** following the [`contributing guide`](../../CONTRIBUTING.md).
+Please make sure you have followed all the steps below before posting to the mailing list with installation and configuration questions.
+
+Only create a GitHub Issue if you want a specific part of this installation guide updated.
+
+Also read the [Read this before you submit an issue](https://github.com/gitlabhq/gitlabhq/wiki/Read-this-before-you-submit-an-issue) wiki page.
- - -
-# Overview
+# Basic setup
-The GitLab installation consists of setting up the following components:
+The basic installation will provide you a GitLab setup with options:
-1. Packages / Dependencies
+1. ruby 1.9.3
+2. mysql as main db
+3. gitolite v3 fork by gitlab
+4. nginx + unicorn
+
+The installation consists of next steps:
+
+1. Packages / dependencies
2. Ruby
-3. System Users
-4. GitLab shell
-5. Database
-6. GitLab
-7. Nginx
+3. Users
+4. Gitolite
+5. Mysql
+6. GitLab.
+7. Nginx
-# 1. Packages / Dependencies
+# 1. Packages / dependencies
-`sudo` is not installed on Debian by default. Make sure your system is
-up-to-date and install it.
+*Keep in mind that `sudo` is not installed on Debian by default. You should install it as root:*
- # run as root
- apt-get update
- apt-get upgrade
- apt-get install sudo
+ apt-get update && apt-get upgrade && apt-get install sudo
-**Note:**
-Vim is an editor that is used here whenever there are files that need to be
-edited by hand. But, you can use any editor you like instead.
+Now install the required packages:
- # Install vim
- sudo apt-get install -y vim
+ sudo apt-get update
+ sudo apt-get upgrade
-Install the required packages:
+ sudo apt-get install -y wget curl gcc checkinstall libxml2-dev libxslt-dev libcurl4-openssl-dev libreadline6-dev libc6-dev libssl-dev libmysql++-dev make build-essential zlib1g-dev libicu-dev redis-server openssh-server git-core python-dev python-pip libyaml-dev postfix libpq-dev
- 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
-
-Make sure you have the right version of Python installed.
-
- # Install Python
- sudo apt-get install python
-
- # Make sure that Python is 2.5+ (3.x is not supported at the moment)
- python --version
-
- # If it's Python 3 you might need to install Python 2 separately
- sudo apt-get install python2.7
-
- # Make sure you can access Python via python2
- python2 --version
-
- # If you get a "command not found" error create a link to the python binary
- sudo ln -s /usr/bin/python /usr/bin/python2
+ sudo pip install pygments
-# 2. Ruby
+# 2. Install Ruby
-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-p194.tar.gz
+ tar xfvz ruby-1.9.3-p194.tar.gz
+ cd ruby-1.9.3-p194
./configure
make
sudo make install
-Install the Bundler Gem:
+# 3. Users
- sudo gem install bundler
+Create user for git:
+
+ sudo adduser \
+ --system \
+ --shell /bin/sh \
+ --gecos 'git version control' \
+ --group \
+ --disabled-password \
+ --home /home/git \
+ git
+
+Create user for GitLab:
+
+ # ubuntu/debian
+ sudo adduser --disabled-login --gecos 'gitlab system' gitlab
+
+Add your users to groups:
+
+ sudo usermod -a -G git gitlab
+ sudo usermod -a -G gitlab git
+
+Generate key:
+
+ sudo -H -u gitlab ssh-keygen -q -N '' -t rsa -f /home/gitlab/.ssh/id_rsa
-# 3. System Users
+# 4. Gitolite
-Create a `git` user for Gitlab:
+Clone GitLab's fork of the Gitolite source code:
- sudo adduser --disabled-login --gecos 'GitLab' git
+ sudo -H -u git git clone -b gl-v304 https://github.com/gitlabhq/gitolite.git /home/git/gitolite
+Setup:
-# 4. GitLab shell
-
-GitLab Shell is a ssh access and repository management software developed specially for GitLab.
-
- # Login as git
- sudo su git
-
- # Go to home directory
cd /home/git
+ sudo -u git -H mkdir bin
+ sudo -u git sh -c 'echo -e "PATH=\$PATH:/home/git/bin\nexport PATH" >> /home/git/.profile'
+ sudo -u git sh -c 'gitolite/install -ln /home/git/bin'
- # Clone gitlab shell
- git clone https://github.com/gitlabhq/gitlab-shell.git
+ sudo cp /home/gitlab/.ssh/id_rsa.pub /home/git/gitlab.pub
+ sudo chmod 0444 /home/git/gitlab.pub
- cd gitlab-shell
- cp config.yml.example config.yml
+ sudo -u git -H sh -c "PATH=/home/git/bin:$PATH; gitolite setup -pk /home/git/gitlab.pub"
+
- # Edit config and replace gitlab_url
- # with something like 'http://domain.com/'
- vim config.yml
+Permissions:
- # Do setup
- ./bin/install
+ sudo chmod -R g+rwX /home/git/repositories/
+ sudo chown -R git:git /home/git/repositories/
+
+ # clone admin repo to add localhost to known_hosts
+ # & be sure your user has access to gitolite
+ sudo -u gitlab -H git clone git@localhost:gitolite-admin.git /tmp/gitolite-admin
+
+ # if succeed you can remove it
+ sudo rm -rf /tmp/gitolite-admin
+
+**IMPORTANT! If you can't clone `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 ensure you have followed all of the above steps carefully.
-# 5. Database
+# 5. Mysql database
-To setup the MySQL/PostgreSQL database and dependencies please see [`doc/install/databases.md`](./databases.md).
+ sudo apt-get install -y mysql-server mysql-client libmysqlclient-dev
+
+ # Login to MySQL
+ $ mysql -u root -p
+
+ # Create the GitLab production database
+ mysql> CREATE DATABASE IF NOT EXISTS `gitlabhq_production` DEFAULT CHARACTER SET `utf8` COLLATE `utf8_unicode_ci`;
+
+ # Create the MySQL User change $password to a real password
+ mysql> CREATE USER 'gitlab'@'localhost' IDENTIFIED BY '$password';
+
+ # Grant proper permissions to the MySQL User
+ mysql> GRANT SELECT, INSERT, UPDATE, DELETE, CREATE, DROP, INDEX, ALTER ON `gitlabhq_production`.* TO 'gitlab'@'localhost';
# 6. GitLab
- # We'll install GitLab into home directory of the user "git"
- cd /home/git
+ cd /home/gitlab
-## Clone the Source
- # Clone GitLab repository
- sudo -u git -H git clone https://github.com/gitlabhq/gitlabhq.git gitlab
+#### Get source code
- # Go to gitlab dir
- cd /home/git/gitlab
+ # Get gitlab code. Use this for stable setup
+ sudo -H -u gitlab git clone -b stable https://github.com/gitlabhq/gitlabhq.git gitlab
- # Checkout to stable release
- sudo -u git -H git checkout 5-0-stable
+ # Skip this for stable setup.
+ # Master branch (recent changes, less stable)
+ sudo -H -u gitlab git clone -b master https://github.com/gitlabhq/gitlabhq.git gitlab
-**Note:**
-You can change `5-0-stable` to `master` if you want the *bleeding edge* version, but
-do so with caution!
-## Configure it
+#### Copy configs
+
+ cd gitlab
- cd /home/git/gitlab
+ # Rename config files
+ #
+ sudo -u gitlab cp config/gitlab.yml.example config/gitlab.yml
- # Copy the example GitLab config
- sudo -u git -H cp config/gitlab.yml.example config/gitlab.yml
+ # Copy mysql db config
+ #
+ # make sure to update username/password in config/database.yml
+ #
+ sudo -u gitlab cp config/database.yml.mysql config/database.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
+ # Copy unicorn config
+ #
+ sudo -u gitlab cp config/unicorn.rb.example config/unicorn.rb
- # Make sure GitLab can write to the log/ and tmp/ directories
- sudo chown -R git log/
- sudo chown -R git tmp/
- sudo chmod -R u+rwX log/
- sudo chmod -R u+rwX tmp/
+#### Install gems
- # 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
-
-**Important Note:**
-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
-
- # PostgreSQL
- sudo -u git 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'
+ sudo gem install bundler
+ sudo -u gitlab -H bundle install --without development test sqlite postgres --deployment
- # For MySQL (note, the option says "without")
- sudo -u git -H bundle install --deployment --without development test postgres
+#### Configure git client
- # Or for PostgreSQL
- sudo -u git -H bundle install --deployment --without development test mysql
+Gitlab needs to be able to commit and push changes to gitolite.
+Git requires a username and email in order to be able to do that.
+
+ sudo -u gitlab -H git config --global user.email "gitlab@localhost"
+ sudo -u gitlab -H git config --global user.name "Gitlab"
+
+#### Setup application
+
+ sudo -u gitlab bundle exec rake gitlab:app:setup RAILS_ENV=production
-## Initialise Database and Activate Advanced Features
+#### Setup GitLab hooks
- sudo -u git -H bundle exec rake gitlab:setup RAILS_ENV=production
+ sudo cp ./lib/hooks/post-receive /home/git/.gitolite/hooks/common/post-receive
+ sudo chown git:git /home/git/.gitolite/hooks/common/post-receive
+
+#### Check application status
+
+Checking status:
+
+ sudo -u gitlab bundle exec rake gitlab:app:status RAILS_ENV=production
-## Install Init Script
+ # OUTPUT EXAMPLE
+ Starting diagnostic
+ config/database.yml............exists
+ config/gitlab.yml............exists
+ /home/git/repositories/............exists
+ /home/git/repositories/ is writable?............YES
+ remote: Counting objects: 603, done.
+ remote: Compressing objects: 100% (466/466), done.
+ remote: Total 603 (delta 174), reused 0 (delta 0)
+ Receiving objects: 100% (603/603), 53.29 KiB, done.
+ Resolving deltas: 100% (174/174), done.
+ Can clone gitolite-admin?............YES
+ UMASK for .gitolite.rc is 0007? ............YES
+ /home/git/share/gitolite/hooks/common/post-receive exists? ............YES
-Download the init script (will be /etc/init.d/gitlab):
+If you got all YES - congratulations! You can run a GitLab app.
- sudo curl --output /etc/init.d/gitlab https://raw.github.com/gitlabhq/gitlab-recipes/master/init.d/gitlab
+#### init script
+
+Create init script in /etc/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:
+GitLab autostart:
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
+#### Now you should start GitLab application:
sudo service gitlab start
- # or
- sudo /etc/init.d/gitlab restart
# 7. Nginx
-**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.
-
-## Installation
+ # Install first
sudo apt-get install nginx
-## Site Configuration
-
-Download an example site config:
-
- sudo curl --output /etc/nginx/sites-available/gitlab https://raw.github.com/gitlabhq/gitlab-recipes/master/nginx/gitlab
+ # Add GitLab to nginx sites & change with your host specific settings
+ 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:
-
# 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
+ # of the host serving GitLab.
+ sudo vim /etc/nginx/sites-enabled/gitlab
-## Restart
-
- sudo service nginx restart
+ # Restart nginx:
+ sudo /etc/init.d/nginx restart
-# Done!
+# Done! Visit YOUR_SERVER for gitlab instance
-Visit YOUR_SERVER for your first GitLab login.
-The setup has created an admin account for you. You can use it to log in:
+You can login via web using admin generated with setup:
admin@local.host
5iveL!fe
-**Important Note:**
-Please go over to your profile page and immediately chage the password, so
-nobody can access your GitLab by using this login information later on.
-
-**Enjoy!**
-
- - -
-# Advanced Setup Tips
+# Advanced setup tips:
-## Custom Redis Connection
+_Checkout databases.md for postgres or sqlite_
+
+## Customizing Resque's Redis connection
If you'd like Resque to connect to a Redis server on a non-standard port or on
-a different host, you can configure its connection string via the
-`config/resque.yml` file.
+a different host, you can configure its connection string in the
+**config/resque.yml** file:
- # example
- production: redis://redis.example.tld:6379
+ production: redis.example.com:6379
-## Custom SSH Connection
-
-If you are running SSH on a non-standard port, you must change the gitlab user's SSH config.
-
- # 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.
+**Ok - we have a working application now. **
+**But keep going - there are some things that should be done **
diff --git a/doc/install/requirements.md b/doc/install/requirements.md
index 9209fad5..75b02d64 100644
--- a/doc/install/requirements.md
+++ b/doc/install/requirements.md
@@ -1,63 +1,28 @@
-# Operating Systems
+## Platform requirements:
-## Linux
+**The project is designed for the Linux operating system.**
-GitLab is developed for the Linux operating system.
+It may work on FreeBSD and Mac OS, but we don't test our application for these systems and can't guarantee stability and full functionality.
-GitLab officially supports (recent versions of) these Linux distributions:
+We officially support (recent versions of) these Linux distributions:
- Ubuntu Linux
- Debian/GNU Linux
-It should also work on (though they are not officially supported):
+It should work on:
-- Arch
-- CentOS
- Fedora
-- Gentoo
+- CentOs
- RedHat
-## Other Unix Systems
+You might have some luck using these, but no guarantees:
-There is nothing that prevents GitLab from running on other Unix operating
-systems. This means you may get it to work on systems running FreeBSD or OS X.
-**If you want to try, please proceed with caution!**
+- FreeBSD will likely work, see https://github.com/gitlabhq/gitlabhq/issues/796
+- MacOS X will likely work, see https://groups.google.com/forum/#!topic/gitlabhq/5IXHbPkjKLA
-## 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.
+GitLab does **not** run on Windows and we have no plans of making GitLab compatible.
-# Rubies
+## Hardware:
-GitLab requires Ruby (MRI) 1.9.3 and several Gems with native components.
-While it is generally possible to use other Rubies (like
-[JRuby](http://jruby.org/) or [Rubinius](http://rubini.us/)) it might require
-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
-
-If you have troubles installing GitLab following the official installation guide
-or want to share your experience installing GitLab on a not officially supported
-platform, please follow the the contribution guide (see CONTRIBUTING.md).
+We recommend to use server with at least 1GB RAM for gitlab instance.
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
deleted file mode 100644
index d2da64f3..00000000
--- a/doc/raketasks/backup_restore.md
+++ /dev/null
@@ -1,80 +0,0 @@
-### Create a backup of the GitLab system
-
-Creates a backup archive of the database and all repositories. This archive will be saved in backup_path (see `config/gitlab.yml`).
-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
-```
-
-Example output:
-
-```
-Dumping database tables:
-- Dumping table events... [DONE]
-- Dumping table issues... [DONE]
-- Dumping table keys... [DONE]
-- Dumping table merge_requests... [DONE]
-- Dumping table milestones... [DONE]
-- Dumping table namespaces... [DONE]
-- Dumping table notes... [DONE]
-- Dumping table projects... [DONE]
-- Dumping table protected_branches... [DONE]
-- Dumping table schema_migrations... [DONE]
-- Dumping table services... [DONE]
-- Dumping table snippets... [DONE]
-- Dumping table taggings... [DONE]
-- Dumping table tags... [DONE]
-- Dumping table users... [DONE]
-- Dumping table users_projects... [DONE]
-- Dumping table web_hooks... [DONE]
-- Dumping table wikis... [DONE]
-Dumping repositories:
-- Dumping repository abcd... [DONE]
-Creating backup archive: $TIMESTAMP_gitlab_backup.tar [DONE]
-Deleting tmp directories...[DONE]
-Deleting old backups... [SKIPPING]
-```
-
-### Restore a previously created backup
-
-```
-bundle exec rake gitlab:backup:restore RAILS_ENV=production
-```
-
-Options:
-
-```
-BACKUP=timestamp_of_backup (required if more than one backup exists)
-```
-
-Example output:
-
-```
-Unpacking backup... [DONE]
-Restoring database tables:
--- create_table("events", {:force=>true})
- -> 0.2231s
-[...]
-- Loading fixture events...[DONE]
-- Loading fixture issues...[DONE]
-- Loading fixture keys...[SKIPPING]
-- Loading fixture merge_requests...[DONE]
-- Loading fixture milestones...[DONE]
-- Loading fixture namespaces...[DONE]
-- Loading fixture notes...[DONE]
-- Loading fixture projects...[DONE]
-- Loading fixture protected_branches...[SKIPPING]
-- Loading fixture schema_migrations...[DONE]
-- Loading fixture services...[SKIPPING]
-- Loading fixture snippets...[SKIPPING]
-- Loading fixture taggings...[SKIPPING]
-- Loading fixture tags...[SKIPPING]
-- Loading fixture users...[DONE]
-- Loading fixture users_projects...[DONE]
-- Loading fixture web_hooks...[SKIPPING]
-- Loading fixture wikis...[SKIPPING]
-Restoring repositories:
-- Restoring repository abcd... [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
deleted file mode 100644
index 018817d2..00000000
--- a/doc/raketasks/features.md
+++ /dev/null
@@ -1,36 +0,0 @@
-### Enable usernames and namespaces for user projects
-
-This command will enable the namespaces feature introduced in v4.0. It will move every project in its namespace folder.
-
-Note:
-
-* Because the **repository location will change**, you will need to **update all your git url's** to point to the new location.
-* Username can be changed at [Profile / Account](/profile/account)
-
-**Example:**
-
-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
-```
-
-
-### Rebuild project satellites
-
-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**.
-
-```
-bundle exec rake gitlab:satellites:create RAILS_ENV=production
-```
-
-Example output:
-
-```
-Creating satellite for abcd.git
-[git clone output]
-Creating satellite for abcd2.git
-[git clone output]
-done
-```
diff --git a/doc/raketasks/maintenance.md b/doc/raketasks/maintenance.md
deleted file mode 100644
index b5514705..00000000
--- a/doc/raketasks/maintenance.md
+++ /dev/null
@@ -1,154 +0,0 @@
-### 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
-```
-
-Example output:
-
-```
-System information
-System: Debian 6.0.6
-Current User: gitlab
-Using RVM: yes
-RVM Version: 1.17.2
-Ruby Version: ruby-1.9.3-p392
-Gem Version: 1.8.24
-Bundler Version:1.2.3
-Rake Version: 10.0.1
-
-GitLab information
-Version: 3.1.0
-Resivion: fd5141d
-Directory: /home/gitlab/gitlab
-DB Adapter: mysql2
-URL: http://localhost:3000
-HTTP Clone URL: http://localhost:3000/some-project.git
-SSH Clone URL: git@localhost:some-project.git
-Using LDAP: no
-Using Omniauth: no
-
-GitLab Shell
-Version: 1.0.4
-Repositories: /home/git/repositories/
-Hooks: /home/git/gitlab-shell/hooks/
-Git: /usr/bin/git
-```
-
-
-### Check GitLab configuration
-
-Runs the following rake tasks:
-
-* gitlab:env:check
-* gitlab:gitlab_shell:check
-* gitlab:sidekiq:check
-* gitlab:app:check
-
-It will check that each component was setup according to the installation guide and suggest fixes for issues found.
-
-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
-```
-
-Example output:
-
-```
-Checking Environment ...
-
-gitlab user is in git group? ... yes
-Has no "-e" in ~git/.profile ... yes
-Git configured for gitlab user? ... yes
-Has python2? ... yes
-python2 is supported version? ... yes
-
-Checking Environment ... Finished
-
-Checking Gitolite ...
-
-Using recommended version ... 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
-post-receive hook exists? ... yes
-post-receive hook up-to-date? ... yes
-post-receive hooks in repos are links: ...
-GitLab ... ok
-Non-Ascii Files Test ... ok
-Touch Commit Test ... ok
-Without Master Test ... ok
-Git config in repos: ...
-GitLab ... ok
-Non-Ascii Files Test ... ok
-Touch Commit Test ... ok
-Without Master Test ... ok
-
-Checking Gitolite ... Finished
-
-Checking Resque ...
-
-Running? ... yes
-
-Checking Resque ... Finished
-
-Checking GitLab ...
-
-Database config exists? ... yes
-Database is not SQLite ... yes
-All migrations up? ... yes
-GitLab config exists? ... yes
-GitLab config not outdated? ... yes
-Log directory writable? ... yes
-Tmp directory writable? ... yes
-Init script exists? ... yes
-Init script up-to-date? ... yes
-Projects have satellites? ...
-GitLab ... yes
-Non-Ascii Files Test ... yes
-Touch Commit Test ... yes
-Without Master Test ... yes
-
-Checking GitLab ... Finished
-```
-
-
-### (Re-)Create satellite repos
-
-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
-```
-
-### Import bare repositories into GitLab project instance
-
-Notes:
-
-* project owner will be a first admin
-* existing projects will be skipped
-
-How to use:
-
-1. copy your bare repos under git base_path (see `config/gitlab.yml` git_host -> base_path)
-2. run the command below
-
-```
-bundle exec rake gitlab:import:repos RAILS_ENV=production
-```
-
-Example output:
-
-```
-Processing abcd.git
- * Created abcd (abcd.git)
-[...]
-```
diff --git a/doc/raketasks/user_management.md b/doc/raketasks/user_management.md
deleted file mode 100644
index 021ce359..00000000
--- a/doc/raketasks/user_management.md
+++ /dev/null
@@ -1,16 +0,0 @@
-### Add user to as a developer to all projects
-
-```
-bundle exec rake gitlab:import:user_to_projects[username@domain.tld]
-```
-
-
-### Add all users to all projects
-
-Notes:
-
-* admin users are added as masters
-
-```
-bundle exec rake gitlab:import:all_users_to_all_projects
-```
diff --git a/features/admin/active_tab.feature b/features/admin/active_tab.feature
index 226d3d5d..fce85ce9 100644
--- a/features/admin/active_tab.feature
+++ b/features/admin/active_tab.feature
@@ -12,11 +12,6 @@ Feature: Admin active tab
Then the active main tab should be Projects
And no other main tabs should be active
- Scenario: On Admin Groups
- Given I visit admin groups page
- Then the active main tab should be Groups
- And no other main tabs should be active
-
Scenario: On Admin Users
Given I visit admin users page
Then the active main tab should be Users
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..24296f46 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
@@ -21,13 +20,11 @@ Feature: Dashboard
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/issues/issues.feature b/features/project/issues/issues.feature
index d6ef384c..596e8bd7 100644
--- a/features/project/issues/issues.feature
+++ b/features/project/issues/issues.feature
@@ -24,9 +24,11 @@ Feature: Project Issues
Given I click link "Release 0.4"
Then I should see issue "Release 0.4"
+ @javascript
Scenario: I submit new unassigned issue
Given I click link "New Issue"
And I submit new issue "500 error on profile"
+ Given I click link "500 error on profile"
Then I should see issue "500 error on profile"
@javascript
@@ -55,19 +57,25 @@ Feature: Project Issues
Then I should see "Release 0.3" in issues
And I should not see "Release 0.4" in issues
- # Disable this two cause of random failing
- # TODO: fix after v4.0 released
- #@javascript
- #Scenario: I create Issue with pre-selected milestone
- #Given project "Shop" has milestone "v2.2"
- #And project "Shop" has milestone "v3.0"
- #And I visit project "Shop" issues page
- #When I select milestone "v3.0"
- #And I click link "New Issue"
- #Then I should see selected milestone with title "v3.0"
+ @javascript
+ Scenario: I clear search
+ Given I click link "All"
+ And I fill in issue search with "Something"
+ And I fill in issue search with ""
+ Then I should see "Release 0.4" in issues
+ And I should see "Release 0.3" in issues
- #@javascript
- #Scenario: I create Issue with pre-selected assignee
- #When I select first assignee from "Shop" project
- #And I click link "New Issue"
- #Then I should see first assignee from "Shop" as selected assignee
+ @javascript
+ Scenario: I create Issue with pre-selected milestone
+ Given project "Shop" has milestone "v2.2"
+ And project "Shop" has milestone "v3.0"
+ And I visit project "Shop" issues page
+ When I select milestone "v3.0"
+ And I click link "New Issue"
+ Then I should see selected milestone with title "v3.0"
+
+ @javascript
+ Scenario: I create Issue with pre-selected assignee
+ When I select first assignee from "Shop" project
+ And I click link "New Issue"
+ Then I should see first assignee from "Shop" as selected assignee
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..51370565 100644
--- a/features/project/wiki.feature
+++ b/features/project/wiki.feature
@@ -5,43 +5,11 @@ 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
+ Given I create Wiki page
+ Then I should see 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
+ @javascript
+ Scenario: I comment wiki page
+ Given I create Wiki page
+ And I leave a comment like "XML attached"
+ Then I should see comment "XML attached"
diff --git a/features/steps/admin/admin_active_tab.rb b/features/steps/admin/admin_active_tab.rb
index f14c5f39..29290892 100644
--- a/features/steps/admin/admin_active_tab.rb
+++ b/features/steps/admin/admin_active_tab.rb
@@ -4,17 +4,13 @@ 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
ensure_active_main_tab('Projects')
end
- Then 'the active main tab should be Groups' do
- ensure_active_main_tab('Groups')
- end
-
Then 'the active main tab should be Users' do
ensure_active_main_tab('Users')
end
@@ -28,6 +24,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..e1759013 100644
--- a/features/steps/admin/admin_groups.rb
+++ b/features/steps/admin/admin_groups.rb
@@ -3,59 +3,22 @@ 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"
+ fill_in 'group_code', :with => 'gitlab'
+ click_button "Save 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..99c48738 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
@@ -74,13 +103,4 @@ class Dashboard < Spinach::FeatureSteps
page.should have_link group.name
end
end
-
- And 'group has a projects that does not belongs to me' do
- @forbidden_project1 = create(:project, group: @group)
- @forbidden_project2 = create(:project, group: @group)
- end
-
- 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..e5caf905 100644
--- a/features/steps/dashboard/dashboard_issues.rb
+++ b/features/steps/dashboard/dashboard_issues.rb
@@ -7,13 +7,12 @@ class DashboardIssues < Spinach::FeatureSteps
issues.each do |issue|
page.should have_content(issue.title[0..10])
page.should have_content(issue.project.name)
- page.should have_link(issue.project.name)
end
end
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..6d2ca3f9 100644
--- a/features/steps/project/create_project.rb
+++ b/features/steps/project/create_project.rb
@@ -3,13 +3,15 @@ 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'
+ fill_in 'project_code', :with => 'NPR'
+ fill_in 'project_path', :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..6bf164e2 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)
@@ -32,8 +32,8 @@ class ProjectBrowseCommits < Spinach::FeatureSteps
end
And 'I fill compare fields with refs' do
- fill_in "from", with: "8716fc78f3c65bbf7bcf7b574febd583bc5d2812"
- fill_in "to", with: "bcf03b5de6c33f3869ef70d68cf06e679d1d7f9a"
+ fill_in "from", with: "bcf03b5de6c33f3869ef70d68cf06e679d1d7f9a"
+ fill_in "to", with: "8716fc78f3c65bbf7bcf7b574febd583bc5d2812"
click_button "Compare"
end
@@ -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..88bfac63 100644
--- a/features/steps/project/project_issues.rb
+++ b/features/steps/project/project_issues.rb
@@ -73,6 +73,7 @@ class ProjectIssues < Spinach::FeatureSteps
end
And 'I fill in issue search with ""' do
+ page.execute_script("$('.issue_search').val('').keyup();");
fill_in 'issue_search', with: ""
end
@@ -95,7 +96,7 @@ class ProjectIssues < Spinach::FeatureSteps
end
Then 'I should see selected milestone with title "v3.0"' do
- issues_milestone_selector = "#issue_milestone_id_chzn > a"
+ issues_milestone_selector = "#milestone_id_chzn > a"
page.find(issues_milestone_selector).should have_content("v3.0")
end
@@ -106,7 +107,7 @@ class ProjectIssues < Spinach::FeatureSteps
end
Then 'I should see first assignee from "Shop" as selected assignee' do
- issues_assignee_selector = "#issue_assignee_id_chzn > a"
+ issues_assignee_selector = "#assignee_id_chzn > a"
project = Project.find_by_name "Shop"
assignee_name = project.users.first.name
page.find(issues_assignee_selector).should have_content(assignee_name)
@@ -122,9 +123,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..33a94027 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
@@ -66,7 +54,7 @@ module SharedPaths
end
Given 'I visit profile account page' do
- visit account_profile_path
+ visit profile_account_path
end
Given 'I visit profile SSH keys page' do
@@ -74,11 +62,15 @@ module SharedPaths
end
Given 'I visit profile design page' do
- visit design_profile_path
+ visit profile_design_path
end
Given 'I visit profile history page' do
- visit history_profile_path
+ visit profile_history_path
+ end
+
+ Given 'I visit profile token page' do
+ visit profile_token_path
end
# ----------------------------------------
@@ -113,10 +105,6 @@ module SharedPaths
visit admin_groups_path
end
- When 'I visit admin teams page' do
- visit admin_teams_path
- end
-
# ----------------------------------------
# Generic Project
# ----------------------------------------
@@ -125,20 +113,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 +130,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 +145,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 +161,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 +174,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 +182,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 +202,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 +211,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 +219,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..1a72d765 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,15 +25,13 @@ 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
end
@@ -48,4 +43,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..7a184544 100644
--- a/lib/api.rb
+++ b/lib/api.rb
@@ -2,37 +2,22 @@ Dir["#{Rails.root}/lib/api/*.rb"].each {|file| require file}
module Gitlab
class API < Grape::API
- version 'v3', using: :path
+ VERSION = 'v2'
+ version VERSION, using: :path
rescue_from ActiveRecord::RecordNotFound do
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
mount Milestones
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..9e605a60 100644
--- a/lib/api/entities.rb
+++ b/lib/api/entities.rb
@@ -1,60 +1,37 @@
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
+ expose :id, :email, :name, :bio, :skype, :linkedin, :twitter,
+ :dark_scheme, :theme_id, :blocked, :created_at
end
class UserBasic < Grape::Entity
- expose :id, :username, :email, :name, :state, :created_at
+ expose :id, :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
- expose :id, :url, :created_at
+ expose :id, :url
end
class Project < Grape::Entity
- expose :id, :name, :description, :default_branch
+ expose :id, :code, :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,29 +57,21 @@ 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
- expose :id, :title, :key, :created_at
+ expose :id, :title, :key
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
-
- class MRNote < Grape::Entity
expose :note
- expose :author, using: Entities::UserBasic
end
end
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..a339ec4a 100644
--- a/lib/api/helpers.rb
+++ b/lib/api/helpers.rb
@@ -5,18 +5,13 @@ module Gitlab
end
def user_project
- @project ||= find_project
- @project || not_found!
- end
-
- def find_project
- project = Project.find_by_id(params[:id]) || Project.find_with_namespace(params[:id])
-
- if project && can?(current_user, :read_project, project)
- project
+ if @project ||= current_user.projects.find_by_id(params[:id]) ||
+ current_user.projects.find_by_code(params[:id])
else
- nil
+ not_found!
end
+
+ @project
end
def paginate(object)
@@ -37,21 +32,6 @@ module Gitlab
end
end
- def can?(object, action, subject)
- 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 +46,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..4ee2d11f 100644
--- a/lib/api/issues.rb
+++ b/lib/api/issues.rb
@@ -17,7 +17,7 @@ module Gitlab
# Get a list of project issues
#
# Parameters:
- # id (required) - The ID of a project
+ # id (required) - The ID or code name of a project
# Example Request:
# GET /projects/:id/issues
get ":id/issues" do
@@ -27,7 +27,7 @@ module Gitlab
# Get a single project issue
#
# Parameters:
- # id (required) - The ID of a project
+ # id (required) - The ID or code name of a project
# issue_id (required) - The ID of a project issue
# Example Request:
# GET /projects/:id/issues/:issue_id
@@ -39,7 +39,7 @@ module Gitlab
# Create a new project issue
#
# Parameters:
- # id (required) - The ID of a project
+ # id (required) - The ID or code name of a project
# title (required) - The title of an issue
# description (optional) - The description of an issue
# assignee_id (optional) - The ID of a user to assign issue
@@ -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
@@ -63,23 +62,22 @@ module Gitlab
# Update an existing issue
#
# Parameters:
- # id (required) - The ID of a project
+ # id (required) - The ID or code name of a project
# issue_id (required) - The ID of a project issue
# title (optional) - The title of an issue
# description (optional) - The description of an issue
# 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
@@ -90,7 +88,7 @@ module Gitlab
# Delete a project issue (deprecated)
#
# Parameters:
- # id (required) - The ID of a project
+ # id (required) - The ID or code name of a project
# issue_id (required) - The ID of a project issue
# Example Request:
# DELETE /projects/:id/issues/:issue_id
diff --git a/lib/api/merge_requests.rb b/lib/api/merge_requests.rb
index d5595d5f..d8f2c512 100644
--- a/lib/api/merge_requests.rb
+++ b/lib/api/merge_requests.rb
@@ -4,45 +4,35 @@ 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
- #
+ #
# Parameters:
- # id (required) - The ID of a project
+ # id (required) - The ID or code name of a project
#
# Example:
# GET /projects/:id/merge_requests
#
get ":id/merge_requests" do
authorize! :read_merge_request, user_project
-
+
present paginate(user_project.merge_requests), with: Entities::MergeRequest
end
-
+
# Show MR
- #
+ #
# Parameters:
- # id (required) - The ID of a project
+ # id (required) - The ID or code name of a project
# merge_request_id (required) - The ID of MR
- #
+ #
# Example:
# GET /projects/:id/merge_request/:merge_request_id
#
get ":id/merge_request/:merge_request_id" do
merge_request = user_project.merge_requests.find(params[:merge_request_id])
-
+
authorize! :read_merge_request, merge_request
-
+
present merge_request, with: Entities::MergeRequest
end
@@ -50,79 +40,74 @@ module Gitlab
#
# Parameters:
#
- # id (required) - The ID of a project
+ # id (required) - The ID or code name of a project
# source_branch (required) - The source branch
# target_branch (required) - The target branch
# assignee_id - Assignee user ID
# title (required) - Title of MR
- #
+ #
# Example:
# POST /projects/:id/merge_requests
#
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)
merge_request.author = current_user
-
+
if merge_request.save
merge_request.reload_code
present merge_request, with: Entities::MergeRequest
else
- handle_merge_request_errors! merge_request.errors
+ not_found!
end
end
# Update MR
#
# Parameters:
- # id (required) - The ID of a project
+ # id (required) - The ID or code name of a project
# merge_request_id (required) - ID of MR
# source_branch - The source branch
# 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
# Post comment to merge request
#
# Parameters:
- # id (required) - The ID of a project
+ # id (required) - The ID or code name of a project
# merge_request_id (required) - ID of MR
# note (required) - Text of comment
- # Examples:
+ # Examples:
# 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
if note.save
- present note, with: Entities::MRNote
+ present note, with: Entities::Note
else
not_found!
end
diff --git a/lib/api/milestones.rb b/lib/api/milestones.rb
index 1adeefec..f55dfd04 100644
--- a/lib/api/milestones.rb
+++ b/lib/api/milestones.rb
@@ -7,7 +7,7 @@ module Gitlab
# Get a list of project milestones
#
# Parameters:
- # id (required) - The ID of a project
+ # id (required) - The ID or code name of a project
# Example Request:
# GET /projects/:id/milestones
get ":id/milestones" do
@@ -19,7 +19,7 @@ module Gitlab
# Get a single project milestone
#
# Parameters:
- # id (required) - The ID of a project
+ # id (required) - The ID or code name of a project
# milestone_id (required) - The ID of a project milestone
# Example Request:
# GET /projects/:id/milestones/:milestone_id
@@ -33,7 +33,7 @@ module Gitlab
# Create a new project milestone
#
# Parameters:
- # id (required) - The ID of the project
+ # id (required) - The ID or code name of the project
# title (required) - The title of the milestone
# description (optional) - The description of the milestone
# due_date (optional) - The due date of the milestone
@@ -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
@@ -55,19 +54,19 @@ module Gitlab
# Update an existing project milestone
#
# Parameters:
- # id (required) - The ID of a project
+ # id (required) - The ID or code name of a project
# milestone_id (required) - The ID of a project milestone
# 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
deleted file mode 100644
index 450faae5..00000000
--- a/lib/api/notes.rb
+++ /dev/null
@@ -1,116 +0,0 @@
-module Gitlab
- # Notes API
- class Notes < Grape::API
- before { authenticate! }
-
- NOTEABLE_TYPES = [Issue, MergeRequest, Snippet]
-
- resource :projects do
- # Get a list of project wall notes
- #
- # Parameters:
- # id (required) - The ID of a project
- # 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]
-
- present paginate(@notes), with: Entities::Note
- end
-
- # Get a single project wall note
- #
- # Parameters:
- # id (required) - The ID of a project
- # note_id (required) - The ID of a note
- # Example Request:
- # GET /projects/:id/notes/:note_id
- get ":id/notes/:note_id" do
- @note = user_project.notes.common.find(params[:note_id])
- present @note, with: Entities::Note
- end
-
- # Create a new project wall note
- #
- # Parameters:
- # id (required) - The ID of a project
- # body (required) - The content of a note
- # 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
-
- NOTEABLE_TYPES.each do |noteable_type|
- noteables_str = noteable_type.to_s.underscore.pluralize
- noteable_id_str = "#{noteable_type.to_s.underscore}_id"
-
- # Get a list of project +noteable+ notes
- #
- # Parameters:
- # id (required) - The ID of a project
- # noteable_id (required) - The ID of an issue or snippet
- # Example Request:
- # GET /projects/:id/issues/:noteable_id/notes
- # GET /projects/:id/snippets/:noteable_id/notes
- get ":id/#{noteables_str}/:#{noteable_id_str}/notes" do
- @noteable = user_project.send(:"#{noteables_str}").find(params[:"#{noteable_id_str}"])
- present paginate(@noteable.notes), with: Entities::Note
- end
-
- # Get a single +noteable+ note
- #
- # Parameters:
- # id (required) - The ID of a project
- # noteable_id (required) - The ID of an issue or snippet
- # note_id (required) - The ID of a note
- # Example Request:
- # GET /projects/:id/issues/:noteable_id/notes/:note_id
- # GET /projects/:id/snippets/:noteable_id/notes/:note_id
- get ":id/#{noteables_str}/:#{noteable_id_str}/notes/:note_id" do
- @noteable = user_project.send(:"#{noteables_str}").find(params[:"#{noteable_id_str}"])
- @note = @noteable.notes.find(params[:note_id])
- present @note, with: Entities::Note
- end
-
- # Create a new +noteable+ note
- #
- # Parameters:
- # id (required) - The ID of a project
- # noteable_id (required) - The ID of an issue or snippet
- # body (required) - The content of a note
- # Example Request:
- # 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
- @note.project = user_project
-
- if @note.save
- present @note, with: Entities::Note
- else
- not_found!
- end
- end
- end
- end
- end
-end
diff --git a/lib/api/projects.rb b/lib/api/projects.rb
index ce94c34b..ac20bbec 100644
--- a/lib/api/projects.rb
+++ b/lib/api/projects.rb
@@ -4,28 +4,19 @@ 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
# Get a single project
#
# Parameters:
- # id (required) - The ID of a project
+ # id (required) - The ID or code name of a project
# Example Request:
# GET /projects/:id
get ":id" do
@@ -36,60 +27,29 @@ module Gitlab
#
# Parameters:
# name (required) - name for new project
+ # code (optional) - code for new project, uses project name if not set
+ # 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,
+ params[:code] ||= params[:name]
+ params[:path] ||= params[:name]
+ attrs = attributes_for_keys [:code,
+ :path,
+ :name,
:description,
:default_branch,
:issues_enabled,
: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,27 +57,21 @@ module Gitlab
end
end
-
# Get a project team members
#
# Parameters:
- # id (required) - The ID of a project
- # query - Query string
+ # id (required) - The ID or code name of a project
# Example Request:
# GET /projects/:id/members
get ":id/members" do
- if params[:query].present?
- @members = paginate user_project.users.where("username LIKE ?", "%#{params[:query]}%")
- else
- @members = paginate user_project.users
- end
+ @members = paginate user_project.users
present @members, with: Entities::ProjectMember, project: user_project
end
# Get a project team members
#
# Parameters:
- # id (required) - The ID of a project
+ # id (required) - The ID or code name of a project
# user_id (required) - The ID of a user
# Example Request:
# GET /projects/:id/members/:user_id
@@ -129,76 +83,63 @@ module Gitlab
# Add a new project team member
#
# Parameters:
- # id (required) - The ID of a project
+ # id (required) - The ID or code name of a project
# user_id (required) - The ID of a user
# access_level (required) - Project access level
# Example Request:
# 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
# Update project team member
#
# Parameters:
- # id (required) - The ID of a project
+ # id (required) - The ID or code name of a project
# user_id (required) - The ID of a team member
# access_level (required) - Project access level
# Example Request:
# 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
# Remove a team member from project
#
# Parameters:
- # id (required) - The ID of a project
+ # id (required) - The ID or code name of a project
# user_id (required) - The ID of a team member
# Example Request:
# 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
#
# Parameters:
- # id (required) - The ID of a project
+ # id (required) - The ID or code name of a project
# Example Request:
# GET /projects/:id/hooks
get ":id/hooks" do
@@ -210,12 +151,11 @@ module Gitlab
# Get a project hook
#
# Parameters:
- # id (required) - The ID of a project
+ # id (required) - The ID or code name of a project
# hook_id (required) - The ID of a project hook
# 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
@@ -224,29 +164,24 @@ module Gitlab
# Add hook to project
#
# Parameters:
- # id (required) - The ID of a project
+ # id (required) - The ID or code name of a project
# url (required) - The hook URL
# Example Request:
# 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
# Update an existing project hook
#
# Parameters:
- # id (required) - The ID of a project
+ # id (required) - The ID or code name of a project
# hook_id (required) - The ID of a project hook
# url (required) - The hook URL
# Example Request:
@@ -254,103 +189,55 @@ 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
+ # id (required) - The ID or code name 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
#
# Parameters:
- # id (required) - The ID of a project
+ # id (required) - The ID or code name of a project
# 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
#
# Parameters:
- # id (required) - The ID of a project
+ # id (required) - The ID or code name of a project
# branch (required) - The name of the branch
# Example Request:
# 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
#
# Parameters:
- # id (required) - The ID of a project
+ # id (required) - The ID or code name of a project
# Example Request:
# GET /projects/:id/repository/tags
get ":id/repository/tags" do
@@ -360,25 +247,25 @@ module Gitlab
# Get a project repository commits
#
# 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
+ # id (required) - The ID or code name of a project
+ # 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
#
# Parameters:
- # id (required) - The ID of a project
+ # id (required) - The ID or code name of a project
# Example Request:
# GET /projects/:id/snippets
get ":id/snippets" do
@@ -388,7 +275,7 @@ module Gitlab
# Get a project snippet
#
# Parameters:
- # id (required) - The ID of a project
+ # id (required) - The ID or code name of a project
# snippet_id (required) - The ID of a project snippet
# Example Request:
# GET /projects/:id/snippets/:snippet_id
@@ -400,7 +287,7 @@ module Gitlab
# Create a new project snippet
#
# Parameters:
- # id (required) - The ID of a project
+ # id (required) - The ID or code name of a project
# title (required) - The title of a snippet
# file_name (required) - The name of a snippet file
# lifetime (optional) - The expiration date of a snippet
@@ -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?
@@ -427,7 +313,7 @@ module Gitlab
# Update an existing project snippet
#
# Parameters:
- # id (required) - The ID of a project
+ # id (required) - The ID or code name of a project
# snippet_id (required) - The ID of a project snippet
# title (optional) - The title of a snippet
# file_name (optional) - The name of a snippet file
@@ -453,23 +339,21 @@ module Gitlab
# Delete a project snippet
#
# Parameters:
- # id (required) - The ID of a project
+ # id (required) - The ID or code name of a project
# snippet_id (required) - The ID of a project snippet
# 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
#
# Parameters:
- # id (required) - The ID of a project
+ # id (required) - The ID or code name of a project
# snippet_id (required) - The ID of a project snippet
# Example Request:
# GET /projects/:id/snippets/:snippet_id/raw
@@ -482,70 +366,26 @@ module Gitlab
# Get a raw file contents
#
# Parameters:
- # id (required) - The ID of a project
+ # id (required) - The ID or code name of a project
# sha (required) - The commit or branch name
# filepath (required) - The path to the file to display
# Example Request:
# 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..57e0aa10 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]
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,19 +91,18 @@ 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
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..5a24c5d0 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"\
@@ -35,18 +34,15 @@ module Gitlab
extern_uid: uid,
provider: provider,
name: name,
- username: email.match(/^[^@]*/)[0],
email: email,
password: password,
password_confirmation: password,
- projects_limit: Gitlab.config.gitlab.default_projects_limit,
+ projects_limit: Gitlab.config.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..fe5dcef4
--- /dev/null
+++ b/lib/gitlab/backend/gitolite.rb
@@ -0,0 +1,43 @@
+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.path, project)
+ end
+
+ def remove_repository project
+ config.destroy_project!(project)
+ end
+
+ def url_to_repo path
+ Gitlab.config.ssh_path + "#{path}.git"
+ end
+
+ def enable_automerge
+ config.admin_all_repo!
+ 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..7ae34de6
--- /dev/null
+++ b/lib/gitlab/backend/gitolite_config.rb
@@ -0,0 +1,209 @@
+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)
+ 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(repo_name, project)
+ repo = update_project_config(project, conf)
+ conf.add_repo(repo, true)
+ end
+
+ def update_project!(repo_name, project)
+ apply do |config|
+ config.update_project(repo_name, project)
+ end
+ end
+
+ # Updates many projects and uses project.path 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
+
+ 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..dd5a9bec 100644
--- a/lib/gitlab/backend/grack_auth.rb
+++ b/lib/gitlab/backend/grack_auth.rb
@@ -1,40 +1,26 @@
-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
+ email, password = @auth.credentials
+ self.user = User.find_by_email(email)
+ return false unless user.try(:valid_password?, password)
+
+ # 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_by_path(m.last)
+ return false unless project
end
# Git upload and receive
@@ -48,12 +34,12 @@ module Grack
end
def validate_get_request
- project.public || can?(user, :download_code, project)
+ true
end
def validate_post_request
if @request.path_info.end_with?('git-upload-pack')
- project.public || can?(user, :download_code, project)
+ can?(user, :push_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 +65,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..af8d7828
--- /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] = escape_once(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..c2c3fa66
--- /dev/null
+++ b/lib/gitlab/graph/json_builder.rb
@@ -0,0 +1,172 @@
+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 days_json
+ @days_json = @days.compact.map { |d| [d.day, d.strftime("%b")] }.to_json
+ end
+
+ def commits_json
+ @commits_json = @commits.map(&:to_graph_hash).to_json
+ 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/logger.rb b/lib/gitlab/logger.rb
index 389eef33..cf9a4c4a 100644
--- a/lib/gitlab/logger.rb
+++ b/lib/gitlab/logger.rb
@@ -11,12 +11,7 @@ module Gitlab
def self.read_latest
path = Rails.root.join("log", file_name)
self.build unless File.exist?(path)
- logs = `tail -n 2000 #{path}`.split("\n")
- end
-
- def self.read_latest_for filename
- path = Rails.root.join("log", filename)
- logs = `tail -n 2000 #{path}`.split("\n")
+ logs = File.read(path).split("\n")
end
def self.build
diff --git a/lib/gitlab/markdown.rb b/lib/gitlab/markdown.rb
index ad6ba3e8..ee0ee05c 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,17 @@ module Gitlab
# >> gfm(":trollface:")
# => "
module Markdown
- include IssuesHelper
+ REFERENCE_PATTERN = %r{
+ (\W)? # Prefix (1)
+ ( # Reference (2)
+ @([\w\._]+) # User name (3)
+ |[#!$](\d+) # Issue/MR/Snippet ID (4)
+ |([\h]{6,40}) # Commit ID (5)
+ )
+ (\W)? # Suffix (6)
+ }x.freeze
+
+ EMOJI_PATTERN = %r{(:(\S+):)}.freeze
attr_reader :html_options
@@ -47,11 +57,12 @@ module Gitlab
# Extract pre blocks so they are not altered
# from http://github.github.com/github-flavored-markdown/
- text.gsub!(%r{
+
+
diff --git a/public/gitlab_logo.png b/public/gitlab_logo.png
deleted file mode 100644
index e3cda597..00000000
Binary files a/public/gitlab_logo.png and /dev/null differ
diff --git a/public/static.css b/public/static.css
index aa834553..6090d7b2 100644
--- a/public/static.css
+++ b/public/static.css
@@ -1,31 +1,57 @@
-body {
- color: #666;
- text-align: center;
- font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
- sans-serif;
- margin:0;
- width: 800px;
- margin: auto;
- font-size: 14px;
-}
-h1 {
- font-size: 56px;
- line-height: 100px;
- font-weight: normal;
- color: #456;
-}
+body { color: #666; text-align: center; font-family: arial, sans-serif; margin:0; padding:0; }
+h1 { font-size: 48px; color: #444; line-height: 1.5em; }
h2 { font-size: 24px; color: #666; line-height: 1.5em; }
-h3 {
- color: #456;
- font-size: 20px;
- font-weight: normal;
+.alert-message {
+ position: relative;
+ padding: 7px 15px;
+ margin-bottom: 18px;
+ color: #404040;
+ background-color: #eedc94;
+ background-repeat: repeat-x;
+ background-image: -khtml-gradient(linear, left top, left bottom, from(#fceec1), to(#eedc94));
+ background-image: -moz-linear-gradient(top, #fceec1, #eedc94);
+ background-image: -ms-linear-gradient(top, #fceec1, #eedc94);
+ background-image: -webkit-gradient(linear, left top, left bottom, color-stop(0%, #fceec1), color-stop(100%, #eedc94));
+ background-image: -webkit-linear-gradient(top, #fceec1, #eedc94);
+ background-image: -o-linear-gradient(top, #fceec1, #eedc94);
+ background-image: linear-gradient(top, #fceec1, #eedc94);
+ filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#FFFCEEC1', endColorstr='#FFEEDC94', GradientType=0);
+ text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25);
+ border-color: #eedc94 #eedc94 #e4c652;
+ border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) fadein(rgba(0, 0, 0, 0.1), 15%);
+ text-shadow: 0 1px 0 rgba(255, 255, 255, 0.5);
+ border-width: 1px;
+ border-style: solid;
+ -webkit-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.25);
+ -moz-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.25);
+ box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.25);
+}
+.alert-message .close {
+ margin-top: 1px;
+ *margin-top: 0;
+}
+.alert-message a {
+ font-weight: bold;
+ color: #404040;
+}
+.alert-message.danger p a, .alert-message.error p a, .alert-message.success p a, .alert-message.info p a {
+ color: #404040;
+}
+.alert-message h5 {
+ line-height: 18px;
+}
+.alert-message p {
+ margin-bottom: 0;
+}
+.alert-message div {
+ margin-top: 5px;
+ margin-bottom: 2px;
line-height: 28px;
}
-hr {
- margin: 18px 0;
- border: 0;
- border-top: 1px solid #EEE;
- border-bottom: 1px solid white;
+.alert-message.block-message.error {
+ background: #FDDFDE;
+ border-color: #FBC7C6;
}
+
diff --git a/resque.sh b/resque.sh
new file mode 100755
index 00000000..0ebf319e
--- /dev/null
+++ b/resque.sh
@@ -0,0 +1,2 @@
+mkdir -p tmp/pids
+nohup bundle exec rake environment resque:work QUEUE=post_receive,mailer,system_hook RAILS_ENV=production PIDFILE=tmp/pids/resque_worker.pid > ./log/resque.log &
diff --git a/resque_dev.sh b/resque_dev.sh
new file mode 100755
index 00000000..b250caa9
--- /dev/null
+++ b/resque_dev.sh
@@ -0,0 +1,2 @@
+mkdir -p tmp/pids
+nohup bundle exec rake environment resque:work QUEUE=post_receive,mailer,system_hook VVERBOSE=1 RAILS_ENV=development PIDFILE=tmp/pids/resque_worker.pid > ./log/resque.log &
diff --git a/script/check b/script/check
deleted file mode 100755
index d2eb4a2f..00000000
--- a/script/check
+++ /dev/null
@@ -1,2 +0,0 @@
-#!/bin/sh
-sudo -u gitlab -H bundle exec rake gitlab:check RAILS_ENV=production
diff --git a/spec/contexts/projects_create_context_spec.rb b/spec/contexts/projects_create_context_spec.rb
deleted file mode 100644
index dd10dd3e..00000000
--- a/spec/contexts/projects_create_context_spec.rb
+++ /dev/null
@@ -1,38 +0,0 @@
-require 'spec_helper'
-
-describe Projects::CreateContext do
- describe :create_by_user do
- before do
- @user = create :user
- @opts = {
- name: "GitLab"
- }
- end
-
- context 'user namespace' do
- before do
- @project = create_project(@user, @opts)
- end
-
- it { @project.should be_valid }
- it { @project.owner.should == @user }
- it { @project.namespace.should == @user.namespace }
- end
-
- context 'group namespace' do
- before do
- @group = create :group, owner: @user
- @opts.merge!(namespace_id: @group.id)
- @project = create_project(@user, @opts)
- end
-
- it { @project.should be_valid }
- it { @project.owner.should == @user }
- it { @project.namespace.should == @group }
- end
- end
-
- def create_project(user, opts)
- Projects::CreateContext.new(user, opts).execute
- end
-end
diff --git a/spec/controllers/commit_controller_spec.rb b/spec/controllers/commit_controller_spec.rb
deleted file mode 100644
index 5fffbf0e..00000000
--- a/spec/controllers/commit_controller_spec.rb
+++ /dev/null
@@ -1,74 +0,0 @@
-require 'spec_helper'
-
-describe CommitController do
- let(:project) { create(:project_with_code) }
- let(:user) { create(:user) }
- let(:commit) { project.repository.last_commit_for("master") }
-
- before do
- sign_in(user)
-
- project.team << [user, :master]
- end
-
- describe "#show" do
- shared_examples "export as" do |format|
- it "should generally work" do
- get :show, project_id: project.code, id: commit.id, format: format
-
- expect(response).to be_success
- end
-
- it "should generate it" do
- Commit.any_instance.should_receive(:"to_#{format}")
-
- get :show, project_id: project.code, id: commit.id, format: format
- end
-
- it "should render it" do
- get :show, project_id: project.code, id: commit.id, format: format
-
- expect(response.body).to eq(commit.send(:"to_#{format}"))
- end
-
- it "should not escape Html" do
- Commit.any_instance.stub(:"to_#{format}").and_return('HTML entities &<>" ')
-
- get :show, project_id: project.code, id: commit.id, format: format
-
- expect(response.body).to_not include('&')
- expect(response.body).to_not include('>')
- expect(response.body).to_not include('<')
- expect(response.body).to_not include('"')
- end
- end
-
- describe "as diff" do
- include_examples "export as", :diff
- let(:format) { :diff }
-
- it "should really only be a git diff" do
- get :show, project_id: project.code, id: commit.id, format: format
-
- expect(response.body).to start_with("diff --git")
- end
- end
-
- describe "as patch" do
- include_examples "export as", :patch
- let(:format) { :patch }
-
- it "should really be a git email patch" do
- get :show, project_id: project.code, id: commit.id, format: format
-
- expect(response.body).to start_with("From #{commit.id}")
- end
-
- it "should contain a git diff" do
- get :show, project_id: project.code, id: commit.id, format: format
-
- expect(response.body).to match(/^diff --git/)
- end
- end
- end
-end
diff --git a/spec/controllers/commits_controller_spec.rb b/spec/controllers/commits_controller_spec.rb
index ce402917..bf335634 100644
--- a/spec/controllers/commits_controller_spec.rb
+++ b/spec/controllers/commits_controller_spec.rb
@@ -1,19 +1,19 @@
require 'spec_helper'
describe CommitsController do
- let(:project) { create(:project_with_code) }
+ let(:project) { create(:project) }
let(:user) { create(:user) }
before do
sign_in(user)
- project.team << [user, :master]
+ project.add_access(user, :read, :admin)
end
describe "GET show" do
context "as atom feed" do
it "should render as atom" do
- get :show, project_id: project.path, id: "master", format: "atom"
+ get :show, project_id: project.code, id: "master.atom"
response.should be_success
response.content_type.should == 'application/atom+xml'
end
diff --git a/spec/controllers/merge_requests_controller_spec.rb b/spec/controllers/merge_requests_controller_spec.rb
deleted file mode 100644
index e8dd9bf9..00000000
--- a/spec/controllers/merge_requests_controller_spec.rb
+++ /dev/null
@@ -1,85 +0,0 @@
-require 'spec_helper'
-
-describe MergeRequestsController do
- let(:project) { create(:project_with_code) }
- let(:user) { create(:user) }
- let(:merge_request) { create(:merge_request_with_diffs, project: project, target_branch: "bcf03b5d~3", source_branch: "bcf03b5d") }
-
- before do
- sign_in(user)
- project.team << [user, :master]
- MergeRequestsController.any_instance.stub(validates_merge_request: true)
- end
-
- describe "#show" do
- shared_examples "export as" do |format|
- it "should generally work" do
- get :show, project_id: project.code, id: merge_request.id, format: format
-
- expect(response).to be_success
- end
-
- it "should generate it" do
- MergeRequest.any_instance.should_receive(:"to_#{format}")
-
- get :show, project_id: project.code, id: merge_request.id, format: format
- end
-
- it "should render it" do
- get :show, project_id: project.code, id: merge_request.id, format: format
-
- expect(response.body).to eq(merge_request.send(:"to_#{format}"))
- end
-
- it "should not escape Html" do
- MergeRequest.any_instance.stub(:"to_#{format}").and_return('HTML entities &<>" ')
-
- get :show, project_id: project.code, id: merge_request.id, format: format
-
- expect(response.body).to_not include('&')
- expect(response.body).to_not include('>')
- expect(response.body).to_not include('<')
- expect(response.body).to_not include('"')
- end
- end
-
- describe "as diff" do
- include_examples "export as", :diff
- let(:format) { :diff }
-
- it "should really only be a git diff" do
- get :show, project_id: project.code, id: merge_request.id, format: format
-
- expect(response.body).to start_with("diff --git")
- end
- end
-
- describe "as patch" do
- include_examples "export as", :patch
- let(:format) { :patch }
-
- it "should really be a git email patch with commit" do
- get :show, project_id: project.code, id: merge_request.id, format: format
-
- expect(response.body[0..100]).to start_with("From #{merge_request.commits.last.id}")
- end
-
- # TODO: fix or remove
- #it "should contain as many patches as there are commits" do
- #get :show, project_id: project.code, id: merge_request.id, format: format
-
- #patch_count = merge_request.commits.count
- #merge_request.commits.each_with_index do |commit, patch_num|
- #expect(response.body).to match(/^From #{commit.id}/)
- #expect(response.body).to match(/^Subject: \[PATCH #{patch_num}\/#{patch_count}\]/)
- #end
- #end
-
- it "should contain git diffs" do
- get :show, project_id: project.code, id: merge_request.id, format: format
-
- expect(response.body).to match(/^diff --git/)
- end
- end
- end
-end
diff --git a/spec/controllers/tree_controller_spec.rb b/spec/controllers/tree_controller_spec.rb
index 8232f147..b9295537 100644
--- a/spec/controllers/tree_controller_spec.rb
+++ b/spec/controllers/tree_controller_spec.rb
@@ -1,13 +1,13 @@
require 'spec_helper'
describe TreeController do
- let(:project) { create(:project_with_code) }
+ let(:project) { create(:project) }
let(:user) { create(:user) }
before do
sign_in(user)
- project.team << [user, :master]
+ project.add_access(user, :read, :admin)
project.stub(:branches).and_return(['master', 'foo/bar/baz'])
project.stub(:tags).and_return(['v1.0.0', 'v2.0.0'])
diff --git a/spec/factories.rb b/spec/factories.rb
index 3205cabd..7c33f0ec 100644
--- a/spec/factories.rb
+++ b/spec/factories.rb
@@ -9,10 +9,9 @@ FactoryGirl.define do
sequence(:url) { Faker::Internet.uri('http') }
- factory :user, aliases: [:author, :assignee, :owner, :creator] do
+ factory :user, aliases: [:author, :assignee, :owner] do
email { Faker::Internet.email }
name
- sequence(:username) { |n| "#{Faker::Internet.user_name}#{n}" }
password "123456"
password_confirmation { password }
@@ -26,35 +25,19 @@ FactoryGirl.define do
factory :project do
sequence(:name) { |n| "project#{n}" }
path { name.downcase.gsub(/\s/, '_') }
- creator
- end
-
- factory :redmine_project, parent: :project do
- issues_tracker { "redmine" }
- issues_tracker_id { "project_name_in_redmine" }
- end
-
- factory :project_with_code, parent: :project do
- path { 'gitlabhq' }
+ code { name.downcase.gsub(/\s/, '_') }
+ owner
end
factory :group do
sequence(:name) { |n| "group#{n}" }
- path { name.downcase.gsub(/\s/, '_') }
- owner
- type 'Group'
- end
-
- factory :namespace do
- sequence(:name) { |n| "namespace#{n}" }
- path { name.downcase.gsub(/\s/, '_') }
+ code { name.downcase.gsub(/\s/, '_') }
owner
end
factory :users_project do
user
project
- project_access { UsersProject::MASTER }
end
factory :issue do
@@ -63,88 +46,35 @@ FactoryGirl.define do
project
trait :closed do
- state :closed
- end
-
- trait :reopened do
- state :reopened
+ closed true
end
factory :closed_issue, traits: [:closed]
- factory :reopened_issue, traits: [:reopened]
end
factory :merge_request do
title
author
- project factory: :project_with_code
+ project
source_branch "master"
target_branch "stable"
- # pick 3 commits "at random" (from bcf03b5d~3 to bcf03b5d)
- trait :with_diffs do
- target_branch "master" # pretend bcf03b5d~3
- source_branch "stable" # pretend bcf03b5d
- st_commits do
- [Commit.new(project.repository.commit('bcf03b5d')),
- Commit.new(project.repository.commit('bcf03b5d~1')),
- Commit.new(project.repository.commit('bcf03b5d~2'))]
- end
- st_diffs do
- project.repo.diff("bcf03b5d~3", "bcf03b5d")
- end
- end
-
trait :closed do
- state :closed
- end
-
- trait :reopened do
- state :reopened
+ closed true
end
factory :closed_merge_request, traits: [:closed]
- factory :reopened_merge_request, traits: [:reopened]
- factory :merge_request_with_diffs, traits: [:with_diffs]
end
factory :note do
project
note "Note"
- author
-
- factory :note_on_commit, traits: [:on_commit]
- factory :note_on_commit_diff, traits: [:on_commit, :on_diff]
- factory :note_on_issue, traits: [:on_issue], aliases: [:votable_note]
- factory :note_on_merge_request, traits: [:on_merge_request]
- factory :note_on_merge_request_diff, traits: [:on_merge_request, :on_diff]
-
- trait :on_commit do
- project factory: :project_with_code
- commit_id "bcf03b5de6c33f3869ef70d68cf06e679d1d7f9a"
- noteable_type "Commit"
- end
-
- trait :on_diff do
- line_code "0_184_184"
- end
-
- trait :on_merge_request do
- project factory: :project_with_code
- noteable_id 1
- noteable_type "MergeRequest"
- end
-
- trait :on_issue do
- noteable_id 1
- noteable_type "Issue"
- end
end
factory :event do
factory :closed_issue_event do
project
- action { Event::CLOSED }
+ action Event::Closed
target factory: :closed_issue
author factory: :user
end
@@ -169,23 +99,11 @@ FactoryGirl.define do
"ssh-rsa AAAAB3NzaC1yc2EAAAABJQAAAIEAiPWx6WM4lhHNedGfBpPJNPpZ7yKu+dnn1SJejgt4596k6YjzGGphH2TUxwKzxcKDKKezwkpfnxPkSMkuEspGRt/aZZ9wa ++Oi7Qkr8prgHc4soW6NUlfDzpvZK2H5E7eQaSeP3SAwGmQKUFHCddNaP0L+hM7zhFNzjFvpaMgJw0="
end
end
-
- factory :invalid_key do
- key do
- "ssh-rsa this_is_invalid_key=="
- end
- end
end
factory :milestone do
title
project
-
- trait :closed do
- state :closed
- end
-
- factory :closed_milestone, traits: [:closed]
end
factory :system_hook do
diff --git a/spec/factories/user_team_project_relationships.rb b/spec/factories/user_team_project_relationships.rb
deleted file mode 100644
index e900d86c..00000000
--- a/spec/factories/user_team_project_relationships.rb
+++ /dev/null
@@ -1,21 +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
-#
-
-# Read about factories at https://github.com/thoughtbot/factory_girl
-
-FactoryGirl.define do
- factory :user_team_project_relationship do
- project
- user_team
- greatest_access { UsersProject::MASTER }
- end
-end
diff --git a/spec/factories/user_team_user_relationships.rb b/spec/factories/user_team_user_relationships.rb
deleted file mode 100644
index 8c729dd8..00000000
--- a/spec/factories/user_team_user_relationships.rb
+++ /dev/null
@@ -1,23 +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
-#
-
-# Read about factories at https://github.com/thoughtbot/factory_girl
-
-FactoryGirl.define do
- factory :user_team_user_relationship do
- user
- user_team
- group_admin false
- permission { UsersProject::MASTER }
- end
-end
diff --git a/spec/factories/user_teams.rb b/spec/factories/user_teams.rb
deleted file mode 100644
index 3aeea40a..00000000
--- a/spec/factories/user_teams.rb
+++ /dev/null
@@ -1,23 +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
-#
-
-# Read about factories at https://github.com/thoughtbot/factory_girl
-
-FactoryGirl.define do
- factory :user_team do
- sequence(:name) { |n| "team#{n}" }
- sequence(:description) { |n| "team_description#{n}" }
- path { name.downcase.gsub(/\s/, '_') }
- owner
- end
-end
diff --git a/spec/factories_spec.rb b/spec/factories_spec.rb
index 8360477d..5ee73546 100644
--- a/spec/factories_spec.rb
+++ b/spec/factories_spec.rb
@@ -1,9 +1,6 @@
require 'spec_helper'
-INVALID_FACTORIES = [
- :key_with_a_space_in_the_middle,
- :invalid_key,
-]
+INVALID_FACTORIES = [:key_with_a_space_in_the_middle]
FactoryGirl.factories.map(&:name).each do |factory_name|
next if INVALID_FACTORIES.include?(factory_name)
diff --git a/spec/features/admin/admin_projects_spec.rb b/spec/features/admin/admin_projects_spec.rb
deleted file mode 100644
index 23370891..00000000
--- a/spec/features/admin/admin_projects_spec.rb
+++ /dev/null
@@ -1,34 +0,0 @@
-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
-end
diff --git a/spec/features/notes_on_merge_requests_spec.rb b/spec/features/notes_on_merge_requests_spec.rb
deleted file mode 100644
index 82f44279..00000000
--- a/spec/features/notes_on_merge_requests_spec.rb
+++ /dev/null
@@ -1,228 +0,0 @@
-require 'spec_helper'
-
-describe "On a merge request", js: true do
- let!(:project) { create(:project_with_code) }
- let!(:merge_request) { create(:merge_request, project: project) }
-
- before do
- login_as :user
- project.team << [@user, :master]
-
- visit project_merge_request_path(project, merge_request)
- end
-
- subject { page }
-
- describe "the note form" do
- # main target form creation
- it { should have_css(".js-main-target-form", visible: true, count: 1) }
-
- # button initalization
- it { find(".js-main-target-form input[type=submit]").value.should == "Add Comment" }
- it { within(".js-main-target-form") { should_not have_link("Cancel") } }
-
- describe "without text" do
- it { within(".js-main-target-form") { should have_css(".js-note-preview-button", visible: false) } }
- end
-
- describe "with text" do
- before do
- within(".js-main-target-form") do
- fill_in "note[note]", with: "This is awesome"
- end
- end
-
- it { within(".js-main-target-form") { should_not have_css(".js-comment-button[disabled]") } }
-
- it { within(".js-main-target-form") { should have_css(".js-note-preview-button", visible: true) } }
- end
-
- describe "with preview" do
- before do
- within(".js-main-target-form") do
- fill_in "note[note]", with: "This is awesome"
- find(".js-note-preview-button").trigger("click")
- end
- end
-
- it { within(".js-main-target-form") { should have_css(".js-note-preview", text: "This is awesome", visible: true) } }
-
- it { within(".js-main-target-form") { should have_css(".js-note-preview-button", visible: false) } }
- it { within(".js-main-target-form") { should have_css(".js-note-edit-button", visible: true) } }
- end
- end
-
- describe "when posting a note" do
- before do
- within(".js-main-target-form") do
- fill_in "note[note]", with: "This is awsome!"
- find(".js-note-preview-button").trigger("click")
- click_button "Add Comment"
- end
- end
-
- # note added
- it { should have_content("This is awsome!") }
-
- # reset form
- it { within(".js-main-target-form") { should have_no_field("note[note]", with: "This is awesome!") } }
-
- # return from preview
- it { within(".js-main-target-form") { should have_css(".js-note-preview", visible: false) } }
- it { within(".js-main-target-form") { should have_css(".js-note-text", visible: true) } }
-
-
- it "should be removable" do
- find(".js-note-delete").trigger("click")
-
- should_not have_css(".note")
- end
- end
-end
-
-
-
-describe "On a merge request diff", js: true, focus: true do
- let!(:project) { create(:project_with_code) }
- let!(:merge_request) { create(:merge_request_with_diffs, project: project) }
-
- before do
- login_as :user
- project.team << [@user, :master]
-
- visit diffs_project_merge_request_path(project, merge_request)
-
- within '.diffs-tab' do
- click_link("Diff")
- end
- end
-
- subject { page }
-
- describe "when adding a note" do
- before do
- find("#4735dfc552ad7bf15ca468adc3cad9d05b624490_185_185.line_holder .js-add-diff-note-button").trigger("click")
- end
-
- describe "the notes holder" do
- it { should have_css("#4735dfc552ad7bf15ca468adc3cad9d05b624490_185_185.line_holder + .js-temp-notes-holder") }
-
- it { within(".js-temp-notes-holder") { should have_css(".new_note") } }
- end
-
- describe "the note form" do
- # set up hidden fields correctly
- it { within(".js-temp-notes-holder") { find("#note_noteable_type").value.should == "MergeRequest" } }
- it { within(".js-temp-notes-holder") { find("#note_noteable_id").value.should == merge_request.id.to_s } }
- it { within(".js-temp-notes-holder") { find("#note_commit_id").value.should == "" } }
- it { within(".js-temp-notes-holder") { find("#note_line_code").value.should == "4735dfc552ad7bf15ca468adc3cad9d05b624490_185_185" } }
-
- # buttons
- it { should have_button("Add Comment") }
- it { should have_css(".js-close-discussion-note-form", text: "Cancel") }
-
- it "shouldn't add a second form for same row" do
- find("#4735dfc552ad7bf15ca468adc3cad9d05b624490_185_185.line_holder .js-add-diff-note-button").trigger("click")
-
- should have_css("#4735dfc552ad7bf15ca468adc3cad9d05b624490_185_185.line_holder + .js-temp-notes-holder form", count: 1)
- end
-
- it "should be removed when canceled" do
- within(".file form[rel$='4735dfc552ad7bf15ca468adc3cad9d05b624490_185_185']") do
- find(".js-close-discussion-note-form").trigger("click")
- end
-
- should have_no_css(".js-temp-notes-holder")
- end
- end
- end
-
- describe "with muliple note forms" do
- before do
- find("#4735dfc552ad7bf15ca468adc3cad9d05b624490_185_185.line_holder .js-add-diff-note-button").trigger("click")
- find("#342e16cbbd482ac2047dc679b2749d248cc1428f_18_17.line_holder .js-add-diff-note-button").trigger("click")
- end
-
- # has two line forms
- it { should have_css(".js-temp-notes-holder", count: 2) }
-
- describe "previewing them separately" do
- before do
- # add two separate texts and trigger previews on both
- within("#4735dfc552ad7bf15ca468adc3cad9d05b624490_185_185.line_holder + .js-temp-notes-holder") do
- fill_in "note[note]", with: "One comment on line 185"
- find(".js-note-preview-button").trigger("click")
- end
- within("#342e16cbbd482ac2047dc679b2749d248cc1428f_18_17.line_holder + .js-temp-notes-holder") do
- fill_in "note[note]", with: "Another comment on line 17"
- find(".js-note-preview-button").trigger("click")
- end
- end
-
- # check if previews were rendered separately
- it { within("#4735dfc552ad7bf15ca468adc3cad9d05b624490_185_185.line_holder + .js-temp-notes-holder") { should have_css(".js-note-preview", text: "One comment on line 185") } }
- it { within("#342e16cbbd482ac2047dc679b2749d248cc1428f_18_17.line_holder + .js-temp-notes-holder") { should have_css(".js-note-preview", text: "Another comment on line 17") } }
- end
-
- describe "posting a note" do
- before do
- within("#342e16cbbd482ac2047dc679b2749d248cc1428f_18_17.line_holder + .js-temp-notes-holder") do
- fill_in "note[note]", with: "Another comment on line 17"
- click_button("Add Comment")
- end
- end
-
- # removed form after submit
- it { should have_no_css("#342e16cbbd482ac2047dc679b2749d248cc1428f_18_17.line_holder + .js-temp-notes-holder") }
-
- # added discussion
- it { should have_content("Another comment on line 17") }
- it { should have_css("#342e16cbbd482ac2047dc679b2749d248cc1428f_18_17.line_holder + .notes_holder") }
- it { should have_css("#342e16cbbd482ac2047dc679b2749d248cc1428f_18_17.line_holder + .notes_holder .note", count: 1) }
- it { should have_link("Reply") }
-
- it "should remove last note of a discussion" do
- within("#342e16cbbd482ac2047dc679b2749d248cc1428f_18_17.line_holder + .notes_holder") do
- find(".js-note-delete").trigger("click")
- end
-
- # removed whole discussion
- should_not have_css(".note_holder")
- should have_css("#342e16cbbd482ac2047dc679b2749d248cc1428f_18_17.line_holder + #342e16cbbd482ac2047dc679b2749d248cc1428f_18_18.line_holder")
- end
- end
- end
-
- describe "when replying to a note" do
- before do
- # create first note
- find("#4735dfc552ad7bf15ca468adc3cad9d05b624490_184_184.line_holder .js-add-diff-note-button").trigger("click")
- within("#4735dfc552ad7bf15ca468adc3cad9d05b624490_184_184.line_holder + .js-temp-notes-holder") do
- fill_in "note[note]", with: "One comment on line 184"
- click_button("Add Comment")
- end
- # create second note
- within("#4735dfc552ad7bf15ca468adc3cad9d05b624490_184_184.line_holder + .notes_holder") do
- find(".js-discussion-reply-button").trigger("click")
- fill_in "note[note]", with: "An additional comment in reply"
- click_button("Add Comment")
- end
- end
-
- # inserted note
- it { should have_content("An additional comment in reply") }
- it { within("#4735dfc552ad7bf15ca468adc3cad9d05b624490_184_184.line_holder + .notes_holder") { should have_css(".note", count: 2) } }
-
- # removed form after reply
- it { within("#4735dfc552ad7bf15ca468adc3cad9d05b624490_184_184.line_holder + .notes_holder") { should have_no_css("form") } }
- it { within("#4735dfc552ad7bf15ca468adc3cad9d05b624490_184_184.line_holder + .notes_holder") { should have_link("Reply") } }
- end
-end
-
-
-
-describe "On merge request discussion", js: true do
- describe "with merge request diff note"
- describe "with commit note"
- describe "with commit diff note"
-end
diff --git a/spec/features/profile_spec.rb b/spec/features/profile_spec.rb
deleted file mode 100644
index 51b95c25..00000000
--- a/spec/features/profile_spec.rb
+++ /dev/null
@@ -1,49 +0,0 @@
-require 'spec_helper'
-
-describe "Profile account page" do
- let(:user) { create(:user) }
-
- before do
- login_as :user
- end
-
- describe "when signup is enabled" do
- before do
- Gitlab.config.gitlab.stub(:signup_enabled).and_return(true)
- visit account_profile_path
- end
-
- it { page.should have_content("Remove account") }
-
- it "should delete the account", js: true do
- expect { click_link "Delete account" }.to change {User.count}.by(-1)
- current_path.should == new_user_session_path
- end
- end
-
- describe "when signup is enabled and user has a project" do
- before do
- Gitlab.config.gitlab.stub(:signup_enabled).and_return(true)
- @project = create(:project, namespace: @user.namespace)
- @project.team << [@user, :master]
- visit account_profile_path
- end
- it { page.should have_content("Remove account") }
-
- it "should not allow user to delete the account" do
- expect { click_link "Delete account" }.not_to change {User.count}.by(-1)
- end
- end
-
- describe "when signup is disabled" do
- before do
- Gitlab.config.gitlab.stub(:signup_enabled).and_return(false)
- visit account_profile_path
- end
-
- it "should not have option to remove account" do
- page.should_not have_content("Remove account")
- current_path.should == account_profile_path
- end
- end
-end
diff --git a/spec/features/projects_spec.rb b/spec/features/projects_spec.rb
deleted file mode 100644
index 1ffc28bf..00000000
--- a/spec/features/projects_spec.rb
+++ /dev/null
@@ -1,17 +0,0 @@
-require 'spec_helper'
-
-describe "Projects" do
- before { login_as :user }
-
- describe "DELETE /projects/:id" do
- before do
- @project = create(:project, namespace: @user.namespace)
- @project.team << [@user, :master]
- visit edit_project_path(@project)
- end
-
- it "should be correct path" do
- expect { click_link "Remove project" }.to change {Project.count}.by(-1)
- end
- end
-end
diff --git a/spec/features/users_spec.rb b/spec/features/users_spec.rb
deleted file mode 100644
index ed9e44fb..00000000
--- a/spec/features/users_spec.rb
+++ /dev/null
@@ -1,19 +0,0 @@
-require 'spec_helper'
-
-describe 'Users' do
- describe "GET /users/sign_up" do
- before do
- Gitlab.config.gitlab.stub(:signup_enabled).and_return(true)
- end
-
- it "should create a new user account" do
- visit new_user_registration_path
- fill_in "user_name", with: "Name Surname"
- fill_in "user_username", with: "Great"
- fill_in "user_email", with: "name@mail.com"
- fill_in "user_password", with: "password1234"
- fill_in "user_password_confirmation", with: "password1234"
- expect { click_button "Sign up" }.to change {User.count}.by(1)
- end
- end
-end
diff --git a/spec/helpers/application_helper_spec.rb b/spec/helpers/application_helper_spec.rb
index ba1af084..a94d5505 100644
--- a/spec/helpers/application_helper_spec.rb
+++ b/spec/helpers/application_helper_spec.rb
@@ -43,7 +43,7 @@ describe ApplicationHelper do
let(:user_email) { 'user@email.com' }
it "should return a generic avatar path when Gravatar is disabled" do
- Gitlab.config.gravatar.stub(:enabled).and_return(false)
+ Gitlab.config.stub(:disable_gravatar?).and_return(true)
gravatar_icon(user_email).should == 'no_avatar.png'
end
@@ -51,36 +51,14 @@ describe ApplicationHelper do
gravatar_icon('').should == 'no_avatar.png'
end
- it "should return default gravatar url" do
- stub!(:request).and_return(double(:ssl? => false))
- gravatar_icon(user_email).should match('http://www.gravatar.com/avatar/b58c6f14d292556214bd64909bcdb118')
- end
-
it "should use SSL when appropriate" do
stub!(:request).and_return(double(:ssl? => true))
gravatar_icon(user_email).should match('https://secure.gravatar.com')
end
- it "should return custom gravatar path when gravatar_url is set" do
- stub!(:request).and_return(double(:ssl? => false))
- Gitlab.config.gravatar.stub(:plain_url).and_return('http://example.local/?s=%{size}&hash=%{hash}')
- gravatar_icon(user_email, 20).should == 'http://example.local/?s=20&hash=b58c6f14d292556214bd64909bcdb118'
- end
-
it "should accept a custom size" do
stub!(:request).and_return(double(:ssl? => false))
gravatar_icon(user_email, 64).should match(/\?s=64/)
end
-
- it "should use default size when size is wrong" do
- stub!(:request).and_return(double(:ssl? => false))
- gravatar_icon(user_email, nil).should match(/\?s=40/)
- end
-
- it "should be case insensitive" do
- stub!(:request).and_return(double(:ssl? => false))
- gravatar_icon(user_email).should == gravatar_icon(user_email.upcase + " ")
- end
-
end
end
diff --git a/spec/helpers/gitlab_markdown_helper_spec.rb b/spec/helpers/gitlab_markdown_helper_spec.rb
index 4140ba48..ec830e40 100644
--- a/spec/helpers/gitlab_markdown_helper_spec.rb
+++ b/spec/helpers/gitlab_markdown_helper_spec.rb
@@ -1,13 +1,10 @@
require "spec_helper"
describe GitlabMarkdownHelper do
- include ApplicationHelper
- include IssuesHelper
+ let!(:project) { create(:project) }
- let!(:project) { create(:project_with_code) }
-
- let(:user) { create(:user, username: 'gfm') }
- let(:commit) { project.repository.commit }
+ let(:user) { create(:user, name: 'gfm') }
+ let(:commit) { CommitDecorator.decorate(project.commit) }
let(:issue) { create(:issue, project: project) }
let(:merge_request) { create(:merge_request, project: project) }
let(:snippet) { create(:snippet, project: project) }
@@ -84,11 +81,11 @@ describe GitlabMarkdownHelper do
end
describe "referencing a team member" do
- let(:actual) { "@#{user.username} you are right." }
- let(:expected) { user_path(user) }
+ let(:actual) { "@#{user.name} you are right." }
+ let(:expected) { project_team_member_path(project, member) }
before do
- project.team << [user, :master]
+ project.users << user
end
it "should link using a simple name" do
@@ -106,18 +103,18 @@ describe GitlabMarkdownHelper do
end
it "should link with adjacent text" do
- actual = "Mail the admin (@#{user.username})"
+ actual = "Mail the admin (@gfm)"
gfm(actual).should match(expected)
end
it "should keep whitespace intact" do
- actual = "Yes, @#{user.username} is right."
- expected = /Yes, @#{user.username}<\/a> is right/
+ actual = "Yes, @#{user.name} is right."
+ expected = /Yes, @#{user.name}<\/a> is right/
gfm(actual).should match(expected)
end
it "should not link with an invalid id" do
- actual = expected = "@#{user.username.reverse} you are right."
+ actual = expected = "@#{user.name.reverse} you are right."
gfm(actual).should == expected
end
@@ -275,7 +272,7 @@ describe GitlabMarkdownHelper do
groups[0].should match(/This should finally fix $/)
# First issue link
- groups[1].should match(/href="#{project_issue_url(project, issues[0])}"/)
+ groups[1].should match(/href="#{project_issue_path(project, issues[0])}"/)
groups[1].should match(/##{issues[0].id}$/)
# Internal commit link
@@ -283,7 +280,7 @@ describe GitlabMarkdownHelper do
groups[2].should match(/ and /)
# Second issue link
- groups[3].should match(/href="#{project_issue_url(project, issues[1])}"/)
+ groups[3].should match(/href="#{project_issue_path(project, issues[1])}"/)
groups[3].should match(/##{issues[1].id}$/)
# Trailing commit link
@@ -317,12 +314,12 @@ describe GitlabMarkdownHelper do
end
it "should handle references in lists" do
- project.team << [user, :master]
+ project.users << user
- actual = "\n* dark: ##{issue.id}\n* light by @#{member.user.username}"
+ actual = "\n* dark: ##{issue.id}\n* light by @#{member.user_name}"
markdown(actual).should match(%r{
dark: ##{issue.id}
})
- markdown(actual).should match(%r{
light by @#{member.user.username}
})
+ markdown(actual).should match(%r{
light by @#{member.user_name}
})
end
it "should handle references in " do
@@ -332,59 +329,13 @@ describe GitlabMarkdownHelper do
end
it "should leave code blocks untouched" do
- helper.stub(:user_color_scheme_class).and_return(:white)
+ markdown("\n some code from $#{snippet.id}\n here too\n").should == "
somecodefrom $#{snippet.id}\nheretoo\n
"
- helper.markdown("\n some code from $#{snippet.id}\n here too\n").should include("
somecodefrom $#{snippet.id}\nheretoo\n
")
-
- helper.markdown("\n```\nsome code from $#{snippet.id}\nhere too\n```\n").should include("
somecodefrom $#{snippet.id}\nheretoo\n
")
+ markdown("\n```\nsome code from $#{snippet.id}\nhere too\n```\n").should == "
somecodefrom $#{snippet.id}\nheretoo\n
"
end
it "should leave inline code untouched" do
markdown("\nDon't use `$#{snippet.id}` here.\n").should == "
Don't use $#{snippet.id} here.
\n"
end
-
- it "should leave ref-like autolinks untouched" do
- markdown("look at http://example.tld/#!#{merge_request.id}").should == "
\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..cc8ce8b2
--- /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.ssh_path + "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/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..b6b1769f 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'
@@ -221,7 +169,9 @@ describe Notify do
end
describe 'project access changed' do
- let(:project) { create(:project) }
+ let(:project) { create(:project,
+ path: "Fuu",
+ code: "Fuu") }
let(:user) { create(:user) }
let(:users_project) { create(:users_project,
project: project,
@@ -243,7 +193,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 +211,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 +227,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 +246,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..49cb49db 100644
--- a/spec/models/event_spec.rb
+++ b/spec/models/event_spec.rb
@@ -52,14 +52,14 @@ describe Event do
@event = Event.create(
project: project,
- action: Event::PUSHED,
+ action: Event::Pushed,
data: data,
author_id: @user.id
)
end
it { @event.push?.should be_true }
- it { @event.proper?.should be_true }
+ it { @event.allowed?.should be_true }
it { @event.new_branch?.should be_true }
it { @event.tag?.should be_false }
it { @event.branch_name.should == "master" }
@@ -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..6ae2cb20 100644
--- a/spec/models/group_spec.rb
+++ b/spec/models/group_spec.rb
@@ -1,15 +1,13 @@
# == Schema Information
#
-# Table name: namespaces
+# Table name: groups
#
-# 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
+# code :string(255) not null
+# owner_id :integer not null
+# created_at :datetime not null
+# updated_at :datetime not null
#
require 'spec_helper'
@@ -20,15 +18,7 @@ describe Group do
it { should have_many :projects }
it { should validate_presence_of :name }
it { should validate_uniqueness_of(:name) }
- it { should validate_presence_of :path }
- it { should validate_uniqueness_of(:path) }
+ it { should validate_presence_of :code }
+ it { should validate_uniqueness_of(:code) }
it { should validate_presence_of :owner }
-
- describe :users do
- it { group.users.should == [group.owner] }
- end
-
- describe :human_name do
- it { group.human_name.should == group.name }
- end
end
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..d70647f6 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,26 +32,17 @@ 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] }
- create(:note, commit_id: merge_request.commits.first.id, noteable_type: 'Commit')
+ merge_request.stub(:commits) { [merge_request.project.commit] }
+ create(:note, noteable: merge_request.commits.first)
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
deleted file mode 100644
index b40a0795..00000000
--- a/spec/models/namespace_spec.rb
+++ /dev/null
@@ -1,79 +0,0 @@
-# == Schema Information
-#
-# 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
-#
-
-require 'spec_helper'
-
-describe Namespace do
- let!(:namespace) { create(:namespace) }
-
- it { should have_many :projects }
- it { should validate_presence_of :name }
- it { should validate_uniqueness_of(:name) }
- it { should validate_presence_of :path }
- it { should validate_uniqueness_of(:path) }
- it { should validate_presence_of :owner }
-
- describe "Mass assignment" do
- it { should allow_mass_assignment_of(:name) }
- it { should allow_mass_assignment_of(:path) }
- end
-
- describe "Respond to" do
- it { should respond_to(:human_name) }
- it { should respond_to(:to_param) }
- end
-
- it { Namespace.global_id.should == 'GLN' }
-
- describe :to_param do
- it { namespace.to_param.should == namespace.path }
- end
-
- describe :human_name do
- it { namespace.human_name.should == namespace.owner_name }
- end
-
- describe :search do
- before do
- @namespace = create :namespace
- end
-
- it { Namespace.search(@namespace.path).should == [@namespace] }
- it { Namespace.search('unknown').should == [] }
- end
-
- describe :move_dir do
- before do
- @namespace = create :namespace
- @namespace.stub(path_changed?: true)
- end
-
- it "should raise error when dirtory exists" do
- expect { @namespace.move_dir }.to raise_error("namespace directory cannot be moved")
- end
-
- it "should move dir if path changed" do
- new_path = @namespace.path + "_new"
- @namespace.stub(path_was: @namespace.path)
- @namespace.stub(path: new_path)
- @namespace.move_dir.should be_true
- end
- end
-
- describe :rm_dir do
- it "should remove dir" do
- namespace.rm_dir.should be_true
- end
- end
-end
diff --git a/spec/models/note_spec.rb b/spec/models/note_spec.rb
index 52e24a78..4f9352b9 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,
+ noteable_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.noteable_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.noteable_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,
+ noteable_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.noteable_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..7c8f05b1
--- /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.url}/#{project.code}/commits/#{@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..60f8d45c 100644
--- a/spec/models/project_security_spec.rb
+++ b/spec/models/project_security_spec.rb
@@ -4,109 +4,38 @@ describe Project do
describe :authorization do
before do
@p1 = create(:project)
-
@u1 = create(:user)
@u2 = create(:user)
- @u3 = create(:user)
- @u4 = @p1.owner
-
@abilities = Six.new
@abilities << Ability
end
- let(:guest_actions) { Ability.project_guest_rules }
- let(:report_actions) { Ability.project_report_rules }
- let(:dev_actions) { Ability.project_dev_rules }
- let(:master_actions) { Ability.project_master_rules }
- let(:admin_actions) { Ability.project_admin_rules }
-
- describe "Non member rules" do
- it "should deny for non-project users any actions" do
- admin_actions.each do |action|
- @abilities.allowed?(@u1, action, @p1).should be_false
- end
- end
- end
-
- describe "Guest Rules" do
- before do
- @p1.users_projects.create(project: @p1, user: @u2, project_access: UsersProject::GUEST)
- end
-
- it "should allow for project user any guest actions" do
- guest_actions.each do |action|
- @abilities.allowed?(@u2, action, @p1).should be_true
- end
- end
- end
-
- describe "Report Rules" do
+ describe "read access" do
before do
@p1.users_projects.create(project: @p1, user: @u2, project_access: UsersProject::REPORTER)
end
- it "should allow for project user any report actions" do
- report_actions.each do |action|
- @abilities.allowed?(@u2, action, @p1).should be_true
- end
- end
+ it { @abilities.allowed?(@u1, :read_project, @p1).should be_false }
+ it { @abilities.allowed?(@u2, :read_project, @p1).should be_true }
end
- describe "Developer Rules" do
- before do
- @p1.users_projects.create(project: @p1, user: @u2, project_access: UsersProject::REPORTER)
- @p1.users_projects.create(project: @p1, user: @u3, project_access: UsersProject::DEVELOPER)
- end
-
- it "should deny for developer master-specific actions" do
- [dev_actions - report_actions].each do |action|
- @abilities.allowed?(@u2, action, @p1).should be_false
- end
- end
-
- it "should allow for project user any dev actions" do
- dev_actions.each do |action|
- @abilities.allowed?(@u3, action, @p1).should be_true
- end
- end
- end
-
- describe "Master Rules" do
+ describe "write access" do
before do
@p1.users_projects.create(project: @p1, user: @u2, project_access: UsersProject::DEVELOPER)
- @p1.users_projects.create(project: @p1, user: @u3, project_access: UsersProject::MASTER)
end
- it "should deny for developer master-specific actions" do
- [master_actions - dev_actions].each do |action|
- @abilities.allowed?(@u2, action, @p1).should be_false
- end
- end
-
- it "should allow for project user any master actions" do
- master_actions.each do |action|
- @abilities.allowed?(@u3, action, @p1).should be_true
- end
- end
+ it { @abilities.allowed?(@u1, :write_project, @p1).should be_false }
+ it { @abilities.allowed?(@u2, :write_project, @p1).should be_true }
end
- describe "Admin Rules" do
+ describe "admin access" do
before do
- @p1.users_projects.create(project: @p1, user: @u2, project_access: UsersProject::DEVELOPER)
- @p1.users_projects.create(project: @p1, user: @u3, project_access: UsersProject::MASTER)
+ @p1.users_projects.create(project: @p1, user: @u1, project_access: UsersProject::DEVELOPER)
+ @p1.users_projects.create(project: @p1, user: @u2, project_access: UsersProject::MASTER)
end
- it "should deny for masters admin-specific actions" do
- [admin_actions - master_actions].each do |action|
- @abilities.allowed?(@u2, action, @p1).should be_false
- end
- end
-
- it "should allow for project owner any admin actions" do
- admin_actions.each do |action|
- @abilities.allowed?(@u4, action, @p1).should be_true
- end
- end
+ it { @abilities.allowed?(@u1, :admin_project, @p1).should be_false }
+ it { @abilities.allowed?(@u2, :admin_project, @p1).should be_true }
end
end
end
diff --git a/spec/models/project_spec.rb b/spec/models/project_spec.rb
index cbc7f278..5bcab924 100644
--- a/spec/models/project_spec.rb
+++ b/spec/models/project_spec.rb
@@ -8,17 +8,15 @@
# description :text
# created_at :datetime not null
# updated_at :datetime not null
-# creator_id :integer
+# private_flag :boolean default(TRUE), not null
+# code :string(255)
+# 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
+# group_id :integer
#
require 'spec_helper'
@@ -26,8 +24,7 @@ require 'spec_helper'
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) }
@@ -43,8 +40,8 @@ describe Project do
end
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,42 +54,117 @@ 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) }
+
+ it { should validate_presence_of(:code) }
+ it { should validate_uniqueness_of(:code) }
+ it { should ensure_length_of(:code).is_within(1..255) }
+ # 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(:transfer) }
- it { should respond_to(:name_with_namespace) }
- it { should respond_to(:namespace_owner) }
- it { should respond_to(:owner) }
- it { should respond_to(:path_with_namespace) }
+ it { should respond_to(:post_receive_data) }
+ it { should respond_to(:trigger_post_receive) }
+ end
+
+ describe 'modules' do
+ it { should include_module(Repository) }
+ it { should include_module(PushObserver) }
+ it { should include_module(Authority) }
+ it { should include_module(Team) }
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.ssh_path + "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
- project = Project.new(path: "somewhere")
- project.web_url.should == "#{Gitlab.config.gitlab.url}/somewhere"
+ project = Project.new(code: "somewhere")
+ project.web_url.should == "#{Gitlab.config.url}/somewhere"
+ 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/", code: "NEOK")
+ project.valid_repo?.should be_false
+ end
end
describe "last_activity methods" do
@@ -118,11 +190,93 @@ describe Project do
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 "Git methods" do
+ let(:project) { create(:project) }
+
+ 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
+ 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 +285,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 +296,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..4ac699b1 100644
--- a/spec/models/user_spec.rb
+++ b/spec/models/user_spec.rb
@@ -22,27 +22,23 @@
# 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'
describe User do
describe "Associations" do
- it { should have_one(:namespace) }
it { should have_many(:users_projects).dependent(:destroy) }
- it { should have_many(:groups) }
+ it { should have_many(:projects) }
+ it { should have_many(:my_own_projects).class_name('Project') }
it { should have_many(:keys).dependent(:destroy) }
it { should have_many(:events).class_name('Event').dependent(:destroy) }
it { should have_many(:recent_events).class_name('Event') }
@@ -59,7 +55,6 @@ describe User do
end
describe 'validations' do
- it { should validate_presence_of(:username) }
it { should validate_presence_of(:projects_limit) }
it { should validate_numericality_of(:projects_limit) }
it { should allow_value(0).for(:projects_limit) }
@@ -70,10 +65,28 @@ describe User do
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 +112,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..0eec41f4 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,21 +30,19 @@ 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
- describe "Issue commented" do
- before do
- Note.observers.enable :activity_observer do
- @issue = create(:issue, project: project)
- @note = create(:note, noteable: @issue, project: project, author: @issue.author)
- @event = Event.last
- end
- end
+ #describe "Issue commented" do
+ #before do
+ #@issue = create(:issue, project: project)
+ #@note = create(:note, noteable: @issue, project: project)
+ #@event = Event.last
+ #end
- it_should_be_valid_event
- it { @event.action.should == Event::COMMENTED }
- it { @event.target.should == @note }
- end
+ #it_should_be_valid_event
+ #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..509c1d02 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
+ 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
+ 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
+ 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
+ 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..08254f44 100644
--- a/spec/observers/user_observer_spec.rb
+++ b/spec/observers/user_observer_spec.rb
@@ -2,24 +2,30 @@ 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') }
+ 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..cbe42248 100644
--- a/spec/observers/users_project_observer_spec.rb
+++ b/spec/observers/users_project_observer_spec.rb
@@ -2,64 +2,75 @@ require 'spec_helper'
describe UsersProjectObserver do
let(:user) { create(:user) }
- let(:project) { create(:project) }
+ let(:project) { create(:project,
+ code: "Fuu",
+ path: "Fuu" ) }
+ 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 88%
rename from spec/features/admin/admin_hooks_spec.rb
rename to spec/requests/admin/admin_hooks_spec.rb
index 102a1b92..3f35b2fd 100644
--- a/spec/features/admin/admin_hooks_spec.rb
+++ b/spec/requests/admin/admin_hooks_spec.rb
@@ -2,7 +2,9 @@ require 'spec_helper'
describe "Admin::Hooks" do
before do
- @project = create(:project)
+ @project = create(:project,
+ name: "LeGiT",
+ code: "LGT")
login_as :admin
@system_hook = create(:system_hook)
@@ -12,7 +14,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..43e39d7c
--- /dev/null
+++ b/spec/requests/admin/admin_projects_spec.rb
@@ -0,0 +1,118 @@
+require 'spec_helper'
+
+describe "Admin::Projects" do
+ before do
+ @project = create(:project,
+ name: "LeGiT",
+ code: "LGT")
+ 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.code)
+ 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("Project name")
+ page.should have_content("URL")
+ end
+
+ describe "Update project" do
+ before do
+ fill_in "project_name", with: "Big Bang"
+ fill_in "project_code", with: "BB1"
+ click_button "Save Project"
+ @project.reload
+ end
+
+ it "should show page with new data" do
+ page.should have_content("BB1")
+ page.should have_content("Big Bang")
+ end
+
+ it "should change project entry" do
+ @project.name.should == "Big Bang"
+ @project.code.should == "BB1"
+ end
+ end
+ end
+
+ describe "GET /admin/projects/new" do
+ before do
+ visit admin_projects_path
+ click_link "New Project"
+ end
+
+ it "should be correct path" do
+ current_path.should == new_admin_project_path
+ end
+
+ it "should have labels for new project" do
+ page.should have_content("Project name is")
+ page.should have_content("Git Clone")
+ page.should have_content("URL")
+ end
+ end
+
+ describe "POST /admin/projects" do
+ before do
+ visit new_admin_project_path
+ fill_in 'project_name', with: 'NewProject'
+ fill_in 'project_code', with: 'NPR'
+ fill_in 'project_path', with: 'gitlabhq_1'
+ expect { click_button "Create project" }.to change { Project.count }.by(1)
+ @project = Project.last
+ end
+
+ it "should be correct path" do
+ current_path.should == admin_project_path(@project)
+ end
+
+ it "should show project" do
+ page.should have_content(@project.name)
+ page.should have_content(@project.path)
+ 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 78%
rename from spec/features/admin/admin_users_spec.rb
rename to spec/requests/admin/admin_users_spec.rb
index 22d1ee91..9f43f07a 100644
--- a/spec/features/admin/admin_users_spec.rb
+++ b/spec/requests/admin/admin_users_spec.rb
@@ -23,7 +23,6 @@ describe "Admin::Users" do
@password = "123ABC"
visit new_admin_user_path
fill_in "user_name", with: "Big Bang"
- fill_in "user_username", with: "bang"
fill_in "user_email", with: "bigbang@mail.com"
fill_in "user_password", with: @password
fill_in "user_password_confirmation", with: @password
@@ -41,7 +40,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 +48,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 +70,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..6ea7e9b5 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.code}/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.code}/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.code}/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.code}/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.code}/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..e83f2467 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.code}/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.code}/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.code}/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.code}/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.code}/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.code}/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..860825ab 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.code}/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.code}/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.code}/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.code}/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
deleted file mode 100644
index 90164083..00000000
--- a/spec/requests/api/notes_spec.rb
+++ /dev/null
@@ -1,177 +0,0 @@
-require 'spec_helper'
-
-describe Gitlab::API do
- include ApiHelpers
-
- let(:user) { create(:user) }
- let!(:project) { create(:project, namespace: user.namespace ) }
- 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] }
-
- describe "GET /projects/:id/notes" do
- context "when unauthenticated" do
- it "should return authentication error" do
- get api("/projects/#{project.id}/notes")
- response.status.should == 401
- end
- end
-
- context "when authenticated" do
- it "should return project wall notes" do
- get api("/projects/#{project.id}/notes", user)
- response.status.should == 200
- json_response.should be_an Array
- json_response.first['body'].should == wall_note.note
- end
- end
- end
-
- describe "GET /projects/:id/notes/:note_id" do
- it "should return a wall note by id" do
- get api("/projects/#{project.id}/notes/#{wall_note.id}", user)
- 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
- it "should create a new wall note" do
- post api("/projects/#{project.id}/notes", user), body: 'hi!'
- 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
- context "when noteable is an Issue" do
- it "should return an array of issue notes" do
- get api("/projects/#{project.id}/issues/#{issue.id}/notes", user)
- response.status.should == 200
- 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
- it "should return an array of snippet notes" do
- get api("/projects/#{project.id}/snippets/#{snippet.id}/notes", user)
- response.status.should == 200
- 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
-
- describe "GET /projects/:id/noteable/:noteable_id/notes/:note_id" do
- context "when noteable is an Issue" do
- it "should return an issue note by id" do
- get api("/projects/#{project.id}/issues/#{issue.id}/notes/#{issue_note.id}", user)
- 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
- it "should return a snippet note by id" do
- get api("/projects/#{project.id}/snippets/#{snippet.id}/notes/#{snippet_note.id}", user)
- 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
-
- describe "POST /projects/:id/noteable/:noteable_id/notes" do
- context "when noteable is an Issue" do
- it "should create a new issue note" do
- post api("/projects/#{project.id}/issues/#{issue.id}/notes", user), body: 'hi!'
- response.status.should == 201
- 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
- it "should create a new snippet note" do
- post api("/projects/#{project.id}/snippets/#{snippet.id}/notes", user), body: 'hi!'
- response.status.should == 201
- 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..d24ce43d 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,21 +33,7 @@ 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
+ it "should create new project without code and path" do
expect { post api("/projects", user), name: 'foo' }.to change {Project.count}.by(1)
end
@@ -58,37 +41,20 @@ 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
project = attributes_for(:project, {
+ path: 'path',
+ code: 'code',
description: Faker::Lorem.sentence,
default_branch: 'stable',
issues_enabled: false,
@@ -100,47 +66,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
@@ -154,8 +79,8 @@ describe Gitlab::API do
json_response['owner']['email'].should == user.email
end
- it "should return a project by path name" do
- get api("/projects/#{project.id}", user)
+ it "should return a project by code name" do
+ get api("/projects/#{project.code}", user)
response.status.should == 200
json_response['name'].should == project.name
end
@@ -165,17 +90,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.code}/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,105 +103,37 @@ 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.code}/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.code}/members", user)
response.status.should == 200
json_response.should be_an Array
json_response.count.should == 2
json_response.first['email'].should == user.email
end
-
- it "finds team members with query string" do
- get api("/projects/#{project.id}/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.code}/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.code}/members", user), user_id: user2.id,
access_level: UsersProject::DEVELOPER
}.to change { UsersProject.count }.by(1)
@@ -290,210 +141,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.code}/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.code}/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.code}/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.code}/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.code}/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.code}/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.code}/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.code}/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 +219,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.code}/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.code}/repository/commits")
response.status.should == 401
end
end
@@ -523,7 +240,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.code}/snippets", user)
response.status.should == 200
json_response.should be_an Array
json_response.first['title'].should == snippet.title
@@ -532,160 +249,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.code}/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.code}/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.code}/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.code}/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.code}/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.code}/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.code}/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.code}/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 66%
rename from spec/features/gitlab_flavored_markdown_spec.rb
rename to spec/requests/gitlab_flavored_markdown_spec.rb
index 653ff865..aedd435e 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
@@ -19,7 +19,7 @@ describe "Gitlab Flavored Markdown" do
@test_file = "gfm_test_file"
i.add(@test_file, "foo\nbar\n")
# add commit with gfm
- i.commit("fix ##{issue.id}\n\nask @#{fred.username} for details", head: @branch_name)
+ i.commit("fix ##{issue.id}\n\nask @#{fred.name} for details", head: @branch_name)
# add test tag
@tag_name = "gfm-test-tag"
@@ -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
@@ -56,7 +56,7 @@ describe "Gitlab Flavored Markdown" do
it "should render description in commits#show" do
visit project_commit_path(project, commit)
- page.should have_link("@#{fred.username}")
+ page.should have_link("@#{fred.name}")
end
it "should render title in refs#tree", js: true 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)
@@ -94,7 +93,7 @@ describe "Gitlab Flavored Markdown" do
assignee: @user,
project: project,
title: "fix ##{@other_issue.id}",
- description: "ask @#{fred.username} for details")
+ description: "ask @#{fred.name} for details")
end
it "should render subject in issues#index" do
@@ -112,7 +111,7 @@ describe "Gitlab Flavored Markdown" do
it "should render details in issues#show" do
visit project_issue_path(project, @issue)
- page.should have_link("@#{fred.username}")
+ page.should have_link("@#{fred.name}")
end
end
@@ -143,7 +142,7 @@ describe "Gitlab Flavored Markdown" do
@milestone = create(:milestone,
project: project,
title: "fix ##{issue.id}",
- description: "ask @#{fred.username} for details")
+ description: "ask @#{fred.name} for details")
end
it "should render title in milestones#index" do
@@ -161,7 +160,7 @@ describe "Gitlab Flavored Markdown" do
it "should render description in milestones#show" do
visit project_milestone_path(project, @milestone)
- page.should have_link("@#{fred.username}")
+ page.should have_link("@#{fred.name}")
end
end
@@ -169,32 +168,67 @@ 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
+
+ it "should render in wikis#index", js: true do
+ visit project_wiki_path(project, :index)
+ fill_in "Title", with: 'Test title'
+ fill_in "Content", with: '[link test](test)'
+ click_on "Save"
+
+ 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 80%
rename from spec/features/issues_spec.rb
rename to spec/requests/issues_spec.rb
index 6fff59f0..ff4d4c8b 100644
--- a/spec/features/issues_spec.rb
+++ b/spec/requests/issues_spec.rb
@@ -7,10 +7,11 @@ 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
+ describe "Edit issue", js: true do
let!(:issue) do
create(:issue,
author: @user,
@@ -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'
@@ -77,6 +79,18 @@ describe "Issues" do
page.should have_content 'foobar2'
page.should_not have_content 'gitlab'
end
+
+ it "should return all results if term has been cleared" do
+ visit project_issues_path(project)
+ fill_in "issue_search", with: "foobar"
+ # Reset the search field and trigger loading the issues
+ fill_in "issue_search", with: ""
+ page.execute_script("$('#issue_search').keyup();");
+
+ page.should have_content 'foobar'
+ page.should have_content 'foobar2'
+ page.should have_content 'gitlab'
+ end
end
describe "Filter issue" do
@@ -89,13 +103,13 @@ describe "Issues" do
title: title)
end
- @issue = Issue.first # with title 'foobar'
- @issue.milestone = create(:milestone, project: project)
- @issue.assignee = nil
- @issue.save
+ issue = Issue.first # with title 'foobar'
+ issue.milestone = create(:milestone, project: project)
+ issue.assignee = nil
+ issue.save
end
- let(:issue) { @issue }
+ let(:issue) { Issue.first }
it "should allow filtering by issues with no specified milestone" do
visit project_issues_path(project, milestone_id: '0')
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..c44bea89
--- /dev/null
+++ b/spec/requests/projects_spec.rb
@@ -0,0 +1,81 @@
+require 'spec_helper'
+
+describe "Projects" do
+ before { login_as :user }
+
+ describe 'GET /project/new' do
+ it "should work autocomplete", :js => true do
+ visit new_project_path
+
+ fill_in 'project_name', with: 'Awesome'
+ find("#project_path").value.should == 'awesome'
+ find("#project_code").value.should == 'awesome'
+ end
+ end
+
+ 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'
+ fill_in 'project_code', with: 'gitlabhq'
+ 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)
+ @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 76%
rename from spec/features/security/profile_access_spec.rb
rename to spec/requests/security/profile_access_spec.rb
index f854f3fb..8562b8e7 100644
--- a/spec/features/security/profile_access_spec.rb
+++ b/spec/requests/security/profile_access_spec.rb
@@ -29,16 +29,7 @@ describe "Users Security" do
end
describe "GET /profile/account" do
- subject { account_profile_path }
-
- it { should be_allowed_for @u1 }
- it { should be_allowed_for :admin }
- it { should be_allowed_for :user }
- it { should be_denied_for :visitor }
- end
-
- describe "GET /profile/design" do
- subject { design_profile_path }
+ subject { profile_account_path }
it { should be_allowed_for @u1 }
it { should be_allowed_for :admin }
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 89%
rename from spec/features/snippets_spec.rb
rename to spec/requests/snippets_spec.rb
index 1a0f6eae..9ef217ba 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
@@ -48,11 +48,11 @@ describe "Snippets" do
page.current_path.should == new_project_snippet_path(project)
end
- describe "fill in", js: true do
+ describe "fill in" do
before do
fill_in "snippet_title", with: "login function"
fill_in "snippet_file_name", with: "test.rb"
- page.execute_script("editor.insert('def login; end');")
+ fill_in "snippet_content", with: "def login; end"
end
it { expect { click_button "Save" }.to change {Snippet.count}.by(1) }
@@ -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
@@ -83,6 +83,7 @@ describe "Snippets" do
before do
fill_in "snippet_title", with: "login function"
fill_in "snippet_file_name", with: "test.rb"
+ fill_in "snippet_content", with: "def login; end"
end
it { expect { click_button "Save" }.to_not change {Snippet.count} }
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..3507585a
--- /dev/null
+++ b/spec/roles/repository_spec.rb
@@ -0,0 +1,72 @@
+require 'spec_helper'
+
+describe Project, "Repository" do
+ let(:project) { build(: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
+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..60261c7a 100644
--- a/spec/routing/admin_routing_spec.rb
+++ b/spec/routing/admin_routing_spec.rb
@@ -66,29 +66,57 @@ 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 #create" do
+ post("/admin/projects").should route_to('admin/projects#create')
+ end
+
+ it "to #new" do
+ get("/admin/projects/new").should route_to('admin/projects#new')
+ 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..dc687d2a 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,24 +191,24 @@ 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
# diffs_project_merge_request GET /:project_id/merge_requests/:id/diffs(.:format) merge_requests#diffs
# automerge_project_merge_request GET /:project_id/merge_requests/:id/automerge(.:format) merge_requests#automerge
# automerge_check_project_merge_request GET /:project_id/merge_requests/:id/automerge_check(.:format) merge_requests#automerge_check
+# raw_project_merge_request GET /:project_id/merge_requests/:id/raw(.:format) merge_requests#raw
# branch_from_project_merge_requests GET /:project_id/merge_requests/branch_from(.:format) merge_requests#branch_from
# branch_to_project_merge_requests GET /:project_id/merge_requests/branch_to(.:format) merge_requests#branch_to
# project_merge_requests GET /:project_id/merge_requests(.:format) merge_requests#index
@@ -222,6 +231,10 @@ describe MergeRequestsController, "routing" do
get("/gitlabhq/merge_requests/1/automerge_check").should route_to('merge_requests#automerge_check', project_id: 'gitlabhq', id: '1')
end
+ it "to #raw" do
+ get("/gitlabhq/merge_requests/1/raw").should route_to('merge_requests#raw', project_id: 'gitlabhq', id: '1')
+ end
+
it "to #branch_from" do
get("/gitlabhq/merge_requests/branch_from").should route_to('merge_requests#branch_from', project_id: 'gitlabhq')
end
@@ -230,14 +243,8 @@ describe MergeRequestsController, "routing" do
get("/gitlabhq/merge_requests/branch_to").should route_to('merge_requests#branch_to', project_id: 'gitlabhq')
end
- it "to #show" do
- get("/gitlabhq/merge_requests/1.diff").should route_to('merge_requests#show', project_id: 'gitlabhq', id: '1', format: 'diff')
- get("/gitlabhq/merge_requests/1.patch").should route_to('merge_requests#show', project_id: 'gitlabhq', id: '1', format: 'patch')
- end
-
it_behaves_like "RESTful project resources" do
let(:controller) { 'merge_requests' }
- let(:actions) { [:index, :create, :new, :edit, :show, :update] }
end
end
@@ -278,7 +285,6 @@ end
describe CommitController, "routing" do
it "to #show" do
get("/gitlabhq/commit/4246fb").should route_to('commit#show', project_id: 'gitlabhq', id: '4246fb')
- get("/gitlabhq/commit/4246fb.diff").should route_to('commit#show', project_id: 'gitlabhq', id: '4246fb', format: 'diff')
get("/gitlabhq/commit/4246fb.patch").should route_to('commit#show', project_id: 'gitlabhq', id: '4246fb', format: 'patch')
get("/gitlabhq/commit/4246fbd13872934f72a8fd0d6fb1317b47b59cb5").should route_to('commit#show', project_id: 'gitlabhq', id: '4246fbd13872934f72a8fd0d6fb1317b47b59cb5')
end
@@ -293,10 +299,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
@@ -322,7 +324,6 @@ end
describe MilestonesController, "routing" do
it_behaves_like "RESTful project resources" do
let(:controller) { 'milestones' }
- let(:actions) { [:index, :create, :new, :edit, :show, :update] }
end
end
@@ -358,7 +359,6 @@ describe IssuesController, "routing" do
it_behaves_like "RESTful project resources" do
let(:controller) { 'issues' }
- let(:actions) { [:index, :create, :new, :edit, :show, :update] }
end
end
@@ -381,7 +381,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 +388,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 +395,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 +415,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..cb8dbf37 100644
--- a/spec/routing/routing_spec.rb
+++ b/spec/routing/routing_spec.rb
@@ -33,7 +33,6 @@ end
# help_system_hooks GET /help/system_hooks(.:format) help#system_hooks
# help_markdown GET /help/markdown(.:format) help#markdown
# help_ssh GET /help/ssh(.:format) help#ssh
-# help_raketasks GET /help/raketasks(.:format) help#raketasks
describe HelpController, "routing" do
it "to #index" do
get("/help").should route_to('help#index')
@@ -66,10 +65,6 @@ describe HelpController, "routing" do
it "to #ssh" do
get("/help/ssh").should route_to('help#ssh')
end
-
- it "to #raketasks" do
- get("/help/raketasks").should route_to('help#raketasks')
- end
end
# errors_githost GET /errors/githost(.:format) errors#githost
@@ -87,25 +82,37 @@ end
# profile GET /profile(.:format) profile#show
# profile_design GET /profile/design(.:format) profile#design
# profile_update PUT /profile/update(.:format) profile#update
-describe ProfilesController, "routing" do
+describe ProfileController, "routing" do
it "to #account" do
- get("/profile/account").should route_to('profiles#account')
+ get("/profile/account").should route_to('profile#account')
end
it "to #history" do
- get("/profile/history").should route_to('profiles#history')
+ get("/profile/history").should route_to('profile#history')
+ end
+
+ it "to #password_update" do
+ put("/profile/password").should route_to('profile#password_update')
+ end
+
+ it "to #token" do
+ get("/profile/token").should route_to('profile#token')
end
it "to #reset_private_token" do
- put("/profile/reset_private_token").should route_to('profiles#reset_private_token')
+ put("/profile/reset_private_token").should route_to('profile#reset_private_token')
end
it "to #show" do
- get("/profile").should route_to('profiles#show')
+ get("/profile").should route_to('profile#show')
end
it "to #design" do
- get("/profile/design").should route_to('profiles#design')
+ get("/profile/design").should route_to('profile#design')
+ end
+
+ it "to #update" do
+ put("/profile/update").should route_to('profile#update')
end
end
@@ -146,14 +153,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..ace5ca00 100644
--- a/spec/spec_helper.rb
+++ b/spec/spec_helper.rb
@@ -1,58 +1,44 @@
-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)
+ end
end
diff --git a/spec/support/api_helpers.rb b/spec/support/api_helpers.rb
index c4514bf3..7d901197 100644
--- a/spec/support/api_helpers.rb
+++ b/spec/support/api_helpers.rb
@@ -18,7 +18,7 @@ module ApiHelpers
#
# Returns the relative path to the requested API resource
def api(path, user = nil)
- "/api/#{Gitlab::API.version}#{path}" +
+ "/api/#{Gitlab::API::VERSION}#{path}" +
# Normalize query string
(path.index('?') ? '' : '?') +
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
deleted file mode 100644
index babbf291..00000000
--- a/spec/tasks/gitlab/backup_rake_spec.rb
+++ /dev/null
@@ -1,47 +0,0 @@
-require 'spec_helper'
-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
- end
-
- describe 'backup_restore' do
- before do
- # avoid writing task output to spec progress
- $stdout.stub :write
- end
-
- let :run_rake_task do
- Rake::Task["gitlab:backup:restore"].reenable
- Rake.application.invoke_task "gitlab:backup:restore"
- end
-
- context 'gitlab version' do
- before do
- Dir.stub :glob => []
- Dir.stub :chdir
- File.stub :exists? => true
- Kernel.stub :system => true
- end
-
- let(:gitlab_version) { %x{git rev-parse HEAD}.gsub(/\n/,"") }
-
- it 'should fail on mismach' do
- YAML.stub :load_file => {:gitlab_version => gitlab_version.reverse}
- expect { run_rake_task }.to raise_error SystemExit
- end
-
- it 'should invoke restoration on mach' do
- YAML.stub :load_file => {:gitlab_version => gitlab_version}
- Rake::Task["gitlab:backup:db:restore"].should_receive :invoke
- Rake::Task["gitlab:backup:repo:restore"].should_receive :invoke
- expect { run_rake_task }.to_not raise_error SystemExit
- end
- end
-
- end # backup_restore task
-end # gitlab:app namespace
diff --git a/spec/workers/post_receive_spec.rb b/spec/workers/post_receive_spec.rb
index 46e86dbe..bbc91f44 100644
--- a/spec/workers/post_receive_spec.rb
+++ b/spec/workers/post_receive_spec.rb
@@ -4,39 +4,37 @@ 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)
+ Project.should_receive(:find_by_path).with(project.path).and_return(project)
+ PostReceive.perform(project.path, '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(project.path, 'sha-old', 'sha-new', 'refs/heads/master', key_id).should be_false
end
it "asks the project to trigger all hooks" do
- Project.stub(find_with_namespace: project)
+ Project.stub(find_by_path: project)
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(project.path, '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)
- 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..e8699bdf
--- /dev/null
+++ b/vendor/assets/javascripts/branch-graph.js
@@ -0,0 +1,181 @@
+var commits = {},
+ comms = {},
+ pixelsX = [],
+ pixelsY = [],
+ mmax = Math.max,
+ mtime = 0,
+ mspace = 0,
+ parents = {},
+ ii = 0,
+ colors = ["#000"];
+
+function initGraph(){
+ commits = chunk1.commits;
+ ii = commits.length;
+ for (var i = 0; i < ii; i++) {
+ for (var j = 0, jj = commits[i].parents.length; j < jj; j++) {
+ parents[commits[i].parents[j][0]] = true;
+ }
+ mtime = Math.max(mtime, commits[i].time);
+ mspace = Math.max(mspace, commits[i].space);
+ }
+ mtime = mtime + 4;
+ mspace = mspace + 10;
+ for (i = 0; i < ii; i++) {
+ if (commits[i].id in parents) {
+ commits[i].isParent = true;
+ }
+ comms[commits[i].id] = commits[i];
+ }
+ for (var k = 0; k < mspace; k++) {
+ colors.push(Raphael.getColor());
+ }
+}
+
+function branchGraph(holder) {
+ var ch = mspace * 20 + 20, cw = mtime * 20 + 20,
+ r = Raphael("holder", cw, ch),
+ top = r.set();
+ var cuday = 0, cumonth = "";
+ r.rect(0, 0, days.length * 20 + 80, 30).attr({fill: "#222"});
+ r.rect(0, 30, days.length * 20 + 80, 20).attr({fill: "#444"});
+
+ for (mm = 0; mm < days.length; mm++) {
+ if(days[mm] != null){
+ if(cuday != days[mm][0]){
+ r.text(10 + mm * 20, 40, days[mm][0]).attr({font: "14px Fontin-Sans, Arial", fill: "#DDD"});
+ cuday = days[mm][0]
+ }
+ if(cumonth != days[mm][1]){
+ r.text(10 + mm * 20, 15, days[mm][1]).attr({font: "14px Fontin-Sans, Arial", fill: "#EEE"});
+ cumonth = days[mm][1]
+ }
+
+ }
+ }
+ for (i = 0; i < ii; i++) {
+ var x = 10 + 20 * commits[i].time,
+ y = 70 + 20 * commits[i].space;
+ r.circle(x, y, 3).attr({fill: colors[commits[i].space], stroke: "none"});
+ if (commits[i].refs != null && commits[i].refs != "") {
+ var longrefs = commits[i].refs
+ var shortrefs = commits[i].refs;
+ if (shortrefs.length > 15){
+ shortrefs = shortrefs.substr(0,13) + "...";
+ }
+ var t = r.text(x+5, y+5, shortrefs).attr({font: "12px Fontin-Sans, Arial", fill: "#666",
+ title: longrefs, cursor: "pointer", rotation: "90"});
+
+ var textbox = t.getBBox();
+ t.translate(textbox.height/-4,textbox.width/2);
+ }
+ for (var j = 0, jj = commits[i].parents.length; j < jj; j++) {
+ var c = comms[commits[i].parents[j][0]];
+ if (c) {
+ var cx = 10 + 20 * c.time,
+ cy = 70 + 20 * c.space;
+ if (c.space == commits[i].space) {
+ r.path("M" + (x - 5) + "," + (y + .0001) + "L" + (15 + 20 * c.time) + "," + (y + .0001))
+ .attr({stroke: colors[c.space], "stroke-width": 2});
+
+ } else if (c.space < 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: colors[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: colors[c.space], "stroke-width": 2});
+ }
+ }
+ }
+ (function (c, x, y) {
+ top.push(r.circle(x, y, 10).attr({fill: "#000", opacity: 0, cursor: "pointer"})
+ .click(function(){
+ location.href = location.href.replace("graph", "commits/" + c.id);
+ })
+ .hover(function () {
+ var s = r.text(100, 100,c.author + "\n \n" +c.id + "\n \n" + c.message).attr({fill: "#fff"});
+ this.popup = r.popupit(x, y + 5, s, 0);
+ top.push(this.popup.insertBefore(this));
+ }, function () {
+ this.popup && this.popup.remove() && delete this.popup;
+ }));
+ }(commits[i], x, y));
+ }
+ top.toFront();
+ var hw = holder.offsetWidth,
+ hh = holder.offsetHeight,
+ v = r.rect(hw - 8, 0, 4, Math.pow(hh, 2) / ch, 2).attr({fill: "#000", opacity: 0}),
+ h = r.rect(0, hh - 8, Math.pow(hw, 2) / cw, 4, 2).attr({fill: "#000", opacity: 0}),
+ bars = r.set(v, h),
+ drag,
+ dragger = function (e) {
+ if (drag) {
+ e = e || window.event;
+ holder.scrollLeft = drag.sl - (e.clientX - drag.x);
+ holder.scrollTop = drag.st - (e.clientY - drag.y);
+ }
+ };
+ holder.onmousedown = function (e) {
+ e = e || window.event;
+ drag = {x: e.clientX, y: e.clientY, st: holder.scrollTop, sl: holder.scrollLeft};
+ document.onmousemove = dragger;
+ bars.animate({opacity: .5}, 300);
+ };
+ document.onmouseup = function () {
+ drag = false;
+ document.onmousemove = null;
+ bars.animate({opacity: 0}, 300);
+ };
+ holder.scrollLeft = cw;
+};
+Raphael.fn.popupit = function (x, y, set, dir, size) {
+ dir = dir == null ? 2 : dir;
+ size = size || 5;
+ x = Math.round(x);
+ y = Math.round(y);
+ var 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);
+};
+Raphael.fn.popup = function (x, y, text, dir, size) {
+ dir = dir == null ? 2 : dir > 3 ? 3 : dir;
+ size = size || 5;
+ text = text || "$9.99";
+ var res = this.set(),
+ d = 3;
+ res.push(this.path().attr({fill: "#000", stroke: "#000"}));
+ res.push(this.text(x, y, text).attr(this.g.txtattr).attr({fill: "#fff", "font-family": "Helvetica, Arial"}));
+ res.update = function (X, Y, withAnimation) {
+ X = X || x;
+ Y = Y || y;
+ var bb = this[1].getBBox(),
+ w = bb.width / 2,
+ h = 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];
+ xy.path = p;
+ if (withAnimation) {
+ this.animate(xy, 500, ">");
+ } else {
+ this.attr(xy);
+ }
+ return this;
+ };
+ return res.update(x, y);
+};
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
diff --git a/vendor/assets/stylesheets/jquery.ui.aristo.css b/vendor/assets/stylesheets/jquery.ui.aristo.css
new file mode 100644
index 00000000..8cc6e787
--- /dev/null
+++ b/vendor/assets/stylesheets/jquery.ui.aristo.css
@@ -0,0 +1,738 @@
+/*
+ * jQuery UI CSS Framework 1.8.7
+ *
+ * Copyright 2010, AUTHORS.txt (http://jqueryui.com/about)
+ * Dual licensed under the MIT or GPL Version 2 licenses.
+ * http://jquery.org/license
+ *
+ * http://docs.jquery.com/UI/Theming/API
+ */
+
+/* Layout helpers
+----------------------------------*/
+.ui-helper-hidden { display: none; }
+.ui-helper-hidden-accessible { position: absolute !important; clip: rect(1px 1px 1px 1px); clip: rect(1px,1px,1px,1px); }
+.ui-helper-reset { margin: 0; padding: 0; border: 0; outline: 0; line-height: 1.3; text-decoration: none; font-size: 100%; list-style: none; }
+.ui-helper-clearfix:after { content: "."; display: block; height: 0; clear: both; visibility: hidden; }
+.ui-helper-clearfix { display: inline-block; }
+/* required comment for clearfix to work in Opera \*/
+* html .ui-helper-clearfix { height:1%; }
+.ui-helper-clearfix { display:block; }
+/* end clearfix */
+.ui-helper-zfix { width: 100%; height: 100%; top: 0; left: 0; position: absolute; opacity: 0; filter:Alpha(Opacity=0); }
+
+
+/* Interaction Cues
+----------------------------------*/
+.ui-state-disabled { cursor: default !important; }
+
+
+/* Icons
+----------------------------------*/
+
+/* states and images */
+.ui-icon { display: block; text-indent: -99999px; overflow: hidden; background-repeat: no-repeat; }
+
+
+/* Misc visuals
+----------------------------------*/
+
+/* Overlays */
+.ui-widget-overlay { position: absolute; top: 0; left: 0; width: 100%; height: 100%; }
+
+
+/*
+ * jQuery UI CSS Framework 1.8.7
+ *
+ * Copyright 2010, AUTHORS.txt (http://jqueryui.com/about)
+ * Dual licensed under the MIT or GPL Version 2 licenses.
+ * http://jquery.org/license
+ *
+ * http://docs.jquery.com/UI/Theming/API
+ *
+ * To view and modify this theme, visit http://jqueryui.com/themeroller/?ctl=themeroller
+ */
+
+
+/* Component containers
+----------------------------------*/
+.ui-widget { font-family: Arial,sans-serif; font-size: 1.1em; }
+.ui-widget .ui-widget { font-size: 1em; }
+.ui-widget input, .ui-widget select, .ui-widget textarea, .ui-widget button { font-family: Arial,sans-serif; font-size: 1em; }
+.ui-widget-content { border: 1px solid #B6B6B6; background: #ffffff; color: #4F4F4F; }
+.ui-widget-content a { color: #4F4F4F; }
+.ui-widget-header { border: 1px solid #B6B6B6; color: #4F4F4F; font-weight: bold; }
+.ui-widget-header {
+ background: #ededed url(bg_fallback.png) 0 0 repeat-x; /* Old browsers */
+ background: -moz-linear-gradient(top, #ededed 0%, #c4c4c4 100%); /* FF3.6+ */
+ background: -webkit-gradient(linear, left top, left bottom, color-stop(0%,#ededed), color-stop(100%,#c4c4c4)); /* Chrome,Safari4+ */
+ background: -webkit-linear-gradient(top, #ededed 0%,#c4c4c4 100%); /* Chrome10+,Safari5.1+ */
+ background: -o-linear-gradient(top, #ededed 0%,#c4c4c4 100%); /* Opera11.10+ */
+ background: -ms-linear-gradient(top, #ededed 0%,#c4c4c4 100%); /* IE10+ */
+ background: linear-gradient(top, #ededed 0%,#c4c4c4 100%); /* W3C */
+}
+.ui-widget-header a { color: #4F4F4F; }
+
+/* Interaction states
+----------------------------------*/
+.ui-state-default, .ui-widget-content .ui-state-default, .ui-widget-header .ui-state-default { border: 1px solid #B6B6B6; font-weight: normal; color: #4F4F4F; }
+.ui-state-default, .ui-widget-content .ui-state-default, .ui-widget-header .ui-state-default {
+ background: #ededed url(bg_fallback.png) 0 0 repeat-x; /* Old browsers */
+ background: -moz-linear-gradient(top, #ededed 0%, #c4c4c4 100%); /* FF3.6+ */
+ background: -webkit-gradient(linear, left top, left bottom, color-stop(0%,#ededed), color-stop(100%,#c4c4c4)); /* Chrome,Safari4+ */
+ background: -webkit-linear-gradient(top, #ededed 0%,#c4c4c4 100%); /* Chrome10+,Safari5.1+ */
+ background: -o-linear-gradient(top, #ededed 0%,#c4c4c4 100%); /* Opera11.10+ */
+ background: -ms-linear-gradient(top, #ededed 0%,#c4c4c4 100%); /* IE10+ */
+ background: linear-gradient(top, #ededed 0%,#c4c4c4 100%); /* W3C */
+ -webkit-box-shadow: 0 1px 0 rgba(255,255,255,0.6) inset;
+ -moz-box-shadow: 0 1px 0 rgba(255,255,255,0.6) inset;
+ box-shadow: 0 1px 0 rgba(255,255,255,0.6) inset;
+}
+.ui-state-default a, .ui-state-default a:link, .ui-state-default a:visited { color: #4F4F4F; text-decoration: none; }
+.ui-state-hover, .ui-widget-content .ui-state-hover, .ui-widget-header .ui-state-hover, .ui-state-focus, .ui-widget-content .ui-state-focus, .ui-widget-header .ui-state-focus { border: 1px solid #9D9D9D; font-weight: normal; color: #313131; }
+.ui-state-hover a, .ui-state-hover a:hover { color: #313131; text-decoration: none; }
+.ui-state-active, .ui-widget-content .ui-state-active, .ui-widget-header .ui-state-active {
+ outline: none;
+ color: #1c4257; border: 1px solid #7096ab;
+ background: #ededed url(bg_fallback.png) 0 -50px repeat-x; /* Old browsers */
+ background: -moz-linear-gradient(top, #b9e0f5 0%, #92bdd6 100%); /* FF3.6+ */
+ background: -webkit-gradient(linear, left top, left bottom, color-stop(0%,#b9e0f5), color-stop(100%,#92bdd6)); /* Chrome,Safari4+ */
+ background: -webkit-linear-gradient(top, #b9e0f5 0%,#92bdd6 100%); /* Chrome10+,Safari5.1+ */
+ background: -o-linear-gradient(top, #b9e0f5 0%,#92bdd6 100%); /* Opera11.10+ */
+ background: -ms-linear-gradient(top, #b9e0f5 0%,#92bdd6 100%); /* IE10+ */
+ background: linear-gradient(top, #b9e0f5 0%,#92bdd6 100%); /* W3C */
+ -webkit-box-shadow: none;
+ -moz-box-shadow: none;
+ box-shadow: none;
+}
+.ui-state-active a, .ui-state-active a:link, .ui-state-active a:visited { color: #313131; text-decoration: none; }
+.ui-widget :active { outline: none; }
+
+/* Interaction Cues
+----------------------------------*/
+.ui-state-highlight, .ui-widget-content .ui-state-highlight, .ui-widget-header .ui-state-highlight { border: 1px solid #d2dbf4; background: #f4f8fd; color: #0d2054; -moz-border-radius: 0 !important; -webkit-border-radius: 0 !important; border-radius: 0 !important; }
+.ui-state-highlight a, .ui-widget-content .ui-state-highlight a,.ui-widget-header .ui-state-highlight a { color: #363636; }
+.ui-state-error, .ui-widget-content .ui-state-error, .ui-widget-header .ui-state-error { border: 1px solid #e2d0d0; background: #fcf0f0; color: #280b0b; -moz-border-radius: 0 !important; -webkit-border-radius: 0 !important; border-radius: 0 !important; }
+.ui-state-error a, .ui-widget-content .ui-state-error a, .ui-widget-header .ui-state-error a { color: #cd0a0a; }
+.ui-state-error-text, .ui-widget-content .ui-state-error-text, .ui-widget-header .ui-state-error-text { color: #cd0a0a; }
+.ui-priority-primary, .ui-widget-content .ui-priority-primary, .ui-widget-header .ui-priority-primary { font-weight: bold; }
+.ui-priority-secondary, .ui-widget-content .ui-priority-secondary, .ui-widget-header .ui-priority-secondary { opacity: .7; filter:Alpha(Opacity=70); font-weight: normal; }
+.ui-state-disabled, .ui-widget-content .ui-state-disabled, .ui-widget-header .ui-state-disabled { opacity: .35; filter:Alpha(Opacity=35); background-image: none; }
+
+/* Icons
+----------------------------------*/
+
+/* states and images */
+.ui-icon { width: 16px; height: 16px; background-image: url(ui-icons_222222_256x240.png); }
+.ui-widget-content .ui-icon {background-image: url(ui-icons_222222_256x240.png); }
+.ui-widget-header .ui-icon {background-image: url(ui-icons_222222_256x240.png); }
+.ui-state-default .ui-icon { background-image: url(ui-icons_454545_256x240.png); }
+.ui-state-hover .ui-icon, .ui-state-focus .ui-icon {background-image: url(ui-icons_454545_256x240.png); }
+.ui-state-active .ui-icon {background-image: url(ui-icons_454545_256x240.png); }
+.ui-state-highlight .ui-icon {background-image: url(ui-icons_454545_256x240.png); }
+.ui-state-error .ui-icon, .ui-state-error-text .ui-icon { background: url(icon_sprite.png) -16px 0 no-repeat !important; }
+.ui-state-highlight .ui-icon, .ui-state-error .ui-icon { margin-top: -1px; }
+
+/* positioning */
+.ui-icon-carat-1-n { background-position: 0 0; }
+.ui-icon-carat-1-ne { background-position: -16px 0; }
+.ui-icon-carat-1-e { background-position: -32px 0; }
+.ui-icon-carat-1-se { background-position: -48px 0; }
+.ui-icon-carat-1-s { background-position: -64px 0; }
+.ui-icon-carat-1-sw { background-position: -80px 0; }
+.ui-icon-carat-1-w { background-position: -96px 0; }
+.ui-icon-carat-1-nw { background-position: -112px 0; }
+.ui-icon-carat-2-n-s { background-position: -128px 0; }
+.ui-icon-carat-2-e-w { background-position: -144px 0; }
+.ui-icon-triangle-1-n { background-position: 0 -16px; }
+.ui-icon-triangle-1-ne { background-position: -16px -16px; }
+.ui-icon-triangle-1-e { background-position: -32px -16px; }
+.ui-icon-triangle-1-se { background-position: -48px -16px; }
+.ui-icon-triangle-1-s { background-position: -64px -16px; }
+.ui-icon-triangle-1-sw { background-position: -80px -16px; }
+.ui-icon-triangle-1-w { background-position: -96px -16px; }
+.ui-icon-triangle-1-nw { background-position: -112px -16px; }
+.ui-icon-triangle-2-n-s { background-position: -128px -16px; }
+.ui-icon-triangle-2-e-w { background-position: -144px -16px; }
+.ui-icon-arrow-1-n { background-position: 0 -32px; }
+.ui-icon-arrow-1-ne { background-position: -16px -32px; }
+.ui-icon-arrow-1-e { background-position: -32px -32px; }
+.ui-icon-arrow-1-se { background-position: -48px -32px; }
+.ui-icon-arrow-1-s { background-position: -64px -32px; }
+.ui-icon-arrow-1-sw { background-position: -80px -32px; }
+.ui-icon-arrow-1-w { background-position: -96px -32px; }
+.ui-icon-arrow-1-nw { background-position: -112px -32px; }
+.ui-icon-arrow-2-n-s { background-position: -128px -32px; }
+.ui-icon-arrow-2-ne-sw { background-position: -144px -32px; }
+.ui-icon-arrow-2-e-w { background-position: -160px -32px; }
+.ui-icon-arrow-2-se-nw { background-position: -176px -32px; }
+.ui-icon-arrowstop-1-n { background-position: -192px -32px; }
+.ui-icon-arrowstop-1-e { background-position: -208px -32px; }
+.ui-icon-arrowstop-1-s { background-position: -224px -32px; }
+.ui-icon-arrowstop-1-w { background-position: -240px -32px; }
+.ui-icon-arrowthick-1-n { background-position: 0 -48px; }
+.ui-icon-arrowthick-1-ne { background-position: -16px -48px; }
+.ui-icon-arrowthick-1-e { background-position: -32px -48px; }
+.ui-icon-arrowthick-1-se { background-position: -48px -48px; }
+.ui-icon-arrowthick-1-s { background-position: -64px -48px; }
+.ui-icon-arrowthick-1-sw { background-position: -80px -48px; }
+.ui-icon-arrowthick-1-w { background-position: -96px -48px; }
+.ui-icon-arrowthick-1-nw { background-position: -112px -48px; }
+.ui-icon-arrowthick-2-n-s { background-position: -128px -48px; }
+.ui-icon-arrowthick-2-ne-sw { background-position: -144px -48px; }
+.ui-icon-arrowthick-2-e-w { background-position: -160px -48px; }
+.ui-icon-arrowthick-2-se-nw { background-position: -176px -48px; }
+.ui-icon-arrowthickstop-1-n { background-position: -192px -48px; }
+.ui-icon-arrowthickstop-1-e { background-position: -208px -48px; }
+.ui-icon-arrowthickstop-1-s { background-position: -224px -48px; }
+.ui-icon-arrowthickstop-1-w { background-position: -240px -48px; }
+.ui-icon-arrowreturnthick-1-w { background-position: 0 -64px; }
+.ui-icon-arrowreturnthick-1-n { background-position: -16px -64px; }
+.ui-icon-arrowreturnthick-1-e { background-position: -32px -64px; }
+.ui-icon-arrowreturnthick-1-s { background-position: -48px -64px; }
+.ui-icon-arrowreturn-1-w { background-position: -64px -64px; }
+.ui-icon-arrowreturn-1-n { background-position: -80px -64px; }
+.ui-icon-arrowreturn-1-e { background-position: -96px -64px; }
+.ui-icon-arrowreturn-1-s { background-position: -112px -64px; }
+.ui-icon-arrowrefresh-1-w { background-position: -128px -64px; }
+.ui-icon-arrowrefresh-1-n { background-position: -144px -64px; }
+.ui-icon-arrowrefresh-1-e { background-position: -160px -64px; }
+.ui-icon-arrowrefresh-1-s { background-position: -176px -64px; }
+.ui-icon-arrow-4 { background-position: 0 -80px; }
+.ui-icon-arrow-4-diag { background-position: -16px -80px; }
+.ui-icon-extlink { background-position: -32px -80px; }
+.ui-icon-newwin { background-position: -48px -80px; }
+.ui-icon-refresh { background-position: -64px -80px; }
+.ui-icon-shuffle { background-position: -80px -80px; }
+.ui-icon-transfer-e-w { background-position: -96px -80px; }
+.ui-icon-transferthick-e-w { background-position: -112px -80px; }
+.ui-icon-folder-collapsed { background-position: 0 -96px; }
+.ui-icon-folder-open { background-position: -16px -96px; }
+.ui-icon-document { background-position: -32px -96px; }
+.ui-icon-document-b { background-position: -48px -96px; }
+.ui-icon-note { background-position: -64px -96px; }
+.ui-icon-mail-closed { background-position: -80px -96px; }
+.ui-icon-mail-open { background-position: -96px -96px; }
+.ui-icon-suitcase { background-position: -112px -96px; }
+.ui-icon-comment { background-position: -128px -96px; }
+.ui-icon-person { background-position: -144px -96px; }
+.ui-icon-print { background-position: -160px -96px; }
+.ui-icon-trash { background-position: -176px -96px; }
+.ui-icon-locked { background-position: -192px -96px; }
+.ui-icon-unlocked { background-position: -208px -96px; }
+.ui-icon-bookmark { background-position: -224px -96px; }
+.ui-icon-tag { background-position: -240px -96px; }
+.ui-icon-home { background-position: 0 -112px; }
+.ui-icon-flag { background-position: -16px -112px; }
+.ui-icon-calendar { background-position: -32px -112px; }
+.ui-icon-cart { background-position: -48px -112px; }
+.ui-icon-pencil { background-position: -64px -112px; }
+.ui-icon-clock { background-position: -80px -112px; }
+.ui-icon-disk { background-position: -96px -112px; }
+.ui-icon-calculator { background-position: -112px -112px; }
+.ui-icon-zoomin { background-position: -128px -112px; }
+.ui-icon-zoomout { background-position: -144px -112px; }
+.ui-icon-search { background-position: -160px -112px; }
+.ui-icon-wrench { background-position: -176px -112px; }
+.ui-icon-gear { background-position: -192px -112px; }
+.ui-icon-heart { background-position: -208px -112px; }
+.ui-icon-star { background-position: -224px -112px; }
+.ui-icon-link { background-position: -240px -112px; }
+.ui-icon-cancel { background-position: 0 -128px; }
+.ui-icon-plus { background-position: -16px -128px; }
+.ui-icon-plusthick { background-position: -32px -128px; }
+.ui-icon-minus { background-position: -48px -128px; }
+.ui-icon-minusthick { background-position: -64px -128px; }
+.ui-icon-close { background-position: -80px -128px; }
+.ui-icon-closethick { background-position: -96px -128px; }
+.ui-icon-key { background-position: -112px -128px; }
+.ui-icon-lightbulb { background-position: -128px -128px; }
+.ui-icon-scissors { background-position: -144px -128px; }
+.ui-icon-clipboard { background-position: -160px -128px; }
+.ui-icon-copy { background-position: -176px -128px; }
+.ui-icon-contact { background-position: -192px -128px; }
+.ui-icon-image { background-position: -208px -128px; }
+.ui-icon-video { background-position: -224px -128px; }
+.ui-icon-script { background-position: -240px -128px; }
+.ui-icon-alert { background-position: 0 -144px; }
+.ui-icon-info { background: url(icon_sprite.png) 0 0 no-repeat !important; }
+.ui-icon-notice { background-position: -32px -144px; }
+.ui-icon-help { background-position: -48px -144px; }
+.ui-icon-check { background-position: -64px -144px; }
+.ui-icon-bullet { background-position: -80px -144px; }
+.ui-icon-radio-off { background-position: -96px -144px; }
+.ui-icon-radio-on { background-position: -112px -144px; }
+.ui-icon-pin-w { background-position: -128px -144px; }
+.ui-icon-pin-s { background-position: -144px -144px; }
+.ui-icon-play { background-position: 0 -160px; }
+.ui-icon-pause { background-position: -16px -160px; }
+.ui-icon-seek-next { background-position: -32px -160px; }
+.ui-icon-seek-prev { background-position: -48px -160px; }
+.ui-icon-seek-end { background-position: -64px -160px; }
+.ui-icon-seek-start { background-position: -80px -160px; }
+/* ui-icon-seek-first is deprecated, use ui-icon-seek-start instead */
+.ui-icon-seek-first { background-position: -80px -160px; }
+.ui-icon-stop { background-position: -96px -160px; }
+.ui-icon-eject { background-position: -112px -160px; }
+.ui-icon-volume-off { background-position: -128px -160px; }
+.ui-icon-volume-on { background-position: -144px -160px; }
+.ui-icon-power { background-position: 0 -176px; }
+.ui-icon-signal-diag { background-position: -16px -176px; }
+.ui-icon-signal { background-position: -32px -176px; }
+.ui-icon-battery-0 { background-position: -48px -176px; }
+.ui-icon-battery-1 { background-position: -64px -176px; }
+.ui-icon-battery-2 { background-position: -80px -176px; }
+.ui-icon-battery-3 { background-position: -96px -176px; }
+.ui-icon-circle-plus { background-position: 0 -192px; }
+.ui-icon-circle-minus { background-position: -16px -192px; }
+.ui-icon-circle-close { background-position: -32px -192px; }
+.ui-icon-circle-triangle-e { background-position: -48px -192px; }
+.ui-icon-circle-triangle-s { background-position: -64px -192px; }
+.ui-icon-circle-triangle-w { background-position: -80px -192px; }
+.ui-icon-circle-triangle-n { background-position: -96px -192px; }
+.ui-icon-circle-arrow-e { background-position: -112px -192px; }
+.ui-icon-circle-arrow-s { background-position: -128px -192px; }
+.ui-icon-circle-arrow-w { background-position: -144px -192px; }
+.ui-icon-circle-arrow-n { background-position: -160px -192px; }
+.ui-icon-circle-zoomin { background-position: -176px -192px; }
+.ui-icon-circle-zoomout { background-position: -192px -192px; }
+.ui-icon-circle-check { background-position: -208px -192px; }
+.ui-icon-circlesmall-plus { background-position: 0 -208px; }
+.ui-icon-circlesmall-minus { background-position: -16px -208px; }
+.ui-icon-circlesmall-close { background-position: -32px -208px; }
+.ui-icon-squaresmall-plus { background-position: -48px -208px; }
+.ui-icon-squaresmall-minus { background-position: -64px -208px; }
+.ui-icon-squaresmall-close { background-position: -80px -208px; }
+.ui-icon-grip-dotted-vertical { background-position: 0 -224px; }
+.ui-icon-grip-dotted-horizontal { background-position: -16px -224px; }
+.ui-icon-grip-solid-vertical { background-position: -32px -224px; }
+.ui-icon-grip-solid-horizontal { background-position: -48px -224px; }
+.ui-icon-gripsmall-diagonal-se { background-position: -64px -224px; }
+.ui-icon-grip-diagonal-se { background-position: -80px -224px; }
+
+
+/* Misc visuals
+----------------------------------*/
+
+/* Corner radius */
+.ui-corner-tl { -moz-border-radius-topleft: 3px; -webkit-border-top-left-radius: 3px; border-top-left-radius: 3px; }
+.ui-corner-tr { -moz-border-radius-topright: 3px; -webkit-border-top-right-radius: 3px; border-top-right-radius: 3px; }
+.ui-corner-bl { -moz-border-radius-bottomleft: 3px; -webkit-border-bottom-left-radius: 3px; border-bottom-left-radius: 3px; }
+.ui-corner-br { -moz-border-radius-bottomright: 3px; -webkit-border-bottom-right-radius: 3px; border-bottom-right-radius: 3px; }
+.ui-corner-top { -moz-border-radius-topleft: 3px; -webkit-border-top-left-radius: 3px; border-top-left-radius: 3px; -moz-border-radius-topright: 3px; -webkit-border-top-right-radius: 3px; border-top-right-radius: 3px; }
+.ui-corner-bottom { -moz-border-radius-bottomleft: 3px; -webkit-border-bottom-left-radius: 3px; border-bottom-left-radius: 3px; -moz-border-radius-bottomright: 3px; -webkit-border-bottom-right-radius: 3px; border-bottom-right-radius: 3px; }
+.ui-corner-right { -moz-border-radius-topright: 3px; -webkit-border-top-right-radius: 3px; border-top-right-radius: 3px; -moz-border-radius-bottomright: 3px; -webkit-border-bottom-right-radius: 3px; border-bottom-right-radius: 3px; }
+.ui-corner-left { -moz-border-radius-topleft: 3px; -webkit-border-top-left-radius: 3px; border-top-left-radius: 3px; -moz-border-radius-bottomleft: 3px; -webkit-border-bottom-left-radius: 3px; border-bottom-left-radius: 3px; }
+.ui-corner-all { -moz-border-radius: 3px; -webkit-border-radius: 3px; border-radius: 3px; }
+
+/* Overlays */
+.ui-widget-overlay { background: #262b33; opacity: .70;filter:Alpha(Opacity=70); }
+.ui-widget-shadow { margin: -8px 0 0 -8px; padding: 8px; background: #000000; opacity: .30;filter:Alpha(Opacity=30); -moz-border-radius: 8px; -webkit-border-radius: 8px; border-radius: 8px; }/*
+ * jQuery UI Resizable 1.8.7
+ *
+ * Copyright 2010, AUTHORS.txt (http://jqueryui.com/about)
+ * Dual licensed under the MIT or GPL Version 2 licenses.
+ * http://jquery.org/license
+ *
+ * http://docs.jquery.com/UI/Resizable#theming
+ */
+.ui-resizable { position: relative;}
+.ui-resizable-handle { position: absolute; font-size: 0.1px; z-index: 999; display: block;}
+.ui-resizable-disabled .ui-resizable-handle, .ui-resizable-autohide .ui-resizable-handle { display: none; }
+.ui-resizable-n { cursor: n-resize; height: 7px; width: 100%; top: -5px; left: 0; }
+.ui-resizable-s { cursor: s-resize; height: 7px; width: 100%; bottom: -5px; left: 0; }
+.ui-resizable-e { cursor: e-resize; width: 7px; right: -5px; top: 0; height: 100%; }
+.ui-resizable-w { cursor: w-resize; width: 7px; left: -5px; top: 0; height: 100%; }
+.ui-resizable-se { cursor: se-resize; width: 12px; height: 12px; right: 1px; bottom: 1px; }
+.ui-resizable-sw { cursor: sw-resize; width: 9px; height: 9px; left: -5px; bottom: -5px; }
+.ui-resizable-nw { cursor: nw-resize; width: 9px; height: 9px; left: -5px; top: -5px; }
+.ui-resizable-ne { cursor: ne-resize; width: 9px; height: 9px; right: -5px; top: -5px;}/*
+ * jQuery UI Selectable 1.8.7
+ *
+ * Copyright 2010, AUTHORS.txt (http://jqueryui.com/about)
+ * Dual licensed under the MIT or GPL Version 2 licenses.
+ * http://jquery.org/license
+ *
+ * http://docs.jquery.com/UI/Selectable#theming
+ */
+.ui-selectable-helper { position: absolute; z-index: 100; border:1px dotted black; }
+/*
+ * jQuery UI Accordion 1.8.7
+ *
+ * Copyright 2010, AUTHORS.txt (http://jqueryui.com/about)
+ * Dual licensed under the MIT or GPL Version 2 licenses.
+ * http://jquery.org/license
+ *
+ * http://docs.jquery.com/UI/Accordion#theming
+ */
+/* IE/Win - Fix animation bug - #4615 */
+.ui-accordion { width: 100%; }
+.ui-accordion .ui-accordion-header { cursor: pointer; position: relative; margin-top: 1px; zoom: 1; }
+.ui-accordion .ui-accordion-header, .ui-accordion .ui-accordion-content { -moz-border-radius: 0; -webkit-border-radius: 0; border-radius: 0; }
+.ui-accordion .ui-accordion-li-fix { display: inline; }
+.ui-accordion .ui-accordion-header-active { border-bottom: 0 !important; }
+.ui-accordion .ui-accordion-header a { display: block; font-size: 12px; font-weight: bold; padding: .5em .5em .5em .7em; }
+.ui-accordion-icons .ui-accordion-header a { padding-left: 2.2em; }
+.ui-accordion .ui-accordion-header .ui-icon { position: absolute; left: .5em; top: 50%; margin-top: -8px; }
+.ui-accordion .ui-accordion-content { padding: 1em 2.2em; border-top: 0; margin-top: -2px; position: relative; top: 1px; margin-bottom: 2px; overflow: auto; display: none; zoom: 1; }
+.ui-accordion .ui-accordion-content-active { display: block; }/*
+ * jQuery UI Autocomplete 1.8.7
+ *
+ * Copyright 2010, AUTHORS.txt (http://jqueryui.com/about)
+ * Dual licensed under the MIT or GPL Version 2 licenses.
+ * http://jquery.org/license
+ *
+ * http://docs.jquery.com/UI/Autocomplete#theming
+ */
+.ui-autocomplete {
+ position: absolute; cursor: default; z-index: 3;
+ -moz-border-radius: 0;
+ -webkit-border-radius: 0;
+ border-radius: 0;
+ -moz-box-shadow: 0 1px 5px rgba(0,0,0,0.3);
+ -webkit-box-shadow: 0 1px 5px rgba(0,0,0,0.3);
+ box-shadow: 0 1px 5px rgba(0,0,0,0.3);
+}
+
+/* workarounds */
+* html .ui-autocomplete { width:1px; } /* without this, the menu expands to 100% in IE6 */
+
+/*
+ * jQuery UI Menu 1.8.7
+ *
+ * Copyright 2010, AUTHORS.txt (http://jqueryui.com/about)
+ * Dual licensed under the MIT or GPL Version 2 licenses.
+ * http://jquery.org/license
+ *
+ * http://docs.jquery.com/UI/Menu#theming
+ */
+.ui-menu {
+ list-style:none;
+ padding: 2px;
+ margin: 0;
+ display:block;
+ float: left;
+}
+.ui-menu .ui-menu {
+ margin-top: -3px;
+}
+.ui-menu .ui-menu-item {
+ margin:0;
+ padding: 0;
+ zoom: 1;
+ float: left;
+ clear: left;
+ width: 100%;
+}
+.ui-menu .ui-menu-item a {
+ text-decoration:none;
+ display:block;
+ padding:.2em .4em;
+ line-height:1.5;
+ zoom:1;
+}
+.ui-menu .ui-menu-item a.ui-state-hover,
+.ui-menu .ui-menu-item a.ui-state-active {
+ font-weight: normal;
+ margin: -1px;
+ background: #5f83b9;
+ color: #FFFFFF;
+ text-shadow: 0px 1px 1px #234386;
+ border-color: #466086;
+ -moz-border-radius: 0;
+ -webkit-border-radius: 0;
+ border-radius: 0;
+}
+/*
+ * jQuery UI Button 1.8.7
+ *
+ * Copyright 2010, AUTHORS.txt (http://jqueryui.com/about)
+ * Dual licensed under the MIT or GPL Version 2 licenses.
+ * http://jquery.org/license
+ *
+ * http://docs.jquery.com/UI/Button#theming
+ */
+.ui-button { display: inline-block; position: relative; padding: 0; margin-right: .1em; text-decoration: none !important; cursor: pointer; text-align: center; zoom: 1; overflow: visible; -webkit-user-select: none; -moz-user-select: none; user-select: none; } /* the overflow property removes extra width in IE */
+.ui-button-icon-only { width: 2.2em; } /* to make room for the icon, a width needs to be set here */
+button.ui-button-icon-only { width: 2.4em; } /* button elements seem to need a little more width */
+.ui-button-icons-only { width: 3.4em; }
+button.ui-button-icons-only { width: 3.7em; }
+
+/* button animation properties */
+.ui-button {
+ -webkit-transition: all 250ms ease-in-out;
+ -moz-transition: all 250ms ease-in-out;
+ -o-transition: all 250ms ease-in-out;
+ transition: all 250ms ease-in-out;
+}
+
+/*states*/
+.ui-button.ui-state-hover {
+ -moz-box-shadow: 0 0 8px rgba(0, 0, 0, 0.15), 0 1px 0 rgba(255,255,255,0.8) inset;
+ -webkit-box-shadow: 0 0 8px rgba(0, 0, 0, 0.15), 0 1px 0 rgba(255,255,255,0.8) inset;
+ box-shadow: 0 0 8px rgba(0, 0, 0, 0.15), 0 1px 0 rgba(255,255,255,0.8) inset;
+}
+.ui-button.ui-state-focus {
+ outline: none;
+ color: #1c4257;
+ border-color: #7096ab;
+ background: #ededed url(bg_fallback.png) 0 -50px repeat-x; /* Old browsers */
+ background: -moz-linear-gradient(top, #b9e0f5 0%, #92bdd6 100%); /* FF3.6+ */
+ background: -webkit-gradient(linear, left top, left bottom, color-stop(0%,#b9e0f5), color-stop(100%,#92bdd6)); /* Chrome,Safari4+ */
+ background: -webkit-linear-gradient(top, #b9e0f5 0%,#92bdd6 100%); /* Chrome10+,Safari5.1+ */
+ background: -o-linear-gradient(top, #b9e0f5 0%,#92bdd6 100%); /* Opera11.10+ */
+ background: -ms-linear-gradient(top, #b9e0f5 0%,#92bdd6 100%); /* IE10+ */
+ background: linear-gradient(top, #b9e0f5 0%,#92bdd6 100%); /* W3C */
+ -moz-box-shadow: 0 0 8px rgba(0, 0, 0, 0.15), 0 1px 0 rgba(255,255,255,0.8) inset;
+ -webkit-box-shadow: 0 0 8px rgba(0, 0, 0, 0.15), 0 1px 0 rgba(255,255,255,0.8) inset;
+ box-shadow: 0 0 8px rgba(0, 0, 0, 0.15), 0 1px 0 rgba(255,255,255,0.8) inset;
+}
+
+/*button text element */
+.ui-button .ui-button-text { display: block; line-height: 1.4; font-size: 14px; font-weight: bold; text-shadow: 0 1px 0 rgba(255, 255, 255, 0.6); }
+.ui-button-text-only .ui-button-text { padding: .4em 1em; }
+.ui-button-icon-only .ui-button-text, .ui-button-icons-only .ui-button-text { padding: .4em; text-indent: -9999999px; }
+.ui-button-text-icon-primary .ui-button-text, .ui-button-text-icons .ui-button-text { padding: .4em 1em .4em 2.1em; }
+.ui-button-text-icon-secondary .ui-button-text, .ui-button-text-icons .ui-button-text { padding: .4em 2.1em .4em 1em; }
+.ui-button-text-icons .ui-button-text { padding-left: 2.1em; padding-right: 2.1em; }
+/* no icon support for input elements, provide padding by default */
+input.ui-button, .ui-widget-content input.ui-button { font-size: 14px; font-weight: bold; text-shadow: 0 1px 0 rgba(255, 255, 255, 0.6); padding: 0 1em !important; height: 33px; }
+/*remove submit button internal padding in Firefox*/
+input.ui-button::-moz-focus-inner {
+ border: 0;
+ padding: 0;
+}
+/* fix webkits handling of the box model */
+@media screen and (-webkit-min-device-pixel-ratio:0) {
+ input.ui-button {
+ height: 31px !important;
+ }
+}
+
+
+/*button icon element(s) */
+.ui-button-icon-only .ui-icon, .ui-button-text-icon-primary .ui-icon, .ui-button-text-icon-secondary .ui-icon, .ui-button-text-icons .ui-icon, .ui-button-icons-only .ui-icon { position: absolute; top: 50%; margin-top: -8px; }
+.ui-button-icon-only .ui-icon { left: 50%; margin-left: -8px; }
+.ui-button-text-icon-primary .ui-button-icon-primary, .ui-button-text-icons .ui-button-icon-primary, .ui-button-icons-only .ui-button-icon-primary { left: .5em; }
+.ui-button-text-icon-secondary .ui-button-icon-secondary, .ui-button-text-icons .ui-button-icon-secondary, .ui-button-icons-only .ui-button-icon-secondary { right: .5em; }
+.ui-button-text-icons .ui-button-icon-secondary, .ui-button-icons-only .ui-button-icon-secondary { right: .5em; }
+
+/*button sets*/
+.ui-buttonset { margin-right: 7px; }
+.ui-buttonset .ui-button { margin-left: 0; margin-right: -.3em; }
+.ui-buttonset .ui-button.ui-state-active { color: #1c4257; border-color: #7096ab; }
+.ui-buttonset .ui-button.ui-state-active {
+ background: #ededed url(bg_fallback.png) 0 -50px repeat-x; /* Old browsers */
+ background: -moz-linear-gradient(top, #b9e0f5 0%, #92bdd6 100%); /* FF3.6+ */
+ background: -webkit-gradient(linear, left top, left bottom, color-stop(0%,#b9e0f5), color-stop(100%,#92bdd6)); /* Chrome,Safari4+ */
+ background: -webkit-linear-gradient(top, #b9e0f5 0%,#92bdd6 100%); /* Chrome10+,Safari5.1+ */
+ background: -o-linear-gradient(top, #b9e0f5 0%,#92bdd6 100%); /* Opera11.10+ */
+ background: -ms-linear-gradient(top, #b9e0f5 0%,#92bdd6 100%); /* IE10+ */
+ background: linear-gradient(top, #b9e0f5 0%,#92bdd6 100%); /* W3C */
+ -webkit-box-shadow: none;
+ -moz-box-shadow: none;
+ box-shadow: none;
+}
+
+/* workarounds */
+button.ui-button::-moz-focus-inner { border: 0; padding: 0; } /* reset extra padding in Firefox */
+/*
+ * jQuery UI Dialog 1.8.7
+ *
+ * Copyright 2010, AUTHORS.txt (http://jqueryui.com/about)
+ * Dual licensed under the MIT or GPL Version 2 licenses.
+ * http://jquery.org/license
+ *
+ * http://docs.jquery.com/UI/Dialog#theming
+ */
+.ui-dialog { position: absolute; padding: 0; width: 300px; overflow: hidden; }
+.ui-dialog {
+ -webkit-box-shadow: 0 2px 12px rgba(0,0,0,0.6);
+ -moz-box-shadow: 0 2px 12px rgba(0,0,0,0.6);
+ box-shadow: 0 2px 12px rgba(0,0,0,0.6);
+}
+.ui-dialog .ui-dialog-titlebar { padding: 0.7em 1em 0.6em 1em; position: relative; border: none; border-bottom: 1px solid #979797; -moz-border-radius: 0; -webkit-border-radius: 0; border-radius: 0; }
+.ui-dialog .ui-dialog-title { float: left; margin: .1em 16px .2em 0; font-size: 14px; text-shadow: 0 1px 0 rgba(255,255,255,0.5); }
+.ui-dialog .ui-dialog-titlebar-close { position: absolute; right: .8em; top: 55%; width: 16px; margin: -10px 0 0 0; padding: 0; height: 16px; }
+.ui-dialog .ui-dialog-titlebar-close span { display: block; margin: 1px; background: url(icon_sprite.png) 0 -16px no-repeat; }
+.ui-dialog .ui-dialog-titlebar-close:hover span { background-position: -16px -16px; }
+.ui-dialog .ui-dialog-titlebar-close:hover, .ui-dialog .ui-dialog-titlebar-close:focus { padding: 0; border: 0; }
+.ui-dialog .ui-dialog-content { position: relative; border: 0; padding: .5em 1em; background: none; overflow: auto; zoom: 1; }
+.ui-dialog .ui-dialog-buttonpane { text-align: left; border-width: 1px 0 0 0; background-image: none; margin: .5em 0 0 0; padding: .3em 1em .5em .4em; }
+.ui-dialog .ui-dialog-buttonpane .ui-dialog-buttonset { float: right; }
+.ui-dialog .ui-dialog-buttonpane button { margin: .5em .4em .5em 0; cursor: pointer; }
+.ui-dialog .ui-resizable-se { width: 14px; height: 14px; right: 3px; bottom: 3px; }
+.ui-draggable .ui-dialog-titlebar { cursor: move; }
+/*
+ * jQuery UI Slider 1.8.7
+ *
+ * Copyright 2010, AUTHORS.txt (http://jqueryui.com/about)
+ * Dual licensed under the MIT or GPL Version 2 licenses.
+ * http://jquery.org/license
+ *
+ * http://docs.jquery.com/UI/Slider#theming
+ */
+.ui-slider { position: relative; text-align: left; background: #d7d7d7; z-index: 1; }
+.ui-slider { -moz-box-shadow: 0 1px 2px rgba(0,0,0,0.5) inset; -webkit-box-shadow: 0 1px 2px rgba(0,0,0,0.5) inset; box-shadow: 0 1px 2px rgba(0,0,0,0.5) inset; }
+.ui-slider .ui-slider-handle { background: url(slider_handles.png) 0px -23px no-repeat; position: absolute; z-index: 2; width: 23px; height: 23px; cursor: default; border: none; outline: none; -moz-box-shadow: none; -webkit-box-shadow: none; box-shadow: none; }
+.ui-slider .ui-state-hover, .ui-slider .ui-state-active { background-position: 0 0; }
+.ui-slider .ui-slider-range { background: #a3cae0; position: absolute; z-index: 1; font-size: .7em; display: block; border: 0; background-position: 0 0; }
+.ui-slider .ui-slider-range { -moz-box-shadow: 0 1px 2px rgba(17,35,45,0.6) inset; -webkit-box-shadow: 0 1px 2px rgba(17,35,45,0.6) inset; box-shadow: 0 1px 2px rgba(17,35,45,0.6) inset; }
+
+
+.ui-slider-horizontal { height: 5px; }
+.ui-slider-horizontal .ui-slider-handle { top: -8px; margin-left: -13px; }
+.ui-slider-horizontal .ui-slider-range { top: 0; height: 100%; }
+.ui-slider-horizontal .ui-slider-range-min { left: 0; }
+.ui-slider-horizontal .ui-slider-range-max { right: 0; }
+
+.ui-slider-vertical { width: 5px; height: 100px; }
+.ui-slider-vertical .ui-slider-handle { left: -8px; margin-left: 0; margin-bottom: -13px; }
+.ui-slider-vertical .ui-slider-range { left: 0; width: 100%; }
+.ui-slider-vertical .ui-slider-range-min { bottom: 0; }
+.ui-slider-vertical .ui-slider-range-max { top: 0; }/*
+ * jQuery UI Tabs 1.8.7
+ *
+ * Copyright 2010, AUTHORS.txt (http://jqueryui.com/about)
+ * Dual licensed under the MIT or GPL Version 2 licenses.
+ * http://jquery.org/license
+ *
+ * http://docs.jquery.com/UI/Tabs#theming
+ */
+.ui-tabs { position: relative; zoom: 1; border: 0; background: transparent; } /* position: relative prevents IE scroll bug (element with position: relative inside container with overflow: auto appear as "fixed") */
+.ui-tabs .ui-tabs-nav { margin: 0; padding: 0; background: transparent; border-width: 0 0 1px 0; }
+.ui-tabs .ui-tabs-nav {
+ -moz-border-radius: 0;
+ -webkit-border-radius: 0;
+ border-radius: 0;
+}
+.ui-tabs .ui-tabs-nav li { list-style: none; float: left; position: relative; top: 1px; margin: 0 .2em 1px 0; border-bottom: 0 !important; padding: 0; white-space: nowrap; }
+.ui-tabs .ui-tabs-nav li a { float: left; padding: .5em 1em; text-decoration: none; font-size: 12px; font-weight: bold; text-shadow: 0 1px 0 rgba(255,255,255,0.5); }
+.ui-tabs .ui-tabs-nav li.ui-tabs-selected { margin-bottom: 0; padding-bottom: 1px; background: #fff; border-color: #B6B6B6; }
+.ui-tabs .ui-tabs-nav li.ui-tabs-selected a, .ui-tabs .ui-tabs-nav li.ui-state-disabled a, .ui-tabs .ui-tabs-nav li.ui-state-processing a { cursor: text; outline: none; }
+.ui-tabs .ui-tabs-nav li a, .ui-tabs.ui-tabs-collapsible .ui-tabs-nav li.ui-tabs-selected a { cursor: pointer; } /* first selector in group seems obsolete, but required to overcome bug in Opera applying cursor: text overall if defined elsewhere... */
+.ui-tabs .ui-tabs-panel { display: block; border-width: 0 1px 1px 1px; padding: 1em 1.4em; background: none; }
+.ui-tabs .ui-tabs-panel { background: #FFF;
+ -moz-border-radius: 0;
+ -webkit-border-radius: 0;
+ border-radius: 0;
+}
+.ui-tabs .ui-tabs-hide { display: none !important; }
+/*
+ * jQuery UI Datepicker 1.8.7
+ *
+ * Copyright 2010, AUTHORS.txt (http://jqueryui.com/about)
+ * Dual licensed under the MIT or GPL Version 2 licenses.
+ * http://jquery.org/license
+ *
+ * http://docs.jquery.com/UI/Datepicker#theming
+ */
+.ui-datepicker { width: 17em; padding: 0; display: none; border-color: #DDDDDD; }
+.ui-datepicker {
+ -moz-box-shadow: 0 4px 8px rgba(0,0,0,0.5);
+ -webkit-box-shadow: 0 4px 8px rgba(0,0,0,0.5);
+ box-shadow: 0 4px 8px rgba(0,0,0,0.5);
+}
+.ui-datepicker .ui-datepicker-header { position:relative; padding:.35em 0; border: none; border-bottom: 1px solid #B6B6B6; -moz-border-radius: 0; -webkit-border-radius: 0; border-radius: 0; }
+.ui-datepicker .ui-datepicker-prev, .ui-datepicker .ui-datepicker-next { position:absolute; top: 6px; width: 1.8em; height: 1.8em; }
+.ui-datepicker .ui-datepicker-prev-hover, .ui-datepicker .ui-datepicker-next-hover { border: 1px none; }
+.ui-datepicker .ui-datepicker-prev { left:2px; }
+.ui-datepicker .ui-datepicker-next { right:2px; }
+.ui-datepicker .ui-datepicker-prev span { background-position: 0px -32px !important; }
+.ui-datepicker .ui-datepicker-next span { background-position: -16px -32px !important; }
+.ui-datepicker .ui-datepicker-prev-hover span { background-position: 0px -48px !important; }
+.ui-datepicker .ui-datepicker-next-hover span { background-position: -16px -48px !important; }
+.ui-datepicker .ui-datepicker-prev span, .ui-datepicker .ui-datepicker-next span { display: block; position: absolute; left: 50%; margin-left: -8px; top: 50%; margin-top: -8px; background: url(icon_sprite.png) no-repeat; }
+.ui-datepicker .ui-datepicker-title { margin: 0 2.3em; line-height: 1.8em; text-align: center; font-size: 12px; text-shadow: 0 1px 0 rgba(255,255,255,0.6); }
+.ui-datepicker .ui-datepicker-title select { font-size:1em; margin:1px 0; }
+.ui-datepicker select.ui-datepicker-month-year {width: 100%;}
+.ui-datepicker select.ui-datepicker-month,
+.ui-datepicker select.ui-datepicker-year { width: 49%;}
+.ui-datepicker table {width: 100%; font-size: .9em; border-collapse: collapse; margin:0 0 .4em; }
+.ui-datepicker th { padding: .7em .3em; text-align: center; font-weight: bold; border: 0; }
+.ui-datepicker td { border: 0; padding: 1px; }
+.ui-datepicker td span, .ui-datepicker td a { display: block; padding: .2em; text-align: right; text-decoration: none; }
+.ui-datepicker .ui-datepicker-buttonpane { background-image: none; margin: .7em 0 0 0; padding:0 .2em; border-left: 0; border-right: 0; border-bottom: 0; }
+.ui-datepicker .ui-datepicker-buttonpane button { float: right; margin: .5em .2em .4em; cursor: pointer; padding: .2em .6em .3em .6em; width:auto; overflow:visible; }
+.ui-datepicker .ui-datepicker-buttonpane button.ui-datepicker-current { float:left; }
+.ui-datepicker table .ui-state-highlight { border-color: #5F83B9; }
+.ui-datepicker table .ui-state-hover { background: #5F83B9; color: #FFF; font-weight: bold; text-shadow: 0 1px 1px #234386; -webkit-box-shadow: 0 0px 0 rgba(255,255,255,0.6) inset; -moz-box-shadow: 0 0px 0 rgba(255,255,255,0.6) inset; box-shadow: 0 0px 0 rgba(255,255,255,0.6) inset; border-color: #5F83B9; }
+.ui-datepicker-calendar .ui-state-default { background: transparent; border-color: #FFF; }
+.ui-datepicker-calendar .ui-state-active { background: #5F83B9; border-color: #5F83B9; color: #FFF; font-weight: bold; text-shadow: 0 1px 1px #234386; }
+
+/* with multiple calendars */
+.ui-datepicker.ui-datepicker-multi { width:auto; }
+.ui-datepicker-multi .ui-datepicker-group { float:left; }
+.ui-datepicker-multi .ui-datepicker-group table { width:95%; margin:0 auto .4em; }
+.ui-datepicker-multi-2 .ui-datepicker-group { width:50%; }
+.ui-datepicker-multi-3 .ui-datepicker-group { width:33.3%; }
+.ui-datepicker-multi-4 .ui-datepicker-group { width:25%; }
+.ui-datepicker-multi .ui-datepicker-group-last .ui-datepicker-header { border-left-width:0; }
+.ui-datepicker-multi .ui-datepicker-group-middle .ui-datepicker-header { border-left-width:0; }
+.ui-datepicker-multi .ui-datepicker-buttonpane { clear:left; }
+.ui-datepicker-row-break { clear:both; width:100%; }
+
+/* RTL support */
+.ui-datepicker-rtl { direction: rtl; }
+.ui-datepicker-rtl .ui-datepicker-prev { right: 2px; left: auto; }
+.ui-datepicker-rtl .ui-datepicker-next { left: 2px; right: auto; }
+.ui-datepicker-rtl .ui-datepicker-prev:hover { right: 1px; left: auto; }
+.ui-datepicker-rtl .ui-datepicker-next:hover { left: 1px; right: auto; }
+.ui-datepicker-rtl .ui-datepicker-buttonpane { clear:right; }
+.ui-datepicker-rtl .ui-datepicker-buttonpane button { float: left; }
+.ui-datepicker-rtl .ui-datepicker-buttonpane button.ui-datepicker-current { float:right; }
+.ui-datepicker-rtl .ui-datepicker-group { float:right; }
+.ui-datepicker-rtl .ui-datepicker-group-last .ui-datepicker-header { border-right-width:0; border-left-width:1px; }
+.ui-datepicker-rtl .ui-datepicker-group-middle .ui-datepicker-header { border-right-width:0; border-left-width:1px; }
+
+/* IE6 IFRAME FIX (taken from datepicker 1.5.3 */
+.ui-datepicker-cover {
+ display: none; /*sorry for IE5*/
+ display/**/: block; /*sorry for IE5*/
+ position: absolute; /*must have*/
+ z-index: -1; /*must have*/
+ filter: mask(); /*must have*/
+ top: -4px; /*must have*/
+ left: -4px; /*must have*/
+ width: 200px; /*must have*/
+ height: 200px; /*must have*/
+}/*
+ * jQuery UI Progressbar 1.8.7
+ *
+ * Copyright 2010, AUTHORS.txt (http://jqueryui.com/about)
+ * Dual licensed under the MIT or GPL Version 2 licenses.
+ * http://jquery.org/license
+ *
+ * http://docs.jquery.com/UI/Progressbar#theming
+ */
+.ui-progressbar { height: 12px; text-align: left; background: #FFF url(progress_bar.gif) 0 -14px repeat-x; }
+.ui-progressbar .ui-progressbar-value {margin: -1px; height:100%; background: url(progress_bar.gif) 0 0 repeat-x; }
+
+/* Extra Input Field Styling */
+.ui-form textarea, .ui-form input:not([type="submit"]):not([type="button"]):not([type="checkbox"]):not([type="radio"]):not([type="file"]):not([type="range"]) {
+ padding: 3px;
+ -webkit-border-radius: 2px;
+ -moz-border-radius: 2px;
+ border-radius: 2px;
+ border: 1px solid #cecece;
+ outline: none;
+ -webkit-box-shadow: 0 1px 3px rgba(0,0,0,0.1) inset, 0 1px 0 rgba(255,255,255,0.2);
+ -moz-box-shadow: 0 1px 3px rgba(0,0,0,0.1) inset, 0 1px 0 rgba(255,255,255,0.2);
+ box-shadow: 0 1px 3px rgba(0,0,0,0.1) inset, 0 1px 0 rgba(255,255,255,0.2);
+ -webkit-transition: all 250ms ease-in-out;
+ -moz-transition: all 250ms ease-in-out;
+ -o-transition: all 250ms ease-in-out;
+ transition: all 250ms ease-in-out;
+}
+.ui-form textarea:hover, .ui-form input:not([type="submit"]):not([type="button"]):not([type="checkbox"]):not([type="radio"]):not([type="file"]):not([type="range"]):hover {
+ border: 1px solid #bdbdbd;
+ -webkit-box-shadow: 0 1px 3px rgba(0,0,0,0.2) inset, 0 1px 0 rgba(255,255,255,0.2);
+ -moz-box-shadow: 0 1px 3px rgba(0,0,0,0.2) inset, 0 1px 0 rgba(255,255,255,0.2);
+ box-shadow: 0 1px 3px rgba(0,0,0,0.2) inset, 0 1px 0 rgba(255,255,255,0.2);
+}
+.ui-form textarea:focus, .ui-form input:not([type="submit"]):not([type="button"]):not([type="checkbox"]):not([type="radio"]):not([type="file"]):not([type="range"]):focus {
+ border: 1px solid #95bdd4;
+ -webkit-box-shadow: 0 2px 3px rgba(161,202,226,0.5) inset, 0 1px 0 rgba(255,255,255,0.2);
+ -moz-box-shadow: 0 2px 3px rgba(161,202,226,0.5) inset, 0 1px 0 rgba(255,255,255,0.2);
+ box-shadow: 0 2px 3px rgba(161,202,226,0.5) inset, 0 1px 0 rgba(255,255,255,0.2);
+}