Merge branch 'master' of dev.gitlab.org:gitlab/gitlab-ee
@@ -1,6 +1,24 @@
|
||||
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)
|
||||
|
||||
@@ -1,6 +1,15 @@
|
||||
v 7.13 (Unrelease)
|
||||
v 7.13.2
|
||||
- Fix group web hook
|
||||
|
||||
v 7.13.1
|
||||
- Merge community edition changes for version 7.13.1
|
||||
- Fix: "Rebase before merge" doesn't work when source branch is in the same project
|
||||
|
||||
v 7.13
|
||||
- Fix git hook validation on initial push to master branch.
|
||||
- Reset approvals on push
|
||||
- Fix 500 error when the source project of an MR is deleted
|
||||
- Ability to define merge request approvers
|
||||
|
||||
v 7.12.2
|
||||
- Fixed the alignment of project settings icons
|
||||
@@ -171,4 +180,4 @@ v 6.2.0
|
||||
- Use omniauth-ldap nickname attribute as GitLab username
|
||||
- Improve group sharing UI for installation with many groups
|
||||
- Fix empty LDAP group raises exception
|
||||
- Respect LDAP user filter for git access
|
||||
- Respect LDAP user filter for git access
|
||||
@@ -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'
|
||||
|
||||
|
||||
@@ -1,3 +1,10 @@
|
||||
# GitLab
|
||||
|
||||
[](https://ci.gitlab.com/projects/1?ref=master)
|
||||
[](https://semaphoreapp.com/gitlabhq/gitlabhq)
|
||||
[](https://codeclimate.com/github/gitlabhq/gitlabhq)
|
||||
[](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.
|
||||
There are two editions of GitLab:
|
||||
|
||||
*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/).
|
||||
- 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/).
|
||||
|
||||
## Code status
|
||||
|
||||
- [](https://ci.gitlab.com/projects/1?ref=master) on ci.gitlab.com (master branch)
|
||||
|
||||
- [](https://semaphoreapp.com/gitlabhq/gitlabhq)
|
||||
|
||||
- [](https://codeclimate.com/github/gitlabhq/gitlabhq)
|
||||
|
||||
- [](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,7 +68,31 @@ On [about.gitlab.com](https://about.gitlab.com/) you can find more information a
|
||||
|
||||
## Requirements
|
||||
|
||||
GitLab requires the following software:
|
||||
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 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 **`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
|
||||
@@ -78,15 +100,7 @@ GitLab requires the following software:
|
||||
- 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.
|
||||
|
||||
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.
|
||||
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.
|
||||
[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
|
||||
|
||||
@@ -0,0 +1,14 @@
|
||||
class Projects::ApproversController < ApplicationController
|
||||
def destroy
|
||||
if params[:merge_request_id]
|
||||
authorize_create_merge_request!
|
||||
merge_request = project.merge_requests.find_by!(iid: params[:merge_request_id])
|
||||
merge_request.approvers.find(params[:id]).destroy
|
||||
else
|
||||
authorize_admin_project!
|
||||
project.approvers.find(params[:id]).destroy
|
||||
end
|
||||
|
||||
redirect_to :back
|
||||
end
|
||||
end
|
||||
@@ -149,6 +149,7 @@ class Projects::MergeRequestsController < Projects::ApplicationController
|
||||
|
||||
def automerge
|
||||
return access_denied! unless @merge_request.can_be_merged_by?(current_user)
|
||||
return render_404 unless @merge_request.approved?
|
||||
|
||||
if @merge_request.automergeable?
|
||||
AutoMergeWorker.perform_async(@merge_request.id, current_user.id, params)
|
||||
@@ -201,6 +202,10 @@ class Projects::MergeRequestsController < Projects::ApplicationController
|
||||
end
|
||||
|
||||
def approve
|
||||
unless @merge_request.can_approve?(current_user)
|
||||
return render_404
|
||||
end
|
||||
|
||||
@approval = @merge_request.approvals.new
|
||||
@approval.user = current_user
|
||||
|
||||
@@ -286,7 +291,7 @@ class Projects::MergeRequestsController < Projects::ApplicationController
|
||||
def merge_request_params
|
||||
params.require(:merge_request).permit(
|
||||
:title, :assignee_id, :source_project_id, :source_branch,
|
||||
:target_project_id, :target_branch, :milestone_id,
|
||||
:target_project_id, :target_branch, :milestone_id, :approver_ids,
|
||||
:state_event, :description, :task_num, label_ids: []
|
||||
)
|
||||
end
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
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]
|
||||
|
||||
@@ -195,7 +195,7 @@ class ProjectsController < ApplicationController
|
||||
:issues_enabled, :merge_requests_enabled, :snippets_enabled, :issues_tracker_id, :default_branch,
|
||||
:wiki_enabled, :merge_requests_template, :visibility_level, :merge_requests_rebase_enabled,
|
||||
:import_url, :last_activity_at, :namespace_id, :avatar, :merge_requests_rebase_default,
|
||||
:approvals_before_merge
|
||||
:approvals_before_merge, :approver_ids
|
||||
)
|
||||
end
|
||||
|
||||
|
||||
@@ -68,4 +68,42 @@ module MergeRequestsHelper
|
||||
}
|
||||
)
|
||||
end
|
||||
|
||||
def render_items_list(items, separator = "and")
|
||||
items_cnt = items.size
|
||||
|
||||
case items_cnt
|
||||
when 1
|
||||
items.first
|
||||
when 2
|
||||
"#{items.first} #{separator} #{items.last}"
|
||||
else
|
||||
last_item = items.pop
|
||||
"#{items.join(", ")} #{separator} #{last_item}"
|
||||
end
|
||||
end
|
||||
|
||||
def render_require_section(merge_request)
|
||||
str = if merge_request.approvals_left == 1
|
||||
"Requires one more approval"
|
||||
else
|
||||
"Requires #{merge_request.approvals_left} more approvals"
|
||||
end
|
||||
|
||||
if merge_request.approvers_left.any?
|
||||
more_approvals = merge_request.approvals_left - merge_request.approvers_left.count
|
||||
approvers_names = merge_request.approvers_left.map(&:name)
|
||||
|
||||
case true
|
||||
when more_approvals > 0
|
||||
str << " (from #{render_items_list(approvers_names + ["#{more_approvals} more"])})"
|
||||
when more_approvals < 0
|
||||
str << " (from #{render_items_list(approvers_names, "or")})"
|
||||
else
|
||||
str << " (from #{render_items_list(approvers_names)})"
|
||||
end
|
||||
end
|
||||
|
||||
str
|
||||
end
|
||||
end
|
||||
|
||||
@@ -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 = []
|
||||
|
||||
|
||||
@@ -1,3 +1,14 @@
|
||||
# == Schema Information
|
||||
#
|
||||
# Table name: approvals
|
||||
#
|
||||
# id :integer not null, primary key
|
||||
# merge_request_id :integer not null
|
||||
# user_id :integer not null
|
||||
# created_at :datetime
|
||||
# updated_at :datetime
|
||||
#
|
||||
|
||||
class Approval < ActiveRecord::Base
|
||||
belongs_to :user
|
||||
belongs_to :merge_request
|
||||
|
||||
@@ -0,0 +1,16 @@
|
||||
# == Schema Information
|
||||
#
|
||||
# Table name: approvers
|
||||
#
|
||||
# id :integer not null, primary key
|
||||
# target_id :integer not null
|
||||
# target_type :string(255)
|
||||
# user_id :integer not null
|
||||
# created_at :datetime
|
||||
# updated_at :datetime
|
||||
#
|
||||
|
||||
class Approver < ActiveRecord::Base
|
||||
belongs_to :target, polymorphic: true
|
||||
belongs_to :user
|
||||
end
|
||||
@@ -36,6 +36,7 @@ class MergeRequest < ActiveRecord::Base
|
||||
|
||||
has_one :merge_request_diff, dependent: :destroy
|
||||
has_many :approvals, dependent: :destroy
|
||||
has_many :approvers, as: :target, dependent: :destroy
|
||||
|
||||
after_create :create_merge_request_diff
|
||||
after_update :update_merge_request_diff
|
||||
@@ -239,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
|
||||
@@ -419,16 +424,29 @@ class MergeRequest < ActiveRecord::Base
|
||||
approvals_required - approvals.count
|
||||
end
|
||||
|
||||
def approvers_left
|
||||
user_ids = overall_approvers.map(&:user_id) - approvals.map(&:user_id)
|
||||
User.where id: user_ids
|
||||
end
|
||||
|
||||
def approvals_required
|
||||
target_project.approvals_before_merge
|
||||
end
|
||||
|
||||
def requires_approve?
|
||||
!approvals_required.zero?
|
||||
approvals_required.nonzero?
|
||||
end
|
||||
|
||||
def overall_approvers
|
||||
if approvers.any?
|
||||
approvers
|
||||
else
|
||||
target_project.approvers
|
||||
end
|
||||
end
|
||||
|
||||
def approved?
|
||||
approvals.count >= approvals_required
|
||||
approvals_left.zero?
|
||||
end
|
||||
|
||||
def approved_by?(user)
|
||||
@@ -439,6 +457,15 @@ class MergeRequest < ActiveRecord::Base
|
||||
approvals.map(&:user)
|
||||
end
|
||||
|
||||
def can_approve?(user)
|
||||
approvers_left.include?(user) ||
|
||||
(any_approver_allowed? && !approved_by?(user))
|
||||
end
|
||||
|
||||
def any_approver_allowed?
|
||||
approvals_left > approvers_left.count
|
||||
end
|
||||
|
||||
def has_ci?
|
||||
source_project.ci_service && commits.any?
|
||||
end
|
||||
@@ -460,4 +487,10 @@ class MergeRequest < ActiveRecord::Base
|
||||
"Open"
|
||||
end
|
||||
end
|
||||
|
||||
def approver_ids=(value)
|
||||
value.split(",").map(&:strip).each do |user_id|
|
||||
approvers.find_or_initialize_by(user_id: user_id, target_id: id)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -117,6 +117,7 @@ class Project < ActiveRecord::Base
|
||||
has_many :deploy_keys, through: :deploy_keys_projects
|
||||
has_many :users_star_projects, dependent: :destroy
|
||||
has_many :starrers, through: :users_star_projects, source: :user
|
||||
has_many :approvers, as: :target, dependent: :destroy
|
||||
|
||||
has_many :project_group_links, dependent: :destroy
|
||||
has_many :invited_groups, through: :project_group_links, source: :group
|
||||
@@ -511,7 +512,7 @@ class Project < ActiveRecord::Base
|
||||
end
|
||||
if group
|
||||
group.hooks.send(hooks_scope).each do |hook|
|
||||
hook.async_execute(data)
|
||||
hook.async_execute(data, hooks_scope.to_s)
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -702,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
|
||||
@@ -760,4 +765,10 @@ class Project < ActiveRecord::Base
|
||||
def jira_tracker_active?
|
||||
jira_tracker? && jira_service.active
|
||||
end
|
||||
|
||||
def approver_ids=(value)
|
||||
value.split(",").map(&:strip).each do |user_id|
|
||||
approvers.find_or_create_by(user_id: user_id, target_id: id)
|
||||
end
|
||||
end
|
||||
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
|
||||
|
||||
@@ -74,7 +74,7 @@ module MergeRequests
|
||||
# Reset approvals for merge request
|
||||
# Note: we should reset approvals for merge requests from forks too
|
||||
def reset_approvals_for_merge_requests
|
||||
if @project.approvals_before_merge.nonzero? && @project.reset_approvers_on_push
|
||||
if @project.approvals_before_merge.nonzero? && @project.reset_approvals_on_push
|
||||
merge_requests = @project.merge_requests.opened.where(source_branch: @branch_name).to_a
|
||||
merge_requests += @fork_merge_requests.where(source_branch: @branch_name).to_a
|
||||
merge_requests = filter_merge_requests(merge_requests)
|
||||
|
||||
@@ -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)
|
||||
·
|
||||
= link_to pluralize(project.repository.branch_names.count, 'branch'), namespace_project_branches_path(project.namespace, project)
|
||||
·
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -28,11 +28,40 @@
|
||||
.col-sm-10
|
||||
= f.number_field :approvals_before_merge, class: "form-control", min: 0
|
||||
.help-block
|
||||
How many users should approve merge request before it can be accepted. 0 - approval is disabled
|
||||
Number of users to approve a merge request before it can be accepted. 0 - approving is disabled
|
||||
|
||||
.form-group.reset-approvers-on-push
|
||||
.form-group.reset-approvals-on-push
|
||||
.col-sm-offset-2.col-sm-10
|
||||
.checkbox
|
||||
= f.label :reset_approvers_on_push do
|
||||
= f.check_box :reset_approvers_on_push
|
||||
%span.descr Reset approvers on push
|
||||
= f.label :reset_approvals_on_push do
|
||||
= f.check_box :reset_approvals_on_push
|
||||
%span.descr Reset approvals on push
|
||||
.help-block Approvals are reset when new data is pushed to the merge request
|
||||
|
||||
.form-group
|
||||
= f.label :approver_ids, class: 'control-label' do
|
||||
Approvers
|
||||
.col-sm-10
|
||||
= users_select_tag("project[approver_ids]", multiple: true, class: 'input-large', scope: :all, email_user: true)
|
||||
.help-block
|
||||
Add an approver suggestion for each merge request
|
||||
|
||||
.panel.panel-default.prepend-top-10
|
||||
.panel-heading
|
||||
Approvers
|
||||
%small
|
||||
(#{@project.approvers.count(:all)})
|
||||
%ul.well-list
|
||||
- @project.approvers.each do |approver|
|
||||
%li
|
||||
= link_to approver.user.name, approver.user
|
||||
.pull-right
|
||||
= link_to namespace_project_approver_path(@project.namespace, @project, approver), data: { confirm: "Are you sure you want to remove approver #{approver.user.name}"}, method: :delete, class: "btn-xs btn btn-remove", title: 'Remove approver' do
|
||||
= icon("sign-out")
|
||||
Remove
|
||||
- if @project.approvers.empty?
|
||||
%li There are no approvers
|
||||
|
||||
|
||||
:coffeescript
|
||||
new UsersSelect()
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
.project-edit-container
|
||||
.project-edit-errors
|
||||
.project-edit-content
|
||||
%div
|
||||
.panel
|
||||
%h3.page-title
|
||||
Project settings
|
||||
%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
|
||||
|
||||
%span
|
||||
%i.fa.fa-comments
|
||||
= note_count
|
||||
- else
|
||||
|
||||
%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
|
||||
|
||||
%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
|
||||
|
||||
%span.issue-no-comments
|
||||
%i.fa.fa-comments
|
||||
= 0
|
||||
|
||||
.pull-right.issue-updated-at
|
||||
%small updated #{time_ago_with_tooltip(issue.updated_at, placement: 'bottom', html_class: 'issue_update_ago')}
|
||||
.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
|
||||
|
||||
%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')}
|
||||
|
||||
@@ -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"
|
||||
|
||||
|
||||
@@ -1,2 +1,3 @@
|
||||
:plain
|
||||
$(".mr_source_commit").html("#{commit_to_html(@commit, @source_project, false)}");
|
||||
$('.js-timeago').timeago()
|
||||
|
||||
@@ -1,2 +1,3 @@
|
||||
:plain
|
||||
$(".mr_target_commit").html("#{commit_to_html(@commit, @target_project, false)}");
|
||||
$('.js-timeago').timeago()
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
%div
|
||||
%h4
|
||||
Requires #{pluralize(@merge_request.approvals_left, 'more approval')}
|
||||
%p Each merge request in this project must be approved by #{pluralize(@merge_request.approvals_required, 'person')} before it can be accepted.
|
||||
- unless @merge_request.approved_by?(current_user)
|
||||
= render_require_section(@merge_request)
|
||||
|
||||
- if @merge_request.can_approve?(current_user)
|
||||
.append-bottom-10
|
||||
= form_for [:approve, @project.namespace.becomes(Namespace), @project, @merge_request], method: :post do |f|
|
||||
= f.submit "Approve Merge Request", class: "btn btn-primary approve-btn"
|
||||
= f.submit "Approve Merge Request", class: "btn btn-primary approve-btn"
|
||||
|
||||
@@ -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'
|
||||
|
||||
@@ -81,6 +81,33 @@
|
||||
= link_to 'Create new label', new_namespace_project_label_path(issuable.project.namespace, issuable.project), target: :blank
|
||||
|
||||
- if issuable.is_a?(MergeRequest)
|
||||
- if @project.approvals_before_merge.nonzero?
|
||||
.form-group
|
||||
= f.label :approver_ids, class: 'control-label' do
|
||||
Approvers
|
||||
.col-sm-10
|
||||
= users_select_tag("merge_request[approver_ids]", multiple: true, class: 'input-large', scope: :all, email_user: true)
|
||||
.help-block
|
||||
Merge Request should be approved by these users.
|
||||
- if @project.approvers.any?
|
||||
Suggested approver(s): #{render_items_list(@project.approvers.map{ |approver| approver.user.name})}.
|
||||
You can override the project settings by setting your own list of approvers.
|
||||
|
||||
.panel.panel-default.prepend-top-10
|
||||
.panel-heading
|
||||
Approvers
|
||||
%small
|
||||
(#{@merge_request.approvers.count(:all)})
|
||||
%ul.well-list
|
||||
- @merge_request.approvers.each do |approver|
|
||||
%li
|
||||
= link_to approver.user.name, approver.user
|
||||
.pull-right
|
||||
= link_to namespace_project_merge_request_approver_path(@project.namespace, @project, @merge_request, approver), data: { confirm: "Are you sure you want to remove approver #{approver.user.name}"}, method: :delete, class: "btn-xs btn btn-remove", title: 'Remove approver' do
|
||||
= icon("sign-out")
|
||||
Remove
|
||||
- if @merge_request.approvers.empty?
|
||||
%li There are no approvers
|
||||
%hr
|
||||
- if @merge_request.new_record?
|
||||
.form-group
|
||||
|
||||
@@ -0,0 +1,15 @@
|
||||
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
|
||||
|
||||
|
||||
@@ -507,6 +507,7 @@ Gitlab::Application.routes.draw do
|
||||
get :branch_to
|
||||
get :update_branches
|
||||
end
|
||||
resources :approvers, only: :destroy
|
||||
end
|
||||
|
||||
resources :branches, only: [:index, :new, :create, :destroy], constraints: { id: Gitlab::Regex.git_reference_regex }
|
||||
@@ -519,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
|
||||
@@ -569,6 +570,8 @@ Gitlab::Application.routes.draw do
|
||||
get ":secret/:filename", action: :show, as: :show, constraints: { filename: /[^\/]+/ }
|
||||
end
|
||||
end
|
||||
|
||||
resources :approvers, only: :destroy
|
||||
end
|
||||
|
||||
get "/audit_events" => "audit_events#project_log"
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
if ENV['GITLAB_ROOT_PASSWORD'].blank?
|
||||
password = 'password'
|
||||
password = '5iveL!fe'
|
||||
expire_time = Time.now
|
||||
else
|
||||
password = ENV['GITLAB_ROOT_PASSWORD']
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
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
|
||||
end
|
||||
|
||||
@@ -0,0 +1,14 @@
|
||||
class AddApproversTable < ActiveRecord::Migration
|
||||
def change
|
||||
create_table :approvers do |t|
|
||||
t.integer :target_id, null: false
|
||||
t.string :target_type
|
||||
t.integer :user_id, null: false
|
||||
|
||||
t.timestamps
|
||||
|
||||
t.index [:target_id, :target_type]
|
||||
t.index :user_id
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,5 @@
|
||||
class AddCommitsCountToProject < ActiveRecord::Migration
|
||||
def change
|
||||
add_column :projects, :commit_count, :integer, default: 0
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,5 @@
|
||||
class RenameResetApprovers < ActiveRecord::Migration
|
||||
def change
|
||||
rename_column :projects, :reset_approvers_on_push, :reset_approvals_on_push
|
||||
end
|
||||
end
|
||||
@@ -11,7 +11,7 @@
|
||||
#
|
||||
# It's strongly recommended that you check this file into your version control system.
|
||||
|
||||
ActiveRecord::Schema.define(version: 20150713160110) do
|
||||
ActiveRecord::Schema.define(version: 20150717155058) do
|
||||
|
||||
# These are extensions that must be enabled in order to support this database
|
||||
enable_extension "plpgsql"
|
||||
@@ -57,6 +57,17 @@ ActiveRecord::Schema.define(version: 20150713160110) do
|
||||
t.datetime "updated_at"
|
||||
end
|
||||
|
||||
create_table "approvers", force: true do |t|
|
||||
t.integer "target_id", null: false
|
||||
t.string "target_type"
|
||||
t.integer "user_id", null: false
|
||||
t.datetime "created_at"
|
||||
t.datetime "updated_at"
|
||||
end
|
||||
|
||||
add_index "approvers", ["target_id", "target_type"], name: "index_approvers_on_target_id_and_target_type", using: :btree
|
||||
add_index "approvers", ["user_id"], name: "index_approvers_on_user_id", using: :btree
|
||||
|
||||
create_table "audit_events", force: true do |t|
|
||||
t.integer "author_id", null: false
|
||||
t.string "type", null: false
|
||||
@@ -443,7 +454,8 @@ ActiveRecord::Schema.define(version: 20150713160110) do
|
||||
t.string "import_source"
|
||||
t.boolean "merge_requests_rebase_default", default: true
|
||||
t.integer "approvals_before_merge", default: 0, null: false
|
||||
t.boolean "reset_approvers_on_push", default: true
|
||||
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)
|
||||
|
||||
@@ -1,58 +1,58 @@
|
||||
# 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.
|
||||
|
||||

|
||||
|
||||
* 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).
|
||||
|
||||

|
||||
|
||||
## 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
|
||||
```
|
||||
|
||||
@@ -0,0 +1,39 @@
|
||||
# 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:
|
||||
|
||||

|
||||
|
||||
Click on "commits" on the menu on the left side of your screen:
|
||||
|
||||

|
||||
|
||||
Click on the "branches" tab:
|
||||
|
||||

|
||||
|
||||
Click on the "new branch" button on the right side of the screen:
|
||||
|
||||

|
||||
|
||||
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"
|
||||
|
||||

|
||||
|
||||
### Note:
|
||||
|
||||
You will be able to find and select the name of your branch in the white box next to a project's name:
|
||||
|
||||

|
||||
@@ -1,14 +1,12 @@
|
||||
# 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.
|
||||
|
||||

|
||||
|
||||
* 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":
|
||||
|
||||

|
||||
|
||||
* On the left side menu click on "SSH Keys"
|
||||
On the left side menu click on "SSH Keys":
|
||||
|
||||

|
||||
|
||||
* Then click on the green button "Add SSH Key"
|
||||
Then click on the green button "Add SSH Key":
|
||||
|
||||

|
||||
|
||||
* 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:
|
||||
|
||||

|
||||
|
||||
## 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.
|
||||
|
||||

|
||||
|
||||
* 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.
|
||||
|
||||
@@ -0,0 +1,19 @@
|
||||
# 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:
|
||||
|
||||

|
||||
|
||||
Click on the "fork" button on the right side of your screen:
|
||||
|
||||

|
||||
|
||||
Click on the user or group to where you'd like to add the forked project.
|
||||
@@ -1,10 +1,10 @@
|
||||
# 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
|
||||
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
# Workflow
|
||||
|
||||
- [Approval for merge requests](approval_for_merge_requests.md)
|
||||
- [Authorization for merge requests](authorization_for_merge_requests.md)
|
||||
- [Change your time zone](timezone.md)
|
||||
- [Feature branch workflow](workflow.md)
|
||||
@@ -10,7 +9,8 @@
|
||||
- [Keyboard shortcuts](shortcuts.md)
|
||||
- [Labels](labels.md)
|
||||
- [Manage large binaries with git annex](git_annex.md)
|
||||
- [Notifications](notifications.md)
|
||||
- [Merge Request Approvals](merge_request_approvals.md)
|
||||
- [Notification emails](notifications.md)
|
||||
- [Project Features](project_features.md)
|
||||
- [Project forking workflow](forking_workflow.md)
|
||||
- [Protected branches](protected_branches.md)
|
||||
|
||||
@@ -1,18 +0,0 @@
|
||||
# Approval for merge requests
|
||||
|
||||
Usually you accept merge request if it is ready and reviewed. But in certain
|
||||
cases you want to be sure that every merge request will be reviewed by several
|
||||
people before it gets merged. You can use GitLab approve feature for enforcing such
|
||||
workflow. To enable it you should go to project settings page and set
|
||||
"Approvals required" field to numeric value. For example if you set it to number 3
|
||||
that means each merge request should receive 3 approves from different people
|
||||
before it can be merged via user interface.
|
||||
|
||||
|
||||

|
||||
|
||||
After you set approves value you can see on merge request page "Approve" button
|
||||
instead of "Accept" one. As soon as merge request get enough approvals it will
|
||||
be available for merge with user interface.
|
||||
|
||||

|
||||
|
Before Width: | Height: | Size: 165 KiB |
|
Before Width: | Height: | Size: 144 KiB |
@@ -0,0 +1,66 @@
|
||||
# Merge Request Approvals
|
||||
|
||||
If you want to make sure every merge request is approved by one or more
|
||||
people, you can enforce this workflow by using merge request approvals.
|
||||
Merge request approvals allow you to set the number of necessary approvals
|
||||
and predefine a list of approvers that will need to approve every
|
||||
merge request in a project.
|
||||
|
||||

|
||||
|
||||
## Configuring Approvals
|
||||
|
||||
You can configure the approvals in the project settings, under merge requests.
|
||||
|
||||

|
||||
|
||||
To enable it, set **Approvals required** to 1 or higher.
|
||||
|
||||
### Approvals Required
|
||||
|
||||
This sets the amount of approvals required before being able to merge a merge request.
|
||||
At 0, this disables the feature. Any value above requires that amount of different
|
||||
users to approve the merge request.
|
||||
|
||||
### Reset approvals on push
|
||||
|
||||
With this setting turned on, approvals are reset when a new push
|
||||
is done to the merge request branch.
|
||||
|
||||
Turn "Reset approvals on push" off if you want approvals to persist,
|
||||
independent of changes to the merge request.
|
||||
|
||||
### Approvers
|
||||
|
||||
At approvers you can define the default set of users that need to approve a
|
||||
merge request.
|
||||
|
||||
If there are more approvers than required approvals, any subset of these users
|
||||
can approve the merge request.
|
||||
|
||||
If there are less approvers than required approvals, all the set approvers plus
|
||||
any other user(s) need to approve the merge request before being able to merge it.
|
||||
|
||||

|
||||
|
||||
If the approvers are equal to the amount of required approvals, all the approvers are
|
||||
required to approve merge requests.
|
||||
|
||||

|
||||
|
||||
Note that approvers can be changed during merge request creation.
|
||||
|
||||
## Using Approvals
|
||||
|
||||
After configuring Approvals, you will see the following during merge request creation.
|
||||
|
||||

|
||||
|
||||
You can change the default set of approvers before creating the merge request.
|
||||
You can't change the amount of required approvals. This ensures that you're
|
||||
not forced to adjust settings when someone is unavailable for approval, yet
|
||||
the process is still enforced.
|
||||
|
||||
To approve a merge request, simply press the button.
|
||||
|
||||

|
||||
|
After Width: | Height: | Size: 34 KiB |
|
After Width: | Height: | Size: 31 KiB |
|
After Width: | Height: | Size: 46 KiB |
|
After Width: | Height: | Size: 36 KiB |
|
After Width: | Height: | Size: 57 KiB |
@@ -1,6 +1,6 @@
|
||||
# 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
|
||||
|
||||
@@ -240,6 +240,21 @@ Feature: Project Merge Requests
|
||||
When I click link "Approve"
|
||||
Then I should see approved merge request "Bug NS-04"
|
||||
|
||||
Scenario: I approve merge request if I am an approver
|
||||
Given merge request 'Bug NS-04' must be approved by current user
|
||||
And I click link "Bug NS-04"
|
||||
And I should not see merge button
|
||||
And I should see message that MR require an approval from me
|
||||
When I click link "Approve"
|
||||
Then I should see approved merge request "Bug NS-04"
|
||||
|
||||
Scenario: I can not approve merge request if I am not an approver
|
||||
Given merge request 'Bug NS-04' must be approved by some user
|
||||
And I click link "Bug NS-04"
|
||||
And I should not see merge button
|
||||
When I should not see Approve button
|
||||
And I should see message that MR require an approval
|
||||
|
||||
Scenario: I should see rebase checkbox
|
||||
Given project "Shop" have "Bug NS-05" open merge request with diffs inside
|
||||
And rebase before merge enabled
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -346,6 +346,24 @@ class Spinach::Features::ProjectMergeRequests < Spinach::FeatureSteps
|
||||
project.save!
|
||||
end
|
||||
|
||||
step 'merge request \'Bug NS-04\' must be approved by current user' do
|
||||
merge_request = MergeRequest.find_by!(title: "Bug NS-04")
|
||||
project = merge_request.target_project
|
||||
project.approvals_before_merge = 1
|
||||
project.approvers.create(user_id: current_user.id)
|
||||
project.ensure_satellite_exists
|
||||
project.save!
|
||||
end
|
||||
|
||||
step 'merge request \'Bug NS-04\' must be approved by some user' do
|
||||
merge_request = MergeRequest.find_by!(title: "Bug NS-04")
|
||||
project = merge_request.target_project
|
||||
project.approvals_before_merge = 1
|
||||
project.approvers.create(user_id: create(:user).id)
|
||||
project.ensure_satellite_exists
|
||||
project.save!
|
||||
end
|
||||
|
||||
step 'I click link "Approve"' do
|
||||
page.within '.mr-state-widget' do
|
||||
click_button 'Approve Merge Request'
|
||||
@@ -358,12 +376,30 @@ class Spinach::Features::ProjectMergeRequests < Spinach::FeatureSteps
|
||||
end
|
||||
end
|
||||
|
||||
step 'I should not see Approve button' do
|
||||
page.within '.mr-state-widget' do
|
||||
expect(page).not_to have_button("Approve")
|
||||
end
|
||||
end
|
||||
|
||||
step 'I should see approved merge request "Bug NS-04"' do
|
||||
page.within '.mr-state-widget' do
|
||||
expect(page).to have_button("Accept Merge Request")
|
||||
end
|
||||
end
|
||||
|
||||
step 'I should see message that MR require an approval from me' do
|
||||
page.within '.mr-state-widget' do
|
||||
expect(page).to have_content("Requires one more approval (from #{current_user.name})")
|
||||
end
|
||||
end
|
||||
|
||||
step 'I should see message that MR require an approval' do
|
||||
page.within '.mr-state-widget' do
|
||||
expect(page).to have_content("Requires one more approval")
|
||||
end
|
||||
end
|
||||
|
||||
step 'rebase before merge enabled' do
|
||||
project = merge_request.target_project
|
||||
project.merge_requests_rebase_enabled = true
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -0,0 +1,28 @@
|
||||
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
|
||||
@@ -1,6 +1,8 @@
|
||||
require 'spec_helper'
|
||||
|
||||
describe "Admin::Projects", feature: true do
|
||||
include AccessMatchers
|
||||
|
||||
describe "GET /admin/projects" do
|
||||
subject { admin_namespaces_projects_path }
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
require 'spec_helper'
|
||||
|
||||
describe "Dashboard access", feature: true do
|
||||
include AccessMatchers
|
||||
|
||||
describe "GET /dashboard" do
|
||||
subject { dashboard_path }
|
||||
|
||||
|
||||
@@ -1,98 +0,0 @@
|
||||
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
|
||||
@@ -1,82 +0,0 @@
|
||||
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
|
||||