Commit f032b15d authored by Douwe Maan's avatar Douwe Maan

Merge branch 'master' of gitlab.com:gitlab-org/gitlab-ce into ce-to-ee

# Conflicts:
#	README.md
#	app/controllers/projects_controller.rb
#	db/schema.rb
#	doc/workflow/README.md
#	lib/gitlab/satellite/merge_action.rb
parents d01153c4 5dd4dea9
Please view this file on the master branch, on stable branches it's out of date.
v 7.14.0 (unreleased)
- Fix full screen mode for snippet comments (Daniel Gerhardt)
- Fix 404 error in files view after deleting the last file in a repository (Stan Hu)
- Fix label read access for unauthenticated users (Daniel Gerhardt)
- Fix access to disabled features for unauthenticated users (Daniel Gerhardt)
- Fix OAuth provider bug where GitLab would not go return to the redirect_uri after sign-in (Stan Hu)
- Fix file upload dialog for comment editing (Daniel Gerhardt)
- Set OmniAuth full_host parameter to ensure redirect URIs are correct (Stan Hu)
- Expire Rails cache entries after two weeks to prevent endless Redis growth
- Add support for destroying project milestones (Stan Hu)
- Add fetch command to the MR page.
- Fix bug causing "Remove source-branch" option not to work for merge requests from the same project.
v 7.13.1
- Revert issue caching
- Reverted cache for events
v 7.13.0 (unreleased)
- Remove repository graph log to fix slow cache updates after push event (Stan Hu)
- Only enable HSTS header for HTTPS and port 443 (Stan Hu)
- Fix user autocomplete for unauthenticated users accessing public projects (Stan Hu)
- Fix redirection to home page URL for unauthorized users (Daniel Gerhardt)
......@@ -15,7 +33,6 @@ v 7.13.0 (unreleased)
- Add `two_factor_enabled` field to admin user API (Stan Hu)
- Fix invalid timestamps in RSS feeds (Rowan Wookey)
- Fix downloading of patches on public merge requests when user logged out (Stan Hu)
- The password for the default administrator (root) account has been changed from "5iveL!fe" to "password".
- Fix Error 500 when relative submodule resolves to a namespace that has a different name from its path (Stan Hu)
- Extract the longest-matching ref from a commit path when multiple matches occur (Stan Hu)
- Update maintenance documentation to explain no need to recompile asssets for omnibus installations (Stan Hu)
......@@ -47,6 +64,8 @@ v 7.13.0 (unreleased)
- Faster code search in repository and wiki. Fixes search page timeout for big repositories
- Allow administrators to disable 2FA for a specific user
- Add error message for SSH key linebreaks
- Store commits count in database (will populate with valid values only after first push)
- Rebuild cache after push to repository in background job
v 7.12.2
- Correctly show anonymous authorized applications under Profile > Applications.
......@@ -122,6 +141,7 @@ v 7.12.0
- Improve group removing logic
- Trigger create-hooks on backup restore task
- Add option to automatically link omniauth and LDAP identities
- Allow special character in users bio. I.e.: I <3 GitLab
v 7.11.4
- Fix missing bullets when creating lists
......@@ -140,9 +160,6 @@ v 7.11.1
v 7.11.0
- Fall back to Plaintext when Syntaxhighlighting doesn't work. Fixes some buggy lexers (Hannes Rosenögger)
- Get editing comments to work in Chrome 43 again.
- Allow special character in users bio. I.e.: I <3 GitLab
v 7.11.0
- Fix broken view when viewing history of a file that includes a path that used to be another file (Stan Hu)
- Don't show duplicate deploy keys
- Fix commit time being displayed in the wrong timezone in some cases (Hannes Rosenögger)
......
......@@ -46,7 +46,7 @@ gem "gitlab_git", '~> 7.2.5'
gem 'gitlab-grack', '~> 2.0.2', require: 'grack'
# LDAP Auth
# GitLab fork with several improvements to original library. For full list of changes
# GitLab fork with several improvements to original library. For full list of changes
# see https://github.com/intridea/omniauth-ldap/compare/master...gitlabhq:master
gem 'gitlab_omniauth-ldap', '1.2.1', require: "omniauth-ldap"
gem 'net-ldap'
......@@ -55,9 +55,9 @@ gem 'net-ldap'
gem 'gollum-lib', '~> 4.0.2'
# Language detection
# GitLab fork of linguist does not require pygments/python dependency.
# New version of original gem also dropped pygments support but it has strict
# dependency to unstable rugged version. We have internal issue for replacing
# GitLab fork of linguist does not require pygments/python dependency.
# New version of original gem also dropped pygments support but it has strict
# dependency to unstable rugged version. We have internal issue for replacing
# fork with original gem when we meet on same rugged version - https://dev.gitlab.org/gitlab/gitlabhq/issues/2052.
gem "gitlab-linguist", "~> 3.0.1", require: "linguist"
......@@ -230,7 +230,7 @@ end
group :development, :test do
gem 'awesome_print'
gem 'byebug'
gem 'byebug', platform: :mri
gem 'fuubar', '~> 2.0.0'
gem 'pry-rails'
......
# GitLab
[![build status](https://ci.gitlab.com/projects/1/status.png?ref=master)](https://ci.gitlab.com/projects/1?ref=master)
[![Build Status](https://semaphoreapp.com/api/v1/projects/2f1a5809-418b-4cc2-a1f4-819607579fe7/243338/badge.png)](https://semaphoreapp.com/gitlabhq/gitlabhq)
[![Code Climate](https://codeclimate.com/github/gitlabhq/gitlabhq.svg)](https://codeclimate.com/github/gitlabhq/gitlabhq)
[![Coverage Status](https://coveralls.io/repos/gitlabhq/gitlabhq/badge.png?branch=master)](https://coveralls.io/r/gitlabhq/gitlabhq?branch=master)
## Canonical source
The source of GitLab Community Edition is [hosted on GitLab.com](https://gitlab.com/gitlab-org/gitlab-ce/) and there are mirrors to make [contributing](CONTRIBUTING.md) as easy as possible.
......@@ -41,21 +48,12 @@ To see how GitLab looks please see the [features page on our website](https://ab
## Editions
There are two editions of GitLab.
*GitLab [Community Edition](https://about.gitlab.com/features/) (CE)* is available without any costs under an MIT license.
*GitLab Enterprise Edition (EE)* includes [extra features](https://about.gitlab.com/features/#compare) that are most useful for organizations with more than 100 users.
To use EE and get official support please [become a subscriber](https://about.gitlab.com/pricing/).
## Code status
- [![build status](https://ci.gitlab.com/projects/1/status.png?ref=master)](https://ci.gitlab.com/projects/1?ref=master) on ci.gitlab.com (master branch)
- [![Build Status](https://semaphoreapp.com/api/v1/projects/2f1a5809-418b-4cc2-a1f4-819607579fe7/243338/badge.png)](https://semaphoreapp.com/gitlabhq/gitlabhq)
There are two editions of GitLab:
- [![Code Climate](https://codeclimate.com/github/gitlabhq/gitlabhq.svg)](https://codeclimate.com/github/gitlabhq/gitlabhq)
- GitLab Community Edition (CE) is available freely under the MIT Expat license.
- GitLab Enterprise Edition (EE) includes [extra features](https://about.gitlab.com/features/#compare) that are more useful for organizations with more than 100 users. To use EE and get official support please [become a subscriber](https://about.gitlab.com/pricing/).
- [![Coverage Status](https://coveralls.io/repos/gitlabhq/gitlabhq/badge.png?branch=master)](https://coveralls.io/r/gitlabhq/gitlabhq?branch=master)
Included with the GitLab Omnibus Packages is [GitLab CI](https://about.gitlab.com/gitlab-ci/) that can easily build, test and deploy code.
## Website
......@@ -70,23 +68,39 @@ On [about.gitlab.com](https://about.gitlab.com/) you can find more information a
## Requirements
GitLab requires the following software:
- Ubuntu/Debian/CentOS/RHEL
- Ruby (MRI) 2.0 or 2.1
- Git 1.7.10+
- Redis 2.0+
- MySQL or PostgreSQL
Please see the [requirements documentation](doc/install/requirements.md) for system requirements and more information about the supported operating systems.
## Installation
The recommended way to install GitLab is using the provided [Omnibus packages](https://about.gitlab.com/downloads/). Compared to an installation from source, this is faster and less error prone. Just select your operating system, download the respective package (Debian or RPM) and install it using the system's package manager.
The recommended way to install GitLab is with the [Omnibus packages](https://about.gitlab.com/downloads/) on our package server.
Compared to an installation from source, this is faster and less error prone.
Just select your operating system, download the respective package (Debian or RPM) and install it using the system's package manager.
There are various other options to install GitLab, please refer to the [installation page on the GitLab website](https://about.gitlab.com/installation/) for more information.
You can access a new installation with the login **`root`** and password **`password`**, after login you are required to set a unique password.
You can access a new installation with the login **`root`** and password **`5iveL!fe`**, after login you are required to set a unique password.
## Install a development environment
To work on GitLab itself, we recommend setting up your development environment with [the GitLab Development Kit](https://gitlab.com/gitlab-org/gitlab-development-kit).
If you do not use the GitLab Development Kit you need to install and setup all the dependencies yourself, this is a lot of work and error prone.
One small thing you also have to do when installing it yourself is to copy the example development unicorn configuration file:
cp config/unicorn.rb.example.development config/unicorn.rb
Instructions on how to start GitLab and how to run the tests can be found in the [development section of the GitLab Development Kit](https://gitlab.com/gitlab-org/gitlab-development-kit#development).
## Software stack
GitLab is a Ruby on Rails application that runs on the following software:
- Ubuntu/Debian/CentOS/RHEL
- Ruby (MRI) 2.0 or 2.1
- Git 1.7.10+
- Redis 2.0+
- MySQL or PostgreSQL
For more information please see the [architecture documentation](http://doc.gitlab.com/ce/development/architecture.html).
## Third-party applications
......@@ -100,16 +114,6 @@ Since 2011 a minor or major version of GitLab is released on the 22nd of every m
For upgrading information please see our [update page](https://about.gitlab.com/update/).
## Install a development environment
To work on GitLab itself, we recommend setting up your development environment with [the GitLab Development Kit](https://gitlab.com/gitlab-org/gitlab-development-kit).
If you do not use the GitLab Development Kit you need to install and setup all the dependencies yourself, this is a lot of work and error prone.
One small thing you also have to do when installing it yourself is to copy the example development unicorn configuration file:
cp config/unicorn.rb.example.development config/unicorn.rb
Instructions on how to start GitLab and how to run the tests can be found in the [development section of the GitLab Development Kit](https://gitlab.com/gitlab-org/gitlab-development-kit#development).
## Documentation
All documentation can be found on [doc.gitlab.com/ee/](http://doc.gitlab.com/ee/).
......@@ -125,4 +129,4 @@ Please see [Getting help for GitLab](https://about.gitlab.com/getting-help/) on
## Is it awesome?
Thanks for [asking this question](https://twitter.com/supersloth/status/489462789384056832) Joshua.
[These people](https://twitter.com/gitlab/favorites) seem to like it.
\ No newline at end of file
[These people](https://twitter.com/gitlab/favorites) seem to like it.
......@@ -132,7 +132,10 @@ class Dispatcher
shortcut_handler = new ShortcutsNavigation()
new ZenMode()
new DropzoneInput($('.wiki-form'))
when 'snippets', 'labels', 'graphs'
when 'snippets'
shortcut_handler = new ShortcutsNavigation()
new ZenMode() if path[2] == 'show'
when 'labels', 'graphs'
shortcut_handler = new ShortcutsNavigation()
when 'project_members', 'deploy_keys', 'hooks', 'services', 'protected_branches'
shortcut_handler = new ShortcutsNavigation()
......
......@@ -70,7 +70,7 @@ class @LineHighlighter
@clearHighlight()
lineNumber = $(event.target).data('line-number')
lineNumber = $(event.target).closest('a').data('line-number')
current = @hashToRange(@_hash)
unless current[0] && event.shiftKey
......
......@@ -15,9 +15,7 @@ class @MergeRequest
this.$('.show-all-commits').on 'click', =>
this.showAllCommits()
# `MergeRequests#new` has no tab-persisting or lazy-loading behavior
unless @opts.action == 'new'
new MergeRequestTabs(@opts)
@initTabs()
# Prevent duplicate event bindings
@disableTaskList()
......@@ -29,6 +27,14 @@ class @MergeRequest
$: (selector) ->
this.$el.find(selector)
initTabs: ->
if @opts.action != 'new'
# `MergeRequests#new` has no tab-persisting or lazy-loading behavior
new MergeRequestTabs(@opts)
else
# Show the first tab (Commits)
$('.merge-request-tabs a[data-toggle="tab"]:first').tab('show')
showAllCommits: ->
this.$('.first-commits').remove()
this.$('.all-commits').removeClass 'hide'
......
......@@ -298,7 +298,7 @@ class @Notes
note.find(".note-header").hide()
base_form = note.find(".note-edit-form")
form = base_form.clone().insertAfter(base_form)
form.addClass('current-note-edit-form')
form.addClass('current-note-edit-form gfm-form')
form.find('.div-dropzone').remove()
# Show the attachment delete link
......
......@@ -64,7 +64,12 @@ class Projects::MilestonesController < Projects::ApplicationController
end
def destroy
return access_denied! unless can?(current_user, :admin_milestone, @milestone)
return access_denied! unless can?(current_user, :admin_milestone, @project)
update_params = { milestone: nil }
@milestone.issues.each do |issue|
Issues::UpdateService.new(@project, current_user, update_params).execute(issue)
end
@milestone.destroy
......
......@@ -7,13 +7,15 @@ class Projects::TreeController < Projects::ApplicationController
before_action :authorize_download_code!
def show
return not_found! unless @repository.commit(@ref)
if tree.entries.empty?
if @repository.blob_at(@commit.id, @path)
redirect_to(
namespace_project_blob_path(@project.namespace, @project,
File.join(@ref, @path))
) and return
else
elsif @path.present?
return not_found!
end
end
......
class ProjectsController < ApplicationController
prepend_before_action :render_go_import, only: [:show]
skip_before_action :authenticate_user!, only: [:show]
prepend_before_filter :render_go_import, only: [:show]
skip_before_action :authenticate_user!, only: [:show, :activity]
before_action :project, except: [:new, :create]
before_action :repository, except: [:new, :create]
......
......@@ -131,8 +131,12 @@ module ProjectsHelper
nav_tabs << :snippets
end
if can?(current_user, :read_label, project)
nav_tabs << :labels
end
if can?(current_user, :read_milestone, project)
nav_tabs << [:milestones, :labels]
nav_tabs << :milestones
end
nav_tabs.flatten
......@@ -284,4 +288,18 @@ module ProjectsHelper
def readme_cache_key
[@project.id, @project.commit.sha, "readme"].join('-')
end
def round_commit_count(project)
count = project.commit_count
if count > 10000
'10000+'
elsif count > 5000
'5000+'
elsif count > 1000
'1000+'
else
count
end
end
end
......@@ -47,10 +47,11 @@ class Ability
end
if project && project.public?
[
rules = [
:read_project,
:read_wiki,
:read_issue,
:read_label,
:read_milestone,
:read_project_snippet,
:read_project_member,
......@@ -58,6 +59,8 @@ class Ability
:read_note,
:download_code
]
rules - project_disabled_features_rules(project)
else
group = if subject.kind_of?(Group)
subject
......@@ -118,28 +121,7 @@ class Ability
rules -= project_archived_rules
end
unless project.issues_enabled
rules -= named_abilities('issue')
end
unless project.merge_requests_enabled
rules -= named_abilities('merge_request')
end
unless project.issues_enabled or project.merge_requests_enabled
rules -= named_abilities('label')
rules -= named_abilities('milestone')
end
unless project.snippets_enabled
rules -= named_abilities('project_snippet')
end
unless project.wiki_enabled
rules -= named_abilities('wiki')
end
rules
rules - project_disabled_features_rules(project)
end
end
......@@ -221,6 +203,33 @@ class Ability
]
end
def project_disabled_features_rules(project)
rules = []
unless project.issues_enabled
rules += named_abilities('issue')
end
unless project.merge_requests_enabled
rules += named_abilities('merge_request')
end
unless project.issues_enabled or project.merge_requests_enabled
rules += named_abilities('label')
rules += named_abilities('milestone')
end
unless project.snippets_enabled
rules += named_abilities('project_snippet')
end
unless project.wiki_enabled
rules += named_abilities('wiki')
end
rules
end
def group_abilities(user, group)
rules = []
......
......@@ -240,6 +240,10 @@ class MergeRequest < ActiveRecord::Base
execute(self, commit_message)
end
def remove_source_branch?
self.should_remove_source_branch && !self.source_project.root_ref?(self.source_branch) && !self.for_fork?
end
def open?
opened? || reopened?
end
......
......@@ -703,6 +703,10 @@ class Project < ActiveRecord::Base
update_attribute(:repository_size, repository.size)
end
def update_commit_count
update_attribute(:commit_count, repository.commit_count)
end
def forks_count
ForkedProjectLink.where(forked_from_project_id: self.id).count
end
......
......@@ -22,8 +22,12 @@ class GitlabCiService < CiService
API_PREFIX = "api/v1"
prop_accessor :project_url, :token
validates :project_url, presence: true, if: :activated?
validates :token, presence: true, if: :activated?
validates :project_url,
presence: true,
format: { with: /\A#{URI.regexp(%w(http https))}\z/, message: "should be a valid url" }, if: :activated?
validates :token,
presence: true,
format: { with: /\A([A-Za-z0-9]+)\z/ }, if: :activated?
after_save :compose_service_hook, if: :activated?
......
......@@ -94,18 +94,6 @@ class Repository
gitlab_shell.rm_tag(path_with_namespace, tag_name)
end
def round_commit_count
if commit_count > 10000
'10000+'
elsif commit_count > 5000
'5000+'
elsif commit_count > 1000
'1000+'
else
commit_count
end
end
def branch_names
cache.fetch(:branch_names) { raw_repository.branch_names }
end
......@@ -130,28 +118,29 @@ class Repository
cache.fetch(:size) { raw_repository.size }
end
def cache_keys
%i(size branch_names tag_names commit_count
readme version contribution_guide changelog license)
end
def build_cache
cache_keys.each do |key|
unless cache.exist?(key)
send(key)
end
end
end
def expire_cache
%i(size branch_names tag_names commit_count graph_log
readme version contribution_guide changelog license).each do |key|
cache_keys.each do |key|
cache.expire(key)
end
end
def graph_log
cache.fetch(:graph_log) do
commits = raw_repository.log(limit: 6000, skip_merges: true,
ref: root_ref)
commits.map do |rugged_commit|
commit = Gitlab::Git::Commit.new(rugged_commit)
{
author_name: commit.author_name,
author_email: commit.author_email,
additions: commit.stats.additions,
deletions: commit.stats.deletions,
}
end
def rebuild_cache
cache_keys.each do |key|
cache.expire(key)
send(key)
end
end
......@@ -442,8 +431,7 @@ class Repository
filename = nil
startline = 0
lines = result.lines
lines.each_with_index do |line, index|
result.each_line.each_with_index do |line, index|
if line =~ /^.*:.*:\d+:/
ref, filename, startline = line.split(':')
startline = startline.to_i - index
......@@ -451,11 +439,11 @@ class Repository
end
end
data = lines.map do |line|
line.sub(ref, '').sub(filename, '').sub(/^:-\d+-/, '').sub(/^::\d+:/, '')
end
data = ""
data = data.join("")
result.each_line do |line|
data << line.sub(ref, '').sub(filename, '').sub(/^:-\d+-/, '').sub(/^::\d+:/, '')
end
OpenStruct.new(
filename: filename,
......
......@@ -43,7 +43,7 @@ module Files
def after_commit(sha, branch)
commit = repository.commit(sha)
full_ref = 'refs/heads/' + branch
full_ref = "#{Gitlab::Git::BRANCH_REF_PREFIX}#{branch}"
old_sha = commit.parent_id || Gitlab::Git::BLANK_SHA
GitPushService.new.execute(project, current_user, old_sha, sha, full_ref)
end
......
......@@ -21,7 +21,6 @@ class GitPushService
project.ensure_satellite_exists
project.repository.expire_cache
project.update_repository_size
if push_remove_branch?(ref, newrev)
@push_commits = []
......@@ -61,6 +60,7 @@ class GitPushService
EventCreateService.new.push(project, user, @push_data)
project.execute_hooks(@push_data.dup, :push_hooks)
project.execute_services(@push_data.dup, :push_hooks)
ProjectCacheWorker.perform_async(project.id)
end
protected
......
......@@ -2,15 +2,15 @@ class GitTagPushService
attr_accessor :project, :user, :push_data
def execute(project, user, oldrev, newrev, ref)
@project, @user = project, user
project.repository.expire_cache
@project, @user = project, user
@push_data = build_push_data(oldrev, newrev, ref)
EventCreateService.new.push(project, user, @push_data)
project.execute_hooks(@push_data.dup, :tag_push_hooks)
project.execute_services(@push_data.dup, :tag_push_hooks)
project.repository.expire_cache
ProjectCacheWorker.perform_async(project.id)
true
end
......
......@@ -37,6 +37,14 @@ module MergeRequests
# Merge local branches using rugged instead of satellites
if sha = commit
after_commit(sha, merge_request.target_branch)
if merge_request.remove_source_branch?
DeleteBranchService.new(merge_request.source_project, current_user).execute(merge_request.source_branch)
end
true
else
false
end
end
end
......@@ -55,7 +63,7 @@ module MergeRequests
def after_commit(sha, branch)
commit = repository.commit(sha)
full_ref = 'refs/heads/' + branch
full_ref = "#{Gitlab::Git::BRANCH_REF_PREFIX}#{branch}"
old_sha = commit.parent_id || Gitlab::Git::BLANK_SHA
GitPushService.new.execute(project, current_user, old_sha, sha, full_ref)
end
......
......@@ -8,11 +8,10 @@
= image_tag avatar_icon(event.author_email, 24), class: "avatar s24", alt:''
= render "events/event/created_project", event: event
- else
= cache event do
= image_tag avatar_icon(event.author_email, 24), class: "avatar s24", alt:''
- if event.push?
= render "events/event/push", event: event
- elsif event.commented?
= render "events/event/note", event: event
- else
= render "events/event/common", event: event
= image_tag avatar_icon(event.author_email, 24), class: "avatar s24", alt:''
- if event.push?
= render "events/event/push", event: event
- elsif event.commented?
= render "events/event/note", event: event
- else
= render "events/event/common", event: event
......@@ -14,7 +14,7 @@
.repo-info
- unless project.empty_repo?
= link_to pluralize(project.repository.round_commit_count, 'commit'), namespace_project_commits_path(project.namespace, project, project.default_branch)
= link_to pluralize(round_commit_count(project), 'commit'), namespace_project_commits_path(project.namespace, project, project.default_branch)
&middot;
= link_to pluralize(project.repository.branch_names.count, 'branch'), namespace_project_branches_path(project.namespace, project)
&middot;
......
......@@ -5,7 +5,7 @@
Download the Google Authenticator application from App Store for iOS or Google
Play for Android and scan this code.
More information is available in the #{link_to('documentation', help_page_path('workflow', 'two_factor_authentication'))}.
More information is available in the #{link_to('documentation', help_page_path('profile', 'two_factor_authentication'))}.
%hr
......
......@@ -3,43 +3,42 @@
.issue-check
= check_box_tag dom_id(issue,"selected"), nil, false, 'data-id' => issue.id, class: "selected_issue"
= cache issue do
.issue-title
%span.issue-title-text
= link_to_gfm issue.title, issue_path(issue), class: "row_title"
.issue-labels
- issue.labels.each do |label|
= link_to_label(label, project: issue.project)
.pull-right.light
- if issue.closed?
%span
CLOSED
- if issue.assignee
= link_to_member(@project, issue.assignee, name: false)
- note_count = issue.notes.user.count
- if note_count > 0
&nbsp;
%span
%i.fa.fa-comments
= note_count
- else
&nbsp;
%span.issue-no-comments
%i.fa.fa-comments
= 0
.issue-info
= "#{issue.to_reference} opened #{time_ago_with_tooltip(issue.created_at, placement: 'bottom')} by #{link_to_member(@project, issue.author, avatar: false)}".html_safe
- if issue.votes_count > 0
= render 'votes/votes_inline', votable: issue
- if issue.milestone
.issue-title
%span.issue-title-text
= link_to_gfm issue.title, issue_path(issue), class: "row_title"
.issue-labels
- issue.labels.each do |label|
= link_to_label(label, project: issue.project)
.pull-right.light
- if issue.closed?
%span
CLOSED
- if issue.assignee
= link_to_member(@project, issue.assignee, name: false)
- note_count = issue.notes.user.count
- if note_count > 0
&nbsp;
%span
%i.fa.fa-clock-o
= issue.milestone.title
- if issue.tasks?
%span.task-status
= issue.task_status
%i.fa.fa-comments
= note_count
- else
&nbsp;
%span.issue-no-comments
%i.fa.fa-comments
= 0
.issue-info
= "#{issue.to_reference} opened #{time_ago_with_tooltip(issue.created_at, placement: 'bottom')} by #{link_to_member(@project, issue.author, avatar: false)}".html_safe
- if issue.votes_count > 0
= render 'votes/votes_inline', votable: issue
- if issue.milestone
&nbsp;
%span
%i.fa.fa-clock-o
= issue.milestone.title
- if issue.tasks?
%span.task-status
= issue.task_status
.pull-right.issue-updated-at
%small updated #{time_ago_with_tooltip(issue.updated_at, placement: 'bottom', html_class: 'issue_update_ago')}
.pull-right.issue-updated-at
%small updated #{time_ago_with_tooltip(issue.updated_at, placement: 'bottom', html_class: 'issue_update_ago')}
......@@ -31,6 +31,16 @@
%li= link_to "Email Patches", merge_request_path(@merge_request, format: :patch)
%li= link_to "Plain Diff", merge_request_path(@merge_request, format: :diff)
- if @merge_request.open? and @merge_request.source_branch_exists?
.append-bottom-20
.slead
%span
Fetch the branch with
%strong.label-branch<
git fetch
\ #{@merge_request.source_project.http_url_to_repo}
\ #{@merge_request.source_branch}
= render "projects/merge_requests/show/how_to_merge"
= render "projects/merge_requests/widget/show.html.haml"
......
:plain
$(".mr_source_commit").html("#{commit_to_html(@commit, @source_project, false)}");
$('.js-timeago').timeago()
:plain
$(".mr_target_commit").html("#{commit_to_html(@commit, @target_project, false)}");
$('.js-timeago').timeago()
......@@ -5,6 +5,10 @@
%i.fa.fa-pencil-square-o
Edit
= link_to 'Close Milestone', namespace_project_milestone_path(@project.namespace, @project, milestone, milestone: {state_event: :close }), method: :put, remote: true, class: "btn btn-sm btn-close"
= link_to namespace_project_milestone_path(milestone.project.namespace, milestone.project, milestone), data: { confirm: 'Are you sure?' }, method: :delete, class: "btn btn-sm btn-remove" do
%i.fa.fa-trash-o
Remove
%h4
= link_to_gfm truncate(milestone.title, length: 100), namespace_project_milestone_path(milestone.project.namespace, milestone.project, milestone)
- if milestone.expired? and not milestone.closed?
......
......@@ -19,6 +19,9 @@
= link_to 'Close Milestone', namespace_project_milestone_path(@project.namespace, @project, @milestone, milestone: {state_event: :close }), method: :put, class: "btn btn-close btn-grouped"
- else
= link_to 'Reopen Milestone', namespace_project_milestone_path(@project.namespace, @project, @milestone, milestone: {state_event: :activate }), method: :put, class: "btn btn-reopen btn-grouped"
= link_to namespace_project_milestone_path(@project.namespace, @project, @milestone), data: { confirm: 'Are you sure?' }, method: :delete, class: "btn btn-grouped btn-remove" do
%i.fa.fa-trash-o
Remove
%hr
- if @milestone.issues.any? && @milestone.can_be_closed?
......
......@@ -56,10 +56,9 @@
.note-body{class: note_editable?(note) ? 'js-task-list-container' : ''}
= cache [note, 'markdown'] do
.note-text
= preserve do
= markdown(note.note, {no_header_anchors: true})
.note-text
= preserve do
= markdown(note.note, {no_header_anchors: true})
= render 'projects/notes/edit_form', note: note
- if note.attachment.url
......
......@@ -6,14 +6,16 @@
= render 'shared/no_ssh'
= render 'shared/no_password'
= render 'projects/last_push'
- if prefer_readme?
= render 'projects/last_push'
= render "home_panel"
.project-stats
%ul.nav.nav-pills
%li
= link_to namespace_project_commits_path(@project.namespace, @project, @ref || @repository.root_ref) do
= pluralize(number_with_delimiter(@repository.commit_count), 'commit')
= pluralize(number_with_delimiter(@project.commit_count), 'commit')
%li
= link_to namespace_project_branches_path(@project.namespace, @project) do
= pluralize(number_with_delimiter(@repository.branch_names.count), 'branch')
......
......@@ -8,7 +8,7 @@
- else
none
.issuable-context-selectbox
- if can?(current_user, :admin_issue, @project)
- if can?(current_user, :"admin_#{issuable.class.to_s.underscore}", @project)
= users_select_tag("#{issuable.class.table_name.singularize}[assignee_id]", placeholder: 'Select assignee', class: 'custom-form-control js-select2 js-assignee', selected: issuable.assignee_id, project: @target_project, null_user: true)
%div.prepend-top-20.clearfix
......@@ -24,7 +24,7 @@
- else
none
.issuable-context-selectbox
- if can?(current_user, :admin_issue, @project)
- if can?(current_user, :"admin_#{issuable.class.to_s.underscore}", @project)
= f.select(:milestone_id, milestone_options(issuable), { include_blank: 'Select milestone' }, {class: 'select2 select2-compact js-select2 js-milestone'})
= hidden_field_tag :issuable_context
= f.submit class: 'btn hide'
......
class ProjectCacheWorker
include Sidekiq::Worker
sidekiq_options queue: :default
def perform(project_id)
project = Project.find(project_id)
project.update_repository_size
project.update_commit_count
if project.repository.root_ref
project.repository.build_cache
end
end
end
......@@ -28,7 +28,7 @@ class RepositoryImportWorker
project.import_finish
project.save
project.satellite.create unless project.satellite.exists?
project.update_repository_size
ProjectCacheWorker.perform_async(project.id)
Gitlab::BitbucketImport::KeyDeleter.new(project).execute if project.import_type == 'bitbucket'
end
end
......@@ -96,6 +96,7 @@ module Gitlab
end
redis_config_hash[:namespace] = 'cache:gitlab'
redis_config_hash[:expires_in] = 2.weeks # Cache should not grow forever
config.cache_store = :redis_store, redis_config_hash
# This is needed for gitlab-shell
......
......@@ -14,6 +14,7 @@ if Gitlab::LDAP::Config.enabled?
end
end
OmniAuth.config.full_host = Settings.gitlab['url']
OmniAuth.config.allowed_request_methods = [:post]
#In case of auto sign-in, the GET method is used (users don't get to click on a button)
OmniAuth.config.allowed_request_methods << :get if Gitlab.config.omniauth.auto_sign_in_with_provider.present?
......
......@@ -6,7 +6,8 @@ Doorkeeper.configure do
# This block will be called to check whether the resource owner is authenticated or not.
resource_owner_authenticator do
# Put your resource owner authentication logic here.
# Example implementation:
# Ensure user is redirected to redirect_uri after login
session[:user_return_to] = request.fullpath
current_user || redirect_to(new_user_session_url)
end
......
......@@ -520,7 +520,7 @@ Gitlab::Application.routes.draw do
end
end
resources :milestones, except: [:destroy], constraints: { id: /\d+/ } do
resources :milestones, constraints: { id: /\d+/ } do
member do
put :sort_issues
put :sort_merge_requests
......
......@@ -5,7 +5,7 @@ Gitlab::Seeder.quiet do
s.email = 'admin@example.com'
s.notification_email = 'admin@example.com'
s.username = 'root'
s.password = 'password'
s.password = '5iveL!fe'
s.admin = true
s.projects_limit = 100
s.confirmed_at = DateTime.now
......
......@@ -11,9 +11,42 @@ Sidekiq::Testing.inline! do
'https://github.com/twitter/flight.git',
'https://github.com/twitter/typeahead.js.git',
'https://github.com/h5bp/html5-boilerplate.git',
'https://github.com/google/material-design-lite.git',
'https://github.com/jlevy/the-art-of-command-line.git',
'https://github.com/FreeCodeCamp/freecodecamp.git',
'https://github.com/google/deepdream.git',
'https://github.com/jtleek/datasharing.git',
'https://github.com/WebAssembly/design.git',
'https://github.com/airbnb/javascript.git',
'https://github.com/tessalt/echo-chamber-js.git',
'https://github.com/atom/atom.git',
'https://github.com/ipselon/react-ui-builder.git',
'https://github.com/mattermost/platform.git',
'https://github.com/purifycss/purifycss.git',
'https://github.com/facebook/nuclide.git',
'https://github.com/wbkd/awesome-d3.git',
'https://github.com/kilimchoi/engineering-blogs.git',
'https://github.com/gilbarbara/logos.git',
'https://github.com/gaearon/redux.git',
'https://github.com/awslabs/s2n.git',
'https://github.com/arkency/reactjs_koans.git',
'https://github.com/twbs/bootstrap.git',
'https://github.com/chjj/ttystudio.git',
'https://github.com/DrBoolean/mostly-adequate-guide.git',
'https://github.com/octocat/Spoon-Knife.git',
'https://github.com/opencontainers/runc.git',
'https://github.com/googlesamples/android-topeka.git'
]
project_urls.each_with_index do |url, i|
# You can specify how many projects you need during seed execution
size = if ENV['SIZE'].present?
ENV['SIZE'].to_i
else
8
end
project_urls.first(size).each_with_index do |url, i|
group_path, project_path = url.split('/')[-2..-1]
group = Group.find_by(path: group_path)
......
if ENV['GITLAB_ROOT_PASSWORD'].blank?
password = 'password'
password = '5iveL!fe'
expire_time = Time.now
else
password = ENV['GITLAB_ROOT_PASSWORD']
......
class AddSessionExpireDelayForApplicationSettings < ActiveRecord::Migration
def change
add_column :application_settings, :session_expire_delay, :integer, default: 10080, null: false
unless column_exists?(:application_settings, :session_expire_delay)
add_column :application_settings, :session_expire_delay, :integer, default: 10080, null: false
end
end
end
\ No newline at end of file
end
class AddCommitsCountToProject < ActiveRecord::Migration
def change
add_column :projects, :commit_count, :integer, default: 0
end
end
......@@ -455,6 +455,7 @@ ActiveRecord::Schema.define(version: 20150717155058) do
t.boolean "merge_requests_rebase_default", default: true
t.integer "approvals_before_merge", default: 0, null: false
t.boolean "reset_approvals_on_push", default: true
t.integer "commit_count", default: 0
end
add_index "projects", ["created_at", "id"], name: "index_projects_on_created_at_and_id", using: :btree
......
......@@ -49,7 +49,8 @@ Parameters:
"state": "active",
"created_at": "2012-04-29T08:46:00Z"
},
"description":"fixed login page css paddings"
"description":"fixed login page css paddings",
"work_in_progress": false
}
]
```
......@@ -94,7 +95,8 @@ Parameters:
"state": "active",
"created_at": "2012-04-29T08:46:00Z"
},
"description":"fixed login page css paddings"
"description":"fixed login page css paddings",
"work_in_progress": false
}
```
......@@ -118,6 +120,7 @@ Parameters:
"project_id": 4,
"title": "Blanditiis beatae suscipit hic assumenda et molestias nisi asperiores repellat et.",
"description": "Qui voluptatibus placeat ipsa alias quasi. Deleniti rem ut sint. Optio velit qui distinctio.",
"work_in_progress": false,
"state": "reopened",
"created_at": "2015-02-02T19:49:39.159Z",
"updated_at": "2015-02-02T20:08:49.959Z",
......@@ -336,14 +339,6 @@ Parameters:
```json
{
"author": {
"id": 1,
"username": "admin",
"email": "admin@example.com",
"name": "Administrator",
"blocked": false,
"created_at": "2012-04-29T08:46:00Z"
},
"note": "text1"
}
```
......
......@@ -13,3 +13,7 @@ Step-by-step guides on the basics of working with Git and GitLab.
* [Create a project](create-project.md)
* [Create a group](create-group.md)
* [Create a branch](create-branch.md)
* [Fork a project](fork-project.md)
# Basic Git commands
* Go to the master branch to pull the latest changes from there
### Go to the master branch to pull the latest changes from there
```
git checkout master
```
* Download the latest changes in the project, so that you work on an up-to-date copy (this is important to do every time you work on a project), while you setup tracking branches
### Download the latest changes in the project
This is for you to work on an up-to-date copy (it is important to do every time you work on a project), while you setup tracking branches.
```
git pull REMOTE NAME-OF-BRANCH -u
```
(REMOTE: origin) (NAME-OF-BRANCH: could be "master" or an existing branch)
* Create a branch (remember that spaces won't be recognized, you need to use a hyphen or underscore)
### Create a branch
Spaces won't be recognized, so you need to use a hyphen or underscore.
```
git checkout -b NAME-OF-BRANCH
```
* Work on a branch that has already been created
### Work on a branch that has already been created
```
git checkout NAME-OF-BRANCH
```
* To see the changes you've made (it's important to be aware of what's happening and what's the status of your changes)
### View the changes you've made
It's important to be aware of what's happening and what's the status of your changes.
```
git status
```
* Add changes to commit (you'll be able to see your changes in red when you type "git status")
### Add changes to commit
You'll see your changes in red when you type "git status".
```
git add CHANGES IN RED
git commit -m "DESCRIBE THE INTENTION OF THE COMMIT"
```
* Send changes to gitlab.com
### Send changes to gitlab.com
```
git push origin NAME-OF-BRANCH
git push REMOTE NAME-OF-BRANCH
```
* Throw away all changes in the Git repository, but leave unstaged things
### Delete all changes in the Git repository, but leave unstaged things
```
git checkout .
```
* Delete all changes in the Git repository, including untracked files
### Delete all changes in the Git repository, including untracked files
```
git clean -f
```
* Remove all the changes that you don't want to send to gitlab.com
```
git add NAME-OF-FILE -all
```
* Merge created branch with master branch. You need to be in the created branch
### Merge created branch with master branch
You need to be in the created branch.
```
git checkout NAME-OF-BRANCH
git merge master
......
......@@ -2,46 +2,47 @@
## Start working on your project
* In Git, when you copy a project you say you "clone" it. To work on a git project locally (from your own computer), you will need to clone it. To do this, sign in to [GitLab.com](https://gitlab.com)
In Git, when you copy a project you say you "clone" it. To work on a git project locally (from your own computer), you will need to clone it. To do this, sign in to [GitLab.com](https://gitlab.com).
* When you are on your Dashboard, click on the project that you'd like to clone, which you'll find at the right side of your screen
When you are on your Dashboard, click on the project that you'd like to clone, which you'll find at the right side of your screen.
![Select a project](basicsimages/select_project.png)
* To work in the project, you can copy a link to the Git repository through a SSH or a HTTPS protocol. SSH is easier to use after it's been [setup](create-your-ssh-keys.md). When you're in the project, click on the HTTPS or SSH button at the right side of your screen. Then copy the link (you'll have to paste it on your shell in the next step)
To work in the project, you can copy a link to the Git repository through a SSH or a HTTPS protocol. SSH is easier to use after it's been [setup](create-your-ssh-keys.md). When you're in the project, click on the HTTPS or SSH button at the right side of your screen. Then copy the link (you'll have to paste it on your shell in the next step).
![Copy the HTTPS or SSH](basicsimages/https.png)
## On the command line
* To clone your project, go to your computer's shell and type the following command
### Clone your project
Go to your computer's shell and type the following command:
```
git clone PASTE HTTPS OR SSH HERE
```
* A clone of the project will be created in your computer
A clone of the project will be created in your computer.
* Go into a project, directory or file to work in it
### Go into a project, directory or file to work in it
```
cd NAME-OF-PROJECT-OR-FILE
```
* Go back one directory or file
### Go back one directory or file
```
cd ../
```
* To see what’s in the directory that you are in
### View what’s in the directory that you are in
```
ls
```
* Create a directory
### Create a directory
```
mkdir NAME-OF-YOUR-DIRECTORY
```
* Create a README.md or file in directory
### Create a README.md or file in directory
```
touch README.md
nano README.md
......@@ -51,22 +52,23 @@ nano README.md
#### Press: enter
```
* Remove a file
### Remove a file
```
rm NAME-OF-FILE
```
* Remove a directory and all of its contents
### Remove a directory and all of its contents
```
rm -rf NAME-OF-DIRECTORY
```
* View history in the command line
### View history in the command line
```
history
```
* Carry out commands for which the account you are using lacks authority. (You will be asked for an administrator’s password)
### Carry out commands for which the account you are using lacks authority
You will be asked for an administrator’s password.
```
sudo
```
# How to create a branch
A branch is an independent line of development.
New commits are recorded in the history for the current branch, which results in taking the source from someone’s repository (the place where the history of your work is stored) at certain point in time, and apply your own changes to it in the history of the project.
To add changes to your GitLab project, you should create a branch. You can do it in your [shell](basic-git-commands.md) or in GitLab.
To create a new branch in GitLab, sign in and then select a project on the right side of your screen:
![Select a project](basicsimages/select_project.png)
Click on "commits" on the menu on the left side of your screen:
![Commits](basicsimages/commits.png)
Click on the "branches" tab:
![Branches](basicsimages/branches.png)
Click on the "new branch" button on the right side of the screen:
![New branch](basicsimages/newbranch.png)
Fill out the information required:
1. Add a name for your new branch (you can't add spaces, so you can use hyphens or underscores)
1. On the "create from" space, add the the name of the branch you want to branch off from
1. Click on the button "create branch"
![Branch info](basicsimages/branch_info.png)
### Note:
You will be able to find and select the name of your branch in the white box next to a project's name:
![Branch name](basicsimages/branch_name.png)
# How to create a project in GitLab
## Create a project
To create a new project, sign in to [GitLab.com](https://gitlab.com).
* Sign in to [GitLab.com](https://gitlab.com)
* Go to your Dashboard and click on "new project" on the right side of your screen
Go to your Dashboard and click on "new project" on the right side of your screen.
![Create a project](basicsimages/new_project.png)
* Fill out the required information
Fill out the required information:
1. Project path or the name of your project (you can't add spaces, so you can use hyphens or underscores)
......
......@@ -4,34 +4,34 @@ You need to connect your computer to your GitLab account through SSH Keys. They
## Generate your SSH Key
* Create an account on GitLab. Sign up and check your email for your confirmation link
Create an account on GitLab. Sign up and check your email for your confirmation link.
* After you confirm, go to [GitLab.com](https://about.gitlab.com/) and sign in to your account
After you confirm, go to [GitLab.com](https://about.gitlab.com/) and sign in to your account.
## Add your SSH Key
* At the top right corner, click on "profile settings"
At the top right corner, click on "profile settings":
![profile settings](basicsimages/profile_settings.png)
* On the left side menu click on "SSH Keys"
On the left side menu click on "SSH Keys":
![SSH Keys](basicsimages/shh_keys.png)
* Then click on the green button "Add SSH Key"
Then click on the green button "Add SSH Key":
![Add SSH Key](basicsimages/add_sshkey.png)
* There, you should paste the SSH Key that your commandline will generate for you. Below you'll find the steps to generate it
There, you should paste the SSH Key that your command line will generate for you. Below you'll find the steps to generate it:
![Paste SSH Key](basicsimages/paste_sshkey.png)
## To generate an SSH Key on your commandline
## To generate an SSH Key on your command line
* Go to your [commandline](start-using-git.md) and follow the [instructions](https://gitlab.com/help/ssh/README) to generate it
Go to your [command line](start-using-git.md) and follow the [instructions](../ssh/README.md) to generate it.
* Copy the SSH Key that your commandline created and paste it on the "Key" box on the GitLab page. The title will be added automatically
Copy the SSH Key that your command line created and paste it on the "Key" box on the GitLab page. The title will be added automatically.
![Paste SSH Key](basicsimages/key.png)
* Now, you'll be able to use Git over SSH, instead of Git over HTTP.
Now, you'll be able to use Git over SSH, instead of Git over HTTP.
# How to fork a project
A fork is a copy of an original repository that you can put somewhere else
or where you can experiment and apply changes that you can later decide if
publishing or not, without affecting your original project.
It takes just a few steps to fork a project in GitLab.
Sign in to [gitlab.com](https://gitlab.com).
Select a project on the right side of your screen:
![Select a project](basicsimages/select_project.png)
Click on the "fork" button on the right side of your screen:
![Fork](basicsimages/fork.png)
Click on the user or group to where you'd like to add the forked project.
# Start using Git on the commandline
# Start using Git on the command line
If you want to start using a Git and GitLab, make sure that you have created an account on [GitLab.com](https://about.gitlab.com/)
If you want to start using a Git and GitLab, make sure that you have created an account on [GitLab.com](https://about.gitlab.com/).
## Open a shell
* Depending on your operating system, find the shell of your preference. Here are some suggestions
Depending on your operating system, find the shell of your preference. Here are some suggestions.
- [Terminal](http://blog.teamtreehouse.com/introduction-to-the-mac-os-x-command-line) on Mac OSX
......@@ -14,54 +14,48 @@ If you want to start using a Git and GitLab, make sure that you have created an
## Check if Git has already been installed
* Git is usually preinstalled on Mac and Linux
* Type the following command and then press enter
Git is usually preinstalled on Mac and Linux.
Type the following command and then press enter:
```
git --version
```
* You should receive a message that will tell you which Git version you have in your computer. If you don’t receive a "Git version" message, it means that you need to [download Git](https://git-scm.com/book/en/v2/Getting-Started-Installing-Git)
You should receive a message that will tell you which Git version you have in your computer. If you don’t receive a "Git version" message, it means that you need to [download Git](https://git-scm.com/book/en/v2/Getting-Started-Installing-Git).
* If Git doesn't automatically download, there's an option on the website to [download manually](https://git-scm.com/downloads). Then follow the steps on the installation window
If Git doesn't automatically download, there's an option on the website to [download manually](https://git-scm.com/downloads). Then follow the steps on the installation window.
* After you finished installing, open a new shell and type "git --version" again to verify that it was correctly installed
After you finished installing, open a new shell and type "git --version" again to verify that it was correctly installed.
## Add your Git username and set your email
* It is important because every Git commit that you create will use this information
* On your shell, type the following command to add your username
It is important because every Git commit that you create will use this information.
On your shell, type the following command to add your username:
```
git config --global user.name ADD YOUR USERNAME
```
* Then verify that you have the correct username
Then verify that you have the correct username:
```
git config --global user.name
```
* To set your email address, type the following command
To set your email address, type the following command:
```
git config --global user.email ADD YOUR EMAIL
```
* To verify that you entered your email correctly, type
To verify that you entered your email correctly, type:
```
git config --global user.email
```
* You'll need to do this only once because you are using the "--global" option. It tells Git to always use this information for anything you do on that system. If you want to override this with a different username or email address for specific projects, you can run the command without the "--global" option when you’re in that project
You'll need to do this only once because you are using the "--global" option. It tells Git to always use this information for anything you do on that system. If you want to override this with a different username or email address for specific projects, you can run the command without the "--global" option when you’re in that project.
## Check your information
* To view the information that you entered, type
To view the information that you entered, type:
```
git config --global --list
```
......@@ -404,7 +404,7 @@ NOTE: Supply `SANITIZE=true` environment variable to `gitlab:check` to omit proj
Visit YOUR_SERVER in your web browser for your first GitLab login. The setup has created a default admin account for you. You can use it to log in:
root
password
5iveL!fe
**Important Note:** On login you'll be prompted to change the password.
......
......@@ -63,5 +63,10 @@ your phone's application or a recovery code to log in.
1. Go to **Account**.
1. Click **Disable Two-factor Authentication**.
## Note to GitLab administrators
You need to take special care to that 2FA keeps working after
[restoring a GitLab backup](../raketasks/backup_restore.md).
[Google Authenticator]: https://support.google.com/accounts/answer/1066447?hl=en
[FreeOTP]: https://fedorahosted.org/freeotp/
......@@ -9,6 +9,13 @@ 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.
You can only restore a backup to exactly the same version of GitLab that you created it on, for example 7.2.1.
You need to keep a separate copy of `/etc/gitlab/gitlab-secrets.json`
(for omnibus packages) or `/home/git/gitlab/.secret` (for installations
from source). This file contains the database encryption key used
for two-factor authentication. If you restore a GitLab backup without
restoring the database encryption key, users who have two-factor
authentication enabled will loose access to your GitLab server.
If you are interested in GitLab CI backup please follow to the [CI backup documentation](https://gitlab.com/gitlab-org/gitlab-ci/blob/master/doc/raketasks/backup_restore.md)*
```
......@@ -143,15 +150,39 @@ with the name of your bucket:
## Storing configuration files
Please be informed that a backup does not store your configuration files.
Please be informed that a backup does not store your configuration
files. One reason for this is that your database contains encrypted
information for two-factor authentication. Storing encrypted
information along with its key in the same place defeats the purpose
of using encryption in the first place!
If you use an Omnibus package please see the [instructions in the readme to backup your configuration](https://gitlab.com/gitlab-org/omnibus-gitlab/blob/master/README.md#backup-and-restore-omnibus-gitlab-configuration).
If you have a cookbook installation there should be a copy of your configuration in Chef.
If you have an installation from source, please consider backing up your `gitlab.yml` file, any SSL keys and certificates, and your [SSH host keys](https://superuser.com/questions/532040/copy-ssh-keys-from-one-server-to-another-server/532079#532079).
If you have an installation from source, please consider backing up your `.secret` file, `gitlab.yml` file, any SSL keys and certificates, and your [SSH host keys](https://superuser.com/questions/532040/copy-ssh-keys-from-one-server-to-another-server/532079#532079).
At the very **minimum** you should backup `/etc/gitlab/gitlab-secrets.json`
(Omnibus) or `/home/git/gitlab/.secret` (source) to preserve your
database encryption key.
## Restore a previously created backup
You can only restore a backup to exactly the same version of GitLab that you created it on, for example 7.2.1.
### Prerequisites
You need to have a working GitLab installation before you can perform
a restore. This is mainly because the system user performing the
restore actions ('git') is usually not allowed to create or delete
the SQL database it needs to import data into ('gitlabhq_production').
All existing data will be either erased (SQL) or moved to a separate
directory (repositories, uploads).
If some or all of your GitLab users are using two-factor authentication
(2FA) then you must also make sure to restore
`/etc/gitlab/gitlab-secrets.json` (Omnibus) or `/home/git/gitlab/.secret`
(installations from source). Note that you need to run `gitlab-ctl
reconfigure` after changing `gitlab-secrets.json`.
### Installation from source
```
......
......@@ -6,6 +6,7 @@ It starts 7 working days before the release.
The release manager doesn't have to perform all the work but must ensure someone is assigned.
The current release manager must schedule the appointment of the next release manager.
The new release manager should create overall issue to track the progress.
The release manager should be the only person pushing/merging commits to the x-y-stable branches.
## Release Manager
......
......@@ -10,7 +10,7 @@
- [Labels](labels.md)
- [Manage large binaries with git annex](git_annex.md)
- [Merge Request Approvals](merge_request_approvals.md)
- [Notifications](notifications.md)
- [Notification emails](notifications.md)
- [Project Features](project_features.md)
- [Project forking workflow](forking_workflow.md)
- [Protected branches](protected_branches.md)
......
# GitLab Notifications
# GitLab Notification Emails
GitLab has notifications system in place to notify a user of events important for the workflow.
GitLab has a notification system in place to notify a user of events that are important for the workflow.
## Notification settings
......@@ -67,5 +67,3 @@ Below is the table of events users can be notified of:
| Reopen merge request | Project members [1] | [1] higher than participating |
| Merge merge request | MR author [1], MR assignee [2], project members [3] | [1] [2] not disabled, [3] higher than participating |
| New comment | Mentioned users [1], users participating [2], project members [3] | [1] [2] not disabled, [3] higher than participating |
......@@ -30,7 +30,9 @@ RUN ( \
echo "" && \
echo "# Docker options" && \
echo "# Prevent Postgres from trying to allocate 25% of total memory" && \
echo "postgresql['shared_buffers'] = '1MB'" ) >> /etc/gitlab/gitlab.rb
echo "postgresql['shared_buffers'] = '1MB'" ) >> /etc/gitlab/gitlab.rb && \
mkdir -p /assets/ && \
cp /etc/gitlab/gitlab.rb /assets/gitlab.rb
# Expose web & ssh
EXPOSE 443 80 22
......
......@@ -10,7 +10,7 @@ It might take a while before the docker container is responding to queries.
You can check the status with something like `sudo docker logs -f gitlab`.
You can login to the web interface with username `root` and password `password`.
You can login to the web interface with username `root` and password `5iveL!fe`.
Next time, you can just use docker start and stop to run the container.
......@@ -165,3 +165,5 @@ sudo docker push gitlab/gitlab-ce:latest
Please see the [troubleshooting](troubleshooting.md) file in this directory.
Note: We use `fig.yml` to have compatibility with fig and because docker-compose also supports it.
Our docker image runs chef at every start to generate GitLab configuration.
......@@ -13,4 +13,9 @@ function entrypoint() {
gitlab-ctl tail # tail all logs
}
if [[ ! -e /etc/gitlab/gitlab.rb ]]; then
cp /assets/gitlab.rb /etc/gitlab/gitlab.rb
chmod 0600 /etc/gitlab/gitlab.rb
fi
entrypoint
......@@ -17,6 +17,10 @@ Feature: Project Issues Milestones
And I submit new milestone "v2.3"
Then I should see milestone "v2.3"
Scenario: I delete new milestone
Given I click link to remove milestone "v2.2"
And I should see no milestones
@javascript
Scenario: Listing closed issues
Given the milestone has open and closed issues
......
......@@ -56,4 +56,12 @@ class Spinach::Features::ProjectIssuesMilestones < Spinach::FeatureSteps
step 'I should see 3 issues' do
expect(page).to have_selector('#tab-issues li.issue-row', count: 4)
end
step 'I click link to remove milestone "v2.2"' do
click_link 'Remove'
end
step 'I should see no milestones' do
expect(page).to have_content('No milestones to show')
end
end
......@@ -181,6 +181,7 @@ module API
expose :source_project_id, :target_project_id
expose :label_names, as: :labels
expose :description
expose :work_in_progress?, as: :work_in_progress
expose :milestone, using: Entities::Milestone
end
......
......@@ -25,6 +25,7 @@ module Backup
abort 'Backup failed' unless success
$progress.print 'Compressing database ... '
FileUtils.rm_f db_file_name_gz
success = system('gzip', db_file_name)
report_success(success)
abort 'Backup failed: compress error' unless success
......
......@@ -327,7 +327,7 @@ module Gitlab
link = "https://storage.googleapis.com/google-code-attachments/#{@repo.name}/issue-#{issue_id}/comment-#{comment_id}/#{filename}"
text = "[#{filename}](#{link})"
text = "!#{text}" if filename =~ /\.(png|jpg|jpeg|gif|bmp|tiff)\z/
text = "!#{text}" if filename =~ /\.(png|jpg|jpeg|gif|bmp|tiff)\z/i
text
end.compact
end
......
......@@ -187,7 +187,7 @@ module Gitlab
end
def remove_source_branch(repo)
if merge_request.should_remove_source_branch && !project.root_ref?(merge_request.source_branch) && !merge_request.for_fork?
if merge_request.remove_source_branch?
# will raise CommandFailed when push fails
repo.git.push(default_options, :origin, ":#{merge_request.source_branch}")
end
......
......@@ -18,4 +18,12 @@ class RepositoryCache
def fetch(key, &block)
backend.fetch(cache_key(key), &block)
end
def exist?(key)
backend.exist?(cache_key(key))
end
def read(key)
backend.read(cache_key(key))
end
end
......@@ -41,7 +41,7 @@ shell_path="/bin/bash"
test -f /etc/default/gitlab && . /etc/default/gitlab
# Switch to the app_user if it is not he/she who is running the script.
if [ "$USER" != "$app_user" ]; then
if [ `whoami` != "$app_user" ]; then
eval su - "$app_user" -s $shell_path -c $(echo \")$0 "$@"$(echo \"); exit;
fi
......
require 'spec_helper'
describe Projects::MilestonesController do
let(:project) { create(:project) }
let(:user) { create(:user) }
let(:milestone) { create(:milestone, project: project) }
let(:issue) { create(:issue, project: project, milestone: milestone) }
before do
sign_in(user)
project.team << [user, :master]
controller.instance_variable_set(:@project, project)
end
describe "#destroy" do
it "should remove milestone" do
expect(issue.milestone_id).to eq(milestone.id)
delete :destroy, namespace_id: project.namespace.id, project_id: project.id, id: milestone.id, format: :js
expect(response).to be_success
expect { Milestone.find(milestone.id) }.to raise_exception(ActiveRecord::RecordNotFound)
issue.reload
expect(issue.milestone_id).to eq(nil)
# Check system note left for milestone removal
last_note = project.issues.find(issue.id).notes[-1].note
expect(last_note).to eq('Milestone removed')
end
end
end
......@@ -8,9 +8,6 @@ describe Projects::TreeController do
sign_in(user)
project.team << [user, :master]
allow(project).to receive(:branches).and_return(['master', 'foo/bar/baz'])
allow(project).to receive(:tags).and_return(['v1.0.0', 'v2.0.0'])
controller.instance_variable_set(:@project, project)
end
......@@ -44,6 +41,32 @@ describe Projects::TreeController do
let(:id) { 'invalid-branch/encoding/' }
it { is_expected.to respond_with(:not_found) }
end
context "valid empty branch, invalid path" do
let(:id) { 'empty-branch/invalid-path/' }
it { is_expected.to respond_with(:not_found) }
end
context "valid empty branch" do
let(:id) { 'empty-branch' }
it { is_expected.to respond_with(:success) }
end
context "invalid SHA commit ID" do
let(:id) { 'ff39438/.gitignore' }
it { is_expected.to respond_with(:not_found) }
end
context "valid SHA commit ID" do
let(:id) { '6d39438' }
it { is_expected.to respond_with(:success) }
end
context "valid SHA commit ID with path" do
let(:id) { '6d39438/.gitignore' }
it { expect(response.status).to eq(302) }
end
end
describe 'GET show with blob path' do
......
require 'spec_helper'
describe "Admin::Projects", feature: true do
include AccessMatchers
describe "GET /admin/projects" do
subject { admin_namespaces_projects_path }
......
require 'spec_helper'
describe "Dashboard access", feature: true do
include AccessMatchers
describe "GET /dashboard" do
subject { dashboard_path }
......
require 'spec_helper'
describe "Group access", feature: true do
describe "GET /projects/new" do
it { expect(new_group_path).to be_allowed_for :admin }
it { expect(new_group_path).to be_allowed_for :user }
it { expect(new_group_path).to be_denied_for :visitor }
end
describe "Group" do
let(:group) { create(:group) }
let(:owner) { create(:owner) }
let(:master) { create(:user) }
let(:reporter) { create(:user) }
let(:guest) { create(:user) }
let(:nonmember) { create(:user) }
before do
group.add_user(owner, Gitlab::Access::OWNER)
group.add_user(master, Gitlab::Access::MASTER)
group.add_user(reporter, Gitlab::Access::REPORTER)
group.add_user(guest, Gitlab::Access::GUEST)
end
describe "GET /groups/:path" do
subject { group_path(group) }
it { is_expected.to be_allowed_for owner }
it { is_expected.to be_allowed_for master }
it { is_expected.to be_allowed_for reporter }
it { is_expected.to be_allowed_for :admin }
it { is_expected.to be_allowed_for guest }
it { is_expected.to be_denied_for :user }
it { is_expected.to be_denied_for :visitor }
end
describe "GET /groups/:path/issues" do
subject { issues_group_path(group) }
it { is_expected.to be_allowed_for owner }
it { is_expected.to be_allowed_for master }
it { is_expected.to be_allowed_for reporter }
it { is_expected.to be_allowed_for :admin }
it { is_expected.to be_allowed_for guest }
it { is_expected.to be_denied_for :user }
it { is_expected.to be_denied_for :visitor }
end
describe "GET /groups/:path/merge_requests" do
subject { merge_requests_group_path(group) }
it { is_expected.to be_allowed_for owner }
it { is_expected.to be_allowed_for master }
it { is_expected.to be_allowed_for reporter }
it { is_expected.to be_allowed_for :admin }
it { is_expected.to be_allowed_for guest }
it { is_expected.to be_denied_for :user }
it { is_expected.to be_denied_for :visitor }
end
describe "GET /groups/:path/group_members" do
subject { group_group_members_path(group) }
it { is_expected.to be_allowed_for owner }
it { is_expected.to be_allowed_for master }
it { is_expected.to be_allowed_for reporter }
it { is_expected.to be_allowed_for :admin }
it { is_expected.to be_allowed_for guest }
it { is_expected.to be_denied_for :user }
it { is_expected.to be_denied_for :visitor }
end
describe "GET /groups/:path/edit" do
subject { edit_group_path(group) }
it { is_expected.to be_allowed_for owner }
it { is_expected.to be_denied_for master }
it { is_expected.to be_denied_for reporter }
it { is_expected.to be_allowed_for :admin }
it { is_expected.to be_denied_for guest }
it { is_expected.to be_denied_for :user }
it { is_expected.to be_denied_for :visitor }
end
describe "GET /groups/:path/projects" do
subject { projects_group_path(group) }
it { is_expected.to be_allowed_for owner }
it { is_expected.to be_denied_for master }
it { is_expected.to be_denied_for reporter }
it { is_expected.to be_allowed_for :admin }
it { is_expected.to be_denied_for guest }
it { is_expected.to be_denied_for :user }
it { is_expected.to be_denied_for :visitor }
end
end
end
require 'spec_helper'
describe "Group with internal project access", feature: true do
describe "Group" do
let(:group) { create(:group) }
let(:owner) { create(:owner) }
let(:master) { create(:user) }
let(:reporter) { create(:user) }
let(:guest) { create(:user) }
let(:nonmember) { create(:user) }
before do
group.add_user(owner, Gitlab::Access::OWNER)
group.add_user(master, Gitlab::Access::MASTER)
group.add_user(reporter, Gitlab::Access::REPORTER)
group.add_user(guest, Gitlab::Access::GUEST)
create(:project, :internal, group: group)
end
describe "GET /groups/:path" do
subject { group_path(group) }
it { is_expected.to be_allowed_for owner }
it { is_expected.to be_allowed_for master }
it { is_expected.to be_allowed_for reporter }
it { is_expected.to be_allowed_for :admin }
it { is_expected.to be_allowed_for guest }
it { is_expected.to be_allowed_for :user }
it { is_expected.to be_denied_for :visitor }
end
describe "GET /groups/:path/issues" do
subject { issues_group_path(group) }
it { is_expected.to be_allowed_for owner }
it { is_expected.to be_allowed_for master }
it { is_expected.to be_allowed_for reporter }
it { is_expected.to be_allowed_for :admin }
it { is_expected.to be_allowed_for guest }
it { is_expected.to be_allowed_for :user }
it { is_expected.to be_denied_for :visitor }
end
describe "GET /groups/:path/merge_requests" do
subject { merge_requests_group_path(group) }
it { is_expected.to be_allowed_for owner }
it { is_expected.to be_allowed_for master }
it { is_expected.to be_allowed_for reporter }
it { is_expected.to be_allowed_for :admin }
it { is_expected.to be_allowed_for guest }
it { is_expected.to be_allowed_for :user }
it { is_expected.to be_denied_for :visitor }
end
describe "GET /groups/:path/group_members" do
subject { group_group_members_path(group) }
it { is_expected.to be_allowed_for owner }
it { is_expected.to be_allowed_for master }
it { is_expected.to be_allowed_for reporter }
it { is_expected.to be_allowed_for :admin }
it { is_expected.to be_allowed_for guest }
it { is_expected.to be_allowed_for :user }
it { is_expected.to be_denied_for :visitor }
end
describe "GET /groups/:path/edit" do
subject { edit_group_path(group) }
it { is_expected.to be_allowed_for owner }
it { is_expected.to be_denied_for master }
it { is_expected.to be_denied_for reporter }
it { is_expected.to be_allowed_for :admin }
it { is_expected.to be_denied_for guest }
it { is_expected.to be_denied_for :user }
it { is_expected.to be_denied_for :visitor }
end
end
end
require 'spec_helper'
describe "Group access", feature: true do
describe "Group" do
let(:group) { create(:group) }
let(:owner) { create(:owner) }
let(:master) { create(:user) }
let(:reporter) { create(:user) }
let(:guest) { create(:user) }
let(:nonmember) { create(:user) }
before do
group.add_user(owner, Gitlab::Access::OWNER)
group.add_user(master, Gitlab::Access::MASTER)
group.add_user(reporter, Gitlab::Access::REPORTER)
group.add_user(guest, Gitlab::Access::GUEST)
create(:project, :internal, path: "internal_project", group: group)
create(:project, :public, path: "public_project", group: group)
end
describe "GET /groups/:path" do
subject { group_path(group) }
it { is_expected.to be_allowed_for owner }
it { is_expected.to be_allowed_for master }
it { is_expected.to be_allowed_for reporter }
it { is_expected.to be_allowed_for :admin }
it { is_expected.to be_allowed_for guest }
it { is_expected.to be_allowed_for :user }
it { is_expected.to be_allowed_for :visitor }
end
describe "GET /groups/:path/issues" do
subject { issues_group_path(group) }
it { is_expected.to be_allowed_for owner }
it { is_expected.to be_allowed_for master }
it { is_expected.to be_allowed_for reporter }
it { is_expected.to be_allowed_for :admin }
it { is_expected.to be_allowed_for guest }
it { is_expected.to be_allowed_for :user }
it { is_expected.to be_allowed_for :visitor }
end
describe "GET /groups/:path/merge_requests" do
subject { merge_requests_group_path(group) }
it { is_expected.to be_allowed_for owner }
it { is_expected.to be_allowed_for master }
it { is_expected.to be_allowed_for reporter }
it { is_expected.to be_allowed_for :admin }
it { is_expected.to be_allowed_for guest }
it { is_expected.to be_allowed_for :user }
it { is_expected.to be_allowed_for :visitor }
end
describe "GET /groups/:path/group_members" do
subject { group_group_members_path(group) }
it { is_expected.to be_allowed_for owner }
it { is_expected.to be_allowed_for master }
it { is_expected.to be_allowed_for reporter }
it { is_expected.to be_allowed_for :admin }
it { is_expected.to be_allowed_for guest }
it { is_expected.to be_allowed_for :user }
it { is_expected.to be_allowed_for :visitor }
end
describe "GET /groups/:path/edit" do
subject { edit_group_path(group) }
it { is_expected.to be_allowed_for owner }
it { is_expected.to be_denied_for master }
it { is_expected.to be_denied_for reporter }
it { is_expected.to be_allowed_for :admin }
it { is_expected.to be_denied_for guest }
it { is_expected.to be_denied_for :user }
it { is_expected.to be_denied_for :visitor }
end
end
end
require 'spec_helper'
describe "Group with public project access", feature: true do
describe "Group" do
let(:group) { create(:group) }
let(:owner) { create(:owner) }
let(:master) { create(:user) }
let(:reporter) { create(:user) }
let(:guest) { create(:user) }
let(:nonmember) { create(:user) }
before do
group.add_user(owner, Gitlab::Access::OWNER)
group.add_user(master, Gitlab::Access::MASTER)
group.add_user(reporter, Gitlab::Access::REPORTER)
group.add_user(guest, Gitlab::Access::GUEST)
create(:project, :public, group: group)
end
describe "GET /groups/:path" do
subject { group_path(group) }
it { is_expected.to be_allowed_for owner }
it { is_expected.to be_allowed_for master }
it { is_expected.to be_allowed_for reporter }
it { is_expected.to be_allowed_for :admin }
it { is_expected.to be_allowed_for guest }
it { is_expected.to be_allowed_for :user }
it { is_expected.to be_allowed_for :visitor }
end
describe "GET /groups/:path/issues" do
subject { issues_group_path(group) }
it { is_expected.to be_allowed_for owner }
it { is_expected.to be_allowed_for master }
it { is_expected.to be_allowed_for reporter }
it { is_expected.to be_allowed_for :admin }
it { is_expected.to be_allowed_for guest }
it { is_expected.to be_allowed_for :user }
it { is_expected.to be_allowed_for :visitor }
end
describe "GET /groups/:path/merge_requests" do
subject { merge_requests_group_path(group) }
it { is_expected.to be_allowed_for owner }
it { is_expected.to be_allowed_for master }
it { is_expected.to be_allowed_for reporter }
it { is_expected.to be_allowed_for :admin }
it { is_expected.to be_allowed_for guest }
it { is_expected.to be_allowed_for :user }
it { is_expected.to be_allowed_for :visitor }
end
describe "GET /groups/:path/group_members" do
subject { group_group_members_path(group) }
it { is_expected.to be_allowed_for owner }
it { is_expected.to be_allowed_for master }
it { is_expected.to be_allowed_for reporter }
it { is_expected.to be_allowed_for :admin }
it { is_expected.to be_allowed_for guest }
it { is_expected.to be_allowed_for :user }
it { is_expected.to be_allowed_for :visitor }
end
describe "GET /groups/:path/edit" do
subject { edit_group_path(group) }
it { is_expected.to be_allowed_for owner }
it { is_expected.to be_denied_for master }
it { is_expected.to be_denied_for reporter }
it { is_expected.to be_allowed_for :admin }
it { is_expected.to be_denied_for guest }
it { is_expected.to be_denied_for :user }
it { is_expected.to be_denied_for :visitor }
end
end
end
This diff is collapsed.
require 'spec_helper'
describe "Profile access", feature: true do
before do
@u1 = create(:user)
end
describe "GET /login" do
it { expect(new_user_session_path).not_to be_not_found_for :visitor }
end
include AccessMatchers
describe "GET /profile/keys" do
subject { profile_keys_path }
it { is_expected.to be_allowed_for @u1 }
it { is_expected.to be_allowed_for :admin }
it { is_expected.to be_allowed_for :user }
it { is_expected.to be_denied_for :visitor }
......@@ -21,7 +14,6 @@ describe "Profile access", feature: true do
describe "GET /profile" do
subject { profile_path }
it { is_expected.to be_allowed_for @u1 }
it { is_expected.to be_allowed_for :admin }
it { is_expected.to be_allowed_for :user }
it { is_expected.to be_denied_for :visitor }
......@@ -30,7 +22,6 @@ describe "Profile access", feature: true do
describe "GET /profile/account" do
subject { profile_account_path }
it { is_expected.to be_allowed_for @u1 }
it { is_expected.to be_allowed_for :admin }
it { is_expected.to be_allowed_for :user }
it { is_expected.to be_denied_for :visitor }
......@@ -39,7 +30,6 @@ describe "Profile access", feature: true do
describe "GET /profile/preferences" do
subject { profile_preferences_path }
it { is_expected.to be_allowed_for @u1 }
it { is_expected.to be_allowed_for :admin }
it { is_expected.to be_allowed_for :user }
it { is_expected.to be_denied_for :visitor }
......@@ -48,7 +38,6 @@ describe "Profile access", feature: true do
describe "GET /profile/audit_log" do
subject { audit_log_profile_path }
it { is_expected.to be_allowed_for @u1 }
it { is_expected.to be_allowed_for :admin }
it { is_expected.to be_allowed_for :user }
it { is_expected.to be_denied_for :visitor }
......@@ -57,7 +46,6 @@ describe "Profile access", feature: true do
describe "GET /profile/notifications" do
subject { profile_notifications_path }
it { is_expected.to be_allowed_for @u1 }
it { is_expected.to be_allowed_for :admin }
it { is_expected.to be_allowed_for :user }
it { is_expected.to be_denied_for :visitor }
......
require 'spec_helper'
describe "Internal Project Access", feature: true do
include AccessMatchers
let(:project) { create(:project, :internal) }
let(:master) { create(:user) }
......
require 'spec_helper'
describe "Private Project Access", feature: true do
include AccessMatchers
let(:project) { create(:project) }
let(:master) { create(:user) }
......
require 'spec_helper'
describe "Public Project Access", feature: true do
include AccessMatchers
let(:project) { create(:project) }
let(:master) { create(:user) }
......@@ -17,7 +19,6 @@ describe "Public Project Access", feature: true do
# readonly
project.team << [reporter, :reporter]
end
describe "Project should be public" do
......
......@@ -382,6 +382,11 @@
"fileName" : "screenshot.png",
"fileSize" : 0,
"mimetype" : "image/png"
}, {
"attachmentId" : "001",
"fileName" : "screenshot1.PNG",
"fileSize" : 0,
"mimetype" : "image/x-png"
} ]
}, {
"id" : 1,
......
......@@ -2,7 +2,9 @@
.file-content
.line-numbers
- 1.upto(25) do |i|
%a{href: "#L#{i}", id: "L#{i}", 'data-line-number' => i}= i
%a{href: "#L#{i}", id: "L#{i}", 'data-line-number' => i}
%i.fa.fa-link
= i
%pre.code.highlight
%code
- 1.upto(25) do |i|
......
......@@ -48,6 +48,14 @@ describe 'LineHighlighter', ->
clickLine(13)
expect(spy).toHaveBeenPrevented()
it 'handles clicking on a child icon element', ->
spy = spyOn(@class, 'setHash').and.callThrough()
$('#L13 i').mousedown().click()
expect(spy).toHaveBeenCalledWith(13)
expect($('#LC13')).toHaveClass(@css)
describe 'without shiftKey', ->
it 'highlights one line when clicked', ->
clickLine(13)
......
......@@ -65,6 +65,7 @@ describe Gitlab::GoogleCodeImport::Importer do
expect(issue.description).to include('all the best!')
expect(issue.description).to include('[tint2_task_scrolling.diff](https://storage.googleapis.com/google-code-attachments/tint2/issue-169/comment-0/tint2_task_scrolling.diff)')
expect(issue.description).to include('![screenshot.png](https://storage.googleapis.com/google-code-attachments/tint2/issue-169/comment-0/screenshot.png)')
expect(issue.description).to include('![screenshot1.PNG](https://storage.googleapis.com/google-code-attachments/tint2/issue-169/comment-0/screenshot1.PNG)')
end
it "imports issue comments" do
......
......@@ -26,6 +26,33 @@ describe GitlabCiService do
it { is_expected.to have_one(:service_hook) }
end
describe 'validations' do
context 'active' do
before { allow(subject).to receive(:activated?).and_return(true) }
it { is_expected.to validate_presence_of(:token) }
it { is_expected.to validate_presence_of(:project_url) }
it { is_expected.to allow_value('ewf9843kdnfdfs89234n').for(:token) }
it { is_expected.to allow_value('http://ci.example.com/project/1').for(:project_url) }
it { is_expected.not_to allow_value('token with spaces').for(:token) }
it { is_expected.not_to allow_value('token/with%spaces').for(:token) }
it { is_expected.not_to allow_value('this is not url').for(:project_url) }
it { is_expected.not_to allow_value('http//noturl').for(:project_url) }
it { is_expected.not_to allow_value('ftp://ci.example.com/projects/3').for(:project_url) }
end
context 'inactive' do
before { allow(subject).to receive(:activated?).and_return(false) }
it { is_expected.not_to validate_presence_of(:token) }
it { is_expected.not_to validate_presence_of(:project_url) }
it { is_expected.to allow_value('ewf9843kdnfdfs89234n').for(:token) }
it { is_expected.to allow_value('http://ci.example.com/project/1').for(:project_url) }
it { is_expected.to allow_value('token with spaces').for(:token) }
it { is_expected.to allow_value('ftp://ci.example.com/projects/3').for(:project_url) }
end
end
describe 'commits methods' do
before do
@service = GitlabCiService.new
......
......@@ -14,10 +14,13 @@ describe API::API, api: true do
describe "GET /projects/:id/repository/branches" do
it "should return an array of project branches" do
project.repository.expire_cache
get api("/projects/#{project.id}/repository/branches", user)
expect(response.status).to eq(200)
expect(json_response).to be_an Array
expect(json_response.first['name']).to eq(project.repository.branch_names.first)
branch_names = json_response.map { |x| x['name'] }
expect(branch_names).to match_array(project.repository.branch_names)
end
end
......
......@@ -89,7 +89,7 @@ describe API::API, api: true do
it 'returns projects in the correct order when ci_enabled_first parameter is passed' do
[project, project2, project3].each{ |project| project.build_missing_services }
project2.gitlab_ci_service.update(active: true, token: "token", project_url: "url")
project2.gitlab_ci_service.update(active: true, token: "token", project_url: "http://ci.example.com/projects/1")
get api('/projects', user), { ci_enabled_first: 'true' }
expect(response.status).to eq(200)
expect(json_response).to be_an Array
......
......@@ -7,7 +7,7 @@ describe API::API, api: true do
describe "POST /projects/:id/services/gitlab-ci" do
it "should update gitlab-ci settings" do
put api("/projects/#{project.id}/services/gitlab-ci", user), token: 'secret-token', project_url: "http://ci.example.com/projects/1"
put api("/projects/#{project.id}/services/gitlab-ci", user), token: 'secrettoken', project_url: "http://ci.example.com/projects/1"
expect(response.status).to eq(200)
end
......@@ -17,6 +17,18 @@ describe API::API, api: true do
expect(response.status).to eq(400)
end
it "should return if the format of token is invalid" do
put api("/projects/#{project.id}/services/gitlab-ci", user), token: 'token-with dashes and spaces%', project_url: "http://ci.example.com/projects/1", active: true
expect(response.status).to eq(404)
end
it "should return if the format of token is invalid" do
put api("/projects/#{project.id}/services/gitlab-ci", user), token: 'token-with dashes and spaces%', project_url: "ftp://ci.example/projects/1", active: true
expect(response.status).to eq(404)
end
end
describe "DELETE /projects/:id/services/gitlab-ci" do
......
RSpec::Matchers.define :be_valid_commit do
match do |actual|
actual &&
actual.id == ValidCommit::ID &&
actual.message == ValidCommit::MESSAGE &&
actual.author_name == ValidCommit::AUTHOR_FULL_NAME
end
end
def emulate_user(user)
user = case user
when :user then create(:user)
when :visitor then nil
when :admin then create(:admin)
else user
end
login_with(user) if user
end
RSpec::Matchers.define :be_allowed_for do |user|
match do |url|
emulate_user(user)
visit url
status_code != 404 && current_path != new_user_session_path
end
end
RSpec::Matchers.define :be_denied_for do |user|
match do |url|
emulate_user(user)
visit url
status_code == 404 || current_path == new_user_session_path
end
end
RSpec::Matchers.define :be_not_found_for do |user|
match do |url|
emulate_user(user)
visit url
status_code == 404
end
end
RSpec::Matchers.define :include_module do |expected|
match do
described_class.included_modules.include?(expected)
end
description do
"includes the #{expected} module"
end
failure_message do
"expected #{described_class} to include the #{expected} module"
end
end
# Extend shoulda-matchers
module Shoulda::Matchers::ActiveModel
class ValidateLengthOfMatcher
# Shortcut for is_at_least and is_at_most
def is_within(range)
is_at_least(range.min) && is_at_most(range.max)
end
end
end
# AccessMatchers
#
# The custom matchers contained in this module are used to test a user's access
# to a URL by emulating a specific user or type of user account, visiting the
# URL, and then checking the response status code and resulting path.
module AccessMatchers
extend RSpec::Matchers::DSL
include Warden::Test::Helpers
def emulate_user(user)
case user
when :user
login_as(create(:user))
when :visitor
logout
when :admin
login_as(create(:admin))
when User
login_as(user)
else
raise ArgumentError, "cannot emulate user #{user}"
end
end
def description_for(user, type)
if user.kind_of?(User)
# User#inspect displays too much information for RSpec's description
# messages
"be #{type} for supplied User"
else
"be #{type} for #{user}"
end
end
matcher :be_allowed_for do |user|
match do |url|
emulate_user(user)
visit url
status_code != 404 && current_path != new_user_session_path
end
description { description_for(user, 'allowed') }
end
matcher :be_denied_for do |user|
match do |url|
emulate_user(user)
visit url
status_code == 404 || current_path == new_user_session_path
end
description { description_for(user, 'denied') }
end
end
RSpec::Matchers.define :include_module do |expected|
match do
described_class.included_modules.include?(expected)
end
description do
"includes the #{expected} module"
end
failure_message do
"expected #{described_class} to include the #{expected} module"
end
end
# Extend shoulda-matchers
module Shoulda::Matchers::ActiveModel
class ValidateLengthOfMatcher
# Shortcut for is_at_least and is_at_most
def is_within(range)
is_at_least(range.min) && is_at_most(range.max)
end
end
end
......@@ -5,6 +5,7 @@ module TestEnv
# When developing the seed repository, comment out the branch you will modify.
BRANCH_SHA = {
'empty-branch' => '7efb185',
'flatten-dir' => 'e56497b',
'feature' => '0b4bc9a',
'feature_conflict' => 'bb5206f',
......@@ -14,9 +15,13 @@ module TestEnv
'master' => '5937ac0'
}
FORKED_BRANCH_SHA = BRANCH_SHA.merge({
'add-submodule-version-bump' => '3f547c08'
})
# gitlab-test-fork is a fork of gitlab-fork, but we don't necessarily
# need to keep all the branches in sync.
# We currently only need a subset of the branches
FORKED_BRANCH_SHA = {
'add-submodule-version-bump' => '3f547c08',
'master' => '5937ac0'
}
# Test environment
#
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment