Commit 48c3bfe5 authored by Douglas Barbosa Alexandre's avatar Douglas Barbosa Alexandre

Merge branch 'master' into fix-personal-snippet-access-workflow

parents 091979bd 5782217b
Please view this file on the master branch, on stable branches it's out of date. Please view this file on the master branch, on stable branches it's out of date.
v 8.2.0 (unreleased) v 8.2.0 (unreleased)
- Force update refs/merge-requests/X/head upon a push to the source branch of a merge request (Stan Hu)
- Improved performance of finding users by one of their Email addresses
- Improved performance of replacing references in comments - Improved performance of replacing references in comments
- Show last project commit to default branch on project home page - Show last project commit to default branch on project home page
- Highlight comment based on anchor in URL - Highlight comment based on anchor in URL
...@@ -15,6 +17,7 @@ v 8.2.0 (unreleased) ...@@ -15,6 +17,7 @@ v 8.2.0 (unreleased)
- Remove deprecated CI events from project settings page - Remove deprecated CI events from project settings page
- Use issue editor as cross reference comment author when issue is edited with a new mention. - Use issue editor as cross reference comment author when issue is edited with a new mention.
- Improve personal snippet access workflow - Improve personal snippet access workflow
- [API] Add ability to fetch the commit ID of the last commit that actually touched a file
v 8.1.1 v 8.1.1
- Fix cloning Wiki repositories via HTTP (Stan Hu) - Fix cloning Wiki repositories via HTTP (Stan Hu)
...@@ -30,6 +33,9 @@ v 8.1.0 ...@@ -30,6 +33,9 @@ v 8.1.0
- Ensure MySQL CI limits DB migrations occur after the fields have been created (Stan Hu) - Ensure MySQL CI limits DB migrations occur after the fields have been created (Stan Hu)
- Fix duplicate repositories in GitHub import page (Stan Hu) - Fix duplicate repositories in GitHub import page (Stan Hu)
- Redirect to a default path if HTTP_REFERER is not set (Stan Hu) - Redirect to a default path if HTTP_REFERER is not set (Stan Hu)
- Adds ability to create directories using the web editor (Ben Ford)
v 8.1.0 (unreleased)
- Send an email to admin email when a user is reported for spam (Jonathan Rochkind) - Send an email to admin email when a user is reported for spam (Jonathan Rochkind)
- Show notifications button when user is member of group rather than project (Grzegorz Bizon) - Show notifications button when user is member of group rather than project (Grzegorz Bizon)
- Fix bug preventing mentioned issued from being closed when MR is merged using fast-forward merge. - Fix bug preventing mentioned issued from being closed when MR is merged using fast-forward merge.
......
...@@ -11,10 +11,10 @@ class @EditBlob ...@@ -11,10 +11,10 @@ class @EditBlob
if ace_mode if ace_mode
editor.getSession().setMode "ace/mode/" + ace_mode editor.getSession().setMode "ace/mode/" + ace_mode
$(".js-commit-button").click -> # Before a form submission, move the content from the Ace editor into the
$("#file-content").val editor.getValue() # submitted textarea
$(".file-editor form").submit() $('form').submit ->
return false $("#file-content").val(editor.getValue())
editModePanes = $(".js-edit-mode-pane") editModePanes = $(".js-edit-mode-pane")
editModeLinks = $(".js-edit-mode a") editModeLinks = $(".js-edit-mode a")
......
...@@ -11,10 +11,10 @@ class @NewBlob ...@@ -11,10 +11,10 @@ class @NewBlob
if ace_mode if ace_mode
editor.getSession().setMode "ace/mode/" + ace_mode editor.getSession().setMode "ace/mode/" + ace_mode
$(".js-commit-button").click -> # Before a form submission, move the content from the Ace editor into the
$("#file-content").val editor.getValue() # submitted textarea
$(".file-editor form").submit() $('form').submit ->
return false $("#file-content").val(editor.getValue())
editor: -> editor: ->
return @editor return @editor
...@@ -50,7 +50,7 @@ ...@@ -50,7 +50,7 @@
.editor-file-name { .editor-file-name {
.new-file-name { .new-file-name {
display: inline-block; display: inline-block;
width: 200px; width: 450px;
} }
.form-control { .form-control {
......
...@@ -161,7 +161,7 @@ class Projects::BlobController < Projects::ApplicationController ...@@ -161,7 +161,7 @@ class Projects::BlobController < Projects::ApplicationController
if params[:file].present? if params[:file].present?
params[:file_name] = params[:file].original_filename params[:file_name] = params[:file].original_filename
end end
File.join(@path, File.basename(params[:file_name])) File.join(@path, params[:file_name])
else else
@path @path
end end
......
...@@ -528,7 +528,7 @@ class Repository ...@@ -528,7 +528,7 @@ class Repository
end end
def fetch_ref(source_path, source_ref, target_ref) def fetch_ref(source_path, source_ref, target_ref)
args = %W(git fetch #{source_path} #{source_ref}:#{target_ref}) args = %W(git fetch -f #{source_path} #{source_ref}:#{target_ref})
Gitlab::Popen.popen(args, path_to_repo) Gitlab::Popen.popen(args, path_to_repo)
end end
......
...@@ -235,21 +235,16 @@ class User < ActiveRecord::Base ...@@ -235,21 +235,16 @@ class User < ActiveRecord::Base
# Find a User by their primary email or any associated secondary email # Find a User by their primary email or any associated secondary email
def find_by_any_email(email) def find_by_any_email(email)
user_table = arel_table sql = 'SELECT *
email_table = Email.arel_table FROM users
WHERE id IN (
# Use ARel to build a query: SELECT id FROM users WHERE email = :email
query = user_table. UNION
# SELECT "users".* FROM "users" SELECT emails.user_id FROM emails WHERE email = :email
project(user_table[Arel.star]). )
# LEFT OUTER JOIN "emails" LIMIT 1;'
join(email_table, Arel::Nodes::OuterJoin).
# ON "users"."id" = "emails"."user_id" User.find_by_sql([sql, { email: email }]).first
on(user_table[:id].eq(email_table[:user_id])).
# WHERE ("user"."email" = '<email>' OR "emails"."email" = '<email>')
where(user_table[:email].eq(email).or(email_table[:email].eq(email)))
find_by_sql(query.to_sql).first
end end
def filter(filter_name) def filter(filter_name)
......
...@@ -5,5 +5,16 @@ module Files ...@@ -5,5 +5,16 @@ module Files
def commit def commit
repository.commit_dir(current_user, @file_path, @commit_message, @target_branch) repository.commit_dir(current_user, @file_path, @commit_message, @target_branch)
end end
def validate
super
unless @file_path =~ Gitlab::Regex.file_path_regex
raise_error(
'Your changes could not be committed, because the file path ' +
Gitlab::Regex.file_path_regex_message
)
end
end
end end
end end
...@@ -9,12 +9,17 @@ module Files ...@@ -9,12 +9,17 @@ module Files
def validate def validate
super super
file_name = File.basename(@file_path) if @file_path =~ Gitlab::Regex.directory_traversal_regex
raise_error(
'Your changes could not be committed, because the file name ' +
Gitlab::Regex.directory_traversal_regex_message
)
end
unless file_name =~ Gitlab::Regex.file_name_regex unless @file_path =~ Gitlab::Regex.file_path_regex
raise_error( raise_error(
'Your changes could not be committed, because the file name ' + 'Your changes could not be committed, because the file name ' +
Gitlab::Regex.file_name_regex_message Gitlab::Regex.file_path_regex_message
) )
end end
......
- if @project.labels.size == 0 - if @project.labels.size == 0
$('.labels').load(document.URL + ' .light-well').hide().fadeIn(1000) $('.labels').load(document.URL + ' .nothing-here-block').hide().fadeIn(1000)
...@@ -14,8 +14,8 @@ ...@@ -14,8 +14,8 @@
= render @labels = render @labels
= paginate @labels, theme: 'gitlab' = paginate @labels, theme: 'gitlab'
- else - else
.light-well .nothing-here-block
- if can? current_user, :admin_label, @project - if can? current_user, :admin_label, @project
.nothing-here-block Create first label or #{link_to 'generate', generate_namespace_project_labels_path(@project.namespace, @project), method: :post} default set of labels Create first label or #{link_to 'generate', generate_namespace_project_labels_path(@project.namespace, @project), method: :post} default set of labels
- else - else
.nothing-here-block No labels created No labels created
= link_to new_snippet_path, class: 'btn btn-grouped new-snippet-link', title: "New Snippet" do = link_to new_snippet_path, class: 'btn btn-grouped new-snippet-link', title: "New Snippet" do
= icon('plus') = icon('plus')
New Snippet New Snippet
- if can?(current_user, :admin_personal_snippet, @snippet)
= link_to snippet_path(@snippet), method: :delete, data: { confirm: "Are you sure?" }, class: "btn btn-grouped btn-remove", title: 'Delete Snippet' do
= icon('trash-o')
Delete
- if can?(current_user, :update_personal_snippet, @snippet) - if can?(current_user, :update_personal_snippet, @snippet)
= link_to edit_snippet_path(@snippet), class: "btn btn-grouped snippable-edit" do = link_to edit_snippet_path(@snippet), class: "btn btn-grouped snippable-edit" do
= icon('pencil-square-o') = icon('pencil-square-o')
Edit Edit
- if can?(current_user, :admin_personal_snippet, @snippet)
= link_to snippet_path(@snippet), method: :delete, data: { confirm: "Are you sure?" }, class: "btn btn-grouped btn-remove", title: 'Delete Snippet' do
= icon('trash-o')
Delete
...@@ -23,7 +23,8 @@ Example response: ...@@ -23,7 +23,8 @@ Example response:
"content": "IyA9PSBTY2hlbWEgSW5mb3...", "content": "IyA9PSBTY2hlbWEgSW5mb3...",
"ref": "master", "ref": "master",
"blob_id": "79f7bbd25901e8334750839545a9bd021f0e4c83", "blob_id": "79f7bbd25901e8334750839545a9bd021f0e4c83",
"commit_id": "d5a3ff139356ce33e37e73add446f16869741b50" "commit_id": "d5a3ff139356ce33e37e73add446f16869741b50",
"last_commit_id": "570e7b2abdd848b95f2f578043fc23bd6f6fd24d"
} }
``` ```
......
...@@ -25,7 +25,7 @@ GitLab CI API has 4 authentication methods: ...@@ -25,7 +25,7 @@ GitLab CI API has 4 authentication methods:
Authentication is done by Authentication is done by
sending the `private-token` of a valid user and the `url` of an sending the `private-token` of a valid user and the `url` of an
authorized Gitlab instance via a query string along with the API authorized GitLab instance via a query string along with the API
request: request:
GET http://gitlab.example.com/ci/api/v1/projects?private_token=QVy1PB7sTxfy4pqfZM1U&url=http://demo.gitlab.com/ GET http://gitlab.example.com/ci/api/v1/projects?private_token=QVy1PB7sTxfy4pqfZM1U&url=http://demo.gitlab.com/
......
# Projects API # Projects API
This API is intended to aid in the setup and configuration of This API is intended to aid in the setup and configuration of
projects on Gitlab CI. projects on GitLab CI.
__Authentication is done by GitLab user token & GitLab url__ __Authentication is done by GitLab user token & GitLab url__
...@@ -88,23 +88,23 @@ authorized. ...@@ -88,23 +88,23 @@ authorized.
Parameters: Parameters:
* `id` (required) - The ID of the Gitlab CI project * `id` (required) - The ID of the GitLab CI project
### Create Project ### Create Project
Creates a Gitlab CI project using Gitlab project details. Creates a GitLab CI project using GitLab project details.
POST /ci/projects POST /ci/projects
Parameters: Parameters:
* `name` (required) - The name of the project * `name` (required) - The name of the project
* `gitlab_id` (required) - The ID of the project on the Gitlab instance * `gitlab_id` (required) - The ID of the project on the GitLab instance
* `default_ref` (optional) - The branch to run on (default to `master`) * `default_ref` (optional) - The branch to run on (default to `master`)
### Update Project ### Update Project
Updates a Gitlab CI project using Gitlab project details that the Updates a GitLab CI project using GitLab project details that the
authenticated user has access to. authenticated user has access to.
PUT /ci/projects/:id PUT /ci/projects/:id
...@@ -116,13 +116,13 @@ Parameters: ...@@ -116,13 +116,13 @@ Parameters:
### Remove Project ### Remove Project
Removes a Gitlab CI project that the authenticated user has access to. Removes a GitLab CI project that the authenticated user has access to.
DELETE /ci/projects/:id DELETE /ci/projects/:id
Parameters: Parameters:
* `id` (required) - The ID of the Gitlab CI project * `id` (required) - The ID of the GitLab CI project
### Link Project to Runner ### Link Project to Runner
...@@ -133,8 +133,8 @@ authorized user). ...@@ -133,8 +133,8 @@ authorized user).
Parameters: Parameters:
* `id` (required) - The ID of the Gitlab CI project * `id` (required) - The ID of the GitLab CI project
* `runner_id` (required) - The ID of the Gitlab CI runner * `runner_id` (required) - The ID of the GitLab CI runner
### Remove Project from Runner ### Remove Project from Runner
...@@ -145,5 +145,5 @@ via authorized user). ...@@ -145,5 +145,5 @@ via authorized user).
Parameters: Parameters:
* `id` (required) - The ID of the Gitlab CI project * `id` (required) - The ID of the GitLab CI project
* `runner_id` (required) - The ID of the Gitlab CI runner * `runner_id` (required) - The ID of the GitLab CI runner
\ No newline at end of file \ No newline at end of file
...@@ -6,7 +6,7 @@ ...@@ -6,7 +6,7 @@
__Authentication is done by GitLab user token & GitLab url__ __Authentication is done by GitLab user token & GitLab url__
Used to get information about all runners registered on the Gitlab CI Used to get information about all runners registered on the GitLab CI
instance. instance.
GET /ci/runners GET /ci/runners
...@@ -31,7 +31,7 @@ Returns: ...@@ -31,7 +31,7 @@ Returns:
__Authentication is done with a Shared runner registration token or a project Specific runner registration token__ __Authentication is done with a Shared runner registration token or a project Specific runner registration token__
Used to make Gitlab CI aware of available runners. Used to make GitLab CI aware of available runners.
POST /ci/runners/register POST /ci/runners/register
......
# Build script examples # Build script examples
+ [Test and deploy Ruby Application to Heroku](test-and-deploy-ruby-application-to-heroku.md) + [Test and deploy Ruby applications to Heroku](test-and-deploy-ruby-application-to-heroku.md)
+ [Test and deploy Python Application to Heroku](test-and-deploy-python-application-to-heroku.md) + [Test and deploy Python applications to Heroku](test-and-deploy-python-application-to-heroku.md)
+ [Test Clojure applications](examples/test-clojure-application.md) + [Test Clojure applications](test-clojure-application.md)
...@@ -9,7 +9,7 @@ bundle exec rake setup ...@@ -9,7 +9,7 @@ bundle exec rake setup
``` ```
The `setup` task is a alias for `gitlab:setup`. The `setup` task is a alias for `gitlab:setup`.
This tasks calls `db:setup` to create the database, calls `add_limits_mysql` that adds limits to the database schema in case of a MySQL database and fianlly it calls `db:seed_fu` to seed the database. This tasks calls `db:setup` to create the database, calls `add_limits_mysql` that adds limits to the database schema in case of a MySQL database and finally it calls `db:seed_fu` to seed the database.
Note: `db:setup` calls `db:seed` but this does nothing. Note: `db:setup` calls `db:seed` but this does nothing.
## Run tests ## Run tests
......
...@@ -330,6 +330,10 @@ GitLab Shell is an SSH access and repository management software developed speci ...@@ -330,6 +330,10 @@ GitLab Shell is an SSH access and repository management software developed speci
### Initialize Database and Activate Advanced Features ### Initialize Database and Activate Advanced Features
# Go to Gitlab installation folder
cd /home/git/gilab
sudo -u git -H bundle exec rake gitlab:setup RAILS_ENV=production sudo -u git -H bundle exec rake gitlab:setup RAILS_ENV=production
# Type 'yes' to create the database tables. # Type 'yes' to create the database tables.
...@@ -489,7 +493,7 @@ See the [omniauth integration document](../integration/omniauth.md) ...@@ -489,7 +493,7 @@ See the [omniauth integration document](../integration/omniauth.md)
### Build your projects ### Build your projects
GitLab can build your projects. To enable that feature you need GitLab Runners to do that for you. GitLab can build your projects. To enable that feature you need GitLab Runners to do that for you.
Checkout the [Gitlab Runner section](https://about.gitlab.com/gitlab-ci/#gitlab-runner) to install it Checkout the [GitLab Runner section](https://about.gitlab.com/gitlab-ci/#gitlab-runner) to install it
### Custom Redis Connection ### Custom Redis Connection
......
...@@ -78,7 +78,7 @@ threshold is a random value between 200 and 250 MB. The master process (PID ...@@ -78,7 +78,7 @@ threshold is a random value between 200 and 250 MB. The master process (PID
``` ```
One other thing that stands out in the log snippet above, taken from One other thing that stands out in the log snippet above, taken from
Gitlab.com, is that 'worker 4' was serving requests for only 23 seconds. This GitLab.com, is that 'worker 4' was serving requests for only 23 seconds. This
is a normal value for our current GitLab.com setup and traffic. is a normal value for our current GitLab.com setup and traffic.
The high frequency of Unicorn memory restarts on some GitLab sites can be a The high frequency of Unicorn memory restarts on some GitLab sites can be a
......
...@@ -15,8 +15,7 @@ Note: It is a best practice to use a password for an SSH key, but it is not ...@@ -15,8 +15,7 @@ Note: It is a best practice to use a password for an SSH key, but it is not
required and you can skip creating a password by pressing enter. Note that required and you can skip creating a password by pressing enter. Note that
the password you choose here can't be altered or retrieved. the password you choose here can't be altered or retrieved.
To generate a new SSH key, use the following command: To generate a new SSH key, use the following commandGitLab```bash
```bash
ssh-keygen -t rsa -C "$your_email" ssh-keygen -t rsa -C "$your_email"
``` ```
This command will prompt you for a location and filename to store the key This command will prompt you for a location and filename to store the key
...@@ -82,7 +81,7 @@ How to add your ssh key to Eclipse: http://wiki.eclipse.org/EGit/User_Guide#Ecli ...@@ -82,7 +81,7 @@ How to add your ssh key to Eclipse: http://wiki.eclipse.org/EGit/User_Guide#Ecli
## Tip: Non-default OpenSSH key file names or locations ## Tip: Non-default OpenSSH key file names or locations
If, for whatever reason, you decide to specify a non-default location and filename for your Gitlab SSH key pair, you must configure your SSH client to find your Gitlab SSH private key for connections to your Gitlab server (perhaps gitlab.com). For OpenSSH clients, this is handled in the `~/.ssh/config` file with a stanza similar to the following: If, for whatever reason, you decide to specify a non-default location and filename for your GitLab SSH key pair, you must configure your SSH client to find your GitLab SSH private key for connections to your GitLab server (perhaps gitlab.com). For OpenSSH clients, this is handled in the `~/.ssh/config` file with a stanza similar to the following:
``` ```
# #
...@@ -97,7 +96,7 @@ User mygitlabusername ...@@ -97,7 +96,7 @@ User mygitlabusername
Another example Another example
``` ```
# #
# Our company's internal Gitlab server # Our company's internal GitLab server
# #
Host my-gitlab.company.com Host my-gitlab.company.com
RSAAuthentication yes RSAAuthentication yes
......
# From 8.1 to 8.2
**NOTE:** GitLab 8.0 introduced several significant changes related to
installation and configuration which *are not duplicated here*. Be sure you're
already running a working version of 8.0 before proceeding with this guide.
### 0. Double-check your Git version
**This notice applies only to /usr/local/bin/git**
If you compiled Git from source on your GitLab server then please double-check
that you are using a version that protects against CVE-2014-9390. For six
months after this vulnerability became known the GitLab installation guide
still contained instructions that would install the outdated, 'vulnerable' Git
version 2.1.2.
Run the following command to get your current Git version:
```sh
/usr/local/bin/git --version
```
If you see 'No such file or directory' then you did not install Git according
to the outdated instructions from the GitLab installation guide and you can go
to the next step 'Stop server' below.
If you see a version string then it should be v1.8.5.6, v1.9.5, v2.0.5, v2.1.4,
v2.2.1 or newer. You can use the [instructions in the GitLab source
installation
guide](https://gitlab.com/gitlab-org/gitlab-ce/blob/master/doc/install/installation.md#1-packages-dependencies)
to install a newer version of Git.
### 1. Stop server
sudo service gitlab stop
### 2. Backup
```bash
cd /home/git/gitlab
sudo -u git -H bundle exec rake gitlab:backup:create RAILS_ENV=production
```
### 3. Get latest code
```bash
sudo -u git -H git fetch --all
sudo -u git -H git checkout -- db/schema.rb # local changes will be restored automatically
```
For GitLab Community Edition:
```bash
sudo -u git -H git checkout 8-2-stable
```
OR
For GitLab Enterprise Edition:
```bash
sudo -u git -H git checkout 8-2-stable-ee
```
### 4. Update gitlab-shell
```bash
cd /home/git/gitlab-shell
sudo -u git -H git fetch
sudo -u git -H git checkout v2.6.5
```
### 5. Replace gitlab-git-http-server with gitlab-workhorse
Install and compile gitlab-workhorse. This requires [Go
1.5](https://golang.org/dl) which should already be on your system
from GitLab 8.1.
```bash
cd /home/git
sudo -u git -H git clone https://gitlab.com/gitlab-org/gitlab-workhorse.git
cd gitlab-workhorse
sudo -u git -H git checkout 0.3.1
sudo -u git -H make
```
Update the GitLab init script and 'default' file.
```
cd /home/git/gitlab
sudo cp lib/support/init.d/gitlab /etc/init.d/gitlab
test -e /etc/default/gitlab && \
sudo sed -i.pre-8.2 's/^\([^=]*\)gitlab_git_http_server/\1gitlab_workhorse/' /etc/default/gitlab
```
Make sure that you also update your **NGINX configuration** to use
the new gitlab-workhorse.socket file.
### 6. Install libs, migrations, etc.
```bash
cd /home/git/gitlab
# MySQL installations (note: the line below states '--without postgres')
sudo -u git -H bundle install --without postgres development test --deployment
# PostgreSQL installations (note: the line below states '--without mysql')
sudo -u git -H bundle install --without mysql development test --deployment
# Run database migrations
sudo -u git -H bundle exec rake db:migrate RAILS_ENV=production
# Clean up assets and cache
sudo -u git -H bundle exec rake assets:clean assets:precompile cache:clear RAILS_ENV=production
# Update init.d script
sudo cp lib/support/init.d/gitlab /etc/init.d/gitlab
```
### 7. Update configuration files
#### New configuration options for `gitlab.yml`
There are new configuration options available for [`gitlab.yml`](config/gitlab.yml.example). View them with the command below and apply them manually to your current `gitlab.yml`:
```sh
git diff origin/8-1-stable:config/gitlab.yml.example origin/8-2-stable:config/gitlab.yml.example
```
#### Nginx configuration
View changes between the previous recommended Nginx configuration and the
current one:
```sh
# For HTTPS configurations
git diff origin/8-1-stable:lib/support/nginx/gitlab-ssl origin/8-2-stable:lib/support/nginx/gitlab-ssl
# For HTTP configurations
git diff origin/8-1-stable:lib/support/nginx/gitlab origin/8-2-stable:lib/support/nginx/gitlab
```
If you are using Apache instead of NGINX please see the updated [Apache templates].
Also note that because Apache does not support upstreams behind Unix sockets you
will need to let gitlab-git-http-server listen on a TCP port. You can do this
via [/etc/default/gitlab].
[Apache templates]: https://gitlab.com/gitlab-org/gitlab-recipes/tree/master/web-server/apache
[/etc/default/gitlab]: https://gitlab.com/gitlab-org/gitlab-ce/blob/8-2-stable/lib/support/init.d/gitlab.default.example#L34
### 8. Start application
sudo service gitlab start
sudo service nginx restart
### 9. Check application status
Check if GitLab and its environment are configured correctly:
sudo -u git -H bundle exec rake gitlab:env:info RAILS_ENV=production
To make sure you didn't miss anything run a more thorough check:
sudo -u git -H bundle exec rake gitlab:check RAILS_ENV=production
If all items are green, then congratulations, the upgrade is complete!
## Things went south? Revert to previous version (8.0)
### 1. Revert the code to the previous version
Follow the [upgrade guide from 7.14 to 8.0](7.14-to-8.0.md), except for the database migration
(The backup is already migrated to the previous version)
### 2. Restore from the backup
```bash
cd /home/git/gitlab
sudo -u git -H bundle exec rake gitlab:backup:restore RAILS_ENV=production
```
If you have more than one backup `*.tar` file(s) please add `BACKUP=timestamp_of_backup` to the command above.
## Troubleshooting
### "You appear to have cloned an empty repository."
See the [7.14 to 8.0 update guide](7.14-to-8.0.md#troubleshooting).
...@@ -2,12 +2,12 @@ ...@@ -2,12 +2,12 @@
You can import your existing GitLab.com projects to your GitLab instance. But keep in mind that it is possible only if You can import your existing GitLab.com projects to your GitLab instance. But keep in mind that it is possible only if
GitLab support is enabled on your GitLab instance. GitLab support is enabled on your GitLab instance.
You can read more about Gitlab support [here](http://doc.gitlab.com/ce/integration/gitlab.html) You can read more about GitLab support [here](http://doc.gitlab.com/ce/integration/gitlab.html)
To get to the importer page you need to go to "New project" page. To get to the importer page you need to go to "New project" page.
![New project page](gitlab_importer/new_project_page.png) ![New project page](gitlab_importer/new_project_page.png)
Click on the "Import projects from Gitlab.com" link and you will be redirected to GitLab.com Click on the "Import projects from GitLab.com" link and you will be redirected to GitLab.com
for permission to access your projects. After accepting, you'll be automatically redirected to the importer. for permission to access your projects. After accepting, you'll be automatically redirected to the importer.
......
...@@ -90,6 +90,16 @@ Feature: Project Source Browse Files ...@@ -90,6 +90,16 @@ Feature: Project Source Browse Files
Then I am on the new file page Then I am on the new file page
And I see a commit error message And I see a commit error message
@javascript
Scenario: I can create file with a directory name
Given I click on "New file" link in repo
And I fill the new file name with a new directory
And I edit code
And I fill the commit message
And I click on "Commit changes"
Then I am redirected to the new file with directory
And I should see its new content
@javascript @javascript
Scenario: I can edit file Scenario: I can edit file
Given I click on ".gitignore" file in repo Given I click on ".gitignore" file in repo
......
...@@ -78,6 +78,10 @@ class Spinach::Features::ProjectSourceBrowseFiles < Spinach::FeatureSteps ...@@ -78,6 +78,10 @@ class Spinach::Features::ProjectSourceBrowseFiles < Spinach::FeatureSteps
fill_in :file_name, with: 'Spaces Not Allowed' fill_in :file_name, with: 'Spaces Not Allowed'
end end
step 'I fill the new file name with a new directory' do
fill_in :file_name, with: new_file_name_with_directory
end
step 'I fill the commit message' do step 'I fill the commit message' do
fill_in :commit_message, with: 'Not yet a commit message.', visible: true fill_in :commit_message, with: 'Not yet a commit message.', visible: true
end end
...@@ -238,6 +242,11 @@ class Spinach::Features::ProjectSourceBrowseFiles < Spinach::FeatureSteps ...@@ -238,6 +242,11 @@ class Spinach::Features::ProjectSourceBrowseFiles < Spinach::FeatureSteps
@project.namespace, @project, 'master/' + new_file_name)) @project.namespace, @project, 'master/' + new_file_name))
end end
step 'I am redirected to the new file with directory' do
expect(current_path).to eq(namespace_project_blob_path(
@project.namespace, @project, 'master/' + new_file_name_with_directory))
end
step 'I am redirected to the new file on new branch' do step 'I am redirected to the new file on new branch' do
expect(current_path).to eq(namespace_project_blob_path( expect(current_path).to eq(namespace_project_blob_path(
@project.namespace, @project, 'new_branch_name/' + new_file_name)) @project.namespace, @project, 'new_branch_name/' + new_file_name))
...@@ -335,6 +344,12 @@ class Spinach::Features::ProjectSourceBrowseFiles < Spinach::FeatureSteps ...@@ -335,6 +344,12 @@ class Spinach::Features::ProjectSourceBrowseFiles < Spinach::FeatureSteps
'not_a_file.md' 'not_a_file.md'
end end
# Constant value that is a valid filename with directory and
# not a filename present at root of the seed repository.
def new_file_name_with_directory
'foo/bar/baz.txt'
end
# Constant value that is a valid directory and # Constant value that is a valid directory and
# not a directory present at root of the seed repository. # not a directory present at root of the seed repository.
def new_dir_name def new_dir_name
......
...@@ -43,7 +43,8 @@ module API ...@@ -43,7 +43,8 @@ module API
# "content": "IyA9PSBTY2hlbWEgSW5mb3...", # "content": "IyA9PSBTY2hlbWEgSW5mb3...",
# "ref": "master", # "ref": "master",
# "blob_id": "79f7bbd25901e8334750839545a9bd021f0e4c83", # "blob_id": "79f7bbd25901e8334750839545a9bd021f0e4c83",
# "commit_id": "d5a3ff139356ce33e37e73add446f16869741b50" # "commit_id": "d5a3ff139356ce33e37e73add446f16869741b50",
# "last_commit_id": "570e7b2abdd848b95f2f578043fc23bd6f6fd24d",
# } # }
# #
get ":id/repository/files" do get ":id/repository/files" do
...@@ -71,6 +72,7 @@ module API ...@@ -71,6 +72,7 @@ module API
ref: ref, ref: ref,
blob_id: blob.id, blob_id: blob.id,
commit_id: commit.id, commit_id: commit.id,
last_commit_id: user_project.repository.last_commit_for_path(commit.sha, file_path).id
} }
else else
not_found! 'File' not_found! 'File'
......
module Backup module Backup
class Builds class Builds < Files
attr_reader :app_builds_dir, :backup_builds_dir, :backup_dir
def initialize def initialize
@app_builds_dir = Settings.gitlab_ci.builds_path super('builds', Settings.gitlab_ci.builds_path)
@backup_dir = Gitlab.config.backup.path
@backup_builds_dir = File.join(Gitlab.config.backup.path, 'builds')
end
# Copy builds from builds directory to backup/builds
def dump
FileUtils.rm_rf(backup_builds_dir)
# Ensure the parent dir of backup_builds_dir exists
FileUtils.mkdir_p(Gitlab.config.backup.path)
# Fail if somebody raced to create backup_builds_dir before us
FileUtils.mkdir(backup_builds_dir, mode: 0700)
FileUtils.cp_r(app_builds_dir, backup_dir)
end end
def restore def create_files_dir
backup_existing_builds_dir Dir.mkdir(app_files_dir, 0700)
FileUtils.cp_r(backup_builds_dir, app_builds_dir)
end
def backup_existing_builds_dir
timestamped_builds_path = File.join(app_builds_dir, '..', "builds.#{Time.now.to_i}")
if File.exists?(app_builds_dir)
FileUtils.mv(app_builds_dir, File.expand_path(timestamped_builds_path))
end
end end
end end
end end
...@@ -2,26 +2,26 @@ require 'yaml' ...@@ -2,26 +2,26 @@ require 'yaml'
module Backup module Backup
class Database class Database
attr_reader :config, :db_dir attr_reader :config, :db_file_name
def initialize def initialize
@config = YAML.load_file(File.join(Rails.root,'config','database.yml'))[Rails.env] @config = YAML.load_file(File.join(Rails.root,'config','database.yml'))[Rails.env]
@db_dir = File.join(Gitlab.config.backup.path, 'db') @db_file_name = File.join(Gitlab.config.backup.path, 'db', 'database.sql.gz')
end end
def dump def dump
FileUtils.rm_rf(@db_dir) FileUtils.mkdir_p(File.dirname(db_file_name))
# Ensure the parent dir of @db_dir exists FileUtils.rm_f(db_file_name)
FileUtils.mkdir_p(Gitlab.config.backup.path) compress_rd, compress_wr = IO.pipe
# Fail if somebody raced to create @db_dir before us compress_pid = spawn(*%W(gzip -1 -c), in: compress_rd, out: [db_file_name, 'w', 0600])
FileUtils.mkdir(@db_dir, mode: 0700) compress_rd.close
success = case config["adapter"] dump_pid = case config["adapter"]
when /^mysql/ then when /^mysql/ then
$progress.print "Dumping MySQL database #{config['database']} ... " $progress.print "Dumping MySQL database #{config['database']} ... "
# Workaround warnings from MySQL 5.6 about passwords on cmd line # Workaround warnings from MySQL 5.6 about passwords on cmd line
ENV['MYSQL_PWD'] = config["password"].to_s if config["password"] ENV['MYSQL_PWD'] = config["password"].to_s if config["password"]
system('mysqldump', *mysql_args, config['database'], out: db_file_name) spawn('mysqldump', *mysql_args, config['database'], out: compress_wr)
when "postgresql" then when "postgresql" then
$progress.print "Dumping PostgreSQL database #{config['database']} ... " $progress.print "Dumping PostgreSQL database #{config['database']} ... "
pg_env pg_env
...@@ -30,48 +30,42 @@ module Backup ...@@ -30,48 +30,42 @@ module Backup
pgsql_args << "-n" pgsql_args << "-n"
pgsql_args << Gitlab.config.backup.pg_schema pgsql_args << Gitlab.config.backup.pg_schema
end end
system('pg_dump', *pgsql_args, config['database'], out: db_file_name) spawn('pg_dump', *pgsql_args, config['database'], out: compress_wr)
end end
report_success(success) compress_wr.close
abort 'Backup failed' unless success
success = [compress_pid, dump_pid].all? { |pid| Process.waitpid(pid); $?.success? }
$progress.print 'Compressing database ... '
success = system('gzip', db_file_name)
report_success(success) report_success(success)
abort 'Backup failed: compress error' unless success abort 'Backup failed' unless success
end end
def restore def restore
$progress.print 'Decompressing database ... ' decompress_rd, decompress_wr = IO.pipe
success = system('gzip', '-d', db_file_name_gz) decompress_pid = spawn(*%W(gzip -cd), out: decompress_wr, in: db_file_name)
report_success(success) decompress_wr.close
abort 'Restore failed: decompress error' unless success
success = case config["adapter"] restore_pid = case config["adapter"]
when /^mysql/ then when /^mysql/ then
$progress.print "Restoring MySQL database #{config['database']} ... " $progress.print "Restoring MySQL database #{config['database']} ... "
# Workaround warnings from MySQL 5.6 about passwords on cmd line # Workaround warnings from MySQL 5.6 about passwords on cmd line
ENV['MYSQL_PWD'] = config["password"].to_s if config["password"] ENV['MYSQL_PWD'] = config["password"].to_s if config["password"]
system('mysql', *mysql_args, config['database'], in: db_file_name) spawn('mysql', *mysql_args, config['database'], in: decompress_rd)
when "postgresql" then when "postgresql" then
$progress.print "Restoring PostgreSQL database #{config['database']} ... " $progress.print "Restoring PostgreSQL database #{config['database']} ... "
pg_env pg_env
system('psql', config['database'], '-f', db_file_name) spawn('psql', config['database'], in: decompress_rd)
end end
decompress_rd.close
success = [decompress_pid, restore_pid].all? { |pid| Process.waitpid(pid); $?.success? }
report_success(success) report_success(success)
abort 'Restore failed' unless success abort 'Restore failed' unless success
end end
protected protected
def db_file_name
File.join(db_dir, 'database.sql')
end
def db_file_name_gz
File.join(db_dir, 'database.sql.gz')
end
def mysql_args def mysql_args
args = { args = {
'host' => '--host', 'host' => '--host',
......
require 'open3'
module Backup
class Files
attr_reader :name, :app_files_dir, :backup_tarball, :files_parent_dir
def initialize(name, app_files_dir)
@name = name
@app_files_dir = File.realpath(app_files_dir)
@files_parent_dir = File.realpath(File.join(@app_files_dir, '..'))
@backup_tarball = File.join(Gitlab.config.backup.path, name + '.tar.gz')
end
# Copy files from public/files to backup/files
def dump
FileUtils.mkdir_p(Gitlab.config.backup.path)
FileUtils.rm_f(backup_tarball)
run_pipeline!([%W(tar -C #{app_files_dir} -cf - .), %W(gzip -c -1)], out: [backup_tarball, 'w', 0600])
end
def restore
backup_existing_files_dir
create_files_dir
run_pipeline!([%W(gzip -cd), %W(tar -C #{app_files_dir} -xf -)], in: backup_tarball)
end
def backup_existing_files_dir
timestamped_files_path = File.join(files_parent_dir, "#{name}.#{Time.now.to_i}")
if File.exists?(app_files_dir)
FileUtils.mv(app_files_dir, File.expand_path(timestamped_files_path))
end
end
def run_pipeline!(cmd_list, options={})
status_list = Open3.pipeline(*cmd_list, options)
abort 'Backup failed' unless status_list.compact.all?(&:success?)
end
end
end
...@@ -150,11 +150,11 @@ module Backup ...@@ -150,11 +150,11 @@ module Backup
private private
def backup_contents def backup_contents
folders_to_backup + ["backup_information.yml"] folders_to_backup + ["uploads.tar.gz", "builds.tar.gz", "backup_information.yml"]
end end
def folders_to_backup def folders_to_backup
folders = %w{repositories db uploads builds} folders = %w{repositories db}
if ENV["SKIP"] if ENV["SKIP"]
return folders.reject{ |folder| ENV["SKIP"].include?(folder) } return folders.reject{ |folder| ENV["SKIP"].include?(folder) }
......
module Backup module Backup
class Uploads class Uploads < Files
attr_reader :app_uploads_dir, :backup_uploads_dir, :backup_dir
def initialize def initialize
@app_uploads_dir = File.realpath(Rails.root.join('public', 'uploads')) super('uploads', Rails.root.join('public/uploads'))
@backup_dir = Gitlab.config.backup.path
@backup_uploads_dir = File.join(Gitlab.config.backup.path, 'uploads')
end end
# Copy uploads from public/uploads to backup/uploads def create_files_dir
def dump Dir.mkdir(app_files_dir)
FileUtils.rm_rf(backup_uploads_dir)
# Ensure the parent dir of backup_uploads_dir exists
FileUtils.mkdir_p(Gitlab.config.backup.path)
# Fail if somebody raced to create backup_uploads_dir before us
FileUtils.mkdir(backup_uploads_dir, mode: 0700)
FileUtils.cp_r(app_uploads_dir, backup_dir)
end
def restore
backup_existing_uploads_dir
FileUtils.cp_r(backup_uploads_dir, app_uploads_dir)
end
def backup_existing_uploads_dir
timestamped_uploads_path = File.join(app_uploads_dir, '..', "uploads.#{Time.now.to_i}")
if File.exists?(app_uploads_dir)
FileUtils.mv(app_uploads_dir, File.expand_path(timestamped_uploads_path))
end
end end
end end
end end
...@@ -34,7 +34,7 @@ module Grack ...@@ -34,7 +34,7 @@ module Grack
auth! auth!
if project && authorized_request? if project && authorized_request?
# Tell gitlab-git-http-server the request is OK, and what the GL_ID is # Tell gitlab-workhorse the request is OK, and what the GL_ID is
render_grack_auth_ok render_grack_auth_ok
elsif @user.nil? && !@ci elsif @user.nil? && !@ci
unauthorized unauthorized
......
...@@ -48,6 +48,12 @@ module Gitlab ...@@ -48,6 +48,12 @@ module Gitlab
# Allow span elements # Allow span elements
whitelist[:elements].push('span') whitelist[:elements].push('span')
# Allow any protocol in `a` elements...
whitelist[:protocols].delete('a')
# ...but then remove links with the `javascript` protocol
whitelist[:transformers].push(remove_javascript_links)
# Remove `rel` attribute from `a` elements # Remove `rel` attribute from `a` elements
whitelist[:transformers].push(remove_rel) whitelist[:transformers].push(remove_rel)
...@@ -57,6 +63,19 @@ module Gitlab ...@@ -57,6 +63,19 @@ module Gitlab
whitelist whitelist
end end
def remove_javascript_links
lambda do |env|
node = env[:node]
return unless node.name == 'a'
return unless node.has_attribute?('href')
if node['href'].start_with?('javascript', ':javascript')
node.remove_attribute('href')
end
end
end
def remove_rel def remove_rel
lambda do |env| lambda do |env|
if env[:node_name] == 'a' if env[:node_name] == 'a'
......
...@@ -51,6 +51,23 @@ module Gitlab ...@@ -51,6 +51,23 @@ module Gitlab
"can contain only letters, digits, '_', '-' and '.'. " "can contain only letters, digits, '_', '-' and '.'. "
end end
def file_path_regex
@file_path_regex ||= /\A[a-zA-Z0-9_\-\.\/]*\z/.freeze
end
def file_path_regex_message
"can contain only letters, digits, '_', '-' and '.'. Separate directories with a '/'. "
end
def directory_traversal_regex
@directory_traversal_regex ||= /\.{2}/.freeze
end
def directory_traversal_regex_message
"cannot include directory traversal. "
end
def archive_formats_regex def archive_formats_regex
# |zip|tar| tar.gz | tar.bz2 | # |zip|tar| tar.gz | tar.bz2 |
......
...@@ -37,10 +37,9 @@ web_server_pid_path="$pid_path/unicorn.pid" ...@@ -37,10 +37,9 @@ web_server_pid_path="$pid_path/unicorn.pid"
sidekiq_pid_path="$pid_path/sidekiq.pid" sidekiq_pid_path="$pid_path/sidekiq.pid"
mail_room_enabled=false mail_room_enabled=false
mail_room_pid_path="$pid_path/mail_room.pid" mail_room_pid_path="$pid_path/mail_room.pid"
gitlab_git_http_server_pid_path="$pid_path/gitlab-git-http-server.pid" gitlab_workhorse_pid_path="$pid_path/gitlab-workhorse.pid"
gitlab_git_http_server_options="-listenUmask 0 -listenNetwork unix -listenAddr $socket_path/gitlab-git-http-server.socket -authBackend http://127.0.0.1:8080" gitlab_workhorse_options="-listenUmask 0 -listenNetwork unix -listenAddr $socket_path/gitlab-workhorse.socket -authBackend http://127.0.0.1:8080"
gitlab_git_http_server_repo_root='/home/git/repositories' gitlab_workhorse_log="$app_root/log/gitlab-workhorse.log"
gitlab_git_http_server_log="$app_root/log/gitlab-git-http-server.log"
shell_path="/bin/bash" shell_path="/bin/bash"
# Read configuration variable file if it is present # Read configuration variable file if it is present
...@@ -76,8 +75,8 @@ check_pids(){ ...@@ -76,8 +75,8 @@ check_pids(){
else else
spid=0 spid=0
fi fi
if [ -f "$gitlab_git_http_server_pid_path" ]; then if [ -f "$gitlab_workhorse_pid_path" ]; then
hpid=$(cat "$gitlab_git_http_server_pid_path") hpid=$(cat "$gitlab_workhorse_pid_path")
else else
hpid=0 hpid=0
fi fi
...@@ -94,7 +93,7 @@ check_pids(){ ...@@ -94,7 +93,7 @@ check_pids(){
wait_for_pids(){ wait_for_pids(){
# We are sleeping a bit here mostly because sidekiq is slow at writing it's pid # We are sleeping a bit here mostly because sidekiq is slow at writing it's pid
i=0; i=0;
while [ ! -f $web_server_pid_path ] || [ ! -f $sidekiq_pid_path ] || [ ! -f $gitlab_git_http_server_pid_path ] || { [ "$mail_room_enabled" = true ] && [ ! -f $mail_room_pid_path ]; }; do while [ ! -f $web_server_pid_path ] || [ ! -f $sidekiq_pid_path ] || [ ! -f $gitlab_workhorse_pid_path ] || { [ "$mail_room_enabled" = true ] && [ ! -f $mail_room_pid_path ]; }; do
sleep 0.1; sleep 0.1;
i=$((i+1)) i=$((i+1))
if [ $((i%10)) = 0 ]; then if [ $((i%10)) = 0 ]; then
...@@ -131,9 +130,9 @@ check_status(){ ...@@ -131,9 +130,9 @@ check_status(){
fi fi
if [ $hpid -ne 0 ]; then if [ $hpid -ne 0 ]; then
kill -0 "$hpid" 2>/dev/null kill -0 "$hpid" 2>/dev/null
gitlab_git_http_server_status="$?" gitlab_workhorse_status="$?"
else else
gitlab_git_http_server_status="-1" gitlab_workhorse_status="-1"
fi fi
if [ "$mail_room_enabled" = true ]; then if [ "$mail_room_enabled" = true ]; then
if [ $mpid -ne 0 ]; then if [ $mpid -ne 0 ]; then
...@@ -143,7 +142,7 @@ check_status(){ ...@@ -143,7 +142,7 @@ check_status(){
mail_room_status="-1" mail_room_status="-1"
fi fi
fi fi
if [ $web_status = 0 ] && [ $sidekiq_status = 0 ] && [ $gitlab_git_http_server_status = 0 ] && { [ "$mail_room_enabled" != true ] || [ $mail_room_status = 0 ]; }; then if [ $web_status = 0 ] && [ $sidekiq_status = 0 ] && [ $gitlab_workhorse_status = 0 ] && { [ "$mail_room_enabled" != true ] || [ $mail_room_status = 0 ]; }; then
gitlab_status=0 gitlab_status=0
else else
# http://refspecs.linuxbase.org/LSB_4.1.0/LSB-Core-generic/LSB-Core-generic/iniscrptact.html # http://refspecs.linuxbase.org/LSB_4.1.0/LSB-Core-generic/LSB-Core-generic/iniscrptact.html
...@@ -171,9 +170,9 @@ check_stale_pids(){ ...@@ -171,9 +170,9 @@ check_stale_pids(){
exit 1 exit 1
fi fi
fi fi
if [ "$hpid" != "0" ] && [ "$gitlab_git_http_server_status" != "0" ]; then if [ "$hpid" != "0" ] && [ "$gitlab_workhorse_status" != "0" ]; then
echo "Removing stale gitlab-git-http-server pid. This is most likely caused by gitlab-git-http-server crashing the last time it ran." echo "Removing stale gitlab-workhorse pid. This is most likely caused by gitlab-workhorse crashing the last time it ran."
if ! rm "$gitlab_git_http_server_pid_path"; then if ! rm "$gitlab_workhorse_pid_path"; then
echo "Unable to remove stale pid, exiting" echo "Unable to remove stale pid, exiting"
exit 1 exit 1
fi fi
...@@ -190,7 +189,7 @@ check_stale_pids(){ ...@@ -190,7 +189,7 @@ check_stale_pids(){
## If no parts of the service is running, bail out. ## If no parts of the service is running, bail out.
exit_if_not_running(){ exit_if_not_running(){
check_stale_pids check_stale_pids
if [ "$web_status" != "0" ] && [ "$sidekiq_status" != "0" ] && [ "$gitlab_git_http_server_status" != "0" ] && { [ "$mail_room_enabled" != true ] || [ "$mail_room_status" != "0" ]; }; then if [ "$web_status" != "0" ] && [ "$sidekiq_status" != "0" ] && [ "$gitlab_workhorse_status" != "0" ] && { [ "$mail_room_enabled" != true ] || [ "$mail_room_status" != "0" ]; }; then
echo "GitLab is not running." echo "GitLab is not running."
exit exit
fi fi
...@@ -206,8 +205,8 @@ start_gitlab() { ...@@ -206,8 +205,8 @@ start_gitlab() {
if [ "$sidekiq_status" != "0" ]; then if [ "$sidekiq_status" != "0" ]; then
echo "Starting GitLab Sidekiq" echo "Starting GitLab Sidekiq"
fi fi
if [ "$gitlab_git_http_server_status" != "0" ]; then if [ "$gitlab_workhorse_status" != "0" ]; then
echo "Starting gitlab-git-http-server" echo "Starting gitlab-workhorse"
fi fi
if [ "$mail_room_enabled" = true ] && [ "$mail_room_status" != "0" ]; then if [ "$mail_room_enabled" = true ] && [ "$mail_room_status" != "0" ]; then
echo "Starting GitLab MailRoom" echo "Starting GitLab MailRoom"
...@@ -230,15 +229,14 @@ start_gitlab() { ...@@ -230,15 +229,14 @@ start_gitlab() {
RAILS_ENV=$RAILS_ENV bin/background_jobs start & RAILS_ENV=$RAILS_ENV bin/background_jobs start &
fi fi
if [ "$gitlab_git_http_server_status" = "0" ]; then if [ "$gitlab_workhorse_status" = "0" ]; then
echo "The gitlab-git-http-server is already running with pid $spid, not restarting" echo "The gitlab-workhorse is already running with pid $spid, not restarting"
else else
# No need to remove a socket, gitlab-git-http-server does this itself # No need to remove a socket, gitlab-workhorse does this itself
$app_root/bin/daemon_with_pidfile $gitlab_git_http_server_pid_path \ $app_root/bin/daemon_with_pidfile $gitlab_workhorse_pid_path \
$app_root/../gitlab-git-http-server/gitlab-git-http-server \ $app_root/../gitlab-workhorse/gitlab-workhorse \
$gitlab_git_http_server_options \ $gitlab_workhorse_options \
$gitlab_git_http_server_repo_root \ >> $gitlab_workhorse_log 2>&1 &
>> $gitlab_git_http_server_log 2>&1 &
fi fi
if [ "$mail_room_enabled" = true ]; then if [ "$mail_room_enabled" = true ]; then
...@@ -268,9 +266,9 @@ stop_gitlab() { ...@@ -268,9 +266,9 @@ stop_gitlab() {
echo "Shutting down GitLab Sidekiq" echo "Shutting down GitLab Sidekiq"
RAILS_ENV=$RAILS_ENV bin/background_jobs stop RAILS_ENV=$RAILS_ENV bin/background_jobs stop
fi fi
if [ "$gitlab_git_http_server_status" = "0" ]; then if [ "$gitlab_workhorse_status" = "0" ]; then
echo "Shutting down gitlab-git-http-server" echo "Shutting down gitlab-workhorse"
kill -- $(cat $gitlab_git_http_server_pid_path) kill -- $(cat $gitlab_workhorse_pid_path)
fi fi
if [ "$mail_room_enabled" = true ] && [ "$mail_room_status" = "0" ]; then if [ "$mail_room_enabled" = true ] && [ "$mail_room_status" = "0" ]; then
echo "Shutting down GitLab MailRoom" echo "Shutting down GitLab MailRoom"
...@@ -278,11 +276,11 @@ stop_gitlab() { ...@@ -278,11 +276,11 @@ stop_gitlab() {
fi fi
# If something needs to be stopped, lets wait for it to stop. Never use SIGKILL in a script. # If something needs to be stopped, lets wait for it to stop. Never use SIGKILL in a script.
while [ "$web_status" = "0" ] || [ "$sidekiq_status" = "0" ] || [ "$gitlab_git_http_server_status" = "0" ] || { [ "$mail_room_enabled" = true ] && [ "$mail_room_status" = "0" ]; }; do while [ "$web_status" = "0" ] || [ "$sidekiq_status" = "0" ] || [ "$gitlab_workhorse_status" = "0" ] || { [ "$mail_room_enabled" = true ] && [ "$mail_room_status" = "0" ]; }; do
sleep 1 sleep 1
check_status check_status
printf "." printf "."
if [ "$web_status" != "0" ] && [ "$sidekiq_status" != "0" ] && [ "$gitlab_git_http_server_status" != "0" ] && { [ "$mail_room_enabled" != true ] || [ "$mail_room_status" != "0" ]; }; then if [ "$web_status" != "0" ] && [ "$sidekiq_status" != "0" ] && [ "$gitlab_workhorse_status" != "0" ] && { [ "$mail_room_enabled" != true ] || [ "$mail_room_status" != "0" ]; }; then
printf "\n" printf "\n"
break break
fi fi
...@@ -292,7 +290,7 @@ stop_gitlab() { ...@@ -292,7 +290,7 @@ stop_gitlab() {
# Cleaning up unused pids # Cleaning up unused pids
rm "$web_server_pid_path" 2>/dev/null rm "$web_server_pid_path" 2>/dev/null
# rm "$sidekiq_pid_path" 2>/dev/null # Sidekiq seems to be cleaning up it's own pid. # rm "$sidekiq_pid_path" 2>/dev/null # Sidekiq seems to be cleaning up it's own pid.
rm -f "$gitlab_git_http_server_pid_path" rm -f "$gitlab_workhorse_pid_path"
if [ "$mail_room_enabled" = true ]; then if [ "$mail_room_enabled" = true ]; then
rm "$mail_room_pid_path" 2>/dev/null rm "$mail_room_pid_path" 2>/dev/null
fi fi
...@@ -303,7 +301,7 @@ stop_gitlab() { ...@@ -303,7 +301,7 @@ stop_gitlab() {
## Prints the status of GitLab and it's components. ## Prints the status of GitLab and it's components.
print_status() { print_status() {
check_status check_status
if [ "$web_status" != "0" ] && [ "$sidekiq_status" != "0" ] && [ "$gitlab_git_http_server_status" != "0" ] && { [ "$mail_room_enabled" != true ] || [ "$mail_room_status" != "0" ]; }; then if [ "$web_status" != "0" ] && [ "$sidekiq_status" != "0" ] && [ "$gitlab_workhorse_status" != "0" ] && { [ "$mail_room_enabled" != true ] || [ "$mail_room_status" != "0" ]; }; then
echo "GitLab is not running." echo "GitLab is not running."
return return
fi fi
...@@ -317,10 +315,10 @@ print_status() { ...@@ -317,10 +315,10 @@ print_status() {
else else
printf "The GitLab Sidekiq job dispatcher is \033[31mnot running\033[0m.\n" printf "The GitLab Sidekiq job dispatcher is \033[31mnot running\033[0m.\n"
fi fi
if [ "$gitlab_git_http_server_status" = "0" ]; then if [ "$gitlab_workhorse_status" = "0" ]; then
echo "The gitlab-git-http-server with pid $hpid is running." echo "The gitlab-workhorse with pid $hpid is running."
else else
printf "The gitlab-git-http-server is \033[31mnot running\033[0m.\n" printf "The gitlab-workhorse is \033[31mnot running\033[0m.\n"
fi fi
if [ "$mail_room_enabled" = true ]; then if [ "$mail_room_enabled" = true ]; then
if [ "$mail_room_status" = "0" ]; then if [ "$mail_room_status" = "0" ]; then
...@@ -360,7 +358,7 @@ reload_gitlab(){ ...@@ -360,7 +358,7 @@ reload_gitlab(){
## Restarts Sidekiq and Unicorn. ## Restarts Sidekiq and Unicorn.
restart_gitlab(){ restart_gitlab(){
check_status check_status
if [ "$web_status" = "0" ] || [ "$sidekiq_status" = "0" ] || [ "$gitlab_git_http_server" = "0" ] || { [ "$mail_room_enabled" = true ] && [ "$mail_room_status" = "0" ]; }; then if [ "$web_status" = "0" ] || [ "$sidekiq_status" = "0" ] || [ "$gitlab_workhorse" = "0" ] || { [ "$mail_room_enabled" = true ] && [ "$mail_room_status" = "0" ]; }; then
stop_gitlab stop_gitlab
fi fi
start_gitlab start_gitlab
......
...@@ -30,15 +30,14 @@ web_server_pid_path="$pid_path/unicorn.pid" ...@@ -30,15 +30,14 @@ web_server_pid_path="$pid_path/unicorn.pid"
# The default is "$pid_path/sidekiq.pid" # The default is "$pid_path/sidekiq.pid"
sidekiq_pid_path="$pid_path/sidekiq.pid" sidekiq_pid_path="$pid_path/sidekiq.pid"
gitlab_git_http_server_pid_path="$pid_path/gitlab-git-http-server.pid" gitlab_workhorse_pid_path="$pid_path/gitlab-workhorse.pid"
# The -listenXxx settings determine where gitlab-git-http-server # The -listenXxx settings determine where gitlab-workhorse
# listens for connections from NGINX. To listen on localhost:8181, write # listens for connections from NGINX. To listen on localhost:8181, write
# '-listenNetwork tcp -listenAddr localhost:8181'. # '-listenNetwork tcp -listenAddr localhost:8181'.
# The -authBackend setting tells gitlab-git-http-server where it can reach # The -authBackend setting tells gitlab-workhorse where it can reach
# Unicorn. # Unicorn.
gitlab_git_http_server_options="-listenUmask 0 -listenNetwork unix -listenAddr $socket_path/gitlab-git-http-server.socket -authBackend http://127.0.0.1:8080" gitlab_workhorse_options="-listenUmask 0 -listenNetwork unix -listenAddr $socket_path/gitlab-workhorse.socket -authBackend http://127.0.0.1:8080"
gitlab_git_http_server_repo_root="/home/git/repositories" gitlab_workhorse_log="$app_root/log/gitlab-workhorse.log"
gitlab_git_http_server_log="$app_root/log/gitlab-git-http-server.log"
# mail_room_enabled specifies whether mail_room, which is used to process incoming email, is enabled. # mail_room_enabled specifies whether mail_room, which is used to process incoming email, is enabled.
# This is required for the Reply by email feature. # This is required for the Reply by email feature.
......
...@@ -38,8 +38,8 @@ upstream gitlab { ...@@ -38,8 +38,8 @@ upstream gitlab {
server unix:/home/git/gitlab/tmp/sockets/gitlab.socket fail_timeout=0; server unix:/home/git/gitlab/tmp/sockets/gitlab.socket fail_timeout=0;
} }
upstream gitlab-git-http-server { upstream gitlab-workhorse {
server unix:/home/git/gitlab/tmp/sockets/gitlab-git-http-server.socket fail_timeout=0; server unix:/home/git/gitlab/tmp/sockets/gitlab-workhorse.socket fail_timeout=0;
} }
## Normal HTTP host ## Normal HTTP host
...@@ -114,24 +114,24 @@ server { ...@@ -114,24 +114,24 @@ server {
} }
location ~ ^/[\w\.-]+/[\w\.-]+/(info/refs|git-upload-pack|git-receive-pack)$ { location ~ ^/[\w\.-]+/[\w\.-]+/(info/refs|git-upload-pack|git-receive-pack)$ {
# 'Error' 418 is a hack to re-use the @gitlab-git-http-server block # 'Error' 418 is a hack to re-use the @gitlab-workhorse block
error_page 418 = @gitlab-git-http-server; error_page 418 = @gitlab-workhorse;
return 418; return 418;
} }
location ~ ^/[\w\.-]+/[\w\.-]+/repository/archive { location ~ ^/[\w\.-]+/[\w\.-]+/repository/archive {
# 'Error' 418 is a hack to re-use the @gitlab-git-http-server block # 'Error' 418 is a hack to re-use the @gitlab-workhorse block
error_page 418 = @gitlab-git-http-server; error_page 418 = @gitlab-workhorse;
return 418; return 418;
} }
location ~ ^/api/v3/projects/.*/repository/archive { location ~ ^/api/v3/projects/.*/repository/archive {
# 'Error' 418 is a hack to re-use the @gitlab-git-http-server block # 'Error' 418 is a hack to re-use the @gitlab-workhorse block
error_page 418 = @gitlab-git-http-server; error_page 418 = @gitlab-workhorse;
return 418; return 418;
} }
location @gitlab-git-http-server { location @gitlab-workhorse {
## If you use HTTPS make sure you disable gzip compression ## If you use HTTPS make sure you disable gzip compression
## to be safe against BREACH attack. ## to be safe against BREACH attack.
# gzip off; # gzip off;
...@@ -147,7 +147,7 @@ server { ...@@ -147,7 +147,7 @@ server {
# The following settings only work with NGINX 1.7.11 or newer # The following settings only work with NGINX 1.7.11 or newer
# #
# # Pass chunked request bodies to gitlab-git-http-server as-is # # Pass chunked request bodies to gitlab-workhorse as-is
# proxy_request_buffering off; # proxy_request_buffering off;
# proxy_http_version 1.1; # proxy_http_version 1.1;
...@@ -156,7 +156,7 @@ server { ...@@ -156,7 +156,7 @@ server {
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme; proxy_set_header X-Forwarded-Proto $scheme;
proxy_pass http://gitlab-git-http-server; proxy_pass http://gitlab-workhorse;
} }
## Enable gzip compression as per rails guide: ## Enable gzip compression as per rails guide:
......
...@@ -42,8 +42,8 @@ upstream gitlab { ...@@ -42,8 +42,8 @@ upstream gitlab {
server unix:/home/git/gitlab/tmp/sockets/gitlab.socket fail_timeout=0; server unix:/home/git/gitlab/tmp/sockets/gitlab.socket fail_timeout=0;
} }
upstream gitlab-git-http-server { upstream gitlab-workhorse {
server unix:/home/git/gitlab/tmp/sockets/gitlab-git-http-server.socket fail_timeout=0; server unix:/home/git/gitlab/tmp/sockets/gitlab-workhorse.socket fail_timeout=0;
} }
## Redirects all HTTP traffic to the HTTPS host ## Redirects all HTTP traffic to the HTTPS host
...@@ -161,24 +161,24 @@ server { ...@@ -161,24 +161,24 @@ server {
} }
location ~ ^/[\w\.-]+/[\w\.-]+/(info/refs|git-upload-pack|git-receive-pack)$ { location ~ ^/[\w\.-]+/[\w\.-]+/(info/refs|git-upload-pack|git-receive-pack)$ {
# 'Error' 418 is a hack to re-use the @gitlab-git-http-server block # 'Error' 418 is a hack to re-use the @gitlab-workhorse block
error_page 418 = @gitlab-git-http-server; error_page 418 = @gitlab-workhorse;
return 418; return 418;
} }
location ~ ^/[\w\.-]+/[\w\.-]+/repository/archive { location ~ ^/[\w\.-]+/[\w\.-]+/repository/archive {
# 'Error' 418 is a hack to re-use the @gitlab-git-http-server block # 'Error' 418 is a hack to re-use the @gitlab-workhorse block
error_page 418 = @gitlab-git-http-server; error_page 418 = @gitlab-workhorse;
return 418; return 418;
} }
location ~ ^/api/v3/projects/.*/repository/archive { location ~ ^/api/v3/projects/.*/repository/archive {
# 'Error' 418 is a hack to re-use the @gitlab-git-http-server block # 'Error' 418 is a hack to re-use the @gitlab-workhorse block
error_page 418 = @gitlab-git-http-server; error_page 418 = @gitlab-workhorse;
return 418; return 418;
} }
location @gitlab-git-http-server { location @gitlab-workhorse {
## If you use HTTPS make sure you disable gzip compression ## If you use HTTPS make sure you disable gzip compression
## to be safe against BREACH attack. ## to be safe against BREACH attack.
gzip off; gzip off;
...@@ -194,7 +194,7 @@ server { ...@@ -194,7 +194,7 @@ server {
# The following settings only work with NGINX 1.7.11 or newer # The following settings only work with NGINX 1.7.11 or newer
# #
# # Pass chunked request bodies to gitlab-git-http-server as-is # # Pass chunked request bodies to gitlab-workhorse as-is
# proxy_request_buffering off; # proxy_request_buffering off;
# proxy_http_version 1.1; # proxy_http_version 1.1;
...@@ -203,7 +203,7 @@ server { ...@@ -203,7 +203,7 @@ server {
proxy_set_header X-Forwarded-Ssl on; proxy_set_header X-Forwarded-Ssl on;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme; proxy_set_header X-Forwarded-Proto $scheme;
proxy_pass http://gitlab-git-http-server; proxy_pass http://gitlab-workhorse;
} }
## Enable gzip compression as per rails guide: ## Enable gzip compression as per rails guide:
......
...@@ -39,4 +39,30 @@ describe User, benchmark: true do ...@@ -39,4 +39,30 @@ describe User, benchmark: true do
it { is_expected.to iterate_per_second(iterations) } it { is_expected.to iterate_per_second(iterations) }
end end
end end
describe '.find_by_any_email' do
let(:user) { create(:user) }
describe 'using a user with only a single Email address' do
let(:email) { user.email }
benchmark_subject { User.find_by_any_email(email) }
it { is_expected.to iterate_per_second(1000) }
end
describe 'using a user with multiple Email addresses' do
let(:email) { user.emails.first.email }
benchmark_subject { User.find_by_any_email(email) }
before do
10.times do
user.emails.create(email: FFaker::Internet.email)
end
end
it { is_expected.to iterate_per_second(1000) }
end
end
end end
...@@ -44,7 +44,7 @@ module Gitlab::Markdown ...@@ -44,7 +44,7 @@ module Gitlab::Markdown
instance = described_class.new('Foo') instance = described_class.new('Foo')
3.times { instance.whitelist } 3.times { instance.whitelist }
expect(instance.whitelist[:transformers].size).to eq 4 expect(instance.whitelist[:transformers].size).to eq 5
end end
it 'allows syntax highlighting' do it 'allows syntax highlighting' do
...@@ -77,19 +77,100 @@ module Gitlab::Markdown ...@@ -77,19 +77,100 @@ module Gitlab::Markdown
end end
it 'removes `rel` attribute from `a` elements' do it 'removes `rel` attribute from `a` elements' do
doc = filter(%q{<a href="#" rel="nofollow">Link</a>}) act = %q{<a href="#" rel="nofollow">Link</a>}
exp = %q{<a href="#">Link</a>}
expect(doc.css('a').size).to eq 1 expect(filter(act).to_html).to eq exp
expect(doc.at_css('a')['href']).to eq '#'
expect(doc.at_css('a')['rel']).to be_nil
end end
it 'removes script-like `href` attribute from `a` elements' do # Adapted from the Sanitize test suite: http://git.io/vczrM
html = %q{<a href="javascript:alert('Hi')">Hi</a>} protocols = {
doc = filter(html) 'protocol-based JS injection: simple, no spaces' => {
input: '<a href="javascript:alert(\'XSS\');">foo</a>',
output: '<a>foo</a>'
},
'protocol-based JS injection: simple, spaces before' => {
input: '<a href="javascript :alert(\'XSS\');">foo</a>',
output: '<a>foo</a>'
},
'protocol-based JS injection: simple, spaces after' => {
input: '<a href="javascript: alert(\'XSS\');">foo</a>',
output: '<a>foo</a>'
},
'protocol-based JS injection: simple, spaces before and after' => {
input: '<a href="javascript : alert(\'XSS\');">foo</a>',
output: '<a>foo</a>'
},
'protocol-based JS injection: preceding colon' => {
input: '<a href=":javascript:alert(\'XSS\');">foo</a>',
output: '<a>foo</a>'
},
'protocol-based JS injection: UTF-8 encoding' => {
input: '<a href="javascript&#58;">foo</a>',
output: '<a>foo</a>'
},
'protocol-based JS injection: long UTF-8 encoding' => {
input: '<a href="javascript&#0058;">foo</a>',
output: '<a>foo</a>'
},
'protocol-based JS injection: long UTF-8 encoding without semicolons' => {
input: '<a href=&#0000106&#0000097&#0000118&#0000097&#0000115&#0000099&#0000114&#0000105&#0000112&#0000116&#0000058&#0000097&#0000108&#0000101&#0000114&#0000116&#0000040&#0000039&#0000088&#0000083&#0000083&#0000039&#0000041>foo</a>',
output: '<a>foo</a>'
},
'protocol-based JS injection: hex encoding' => {
input: '<a href="javascript&#x3A;">foo</a>',
output: '<a>foo</a>'
},
'protocol-based JS injection: long hex encoding' => {
input: '<a href="javascript&#x003A;">foo</a>',
output: '<a>foo</a>'
},
'protocol-based JS injection: hex encoding without semicolons' => {
input: '<a href=&#x6A&#x61&#x76&#x61&#x73&#x63&#x72&#x69&#x70&#x74&#x3A&#x61&#x6C&#x65&#x72&#x74&#x28&#x27&#x58&#x53&#x53&#x27&#x29>foo</a>',
output: '<a>foo</a>'
},
'protocol-based JS injection: null char' => {
input: "<a href=java\0script:alert(\"XSS\")>foo</a>",
output: '<a href="java"></a>'
},
'protocol-based JS injection: spaces and entities' => {
input: '<a href=" &#14; javascript:alert(\'XSS\');">foo</a>',
output: '<a href="">foo</a>'
},
}
protocols.each do |name, data|
it "handles #{name}" do
doc = filter(data[:input])
expect(doc.to_html).to eq data[:output]
end
end
it 'allows non-standard anchor schemes' do
exp = %q{<a href="irc://irc.freenode.net/git">IRC</a>}
act = filter(exp)
expect(act.to_html).to eq exp
end
it 'allows relative links' do
exp = %q{<a href="foo/bar.md">foo/bar.md</a>}
act = filter(exp)
expect(doc.css('a').size).to eq 1 expect(act.to_html).to eq exp
expect(doc.at_css('a')['href']).to be_nil
end end
end end
......
...@@ -19,6 +19,7 @@ describe API::API, api: true do ...@@ -19,6 +19,7 @@ describe API::API, api: true do
expect(response.status).to eq(200) expect(response.status).to eq(200)
expect(json_response['file_path']).to eq(file_path) expect(json_response['file_path']).to eq(file_path)
expect(json_response['file_name']).to eq('popen.rb') expect(json_response['file_name']).to eq('popen.rb')
expect(json_response['last_commit_id']).to eq('570e7b2abdd848b95f2f578043fc23bd6f6fd24d')
expect(Base64.decode64(json_response['content']).lines.first).to eq("require 'fileutils'\n") expect(Base64.decode64(json_response['content']).lines.first).to eq("require 'fileutils'\n")
end end
......
...@@ -55,6 +55,7 @@ describe 'gitlab:app namespace rake task' do ...@@ -55,6 +55,7 @@ describe 'gitlab:app namespace rake task' do
expect(Rake::Task["gitlab:backup:db:restore"]).to receive(:invoke) expect(Rake::Task["gitlab:backup:db:restore"]).to receive(:invoke)
expect(Rake::Task["gitlab:backup:repo:restore"]).to receive(:invoke) expect(Rake::Task["gitlab:backup:repo:restore"]).to receive(:invoke)
expect(Rake::Task["gitlab:backup:builds:restore"]).to receive(:invoke) expect(Rake::Task["gitlab:backup:builds:restore"]).to receive(:invoke)
expect(Rake::Task["gitlab:backup:uploads:restore"]).to receive(:invoke)
expect(Rake::Task["gitlab:shell:setup"]).to receive(:invoke) expect(Rake::Task["gitlab:shell:setup"]).to receive(:invoke)
expect { run_rake_task('gitlab:backup:restore') }.not_to raise_error expect { run_rake_task('gitlab:backup:restore') }.not_to raise_error
end end
...@@ -112,14 +113,14 @@ describe 'gitlab:app namespace rake task' do ...@@ -112,14 +113,14 @@ describe 'gitlab:app namespace rake task' do
it 'should set correct permissions on the tar contents' do it 'should set correct permissions on the tar contents' do
tar_contents, exit_status = Gitlab::Popen.popen( tar_contents, exit_status = Gitlab::Popen.popen(
%W{tar -tvf #{@backup_tar} db uploads repositories builds} %W{tar -tvf #{@backup_tar} db uploads.tar.gz repositories builds.tar.gz}
) )
expect(exit_status).to eq(0) expect(exit_status).to eq(0)
expect(tar_contents).to match('db/') expect(tar_contents).to match('db/')
expect(tar_contents).to match('uploads/') expect(tar_contents).to match('uploads.tar.gz')
expect(tar_contents).to match('repositories/') expect(tar_contents).to match('repositories/')
expect(tar_contents).to match('builds/') expect(tar_contents).to match('builds.tar.gz')
expect(tar_contents).not_to match(/^.{4,9}[rwx].* (db|uploads|repositories|builds)\/$/) expect(tar_contents).not_to match(/^.{4,9}[rwx].* (database.sql.gz|uploads.tar.gz|repositories|builds.tar.gz)\/$/)
end end
it 'should delete temp directories' do it 'should delete temp directories' do
...@@ -160,12 +161,12 @@ describe 'gitlab:app namespace rake task' do ...@@ -160,12 +161,12 @@ describe 'gitlab:app namespace rake task' do
it "does not contain skipped item" do it "does not contain skipped item" do
tar_contents, _exit_status = Gitlab::Popen.popen( tar_contents, _exit_status = Gitlab::Popen.popen(
%W{tar -tvf #{@backup_tar} db uploads repositories builds} %W{tar -tvf #{@backup_tar} db uploads.tar.gz repositories builds.tar.gz}
) )
expect(tar_contents).to match('db/') expect(tar_contents).to match('db/')
expect(tar_contents).to match('uploads/') expect(tar_contents).to match('uploads.tar.gz')
expect(tar_contents).to match('builds/') expect(tar_contents).to match('builds.tar.gz')
expect(tar_contents).not_to match('repositories/') expect(tar_contents).not_to match('repositories/')
end end
......
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