Commit 270d93b3 authored by Dmitriy Zaporozhets's avatar Dmitriy Zaporozhets

Merge branch 'ce-non-conflict' into 'master'

7.7 CE into master

```
Unmerged paths:
  (use "git add <file>..." to mark resolution)

	both modified:      app/controllers/projects/merge_requests_controller.rb
```

See merge request !293
parents 7453e142 f9065eb7
Note: The upcoming release contains empty lines to reduce the number of merge conflicts, scroll down to see past releases.
v 7.7.0
-
-
- Import from GitHub.com feature
- Add Jetbrains Teamcity CI service (Jason Lippert)
-
-
- Mention notification level
- Markdown preview in wiki (Yuriy Glukhov)
- Raise group avatar filesize limit to 200kb
......@@ -11,35 +10,21 @@ v 7.7.0
- Show user SSH keys in admin area
- Developer can push to protected branches option
- Set project path instead of project name in create form
-
-
- Block Git HTTP access after 10 failed authentication attempts
- Updates to the messages returned by API (sponsored by O'Reilly Media)
- New UI layout with side navigation
-
-
-
- Add alert message in case of outdated browser (IE < 10)
-
- Added API support for sorting projects
- Update gitlab_git to version 7.0.0.rc13
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- Update gitlab_git to version 7.0.0.rc14
- Add API project search filter option for authorized projects
- Fix File blame not respecting branch selection
- Change some of application settings on fly in admin area UI
- Redesign signin/signup pages
- Close standard input in Gitlab::Popen.popen
- Trigger GitLab CI when push tags
- When accept merge request - do merge using sidaekiq job
- Enable web signups by default
v 7.6.0
- Fork repository to groups
......
......@@ -151,6 +151,7 @@ If you add a dependency in GitLab (such as an operating system package) please c
1. [CoffeeScript](https://github.com/thoughtbot/guides/tree/master/style#coffeescript)
1. [Shell commands](doc/development/shell_commands.md) created by GitLab contributors to enhance security
1. [Markdown](http://www.cirosantilli.com/markdown-styleguide)
1. Interface text should be written subjectively instead of objectively. It should be the gitlab core team addressing a person. It should be written in present time and never use past tense (has been/was). For example instead of "prohibited this user from being saved due to the following errors:" the text should be "sorry, we could not create your account because:". Also these [excellent writing guidelines](https://github.com/NARKOZ/guides#writing).
This is also the style used by linting tools such as [RuboCop](https://github.com/bbatsov/rubocop), [PullReview](https://www.pullreview.com/) and [Hound CI](https://houndci.com).
......
......@@ -29,7 +29,7 @@ gem 'omniauth-twitter'
gem 'omniauth-github'
gem 'omniauth-shibboleth'
gem 'omniauth-kerberos'
gem 'doorkeeper', '2.0.1'
gem 'doorkeeper', '2.1.0'
gem "rack-oauth2", "~> 1.0.5"
# Browser detection
......@@ -37,7 +37,7 @@ gem "browser"
# Extracting information from a git repository
# Provide access to Gitlab::Git library
gem "gitlab_git", '7.0.0.rc13'
gem "gitlab_git", '7.0.0.rc14'
# Ruby/Rack Git Smart-HTTP Server Handler
gem 'gitlab-grack', '~> 2.0.0.pre', require: 'grack'
......@@ -177,7 +177,6 @@ gem 'semantic-ui-sass', '~> 0.16.1.0'
gem "sass-rails", '~> 4.0.2'
gem "coffee-rails"
gem "uglifier"
gem "therubyracer"
gem 'turbolinks'
gem 'jquery-turbolinks'
......@@ -262,6 +261,9 @@ end
group :production do
gem "gitlab_meta", '7.0'
gem "therubyracer"
end
gem "newrelic_rpm"
gem 'octokit', '3.7.0'
......@@ -109,7 +109,7 @@ GEM
diff-lcs (1.2.5)
diffy (3.0.3)
docile (1.1.5)
doorkeeper (2.0.1)
doorkeeper (2.1.0)
railties (>= 3.1)
dotenv (0.9.0)
dropzonejs-rails (0.4.14)
......@@ -183,7 +183,7 @@ GEM
mime-types (~> 1.19)
gitlab_emoji (0.0.1.1)
emoji (~> 1.0.1)
gitlab_git (7.0.0.rc13)
gitlab_git (7.0.0.rc14)
activesupport (~> 4.0)
charlock_holmes (~> 0.6)
gitlab-linguist (~> 3.0)
......@@ -319,6 +319,8 @@ GEM
jwt (~> 0.1.4)
multi_json (~> 1.0)
rack (~> 1.2)
octokit (3.7.0)
sawyer (~> 0.6.0, >= 0.5.3)
omniauth (1.1.4)
hashie (>= 1.2, < 3)
rack
......@@ -367,7 +369,7 @@ GEM
rack (1.5.2)
rack-accept (0.4.5)
rack (>= 0.4)
rack-attack (2.3.0)
rack-attack (4.2.0)
rack
rack-cors (0.2.9)
rack-mini-profiler (0.9.0)
......@@ -473,6 +475,9 @@ GEM
sass (~> 3.2.0)
sprockets (~> 2.8, <= 2.11.0)
sprockets-rails (~> 2.0)
sawyer (0.6.0)
addressable (~> 2.3.5)
faraday (~> 0.8, < 0.10)
sdoc (0.3.20)
json (>= 1.1.3)
rdoc (~> 3.10)
......@@ -633,7 +638,7 @@ DEPENDENCIES
devise (= 3.2.4)
devise-async (= 0.9.0)
diffy (~> 3.0.3)
doorkeeper (= 2.0.1)
doorkeeper (= 2.1.0)
dropzonejs-rails
email_spec
enumerize
......@@ -648,7 +653,7 @@ DEPENDENCIES
gitlab-grack (~> 2.0.0.pre)
gitlab-linguist (~> 3.0.0)
gitlab_emoji (~> 0.0.1.1)
gitlab_git (= 7.0.0.rc13)
gitlab_git (= 7.0.0.rc14)
gitlab_meta (= 7.0)
gitlab_omniauth-ldap (= 1.2.0)
gollum-lib (~> 3.0.0)
......@@ -677,6 +682,7 @@ DEPENDENCIES
net-ldap
newrelic_rpm
nprogress-rails
octokit (= 3.7.0)
omniauth (~> 1.1.3)
omniauth-github
omniauth-google-oauth2
......
......@@ -35,6 +35,14 @@ For all other questions, contact us at sales@gitlab.com
- Completely free and open source (MIT Expat license)
- Powered by Ruby on Rails
## Editions
There are two editions of GitLab.
GitLab [Community Edition](https://about.gitlab.com/features/) (CE) is available without any costs under an MIT license.
GitLab Enterprise Edition (EE) includes [extra features](https://about.gitlab.com/features/#compare) that are most useful for organizations with more than 100 users.
To get access to the EE and support please [become a subscriber](https://about.gitlab.com/pricing/).
## Canonical source
- The source of GitLab Enterprise Edition is [hosted on GitLab.com](https://dev.gitlab.org/gitlab/gitlab-ee/) and acessible only to [subscribers](https://about.gitlab.com/subscription/).
......
......@@ -135,3 +135,16 @@ class @MergeRequest
this.$('.automerge_widget').hide()
this.$('.merge-in-progress').hide()
this.$('.automerge_widget.already_cannot_be_merged').show()
mergeInProgress: ->
$.ajax
type: 'GET'
url: $('.merge-request').data('url')
success: (data) =>
switch data.state
when 'merged'
location.reload()
else
setTimeout(merge_request.mergeInProgress, 3000)
dataType: 'json'
......@@ -13,3 +13,20 @@ class @ProjectShow
$("a[href=" + defaultView + "]").tab "show"
else
$("a[data-toggle='tab']:first").tab "show"
$(document).ready ->
$(window).load (e) ->
e.preventDefault()
unless location.hash is ""
$("html, body").animate
scrollTop: $(".navbar").offset().top - $(".navbar").height()
, 200
$("a").click (event) ->
link = event.target
isAnchor = link instanceof HTMLAnchorElement
if (location.hash != "" || isAnchor)
$("html,body").animate
scrollTop: $(this).offset().top - $(".navbar").height() - 3
, 200
$(document).ready ->
$(window).load (e) ->
e.preventDefault()
unless location.hash is ""
$("html, body").animate
scrollTop: $(".navbar").offset().top - $(".navbar").height()
, 200
$("a").click (event) ->
link = event.target
isAnchor = link instanceof HTMLAnchorElement
if (location.hash != "" || isAnchor)
$("html,body").animate
scrollTop: $(this).offset().top - $(".navbar").height() - 3
, 200
......@@ -29,7 +29,7 @@
line-height: 20px;
font-weight: bold;
.checkbox {
.remove_source_checkbox {
margin: 0;
}
}
......
class GithubImportsController < ApplicationController
before_filter :github_auth, except: :callback
rescue_from Octokit::Unauthorized, with: :github_unauthorized
def callback
token = client.auth_code.get_token(params[:code]).token
current_user.github_access_token = token
current_user.save
redirect_to status_github_import_url
end
def status
@repos = octo_client.repos
octo_client.orgs.each do |org|
@repos += octo_client.repos(org.login)
end
@already_added_projects = current_user.created_projects.where(import_type: "github")
already_added_projects_names = @already_added_projects.pluck(:import_source)
@repos.reject!{|repo| already_added_projects_names.include? repo.full_name}
end
def create
@repo_id = params[:repo_id].to_i
repo = octo_client.repo(@repo_id)
target_namespace = params[:new_namespace].presence || repo.owner.login
existing_namespace = Namespace.find_by("path = ? OR name = ?", target_namespace, target_namespace)
if existing_namespace
if existing_namespace.owner == current_user
namespace = existing_namespace
else
@already_been_taken = true
@target_namespace = target_namespace
@project_name = repo.name
render and return
end
else
namespace = Group.create(name: target_namespace, path: target_namespace, owner: current_user)
namespace.add_owner(current_user)
end
Gitlab::Github::ProjectCreator.new(repo, namespace, current_user).execute
end
private
def client
@client ||= Gitlab::Github::Client.new.client
end
def octo_client
Octokit.auto_paginate = true
@octo_client ||= Octokit::Client.new(:access_token => current_user.github_access_token)
end
def github_auth
if current_user.github_access_token.blank?
go_to_gihub_for_permissions
end
end
def go_to_gihub_for_permissions
redirect_to client.auth_code.authorize_url({
redirect_uri: callback_github_import_url,
scope: "repo, user, user:email"
})
end
def github_unauthorized
go_to_gihub_for_permissions
end
end
......@@ -66,7 +66,7 @@ class OmniauthCallbacksController < Devise::OmniauthCallbacksController
redirect_to omniauth_error_path(oauth['provider'], error: error_message) and return
end
end
rescue ForbiddenAction => e
rescue Gitlab::OAuth::ForbiddenAction => e
flash[:notice] = e.message
redirect_to new_user_session_path
end
......
......@@ -27,6 +27,7 @@ class Projects::MergeRequestsController < Projects::ApplicationController
respond_to do |format|
format.html
format.json { render json: @merge_request }
format.diff { render text: @merge_request.to_diff(current_user) }
format.patch { render text: @merge_request.to_patch(current_user) }
end
......@@ -104,16 +105,15 @@ class Projects::MergeRequestsController < Projects::ApplicationController
if @merge_request.unchecked?
@merge_request.check_if_can_be_merged
end
render json: {merge_status: @merge_request.merge_status_name}
render json: { merge_status: @merge_request.merge_status_name }
end
def automerge
return access_denied! unless allowed_to_merge?
if @merge_request.open? && @merge_request.can_be_merged?
@merge_request.should_remove_source_branch = params[:should_remove_source_branch]
@merge_request.should_rebase = params[:should_rebase]
@merge_request.automerge!(current_user, params[:commit_message])
AutoMergeWorker.perform_async(@merge_request.id, current_user.id, params)
@status = true
else
@status = false
......
......@@ -24,8 +24,7 @@ class Projects::ServicesController < Projects::ApplicationController
end
def test
data = GitPushService.new.sample_data(project, current_user)
data = Gitlab::PushDataBuilder.build_sample(project, current_user)
@service.execute(data)
redirect_to :back
......
......@@ -13,6 +13,7 @@ class Projects::TagsController < Projects::ApplicationController
def create
result = CreateTagService.new(@project, current_user).
execute(params[:tag_name], params[:ref], params[:message])
if result[:status] == :success
@tag = result[:tag]
redirect_to project_tags_path(@project)
......
......@@ -238,6 +238,26 @@ module ProjectsHelper
result
end
def project_wiki_path_with_version(proj, page, version, is_newest)
url_params = is_newest ? {} : { version_id: version }
project_wiki_path(proj, page, url_params)
end
def project_status_css_class(status)
case status
when "started"
"active"
when "failed"
"danger"
when "finished"
"success"
end
end
def github_import_enabled?
Gitlab.config.omniauth.enabled && enabled_oauth_providers.include?(:github)
end
def membership_locked?
if @project.group && @project.group.membership_lock
true
......@@ -246,3 +266,4 @@ module ProjectsHelper
end
end
end
......@@ -113,6 +113,16 @@ module TreeHelper
tree_join(@ref, file)
end
# returns the relative path of the first subdir that doesn't have only one directory descendand
def flatten_tree(tree)
subtree = Gitlab::Git::Tree.where(@repository, @commit.id, tree.path)
if subtree.count == 1 && subtree.first.dir?
return tree_join(tree.name, flatten_tree(subtree.first))
else
return tree.name
end
end
def leave_edit_message
"Leave edit mode?\nAll unsaved changes will be lost."
end
......
......@@ -296,6 +296,7 @@ class Note < ActiveRecord::Base
# If not - its outdated diff
def active?
return true unless self.diff
return false unless noteable
noteable.diffs.each do |mr_diff|
next unless mr_diff.new_path == self.diff.new_path
......
......@@ -21,10 +21,15 @@ class CreateTagService < BaseService
new_tag = repository.find_tag(tag_name)
if new_tag
if project.gitlab_ci?
push_data = create_push_data(project, current_user, new_tag)
project.gitlab_ci_service.async_execute(push_data)
end
Event.create_ref_event(project, current_user, new_tag, 'add', 'refs/tags')
return success(new_tag)
success(new_tag)
else
return error('Invalid reference name')
error('Invalid reference name')
end
end
......@@ -33,4 +38,9 @@ class CreateTagService < BaseService
out[:tag] = branch
out
end
def create_push_data(project, user, tag)
Gitlab::PushDataBuilder.
build(project, user, Gitlab::Git::BLANK_SHA, tag.target, 'refs/tags/' + tag.name, [])
end
end
......@@ -52,16 +52,6 @@ class GitPushService
end
end
# This method provide a sample data
# generated with post_receive_data method
# for given project
#
def sample_data(project, user)
@project, @user = project, user
@push_commits = project.repository.commits(project.default_branch, nil, 3)
post_receive_data(@push_commits.last.id, @push_commits.first.id, "refs/heads/#{project.default_branch}")
end
protected
def create_push_event(push_data)
......@@ -116,58 +106,9 @@ class GitPushService
end
end
# Produce a hash of post-receive data
#
# data = {
# before: String,
# after: String,
# ref: String,
# user_id: String,
# user_name: String,
# project_id: String,
# repository: {
# name: String,
# url: String,
# description: String,
# homepage: String,
# },
# commits: Array,
# total_commits_count: Fixnum
# }
#
def post_receive_data(oldrev, newrev, ref)
# Total commits count
push_commits_count = push_commits.size
# Get latest 20 commits ASC
push_commits_limited = push_commits.last(20)
# Hash to be passed as post_receive_data
data = {
before: oldrev,
after: newrev,
ref: ref,
user_id: user.id,
user_name: user.name,
project_id: project.id,
repository: {
name: project.name,
url: project.url_to_repo,
description: project.description,
homepage: project.web_url,
},
commits: [],
total_commits_count: push_commits_count
}
# For performance purposes maximum 20 latest commits
# will be passed as post receive hook data.
#
push_commits_limited.each do |commit|
data[:commits] << commit.hook_attrs(project)
end
data
Gitlab::PushDataBuilder.
build(project, user, oldrev, newrev, ref, push_commits)
end
def push_to_existing_branch?(ref, oldrev)
......
......@@ -8,25 +8,19 @@ class GitTagPushService
create_push_event
project.repository.expire_cache
project.execute_hooks(@push_data.dup, :tag_push_hooks)
if project.gitlab_ci?
project.gitlab_ci_service.async_execute(@push_data)
end
true
end
private
def create_push_data(oldrev, newrev, ref)
data = {
ref: ref,
before: oldrev,
after: newrev,
user_id: user.id,
user_name: user.name,
project_id: project.id,
repository: {
name: project.name,
url: project.url_to_repo,
description: project.description,
homepage: project.web_url
}
}
Gitlab::PushDataBuilder.
build(project, user, oldrev, newrev, ref, [])
end
def create_push_event
......
class TestHookService
def execute(hook, current_user)
data = GitPushService.new.sample_data(hook.project, current_user)
data = Gitlab::PushDataBuilder.build_sample(hook.project, current_user)
hook.execute(data)
end
end
- if @already_been_taken
:plain
target_field = $("tr#repo_#{@repo_id} .import-target")
origin_target = target_field.text()
project_name = "#{@project_name}"
origin_namespace = "#{@target_namespace}"
target_field.empty()
target_field.append("<p class='alert alert-danger'>This namespace already been taken! Please choose another one</p>")
target_field.append("<input type='text' name='target_namespace' />")
target_field.append("/" + project_name)
target_field.data("project_name", project_name)
target_field.find('input').prop("value", origin_namespace)
- else
:plain
$("table.import-jobs tbody").prepend($("tr#repo_#{@repo_id}"))
$("tr#repo_#{@repo_id}").addClass("active").find(".import-actions").html("<i class='fa fa-spinner fa-spin'></i> started")
%h3.page-title
%i.fa.fa-github
Import repositories from GitHub.com
%p.light
Select projects you want to import.
%span.pull-right
Reload to see the progress.
%hr
%table.table.import-jobs
%thead
%tr
%th From GitHub
%th To GitLab
%th Status
%tbody
- @already_added_projects.each do |project|
%tr{id: "repo_#{project.id}", class: "#{project_status_css_class(project.import_status)}"}
%td= project.import_source
%td
%strong= link_to project.name_with_namespace, project
%td
- if project.import_status == 'finished'
%span.cgreen
%i.fa.fa-check
done
- else
= project.human_import_status_name
- @repos.each do |repo|
%tr{id: "repo_#{repo.id}"}
%td= repo.full_name
%td.import-target
= repo.full_name
%td.import-actions
= button_tag "Add", class: "btn btn-add-to-import"
:coffeescript
$(".btn-add-to-import").click () ->
new_namespace = null
tr = $(this).closest("tr")
id = tr.attr("id").replace("repo_", "")
if tr.find(".import-target input").length > 0
new_namespace = tr.find(".import-target input").prop("value")
tr.find(".import-target").empty().append(new_namespace + "/" + tr.find(".import-target").data("project_name"))
$.post "#{github_import_url}", {repo_id: id, new_namespace: new_namespace}, dataType: 'script'
.merge-request
.merge-request{'data-url' => project_merge_request_path(@project, @merge_request)}
= render "projects/merge_requests/show/mr_title"
%hr
= render "projects/merge_requests/show/mr_box"
......
-if @status
:plain
location.reload();
merge_request.mergeInProgress();
-else
:plain
merge_request.alreadyOrCannotBeMerged()
......@@ -18,7 +18,7 @@
= f.submit "Accept Merge Request", class: "btn btn-create accept_merge_request"
- if can_remove_branch?(@merge_request.source_project, @merge_request.source_branch) && !@merge_request.for_fork?
.accept-control
= label_tag :should_remove_source_branch, class: "checkbox" do
= label_tag :should_remove_source_branch, class: "remove_source_checkbox" do
= check_box_tag :should_remove_source_branch
Remove source-branch
- if @merge_request.target_project.merge_requests_rebase_enabled && can_rebase?(@merge_request.target_project, @merge_request.target_branch)
......
......@@ -27,7 +27,7 @@
.col-sm-10
= link_to "#", class: 'js-toggle-button' do
%i.fa.fa-upload
%span Import existing repository?
%span Import existing repository by URL
.js-toggle-content.hide
.form-group.import-url-data
= f.label :import_url, class: 'control-label' do
......@@ -39,7 +39,16 @@
%br
The import will time out after 4 minutes. For big repositories, use a clone/push combination.
For SVN repositories, check #{link_to "this migrating from SVN doc.", "http://doc.gitlab.com/ce/workflow/migrating_from_svn.html"}
%hr
- if github_import_enabled?
.project-import.form-group
.col-sm-2
.col-sm-10
= link_to status_github_import_path do
%i.fa.fa-github
Import projects from GitHub
%hr.prepend-botton-10
.form-group
= f.label :description, class: 'control-label' do
......
......@@ -2,7 +2,8 @@
%td.tree-item-file-name
= tree_icon(type)
%span.str-truncated
= link_to tree_item.name, project_tree_path(@project, tree_join(@id || @commit.id, tree_item.name))
- path = flatten_tree(tree_item)
= link_to path, project_tree_path(@project, tree_join(@id || @commit.id, path))
%td.tree_time_ago.cgray
= render 'spinner'
%td.hidden-xs.tree_commit
......@@ -12,11 +12,12 @@
%th Last updated
%th Format
%tbody
- @page.versions.each do |version|
- @page.versions.each_with_index do |version, index|
- commit = version
%tr
%td
= link_to project_wiki_path(@project, @page, version_id: commit.id) do
= link_to project_wiki_path_with_version(@project, @page,
commit.id, index == 0) do
= truncate_sha(commit.id)
%td
= commit.author.name
......
class AutoMergeWorker
include Sidekiq::Worker
sidekiq_options queue: :default
def perform(merge_request_id, current_user_id, params)
params = params.with_indifferent_access
current_user = User.find(current_user_id)
merge_request = MergeRequest.find(merge_request_id)
merge_request.should_remove_source_branch = params[:should_remove_source_branch]
merge_request.should_rebase = params[:should_rebase]
merge_request.automerge!(current_user, params[:commit_message])
end
end
......@@ -10,7 +10,13 @@ class RepositoryImportWorker
project.path_with_namespace,
project.import_url)
if result
if project.import_type == 'github'
result_of_data_import = Gitlab::Github::Importer.new(project).execute
else
result_of_data_import = true
end
if result && result_of_data_import
project.import_finish
project.save
project.satellite.create unless project.satellite.exists?
......
......@@ -332,6 +332,20 @@ production: &base
# ![Company Logo](http://www.companydomain.com/logo.png)
# [Learn more about CompanyName](http://www.companydomain.com/)
rack_attack:
git_basic_auth:
# Whitelist requests from 127.0.0.1 for web proxies (NGINX/Apache) with incorrect headers
# ip_whitelist: ["127.0.0.1"]
#
# Limit the number of Git HTTP authentication attempts per IP
# maxretry: 10
#
# Reset the auth attempt counter per IP after 60 seconds
# findtime: 60
#
# Ban an IP for one hour (3600s) after too many auth attempts
# bantime: 3600
development:
<<: *base
......
......@@ -112,7 +112,7 @@ rescue ArgumentError # no user configured
'/home/' + Settings.gitlab['user']
end
Settings.gitlab['time_zone'] ||= nil
Settings.gitlab['signup_enabled'] ||= false
Settings.gitlab['signup_enabled'] ||= true
Settings.gitlab['signin_enabled'] ||= true if Settings.gitlab['signin_enabled'].nil?
Settings.gitlab['restricted_visibility_levels'] = Settings.send(:verify_constant_array, Gitlab::VisibilityLevel, Settings.gitlab['restricted_visibility_levels'], [])
Settings.gitlab['username_changing_enabled'] = true if Settings.gitlab['username_changing_enabled'].nil?
......@@ -178,6 +178,16 @@ Settings.satellites['timeout'] ||= 30
#
Settings['extra'] ||= Settingslogic.new({})
#
# Rack::Attack settings
#
Settings['rack_attack'] ||= Settingslogic.new({})
Settings.rack_attack['git_basic_auth'] ||= Settingslogic.new({})
Settings.rack_attack.git_basic_auth['ip_whitelist'] ||= %w{127.0.0.1}
Settings.rack_attack.git_basic_auth['maxretry'] ||= 10
Settings.rack_attack.git_basic_auth['findtime'] ||= 1.minute
Settings.rack_attack.git_basic_auth['bantime'] ||= 1.hour
#
# Testing settings
#
......
......@@ -10,6 +10,11 @@ Doorkeeper.configure do
current_user || redirect_to(new_user_session_url)
end
resource_owner_from_credentials do |routes|
u = User.find_by(email: params[:username])
u if u && u.valid_password?(params[:password])
end
# If you want to restrict access to the web interface for adding oauth authorized applications, you need to declare the block below.
# admin_authenticator do
# # Put your admin authentication logic here.
......
unless Rails.env.test?
# Tell the Rack::Attack Rack middleware to maintain an IP blacklist. We will
# update the blacklist from Grack::Auth#authenticate_user.
Rack::Attack.blacklist('Git HTTP Basic Auth') do |req|
Rack::Attack::Allow2Ban.filter(req.ip, Gitlab.config.rack_attack.git_basic_auth) do
# This block only gets run if the IP was not already banned.
# Return false, meaning that we do not see anything wrong with the
# request at this time
false
end
end
end
# Monkey-patch Redis::Store to make 'setex' and 'expire' work with namespacing
module Gitlab
class Redis
class Store
module Namespace
# Redis::Store#setex in redis-store 1.1.4 does not respect namespaces;
# this new method does.
def setex(key, expires_in, value, options=nil)
namespace(key) { |key| super(key, expires_in, value) }
end
# Redis::Store#expire in redis-store 1.1.4 does not respect namespaces;
# this new method does.
def expire(key, expires_in)
namespace(key) { |key| super(key, expires_in) }
end
private
# Our new definitions of #setex and #expire above assume that the
# #namespace method exists. Because we cannot be sure of that, we
# re-implement the #namespace method from Redis::Store::Namespace so
# that it is available for all Redis::Store instances, whether they use
# namespacing or not.
#
# Based on lib/redis/store/namespace.rb L49-51 (redis-store 1.1.4)
def namespace(key)
if @namespace
yield interpolate(key)
else
# This Redis::Store instance does not use a namespace so we should
# just pass through the key.
yield key
end
end
end
end
end
end
Redis::Store.class_eval do
include Gitlab::Redis::Store::Namespace
end
......@@ -52,6 +52,14 @@ Gitlab::Application.routes.draw do
end
get "/s/:username" => "snippets#user_index", as: :user_snippets, constraints: { username: /.*/ }
#
# Github importer area
#
resource :github_import, only: [:create, :new] do
get :status
get :callback
end
#
# Explroe area
#
......
class AddImportDataToProjectTable < ActiveRecord::Migration
def change
add_column :projects, :import_type, :string
add_column :projects, :import_source, :string
add_column :users, :github_access_token, :string
end
end
......@@ -378,6 +378,8 @@ ActiveRecord::Schema.define(version: 20150108073740) do
t.integer "visibility_level", default: 0, null: false
t.boolean "archived", default: false, null: false
t.string "import_status"
t.string "import_type"
t.string "import_source"
t.float "repository_size", default: 0.0
t.integer "star_count", default: 0, null: false
t.text "merge_requests_template"
......@@ -487,6 +489,7 @@ ActiveRecord::Schema.define(version: 20150108073740) do
t.boolean "hide_no_ssh_key", default: false
t.string "website_url", default: "", null: false
t.datetime "last_credential_check_at"
t.string "github_access_token"
t.datetime "admin_email_unsubscribed_at"
end
......
......@@ -51,6 +51,24 @@ curl --header "PRIVATE-TOKEN: QVy1PB7sTxfy4pqfZM1U" "http://example.com/api/v3/p
The API uses JSON to serialize data. You don't need to specify `.json` at the end of API URL.
## Authentication with OAuth2 token
Instead of the private_token you can transmit the OAuth2 access token as a header or as a parameter.
### OAuth2 token (as a parameter)
```
curl https://localhost:3000/api/v3/user?access_token=OAUTH-TOKEN
```
### OAuth2 token (as a header)
```
curl -H "Authorization: Bearer OAUTH-TOKEN" https://localhost:3000/api/v3/user
```
Read more about [OAuth2 in GitLab](oauth2.md).
## Status codes
The API is designed to return different status codes according to context and action. In this way if a request results in an error the caller is able to get insight into what went wrong, e.g. status code `400 Bad Request` is returned if a required attribute is missing from the request. The following list gives an overview of how the API functions generally behave.
......
# OAuth2 authentication
OAuth2 is a protocol that enables us to get access to private details of user's account without getting its password.
Before using the OAuth2 you should create an application in user's account. Each application getting unique App ID and App Secret parameters. You should not share them.
This functianolity is based on [doorkeeper gem](https://github.com/doorkeeper-gem/doorkeeper)
## Web Application Flow
This flow is using for authentication from third-party web sites and probably is most used.
It basically consists of an exchange of an authorization token for an access token. For more detailed info, check out the [RFC spec here](http://tools.ietf.org/html/rfc6749#section-4.1)
This flow consists from 3 steps.
### 1. Registering the client
Creat an application in user's account profile.
### 2. Requesting authorization
To request the authorization token, you should visit the `/oauth/authorize` endpoint. You can do that by visiting manually the URL:
```
http://localhost:3000/oauth/authorize?client_id=APP_ID&redirect_uri=REDIRECT_URI&response_type=code
```
Where REDIRECT_URI is the URL in your app where users will be sent after authorization.
### 3. Requesting the access token
To request the access token, you should use the returned code and exchange it for an access token. To do that you can use any HTTP client. In this case, I used rest-client:
```
parameters = 'client_id=APP_ID&client_secret=APP_SECRET&code=RETURNED_CODE&grant_type=AUTHORIZATION_CODE&redirect_uri=REDIRECT_URI'
RestClient.post 'http://localhost:3000/oauth/token', parameters
# The response will be
{
"access_token": "de6780bc506a0446309bd9362820ba8aed28aa506c71eedbe1c5c4f9dd350e54",
"token_type": "bearer",
"expires_in": 7200,
"refresh_token": "8257e65c97202ed1726cf9571600918f3bffb2544b26e00a61df9897668c33a1"
}
```
You can now make requests to the API with the access token returned.
### Use the access token to access the API
The access token allows you to make requests to the API on a behalf of a user.
```
GET https://localhost:3000/api/v3/user?access_token=OAUTH-TOKEN
```
Or you can put the token to the Authorization header:
```
curl -H "Authorization: Bearer OAUTH-TOKEN" https://localhost:3000/api/v3/user
```
## Resource Owner Password Credentials
In this flow, a token is requested in exchange for the resource owner credentials (username and password).
The credentials should only be used when there is a high degree of trust between the resource owner and the client (e.g. the
client is part of the device operating system or a highly privileged application), and when other authorization grant types are not
available (such as an authorization code).
Even though this grant type requires direct client access to the resource owner credentials, the resource owner credentials are used
for a single request and are exchanged for an access token. This grant type can eliminate the need for the client to store the
resource owner credentials for future use, by exchanging the credentials with a long-lived access token or refresh token.
You can do POST request to `/oauth/token` with parameters:
```
{
"grant_type" : "password",
"username" : "user@example.com",
"password" : "sekret"
}
```
Then, you'll receive the access token back in the response:
```
{
"access_token": "1f0af717251950dbd4d73154fdf0a474a5c5119adad999683f5b450c460726aa",
"token_type": "bearer",
"expires_in": 7200
}
```
For testing you can use the oauth2 ruby gem:
```
client = OAuth2::Client.new('the_client_id', 'the_client_secret', :site => "http://example.com")
access_token = client.password.get_token('user@example.com', 'sekret')
puts access_token.token
```
\ No newline at end of file
......@@ -13,6 +13,7 @@ Parameters:
- `archived` (optional) - if passed, limit by archived status
- `order_by` (optional) - Return requests ordered by `id`, `name`, `created_at` or `last_activity_at` fields
- `sort` (optional) - Return requests sorted in `asc` or `desc` order
- `search` (optional) - Return list of authorized projects according to a search criteria
```json
[
......
# How to create RC1
The RC1 release comes with the task to update the installation and upgrade docs. Be mindful that there might already be merge requests for this on GitLab or GitHub.
### **1. Update the installation guide**
1. Check if it references the correct branch `x-x-stable` (doesn't exist yet, but that is okay)
1. Check the [GitLab Shell version](/lib/tasks/gitlab/check.rake#L782)
1. Check the [Git version](/lib/tasks/gitlab/check.rake#L794)
1. There might be other changes. Ask around.
### **2. Create update guides**
1. Create: CE update guide from previous version. Like `7.3-to-7.4.md`
1. Create: CE to EE update guide in EE repository for latest version.
1. Update: `6.x-or-7.x-to-7.x.md` to latest version.
1. Create: CI update guide from previous version
It's best to copy paste the previous guide and make changes where necessary.
The typical steps are listed below with any points you should specifically look at.
#### 0. Any major changes?
List any major changes here, so the user is aware of them before starting to upgrade. For instance:
- Database updates
- Web server changes
- File structure changes
#### 1. Stop server
#### 2. Make backup
#### 3. Do users need to update dependencies like `git`?
- Check if the [GitLab Shell version](/lib/tasks/gitlab/check.rake#L782) changed since the last release.
- Check if the [Git version](/lib/tasks/gitlab/check.rake#L794) changed since the last release.
#### 4. Get latest code
#### 5. Does GitLab shell need to be updated?
#### 6. Install libs, migrations, etc.
#### 7. Any config files updated since last release?
Check if any of these changed since last release:
- [lib/support/nginx/gitlab](/lib/support/nginx/gitlab)
- [lib/support/nginx/gitlab-ssl](/lib/support/nginx/gitlab-ssl)
- <https://gitlab.com/gitlab-org/gitlab-shell/commits/master/config.yml.example>
- [config/gitlab.yml.example](/config/gitlab.yml.example)
- [config/unicorn.rb.example](/config/unicorn.rb.example)
- [config/database.yml.mysql](/config/database.yml.mysql)
- [config/database.yml.postgresql](/config/database.yml.postgresql)
- [config/initializers/rack_attack.rb.example](/config/initializers/rack_attack.rb.example)
- [config/resque.yml.example](/config/resque.yml.example)
#### 8. Need to update init script?
Check if the `init.d/gitlab` script changed since last release: [lib/support/init.d/gitlab](/lib/support/init.d/gitlab)
#### 9. Start application
#### 10. Check application status
### **3. Code quality indicators**
Make sure the code quality indicators are green / good.
- [![Build status](http://ci.gitlab.org/projects/1/status.png?ref=master)](http://ci.gitlab.org/projects/1?ref=master) on ci.gitlab.org (master branch)
- [![Build Status](https://semaphoreapp.com/api/v1/projects/2f1a5809-418b-4cc2-a1f4-819607579fe7/243338/badge.png)](https://semaphoreapp.com/gitlabhq/gitlabhq) (master branch)
- [![Code Climate](https://codeclimate.com/github/gitlabhq/gitlabhq.png)](https://codeclimate.com/github/gitlabhq/gitlabhq)
- [![Dependency Status](https://gemnasium.com/gitlabhq/gitlabhq.png)](https://gemnasium.com/gitlabhq/gitlabhq) this button can be yellow (small updates are available) but must not be red (a security fix or an important update is available)
- [![Coverage Status](https://coveralls.io/repos/gitlabhq/gitlabhq/badge.png?branch=master)](https://coveralls.io/r/gitlabhq/gitlabhq)
### 4. Run release tool for CE and EE
**Make sure EE `master` has latest changes from CE `master`**
Get release tools
```
git clone git@dev.gitlab.org:gitlab/release-tools.git
cd release-tools
```
Release candidate creates stable branch from master.
So we need to sync master branch between all CE remotes. Also do same for EE.
```
bundle exec rake sync
```
Create release candidate and stable branch:
```
bundle exec rake release["x.x.0.rc1"]
```
Now developers can use master for merging new features.
So you should use stable branch for future code chages related to release.
### 5. Release GitLab CI RC1
Add to your local `gitlab-ci/.git/config`:
```
[remote "public"]
url = none
pushurl = git@dev.gitlab.org:gitlab/gitlab-ci.git
pushurl = git@gitlab.com:gitlab-org/gitlab-ci.git
pushurl = git@github.com:gitlabhq/gitlab-ci.git
```
* Create a stable branch `x-y-stable`
* Bump VERSION to `x.y.0.rc1`
* `git tag -a v$(cat VERSION) -m "Version $(cat VERSION)"
* `git push public x-y-stable v$(cat VERSION)`
# Monthly Release
NOTE: This is a guide for GitLab developers.
NOTE: This is a guide used by the GitLab B.V. developers.
# **7 workdays before release - Code Freeze & Release Manager**
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.
### **1. Stop merging in code, except for important bug fixes**
### **2. Release Manager**
## Release Manager
A release manager is selected that coordinates all releases the coming month, including the patch releases for previous releases.
The release manager has to make sure all the steps below are done and delegated where necessary.
This person should also make sure this document is kept up to date and issues are created and updated.
### **3. Create an overall issue**
## Take vacations into account
The time is measured in weekdays to compensate for weekends.
Do everything on time to prevent problems due to rush jobs or too little testing time.
Make sure that you take into account any vacations of maintainers.
If the release is falling behind immediately warn the team.
## Create an overall issue and follow it
Create issue for GitLab CE project(internal). Name it "Release x.x.x" for easier searching.
Replace the dates with actual dates based on the number of workdays before the release.
All steps from issue template are explained below
```
Xth:
Xth: (7 working days before the 22nd)
- [ ] Code freeze
- [ ] Update the CE changelog (#LINK)
- [ ] Update the EE changelog (#LINK)
- [ ] Update the CI changelog (#LINK)
- [ ] Triage the omnibus-gitlab milestone
Xth:
- [ ] Merge CE in to EE (#LINK)
- [ ] Close the omnibus-gitlab milestone
Xth:
Xth: (6 working days before the 22nd)
- [ ] Create x.x.0.rc1 (#LINK)
- [ ] Create x.x.0.rc1-ee (#LINK)
- [ ] Create CI y.y.0.rc1 (#LINK)
- [ ] Build package for GitLab.com (https://dev.gitlab.org/cookbooks/chef-repo/blob/master/doc/administration.md#build-a-package)
- [ ] Merge CE master in to EE master via merge request (#LINK)
- [ ] Create CE, EE, CI RC1 versions (#LINK)
- [ ] Determine QA person and notify this person
Xth:
- [ ] Update GitLab.com with rc1 (#LINK) (https://dev.gitlab.org/cookbooks/chef-repo/blob/master/doc/administration.md#deploy-the-package)
- [ ] Regression issues (CE, CI) and tweet about rc1 (#LINK)
- [ ] Start blog post (#LINK)
Xth:
Xth: (5 working days before the 22nd)
- [ ] Do QA and fix anything coming out of it (#LINK)
- [ ] Close the omnibus-gitlab milestone
22nd:
- [ ] Release CE, EE and CI (#LINK)
Xth:
- [ ] Deploy to GitLab.com (#LINK)
```
### **4. Update changelog**
Any changes not yet added to the changelog are added by lead developer and in that merge request the complete team is asked if there is anything missing.
There are three changelogs that need to be updated: CE, EE and CI.
### **5. Take weekend and vacations into account**
Ensure that there is enough time to incorporate the findings of the release candidate, etc.
# **6 workdays before release- Merge the CE into EE**
Do this via a merge request.
# **5 workdays before release - Create RC1**
The RC1 release comes with the task to update the installation and upgrade docs. Be mindful that there might already be merge requests for this on GitLab or GitHub.
### **1. Update the installation guide**
1. Check if it references the correct branch `x-x-stable` (doesn't exist yet, but that is okay)
1. Check the [GitLab Shell version](/lib/tasks/gitlab/check.rake#L782)
1. Check the [Git version](/lib/tasks/gitlab/check.rake#L794)
1. There might be other changes. Ask around.
### **2. Create update guides**
1. Create: CE update guide from previous version. Like `7.3-to-7.4.md`
1. Create: CE to EE update guide in EE repository for latest version.
1. Update: `6.x-or-7.x-to-7.x.md` to latest version.
1. Create: CI update guide from previous version
It's best to copy paste the previous guide and make changes where necessary.
The typical steps are listed below with any points you should specifically look at.
#### 0. Any major changes?
List any major changes here, so the user is aware of them before starting to upgrade. For instance:
- Database updates
- Web server changes
- File structure changes
#### 1. Stop server
#### 2. Make backup
#### 3. Do users need to update dependencies like `git`?
- Check if the [GitLab Shell version](/lib/tasks/gitlab/check.rake#L782) changed since the last release.
- Check if the [Git version](/lib/tasks/gitlab/check.rake#L794) changed since the last release.
#### 4. Get latest code
#### 5. Does GitLab shell need to be updated?
#### 6. Install libs, migrations, etc.
Xth: (4 working days before the 22nd)
#### 7. Any config files updated since last release?
- [ ] Build rc1 package for GitLab.com (https://dev.gitlab.org/cookbooks/chef-repo/blob/master/doc/administration.md#build-a-package)
- [ ] Update GitLab.com with rc1 (#LINK) (https://dev.gitlab.org/cookbooks/chef-repo/blob/master/doc/administration.md#deploy-the-package)
Check if any of these changed since last release:
Xth: (3 working days before the 22nd)
- [lib/support/nginx/gitlab](/lib/support/nginx/gitlab)
- [lib/support/nginx/gitlab-ssl](/lib/support/nginx/gitlab-ssl)
- <https://gitlab.com/gitlab-org/gitlab-shell/commits/master/config.yml.example>
- [config/gitlab.yml.example](/config/gitlab.yml.example)
- [config/unicorn.rb.example](/config/unicorn.rb.example)
- [config/database.yml.mysql](/config/database.yml.mysql)
- [config/database.yml.postgresql](/config/database.yml.postgresql)
- [config/initializers/rack_attack.rb.example](/config/initializers/rack_attack.rb.example)
- [config/resque.yml.example](/config/resque.yml.example)
- [ ] Create regression issues (CE, CI) (#LINK)
- [ ] Tweet about rc1 (#LINK)
- [ ] Prepare the blog post (#LINK)
#### 8. Need to update init script?
Xth: (2 working days before the 22nd)
Check if the `init.d/gitlab` script changed since last release: [lib/support/init.d/gitlab](/lib/support/init.d/gitlab)
- [ ] Merge CE stable branch into EE stable branch
- [ ] Check that everyone is mentioned on the blog post (the reviewer should have done this one working day ago)
#### 9. Start application
Xth: (1 working day before the 22nd)
#### 10. Check application status
- [ ] Create CE, EE, CI stable versions (#LINK)
- [ ] Create Omnibus tags and build packages
### **3. Code quality indicators**
22nd:
Make sure the code quality indicators are green / good.
- [ ] Release CE, EE and CI (#LINK)
- [![Build status](http://ci.gitlab.org/projects/1/status.png?ref=master)](http://ci.gitlab.org/projects/1?ref=master) on ci.gitlab.org (master branch)
Xth: (1 working day after the 22nd)
- [![Build Status](https://semaphoreapp.com/api/v1/projects/2f1a5809-418b-4cc2-a1f4-819607579fe7/243338/badge.png)](https://semaphoreapp.com/gitlabhq/gitlabhq) (master branch)
- [ ] Update GitLab.com with the stable version (#LINK)
- [![Code Climate](https://codeclimate.com/github/gitlabhq/gitlabhq.png)](https://codeclimate.com/github/gitlabhq/gitlabhq)
```
- [![Dependency Status](https://gemnasium.com/gitlabhq/gitlabhq.png)](https://gemnasium.com/gitlabhq/gitlabhq) this button can be yellow (small updates are available) but must not be red (a security fix or an important update is available)
- - -
- [![Coverage Status](https://coveralls.io/repos/gitlabhq/gitlabhq/badge.png?branch=master)](https://coveralls.io/r/gitlabhq/gitlabhq)
## Code Freeze
### **4. Run release tool**
Stop merging code in master, except for important bug fixes
**Make sure EE `master` has latest changes from CE `master`**
## Update changelog
Get release tools
Any changes not yet added to the changelog are added by lead developer and in that merge request the complete team is
asked if there is anything missing.
```
git clone git@dev.gitlab.org:gitlab/release-tools.git
cd release-tools
```
There are three changelogs that need to be updated: CE, EE and CI.
Release candidate creates stable branch from master.
So we need to sync master branch between all CE remotes. Also do same for EE.
Remove the Note text in the stable branches.
```
bundle exec rake sync
```
## Create RC1 (CE, EE, CI)
Create release candidate and stable branch:
[Follow this How-to guide](howto_rc1.md) to create RC1.
```
bundle exec rake release["x.x.0.rc1"]
```
## Prepare CHANGELOG for next release
Now developers can use master for merging new features.
So you should use stable branch for future code chages related to release.
Once the stable branches have been created, update the CHANGELOG in `master` with the upcoming version and add 70 empty
lines to it. We do this in order to avoid merge conflicts when merging the CHANGELOG.
Make sure that the CHANGELOG im master contains the following disclaimer message:
### 5. Release GitLab CI RC1
> Note: The upcoming release contains empty lines to reduce the number of merge conflicts, scroll down to see past releases.
Add to your local `gitlab-ci/.git/config`:
## QA
```
[remote "public"]
url = none
pushurl = git@dev.gitlab.org:gitlab/gitlab-ci.git
pushurl = git@gitlab.com:gitlab-org/gitlab-ci.git
pushurl = git@github.com:gitlabhq/gitlab-ci.git
```
Create issue on dev.gitlab.org `gitlab` repository, named "GitLab X.X QA" in order to keep track of the progress.
* Create a stable branch `x-y-stable`
* Bump VERSION to `x.y.0.rc1`
* `git tag -a v$(cat VERSION) -m "Version $(cat VERSION)"
* `git push public x-y-stable v$(cat VERSION)`
Use the omnibus packages of Enterprise Edition using [this guide](https://dev.gitlab.org/gitlab/gitlab-ee/blob/master/doc/release/manual_testing.md).
**NOTE** Upgrader can only be tested when tags are pushed to all repositories. Do not forget to confirm it is working before releasing. Note that in the issue.
# **4 workdays before release - Release RC1**
#### Fix anything coming out of the QA
### **1. Determine QA person**
Create an issue with description of a problem, if it is quick fix fix it yourself otherwise contact the team for advice.
Notify person of QA day.
**NOTE** If there is a problem that cannot be fixed in a timely manner, reverting the feature is an option! If the feature is reverted,
create an issue about it in order to discuss the next steps after the release.
### **2. Update GitLab.com**
## Update GitLab.com with RC1
Merge the RC1 EE code into GitLab.com.
Once the build is green, create a package.
......@@ -212,23 +128,7 @@ If there are big database migrations consider testing them with the production d
Try to deploy in the morning.
It is important to do this as soon as possible, so we can catch any errors before we release the full version.
### **3. Prepare the blog post**
- Start with a complete copy of the [release blog template](https://gitlab.com/gitlab-com/www-gitlab-com/blob/master/doc/release_blog_template.md) and fill it out.
- Make sure the blog post contains information about the GitLab CI release.
- Check the changelog of CE and EE for important changes.
- Also check the CI changelog
- Add a proposed tweet text to the blog post WIP MR description.
- Create a WIP MR for the blog post
- Ask Dmitriy to add screenshots to the WIP MR.
- Decide with team who will be the MVP user.
- Create WIP MR for adding MVP to MVP page on website
- Add a note if there are security fixes: This release fixes an important security issue and we advise everyone to upgrade as soon as possible.
- Create a merge request on [GitLab.com](https://gitlab.com/gitlab-com/www-gitlab-com/tree/master)
- Assign to one reviewer who will fix spelling issues by editing the branch (either with a git client or by using the online editor)
- Comment to the reviewer: '@person Please mention the whole team as soon as you are done (3 workdays before release at the latest)'
### **4. Create a regressions issue**
## Create a regressions issue
On [the GitLab CE issue tracker on GitLab.com](https://gitlab.com/gitlab-org/gitlab-ce/issues/) create an issue titled "GitLab X.X regressions" add the following text:
......@@ -239,43 +139,29 @@ The release manager will comment here about the plans for patch releases.
Assign the issue to the release manager and /cc all the core-team members active on the issue tracker. If there are any known bugs in the release add them immediately.
### **5. Tweet**
## Tweet about RC1
Tweet about the RC release:
> GitLab x.x.0.rc1 is out. This release candidate is only suitable for testing. Please link regressions issues from LINK_TO_REGRESSION_ISSUE
# **1 workdays before release - Preparation**
## Prepare the blog post
### **0. Doublecheck blog post**
1. Start with a complete copy of the [release blog template](https://gitlab.com/gitlab-com/www-gitlab-com/blob/master/doc/release_blog_template.md) and fill it out.
1. Make sure the blog post contains information about the GitLab CI release.
1. Check the changelog of CE and EE for important changes.
1. Also check the CI changelog
1. Add a proposed tweet text to the blog post WIP MR description.
1. Create a WIP MR for the blog post
1. Ask Dmitriy to add screenshots to the WIP MR.
1. Decide with team who will be the MVP user.
1. Create WIP MR for adding MVP to MVP page on website
1. Add a note if there are security fixes: This release fixes an important security issue and we advise everyone to upgrade as soon as possible.
1. Create a merge request on [GitLab.com](https://gitlab.com/gitlab-com/www-gitlab-com/tree/master)
1. Assign to one reviewer who will fix spelling issues by editing the branch (either with a git client or by using the online editor)
1. Comment to the reviewer: '@person Please mention the whole team as soon as you are done (3 workdays before release at the latest)'
Doublecheck the everyone has been mentioned in the blog post.
### **1. Pre QA merge**
Merge CE into EE before doing the QA.
### **2. QA**
Create issue on dev.gitlab.org `gitlab` repository, named "GitLab X.X QA" in order to keep track of the progress.
Use the omnibus packages of Enterprise Edition using [this guide](https://dev.gitlab.org/gitlab/gitlab-ee/blob/master/doc/release/manual_testing.md).
**NOTE** Upgrader can only be tested when tags are pushed to all repositories. Do not forget to confirm it is working before releasing. Note that in the issue.
### **3. Fix anything coming out of the QA**
Create an issue with description of a problem, if it is quick fix fix it yourself otherwise contact the team for advice.
**NOTE** If there is a problem that cannot be fixed in a timely manner, reverting the feature is an option! If the feature is reverted,
create an issue about it in order to discuss the next steps after the release.
# **Workday before release - Create Omnibus tags and build packages**
**Make sure EE `x-x-stable-ee` has latest changes from CE `x-x-stable`**
### **1. Release code**
## Create CE, EE, CI stable versions
Get release tools
......@@ -292,32 +178,31 @@ bundle exec rake release["x.x.0"]
Also perform these steps for GitLab CI:
- bump version in the stable branch
- create annotated tag
- push the stable branch and the annotated tag to the public repositories
### **2. Update installation.md**
1. bump version in the stable branch
1. create annotated tag
1. push the stable branch and the annotated tag to the public repositories
Update [installation.md](/doc/install/installation.md) to the newest version in master.
### **3. Build the Omnibus packages**
## Create Omnibus tags and build packages
Follow the [release doc in the Omnibus repository](https://gitlab.com/gitlab-org/omnibus-gitlab/blob/master/doc/release.md).
This can happen before tagging because Omnibus uses tags in its own repo and SHA1's to refer to the GitLab codebase.
# **22nd - Release CE, EE and CI**
## Release CE, EE and CI
### **1. Publish packages for new release**
__1. Publish packages for new release__
Update `downloads/index.html` and `downloads/archive/index.html` in `www-gitlab-com` repository.
### **2. Publish blog for new release**
__2. Publish blog for new release__
Doublecheck the everyone has been mentioned in the blog post.
Merge the [blog merge request](#1-prepare-the-blog-post) in `www-gitlab-com` repository.
### **3. Tweet to blog**
__3. Tweet to blog__
Send out a tweet to share the good news with the world.
List the most important features and link to the blog post.
......@@ -326,7 +211,6 @@ Proposed tweet "Release of GitLab X.X & CI Y.Y! FEATURE, FEATURE and FEATURE <li
Consider creating a post on Hacker News.
# **1 workday after release - Update GitLab.com**
## Update GitLab.com with the stable version
- Build a package for gitlab.com based on the official release instead of RC1
- Deploy the package (should not need downtime because of the small difference with RC1)
......@@ -279,7 +279,7 @@ class Spinach::Features::ProjectMergeRequests < Spinach::FeatureSteps
end
step 'I should see comments on the side-by-side diff page' do
within '.files [id^=diff]:nth-child(1) .note-text' do
within '.files [id^=diff]:nth-child(1) .parallel .note-text' do
page.should have_visible_content "Line is correct"
end
end
......
......@@ -15,9 +15,6 @@ module API
# Get a projects list for authenticated user
#
# Parameters:
# archived (optional) - if passed, limit by archived status
#
# Example Request:
# GET /projects
get do
......
......@@ -72,8 +72,26 @@ module Grack
end
def authenticate_user(login, password)
auth = Gitlab::Auth.new
auth.find(login, password)
user = Gitlab::Auth.new.find(login, password)
return user if user.present?
# At this point, we know the credentials were wrong. We let Rack::Attack
# know there was a failed authentication attempt from this IP. This
# information is stored in the Rails cache (Redis) and will be used by
# the Rack::Attack middleware to decide whether to block requests from
# this IP.
config = Gitlab.config.rack_attack.git_basic_auth
Rack::Attack::Allow2Ban.filter(@request.ip, config) do
# Unless the IP is whitelisted, return true so that Allow2Ban
# increments the counter (stored in Rails.cache) for the IP
if config.ip_whitelist.include?(@request.ip)
false
else
true
end
end
nil # No user was found
end
def authorized_request?
......
module Gitlab
module CurrentSettings
def current_application_settings
begin
if ActiveRecord::Base.connection.table_exists?('application_settings')
ApplicationSetting.current ||
ApplicationSetting.create_from_defaults
else
fake_application_settings
end
rescue ActiveRecord::NoDatabaseError, database_adapter.constantize::Error
fake_application_settings
end
end
def fake_application_settings
......@@ -18,5 +22,16 @@ module Gitlab
sign_in_text: Settings.extra['sign_in_text'],
)
end
# We need to check which database is setup
# but we cannot assume that the database exists already.
# Not checking this will break "rake gitlab:setup".
def database_adapter
if Rails.configuration.database_configuration[Rails.env]['adapter'] == 'mysql2'
"Mysql2"
else
"PG"
end
end
end
end
module Gitlab
module Github
class Client
attr_reader :client
def initialize
@client = ::OAuth2::Client.new(
config.app_id,
config.app_secret,
github_options
)
end
private
def config
Gitlab.config.omniauth.providers.select{|provider| provider.name == "github"}.first
end
def github_options
{
site: 'https://api.github.com',
authorize_url: 'https://github.com/login/oauth/authorize',
token_url: 'https://github.com/login/oauth/access_token'
}
end
end
end
end
module Gitlab
module Github
class Importer
attr_reader :project
def initialize(project)
@project = project
end
def execute
client = octo_client(project.creator.github_access_token)
#Issues && Comments
client.list_issues(project.import_source, state: :all).each do |issue|
if issue.pull_request.nil?
body = "*Created by: #{issue.user.login}*\n\n#{issue.body}"
if issue.comments > 0
body += "\n\n\n**Imported comments:**\n"
client.issue_comments(project.import_source, issue.number).each do |c|
body += "\n\n*By #{c.user.login} on #{c.created_at}*\n\n#{c.body}"
end
end
project.issues.create!(
description: body,
title: issue.title,
state: issue.state == 'closed' ? 'closed' : 'opened',
author_id: gl_user_id(project, issue.user.id)
)
end
end
end
private
def octo_client(access_token)
::Octokit.auto_paginate = true
::Octokit::Client.new(:access_token => access_token)
end
def gl_user_id(project, github_id)
user = User.joins(:identities).find_by("identities.extern_uid = ?", github_id.to_s)
(user && user.id) || project.creator_id
end
end
end
end
module Gitlab
module Github
class ProjectCreator
attr_reader :repo, :namespace, :current_user
def initialize(repo, namespace, current_user)
@repo = repo
@namespace = namespace
@current_user = current_user
end
def execute
@project = Project.new(
name: repo.name,
path: repo.name,
description: repo.description,
namespace: namespace,
creator: current_user,
visibility_level: repo.private ? Gitlab::VisibilityLevel::PRIVATE : Gitlab::VisibilityLevel::PUBLIC,
import_type: "github",
import_source: repo.full_name,
import_url: repo.clone_url.sub("https://", "https://#{current_user.github_access_token}@")
)
if @project.save!
@project.reload
if @project.import_failed?
@project.import_retry
else
@project.import_start
end
end
end
end
end
end
module Gitlab
class PushDataBuilder
# Produce a hash of post-receive data
#
# data = {
# before: String,
# after: String,
# ref: String,
# user_id: String,
# user_name: String,
# project_id: String,
# repository: {
# name: String,
# url: String,
# description: String,
# homepage: String,
# },
# commits: Array,
# total_commits_count: Fixnum
# }
#
def self.build(project, user, oldrev, newrev, ref, commits = [])
# Total commits count
commits_count = commits.size
# Get latest 20 commits ASC
commits_limited = commits.last(20)
# Hash to be passed as post_receive_data
data = {
before: oldrev,
after: newrev,
ref: ref,
user_id: user.id,
user_name: user.name,
project_id: project.id,
repository: {
name: project.name,
url: project.url_to_repo,
description: project.description,
homepage: project.web_url,
},
commits: [],
total_commits_count: commits_count
}
# For performance purposes maximum 20 latest commits
# will be passed as post receive hook data.
commits_limited.each do |commit|
data[:commits] << commit.hook_attrs(project)
end
data
end
# This method provide a sample data generated with
# existing project and commits to test web hooks
def self.build_sample(project, user)
commits = project.repository.commits(project.default_branch, nil, 3)
build(project, user, commits.last.id, commits.first.id, "refs/heads/#{project.default_branch}", commits)
end
end
end
......@@ -11,7 +11,7 @@ module Gitlab
end
def project_name_regex
/\A[a-zA-Z0-9_][a-zA-Z0-9_\-\. ]*\z/
/\A[a-zA-Z0-9_.][a-zA-Z0-9_\-\. ]*\z/
end
def project_regex_message
......
require 'spec_helper'
describe GithubImportsController do
let(:user) { create(:user, github_access_token: 'asd123') }
before do
sign_in(user)
end
describe "GET callback" do
it "updates access token" do
token = "asdasd12345"
Gitlab::Github::Client.any_instance.stub_chain(:client, :auth_code, :get_token, :token).and_return(token)
Gitlab.config.omniauth.providers << OpenStruct.new(app_id: "asd123", app_secret: "asd123", name: "github")
get :callback
user.reload.github_access_token.should == token
controller.should redirect_to(status_github_import_url)
end
end
describe "GET status" do
before do
@repo = OpenStruct.new(login: 'vim', full_name: 'asd/vim')
end
it "assigns variables" do
@project = create(:project, import_type: 'github', creator_id: user.id)
controller.stub_chain(:octo_client, :repos).and_return([@repo])
controller.stub_chain(:octo_client, :orgs).and_return([])
get :status
expect(assigns(:already_added_projects)).to eq([@project])
expect(assigns(:repos)).to eq([@repo])
end
it "does not show already added project" do
@project = create(:project, import_type: 'github', creator_id: user.id, import_source: 'asd/vim')
controller.stub_chain(:octo_client, :repos).and_return([@repo])
controller.stub_chain(:octo_client, :orgs).and_return([])
get :status
expect(assigns(:already_added_projects)).to eq([@project])
expect(assigns(:repos)).to eq([])
end
end
describe "POST create" do
before do
@repo = OpenStruct.new(login: 'vim', full_name: 'asd/vim', owner: OpenStruct.new(login: "john"))
end
it "takes already existing namespace" do
namespace = create(:namespace, name: "john", owner: user)
Gitlab::Github::ProjectCreator.should_receive(:new).with(@repo, namespace, user).
and_return(double(execute: true))
controller.stub_chain(:octo_client, :repo).and_return(@repo)
post :create, format: :js
end
end
end
......@@ -20,4 +20,13 @@ describe ProjectsHelper do
"<option value=\"gitlab\">GitLab</option>"
end
end
describe "#project_status_css_class" do
it "returns appropriate class" do
project_status_css_class("started").should == "active"
project_status_css_class("failed").should == "danger"
project_status_css_class("finished").should == "success"
end
end
end
require 'spec_helper'
describe TreeHelper do
describe 'flatten_tree' do
let(:project) { create(:project) }
before {
@repository = project.repository
@commit = project.repository.commit("e56497bb")
}
context "on a directory containing more than one file/directory" do
let(:tree_item) { double(name: "files", path: "files") }
it "should return the directory name" do
flatten_tree(tree_item).should match('files')
end
end
context "on a directory containing only one directory" do
let(:tree_item) { double(name: "foo", path: "foo") }
it "should return the flattened path" do
flatten_tree(tree_item).should match('foo/bar')
end
end
end
end
require 'spec_helper'
describe Gitlab::Github::ProjectCreator do
let(:user) { create(:user, github_access_token: "asdffg") }
let(:repo) { OpenStruct.new(
login: 'vim',
name: 'vim',
private: true,
full_name: 'asd/vim',
clone_url: "https://gitlab.com/asd/vim.git",
owner: OpenStruct.new(login: "john"))
}
let(:namespace){ create(:namespace) }
it 'creates project' do
Project.any_instance.stub(:add_import_job)
project_creator = Gitlab::Github::ProjectCreator.new(repo, namespace, user)
project_creator.execute
project = Project.last
project.import_url.should == "https://asdffg@gitlab.com/asd/vim.git"
project.visibility_level.should == Gitlab::VisibilityLevel::PRIVATE
end
end
require 'spec_helper'
describe 'Gitlab::PushDataBuilder' do
let(:project) { create(:project) }
let(:user) { create(:user) }
describe :build_sample do
let(:data) { Gitlab::PushDataBuilder.build_sample(project, user) }
it { data.should be_a(Hash) }
it { data[:before].should == '6f6d7e7ed97bb5f0054f2b1df789b39ca89b6ff9' }
it { data[:after].should == '5937ac0a7beb003549fc5fd26fc247adbce4a52e' }
it { data[:ref].should == 'refs/heads/master' }
it { data[:commits].size.should == 3 }
it { data[:total_commits_count].should == 3 }
end
describe :build do
let(:data) do
Gitlab::PushDataBuilder.build(project,
user,
Gitlab::Git::BLANK_SHA,
'5937ac0a7beb003549fc5fd26fc247adbce4a52e',
'refs/tags/v1.1.0')
end
it { data.should be_a(Hash) }
it { data[:before].should == Gitlab::Git::BLANK_SHA }
it { data[:after].should == '5937ac0a7beb003549fc5fd26fc247adbce4a52e' }
it { data[:ref].should == 'refs/tags/v1.1.0' }
it { data[:commits].should be_empty }
it { data[:total_commits_count].should be_zero }
end
end
......@@ -33,7 +33,7 @@ describe AssemblaService, models: true do
token: 'verySecret',
subdomain: 'project_name'
)
@sample_data = GitPushService.new.sample_data(project, user)
@sample_data = Gitlab::PushDataBuilder.build_sample(project, user)
@api_url = 'https://atlas.assembla.com/spaces/project_name/github_tool?secret_key=verySecret'
WebMock.stub_request(:post, @api_url)
end
......
......@@ -32,7 +32,7 @@ describe FlowdockService do
service_hook: true,
token: 'verySecret'
)
@sample_data = GitPushService.new.sample_data(project, user)
@sample_data = Gitlab::PushDataBuilder.build_sample(project, user)
@api_url = 'https://api.flowdock.com/v1/git/verySecret'
WebMock.stub_request(:post, @api_url)
end
......
......@@ -33,7 +33,7 @@ describe GemnasiumService do
token: 'verySecret',
api_key: 'GemnasiumUserApiKey'
)
@sample_data = GitPushService.new.sample_data(project, user)
@sample_data = Gitlab::PushDataBuilder.build_sample(project, user)
end
it "should call Gemnasium service" do
Gemnasium::GitlabService.should_receive(:execute).with(an_instance_of(Hash)).once
......
......@@ -42,7 +42,7 @@ describe JiraService, models: true do
password: 'gitlab_jira_password',
api_version: '2'
)
@sample_data = GitPushService.new.sample_data(project, user)
@sample_data = Gitlab::PushDataBuilder.build_sample(project, user)
# https://github.com/bblimke/webmock#request-with-basic-authentication
@api_url = 'http://gitlab_jira_username:gitlab_jira_password@jira.example.com/rest/api/2/issue/JIRA-123/transitions'
......
......@@ -36,7 +36,7 @@ describe PushoverService do
let(:pushover) { PushoverService.new }
let(:user) { create(:user) }
let(:project) { create(:project) }
let(:sample_data) { GitPushService.new.sample_data(project, user) }
let(:sample_data) { Gitlab::PushDataBuilder.build_sample(project, user) }
let(:api_key) { 'verySecret' }
let(:user_key) { 'verySecret' }
......
......@@ -34,7 +34,7 @@ describe SlackService do
let(:slack) { SlackService.new }
let(:user) { create(:user) }
let(:project) { create(:project) }
let(:sample_data) { GitPushService.new.sample_data(project, user) }
let(:sample_data) { Gitlab::PushDataBuilder.build_sample(project, user) }
let(:webhook_url) { 'https://hooks.slack.com/services/SVRWFV0VVAR97N/B02R25XN3/ZBqu7xMupaEEICInN685' }
before do
......
......@@ -7,6 +7,8 @@ describe API::API, api: true do
let(:user3) { create(:user) }
let(:admin) { create(:admin) }
let(:project) { create(:project, creator_id: user.id, namespace: user.namespace) }
let(:project2) { create(:project, path: 'project2', creator_id: user.id, namespace: user.namespace) }
let(:project3) { create(:project, path: 'project3', creator_id: user.id, namespace: user.namespace) }
let(:snippet) { create(:project_snippet, author: user, project: project, title: 'example') }
let(:project_member) { create(:project_member, user: user, project: project, access_level: ProjectMember::MASTER) }
let(:project_member2) { create(:project_member, user: user3, project: project, access_level: ProjectMember::DEVELOPER) }
......@@ -29,6 +31,29 @@ describe API::API, api: true do
json_response.first['name'].should == project.name
json_response.first['owner']['username'].should == user.username
end
context "and using search" do
it "should return searched project" do
get api("/projects", user), { search: project.name }
response.status.should eq(200)
json_response.should be_an Array
json_response.length.should eq(1)
end
end
context "and using sorting" do
before do
project2
project3
end
it "should return the correct order when sorted by id" do
get api("/projects", user), { order_by: 'id', sort: 'desc'}
response.status.should eq(200)
json_response.should be_an Array
json_response.first['id'].should eq(project3.id)
end
end
end
end
......
......@@ -5,6 +5,7 @@ module TestEnv
# When developing the seed repository, comment out the branch you will modify.
BRANCH_SHA = {
'flatten-dir' => 'e56497b',
'feature' => '0b4bc9a',
'feature_conflict' => 'bb5206f',
'fix' => '12d65c8',
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment