Commit e45e6ba2 authored by Dmitriy Zaporozhets's avatar Dmitriy Zaporozhets

Merge branch 'master' into sidebar-nav

Signed-off-by: default avatarDmitriy Zaporozhets <dmitriy.zaporozhets@gmail.com>

Conflicts:
	app/views/layouts/group.html.haml
parents bcc04adb 0f7d47f6
...@@ -3,25 +3,24 @@ v 7.6.0 ...@@ -3,25 +3,24 @@ v 7.6.0
- New rugged version - New rugged version
- Add CRON=1 backup setting for quiet backups - Add CRON=1 backup setting for quiet backups
- Fix failing wiki restore - Fix failing wiki restore
-
- Add optional Sidekiq MemoryKiller middleware (enabled via SIDEKIQ_MAX_RSS env variable) - Add optional Sidekiq MemoryKiller middleware (enabled via SIDEKIQ_MAX_RSS env variable)
-
-
- Monokai highlighting style now more faithful to original design (Mark Riedesel) - Monokai highlighting style now more faithful to original design (Mark Riedesel)
- Create project with repository in synchrony - Create project with repository in synchrony
- Added ability to create empty repo or import existing one if project does not have repository - Added ability to create empty repo or import existing one if project does not have repository
-
-
- Reactivate highlight.js language autodetection - Reactivate highlight.js language autodetection
- Mobile UI improvements - Mobile UI improvements
-
- Change maximum avatar file size from 100KB to 200KB - Change maximum avatar file size from 100KB to 200KB
- - Strict validation for snippet file names
- - Enable Markdown preview for issues, merge requests, milestones, and notes (Vinnie Okada)
- In the docker directory is a container template based on the Omnibus packages. - In the docker directory is a container template based on the Omnibus packages.
- Update Sidekiq to version 2.17.8 - Update Sidekiq to version 2.17.8
- Add author filter to project issues and merge requests pages - Add author filter to project issues and merge requests pages
- Atom feed for user activity - Atom feed for user activity
- Support multiple omniauth providers for the same user
- Rendering cross reference in issue title and tooltip for merge request
- Show username in comments
- Possibility to create Milestones or Labels when Issues are disabled
- Fix bug with showing gpg signature in tag
v 7.5.2 v 7.5.2
- Don't log Sidekiq arguments by default - Don't log Sidekiq arguments by default
......
...@@ -75,6 +75,7 @@ If you can, please submit a merge request with the fix or improvements including ...@@ -75,6 +75,7 @@ If you can, please submit a merge request with the fix or improvements including
1. Link relevant [issues](https://gitlab.com/gitlab-org/gitlab-ce/issues) and/or [feature requests](http://feedback.gitlab.com/) from the merge request description and leave a comment on them with a link back to the MR 1. Link relevant [issues](https://gitlab.com/gitlab-org/gitlab-ce/issues) and/or [feature requests](http://feedback.gitlab.com/) from the merge request description and leave a comment on them with a link back to the MR
1. Be prepared to answer questions and incorporate feedback even if requests for this arrive weeks or months after your MR submission 1. Be prepared to answer questions and incorporate feedback even if requests for this arrive weeks or months after your MR submission
1. If your MR touches code that executes shell commands, make sure it adheres to the [shell command guidelines]( doc/development/shell_commands.md). 1. If your MR touches code that executes shell commands, make sure it adheres to the [shell command guidelines]( doc/development/shell_commands.md).
1. Also have a look at the [shell command guidelines](doc/development/shell_commands.md) if your code reads or opens files, or handles paths to files on disk.
The **official merge window** is in the beginning of the month from the 1st to the 7th day of the month. The best time to submit a MR and get feedback fast. Before this time the GitLab B.V. team is still dealing with work that is created by the monthly release such as assisting subscribers with upgrade issues, the release of Enterprise Edition and the upgrade of GitLab Cloud. After the 7th it is already getting closer to the release date of the next version. This means there is less time to fix the issues created by merging large new features. The **official merge window** is in the beginning of the month from the 1st to the 7th day of the month. The best time to submit a MR and get feedback fast. Before this time the GitLab B.V. team is still dealing with work that is created by the monthly release such as assisting subscribers with upgrade issues, the release of Enterprise Edition and the upgrade of GitLab Cloud. After the 7th it is already getting closer to the release date of the next version. This means there is less time to fix the issues created by merging large new features.
...@@ -141,3 +142,17 @@ Please ensure you support the feature you contribute through all of these steps. ...@@ -141,3 +142,17 @@ Please ensure you support the feature you contribute through all of these steps.
1. [Markdown](http://www.cirosantilli.com/markdown-styleguide) 1. [Markdown](http://www.cirosantilli.com/markdown-styleguide)
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). 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).
## Code of conduct
As contributors and maintainers of this project, we pledge to respect all people who contribute through reporting issues, posting feature requests, updating documentation, submitting pull requests or patches, and other activities.
We are committed to making participation in this project a harassment-free experience for everyone, regardless of level of experience, gender, gender identity and expression, sexual orientation, disability, personal appearance, body size, race, age, or religion.
Examples of unacceptable behavior by participants include the use of sexual language or imagery, derogatory comments or personal attacks, trolling, public or private harassment, insults, or other unprofessional conduct.
Project maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct. Project maintainers who do not follow the Code of Conduct may be removed from the project team.
Instances of abusive, harassing, or otherwise unacceptable behavior can be
reported by emailing contact@gitlab.com
This Code of Conduct is adapted from the [Contributor Covenant](http:contributor-covenant.org), version 1.0.0, available at [http://contributor-covenant.org/version/1/0/0/](http://contributor-covenant.org/version/1/0/0/)
...@@ -28,6 +28,7 @@ gem 'omniauth-google-oauth2' ...@@ -28,6 +28,7 @@ gem 'omniauth-google-oauth2'
gem 'omniauth-twitter' gem 'omniauth-twitter'
gem 'omniauth-github' gem 'omniauth-github'
gem 'omniauth-shibboleth' gem 'omniauth-shibboleth'
gem 'omniauth-kerberos'
# Extracting information from a git repository # Extracting information from a git repository
# Provide access to Gitlab::Git library # Provide access to Gitlab::Git library
......
...@@ -158,7 +158,7 @@ GEM ...@@ -158,7 +158,7 @@ GEM
dotenv (>= 0.7) dotenv (>= 0.7)
thor (>= 0.13.6) thor (>= 0.13.6)
formatador (0.2.4) formatador (0.2.4)
gemnasium-gitlab-service (0.2.2) gemnasium-gitlab-service (0.2.3)
rugged (~> 0.19) rugged (~> 0.19)
gherkin-ruby (0.3.1) gherkin-ruby (0.3.1)
racc racc
...@@ -322,6 +322,11 @@ GEM ...@@ -322,6 +322,11 @@ GEM
omniauth-google-oauth2 (0.2.5) omniauth-google-oauth2 (0.2.5)
omniauth (> 1.0) omniauth (> 1.0)
omniauth-oauth2 (~> 1.1) omniauth-oauth2 (~> 1.1)
omniauth-kerberos (0.2.0)
omniauth-multipassword
timfel-krb5-auth (~> 0.8)
omniauth-multipassword (0.4.1)
omniauth (~> 1.0)
omniauth-oauth (1.0.1) omniauth-oauth (1.0.1)
oauth oauth
omniauth (~> 1.0) omniauth (~> 1.0)
...@@ -531,6 +536,7 @@ GEM ...@@ -531,6 +536,7 @@ GEM
thread_safe (0.3.4) thread_safe (0.3.4)
tilt (1.4.1) tilt (1.4.1)
timers (1.1.0) timers (1.1.0)
timfel-krb5-auth (0.8)
tinder (1.9.3) tinder (1.9.3)
eventmachine (~> 1.0) eventmachine (~> 1.0)
faraday (~> 0.8) faraday (~> 0.8)
...@@ -655,6 +661,7 @@ DEPENDENCIES ...@@ -655,6 +661,7 @@ DEPENDENCIES
omniauth (~> 1.1.3) omniauth (~> 1.1.3)
omniauth-github omniauth-github
omniauth-google-oauth2 omniauth-google-oauth2
omniauth-kerberos
omniauth-shibboleth omniauth-shibboleth
omniauth-twitter omniauth-twitter
org-ruby (= 0.9.9) org-ruby (= 0.9.9)
......
...@@ -104,3 +104,10 @@ This merge request has been closed because a request for more information has no ...@@ -104,3 +104,10 @@ This merge request has been closed because a request for more information has no
### Accepting merge requests ### Accepting merge requests
Is there a request on [the feature request forum](http://feedback.gitlab.com/forums/176466-general) that is similar to this? If so, can you make a comment with a link to it? Please be aware that new functionality that is not marked [accepting merge/pull requests](http://feedback.gitlab.com/forums/176466-general/status/796455) on the forum might not make it into GitLab. You might be asked to make changes and even after implementing them your feature might still be declined. If you want to reduce the chance of this happening please have a discussion in the forum first. Is there a request on [the feature request forum](http://feedback.gitlab.com/forums/176466-general) that is similar to this? If so, can you make a comment with a link to it? Please be aware that new functionality that is not marked [accepting merge/pull requests](http://feedback.gitlab.com/forums/176466-general/status/796455) on the forum might not make it into GitLab. You might be asked to make changes and even after implementing them your feature might still be declined. If you want to reduce the chance of this happening please have a discussion in the forum first.
### Only accepting merge requests with green tests
We can only accept a merge request if all the tests are green. I've just
restarted the build. When the tests are still not passing after this restart and
you're sure that is does not have anything to do with your code changes, please
rebase with master to see if that solves the issue.
...@@ -52,69 +52,30 @@ On [about.gitlab.com](https://about.gitlab.com/) you can find more information a ...@@ -52,69 +52,30 @@ On [about.gitlab.com](https://about.gitlab.com/) you can find more information a
Please see [the installation page on the GitLab website](https://about.gitlab.com/installation/) for the various options. Please see [the installation page on the GitLab website](https://about.gitlab.com/installation/) for the various options.
Since a manual installation is a lot of work and error prone we strongly recommend the fast and reliable [Omnibus package installation](https://about.gitlab.com/downloads/) (deb/rpm). Since a manual installation is a lot of work and error prone we strongly recommend the fast and reliable [Omnibus package installation](https://about.gitlab.com/downloads/) (deb/rpm).
You can access new installation with the login `root` and password `5iveL!fe`, after login you are required to set a unique password.
## Third-party applications ## Third-party applications
There are a lot of applications and API wrappers for GitLab. There are a lot of applications and API wrappers for GitLab.
Find them [on our website](https://about.gitlab.com/applications/). Find them [on our website](https://about.gitlab.com/applications/).
### New versions ## New versions
Since 2011 a minor or major version of GitLab is released on the 22nd of every month. Patch and security releases come out when needed. New features are detailed on the [blog](https://about.gitlab.com/blog/) and in the [changelog](CHANGELOG). For more information about the release process see the release [documentation](https://gitlab.com/gitlab-org/gitlab-ce/tree/master/doc/release). Features that will likely be in the next releases can be found on the [feature request forum](http://feedback.gitlab.com/forums/176466-general) with the status [started](http://feedback.gitlab.com/forums/176466-general/status/796456) and [completed](http://feedback.gitlab.com/forums/176466-general/status/796457). Since 2011 a minor or major version of GitLab is released on the 22nd of every month. Patch and security releases come out when needed. New features are detailed on the [blog](https://about.gitlab.com/blog/) and in the [changelog](CHANGELOG). For more information about the release process see the release [documentation](https://gitlab.com/gitlab-org/gitlab-ce/tree/master/doc/release). Features that will likely be in the next releases can be found on the [feature request forum](http://feedback.gitlab.com/forums/176466-general) with the status [started](http://feedback.gitlab.com/forums/176466-general/status/796456) and [completed](http://feedback.gitlab.com/forums/176466-general/status/796457).
### Upgrading ## Upgrading
For updating the the Omnibus installation please see the [update documentation](https://gitlab.com/gitlab-org/omnibus-gitlab/blob/master/doc/update.md). For manual installations there is an [upgrader script](doc/update/upgrader.md) and there are [upgrade guides](doc/update). For updating the the Omnibus installation please see the [update documentation](https://gitlab.com/gitlab-org/omnibus-gitlab/blob/master/doc/update.md). For manual installations there is an [upgrader script](doc/update/upgrader.md) and there are [upgrade guides](doc/update).
## Run in production mode
The Installation guide contains instructions on how to download an init script and run it automatically on boot. You can also start the init script manually:
sudo service gitlab start
or by directly calling the script:
sudo /etc/init.d/gitlab start
Please login with `root` / `5iveL!fe`
## Install a development environment ## Install a development environment
We recommend setting up your development environment with [the GitLab Development Kit](https://gitlab.com/gitlab-org/gitlab-development-kit). We recommend setting up your development environment with [the GitLab Development Kit](https://gitlab.com/gitlab-org/gitlab-development-kit).
If you do not use the development kit you might need to copy the example development unicorn configuration file If you do not use the GitLab Development Development kit you need to install and setup all the dependencies yourself, this is a lot of work and error prone.
One small thing you also have to do when installing it yourself is to copy the example development unicorn configuration file:
cp config/unicorn.rb.example.development config/unicorn.rb cp config/unicorn.rb.example.development config/unicorn.rb
## Run in development mode Instructions on how to start Gitlab and how to run the tests can be found in the [development section of the GitLab Development Kit](https://gitlab.com/gitlab-org/gitlab-development-kit#development).
Start it with [Foreman](https://github.com/ddollar/foreman)
bundle exec foreman start -p 3000
or start each component separately:
bundle exec rails s
bin/background_jobs start
And surf to [localhost:3000](http://localhost:3000/) and login with `root` / `5iveL!fe`.
## Run the tests
- Run all tests:
bundle exec rake test
- [RSpec](http://rspec.info/) unit and functional tests.
All RSpec tests: `bundle exec rake spec`
Single RSpec file: `bundle exec rspec spec/controllers/commit_controller_spec.rb`
- [Spinach](https://github.com/codegram/spinach) integration tests.
All Spinach tests: `bundle exec rake spinach`
Single Spinach test: `bundle exec spinach features/project/issues/milestones.feature`
## Documentation ## Documentation
......
...@@ -51,12 +51,6 @@ window.ajaxGet = (url) -> ...@@ -51,12 +51,6 @@ window.ajaxGet = (url) ->
window.showAndHide = (selector) -> window.showAndHide = (selector) ->
window.errorMessage = (message) ->
ehtml = $("<p>")
ehtml.addClass("error_message")
ehtml.html(message)
ehtml
window.split = (val) -> window.split = (val) ->
return val.split( /,\s*/ ) return val.split( /,\s*/ )
......
...@@ -24,6 +24,51 @@ $(document).ready -> ...@@ -24,6 +24,51 @@ $(document).ready ->
"opacity": 0 "opacity": 0
"display": "none" "display": "none"
# Preview button
$(document).off "click", ".js-md-preview-button"
$(document).on "click", ".js-md-preview-button", (e) ->
###
Shows the Markdown preview.
Lets the server render GFM into Html and displays it.
###
e.preventDefault()
form = $(this).closest("form")
# toggle tabs
form.find(".js-md-write-button").parent().removeClass "active"
form.find(".js-md-preview-button").parent().addClass "active"
# toggle content
form.find(".md-write-holder").hide()
form.find(".md-preview-holder").show()
preview = form.find(".js-md-preview")
mdText = form.find(".markdown-area").val()
if mdText.trim().length is 0
preview.text "Nothing to preview."
else
preview.text "Loading..."
$.get($(this).data("url"),
md_text: mdText
).success (previewData) ->
preview.html previewData
# Write button
$(document).off "click", ".js-md-write-button"
$(document).on "click", ".js-md-write-button", (e) ->
###
Shows the Markdown textarea.
###
e.preventDefault()
form = $(this).closest("form")
# toggle tabs
form.find(".js-md-write-button").parent().addClass "active"
form.find(".js-md-preview-button").parent().removeClass "active"
# toggle content
form.find(".md-write-holder").show()
form.find(".md-preview-holder").hide()
dropzone = $(".div-dropzone").dropzone( dropzone = $(".div-dropzone").dropzone(
url: project_image_path_upload url: project_image_path_upload
dictDefaultMessage: "" dictDefaultMessage: ""
......
...@@ -36,12 +36,6 @@ class @Notes ...@@ -36,12 +36,6 @@ class @Notes
# delete note attachment # delete note attachment
$(document).on "click", ".js-note-attachment-delete", @removeAttachment $(document).on "click", ".js-note-attachment-delete", @removeAttachment
# Preview button
$(document).on "click", ".js-note-preview-button", @previewNote
# Preview button
$(document).on "click", ".js-note-write-button", @writeNote
# reset main target form after submit # reset main target form after submit
$(document).on "ajax:complete", ".js-main-target-form", @resetMainTargetForm $(document).on "ajax:complete", ".js-main-target-form", @resetMainTargetForm
...@@ -77,8 +71,6 @@ class @Notes ...@@ -77,8 +71,6 @@ class @Notes
$(document).off "click", ".note-edit-cancel" $(document).off "click", ".note-edit-cancel"
$(document).off "click", ".js-note-delete" $(document).off "click", ".js-note-delete"
$(document).off "click", ".js-note-attachment-delete" $(document).off "click", ".js-note-attachment-delete"
$(document).off "click", ".js-note-preview-button"
$(document).off "click", ".js-note-write-button"
$(document).off "ajax:complete", ".js-main-target-form" $(document).off "ajax:complete", ".js-main-target-form"
$(document).off "click", ".js-choose-note-attachment-button" $(document).off "click", ".js-choose-note-attachment-button"
$(document).off "click", ".js-discussion-reply-button" $(document).off "click", ".js-discussion-reply-button"
...@@ -165,47 +157,6 @@ class @Notes ...@@ -165,47 +157,6 @@ class @Notes
# cleanup after successfully creating a diff/discussion note # cleanup after successfully creating a diff/discussion note
@removeDiscussionNoteForm(form) @removeDiscussionNoteForm(form)
###
Shows write note textarea.
###
writeNote: (e) ->
e.preventDefault()
form = $(this).closest("form")
# toggle tabs
form.find(".js-note-write-button").parent().addClass "active"
form.find(".js-note-preview-button").parent().removeClass "active"
# toggle content
form.find(".note-write-holder").show()
form.find(".note-preview-holder").hide()
###
Shows the note preview.
Lets the server render GFM into Html and displays it.
###
previewNote: (e) ->
e.preventDefault()
form = $(this).closest("form")
# toggle tabs
form.find(".js-note-write-button").parent().removeClass "active"
form.find(".js-note-preview-button").parent().addClass "active"
# toggle content
form.find(".note-write-holder").hide()
form.find(".note-preview-holder").show()
preview = form.find(".js-note-preview")
noteText = form.find(".js-note-text").val()
if noteText.trim().length is 0
preview.text "Nothing to preview."
else
preview.text "Loading..."
$.post($(this).data("url"),
note: noteText
).success (previewData) ->
preview.html previewData
### ###
Called in response the main target form has been successfully submitted. Called in response the main target form has been successfully submitted.
...@@ -220,7 +171,7 @@ class @Notes ...@@ -220,7 +171,7 @@ class @Notes
form.find(".js-errors").remove() form.find(".js-errors").remove()
# reset text and preview # reset text and preview
form.find(".js-note-write-button").click() form.find(".js-md-write-button").click()
form.find(".js-note-text").val("").trigger "input" form.find(".js-note-text").val("").trigger "input"
### ###
...@@ -270,8 +221,8 @@ class @Notes ...@@ -270,8 +221,8 @@ class @Notes
form.removeClass "js-new-note-form" form.removeClass "js-new-note-form"
# setup preview buttons # setup preview buttons
form.find(".js-note-write-button, .js-note-preview-button").tooltip placement: "left" form.find(".js-md-write-button, .js-md-preview-button").tooltip placement: "left"
previewButton = form.find(".js-note-preview-button") previewButton = form.find(".js-md-preview-button")
form.find(".js-note-text").on "input", -> form.find(".js-note-text").on "input", ->
if $(this).val().trim() isnt "" if $(this).val().trim() isnt ""
previewButton.removeClass("turn-off").addClass "turn-on" previewButton.removeClass("turn-off").addClass "turn-on"
......
...@@ -20,6 +20,7 @@ ...@@ -20,6 +20,7 @@
opacity: 0; opacity: 0;
font-size: 50px; font-size: 50px;
transition: opacity 200ms ease-in-out; transition: opacity 200ms ease-in-out;
pointer-events: none;
} }
.div-dropzone-spinner { .div-dropzone-spinner {
...@@ -50,3 +51,28 @@ ...@@ -50,3 +51,28 @@
margin-bottom: 0; margin-bottom: 0;
transition: opacity 200ms ease-in-out; transition: opacity 200ms ease-in-out;
} }
.md-preview-holder {
background: #FFF;
border: 1px solid #ddd;
min-height: 100px;
padding: 5px;
font-size: 14px;
box-shadow: none;
}
.new_note,
.edit_note,
.issuable-description,
.milestone-description,
.merge-request-form {
.nav-tabs {
margin-bottom: 0;
border: none;
li a,
li.active a {
border: 1px solid #DDD;
}
}
}
...@@ -227,7 +227,6 @@ ul.notes { ...@@ -227,7 +227,6 @@ ul.notes {
margin-bottom: 0; margin-bottom: 0;
} }
.note-preview-holder,
.note_text { .note_text {
background: #FFF; background: #FFF;
border: 1px solid #ddd; border: 1px solid #ddd;
...@@ -246,15 +245,6 @@ ul.notes { ...@@ -246,15 +245,6 @@ ul.notes {
.note_text { .note_text {
width: 100%; width: 100%;
} }
.nav-tabs {
margin-bottom: 0;
border: none;
li a,
li.active a {
border: 1px solid #DDD;
}
}
} }
/* loading indicator */ /* loading indicator */
......
...@@ -61,10 +61,6 @@ class Projects::NotesController < Projects::ApplicationController ...@@ -61,10 +61,6 @@ class Projects::NotesController < Projects::ApplicationController
end end
end end
def preview
render text: view_context.markdown(params[:note])
end
private private
def note def note
......
...@@ -68,7 +68,7 @@ class Projects::SnippetsController < Projects::ApplicationController ...@@ -68,7 +68,7 @@ class Projects::SnippetsController < Projects::ApplicationController
@snippet.content, @snippet.content,
type: 'text/plain; charset=utf-8', type: 'text/plain; charset=utf-8',
disposition: 'inline', disposition: 'inline',
filename: @snippet.file_name filename: @snippet.sanitized_file_name
) )
end end
......
...@@ -44,6 +44,9 @@ class ProjectsController < ApplicationController ...@@ -44,6 +44,9 @@ class ProjectsController < ApplicationController
def transfer def transfer
::Projects::TransferService.new(project, current_user, project_params).execute ::Projects::TransferService.new(project, current_user, project_params).execute
if @project.errors[:namespace_id].present?
flash[:alert] = @project.errors[:namespace_id].first
end
end end
def show def show
...@@ -147,6 +150,10 @@ class ProjectsController < ApplicationController ...@@ -147,6 +150,10 @@ class ProjectsController < ApplicationController
render json: { star_count: @project.star_count } render json: { star_count: @project.star_count }
end end
def markdown_preview
render text: view_context.markdown(params[:md_text])
end
private private
def upload_path def upload_path
......
...@@ -79,7 +79,7 @@ class SnippetsController < ApplicationController ...@@ -79,7 +79,7 @@ class SnippetsController < ApplicationController
@snippet.content, @snippet.content,
type: 'text/plain; charset=utf-8', type: 'text/plain; charset=utf-8',
disposition: 'inline', disposition: 'inline',
filename: @snippet.file_name filename: @snippet.sanitized_file_name
) )
end end
......
...@@ -114,6 +114,10 @@ module ApplicationHelper ...@@ -114,6 +114,10 @@ module ApplicationHelper
Gitlab::Theme.css_class_by_id(current_user.try(:theme_id)) Gitlab::Theme.css_class_by_id(current_user.try(:theme_id))
end end
def theme_type
Gitlab::Theme.type_css_class_by_id(current_user.try(:theme_id))
end
def user_color_scheme_class def user_color_scheme_class
COLOR_SCHEMES[current_user.try(:color_scheme_id)] if defined?(current_user) COLOR_SCHEMES[current_user.try(:color_scheme_id)] if defined?(current_user)
end end
......
...@@ -53,13 +53,34 @@ module TreeHelper ...@@ -53,13 +53,34 @@ module TreeHelper
File.join(*args) File.join(*args)
end end
def allowed_tree_edit? def allowed_tree_edit?(project = nil, ref = nil)
return false unless @repository.branch_names.include?(@ref) project ||= @project
ref ||= @ref
return false unless project.repository.branch_names.include?(ref)
if @project.protected_branch? @ref if project.protected_branch? ref
can?(current_user, :push_code_to_protected_branches, @project) can?(current_user, :push_code_to_protected_branches, project)
else else
can?(current_user, :push_code, @project) can?(current_user, :push_code, project)
end
end
def edit_blob_link(project, ref, path, options = {})
if project.repository.blob_at(ref, path).text?
text = 'Edit'
after = options[:after] || ''
from_mr = options[:from_merge_request_id]
link_opts = {}
link_opts[:from_merge_request_id] = from_mr if from_mr
cls = 'btn btn-small'
if allowed_tree_edit?(project, ref)
link_to text, project_edit_tree_path(project, tree_join(ref, path),
link_opts), class: cls
else
content_tag :span, text, class: cls + ' disabled'
end + after.html_safe
else
''
end end
end end
......
...@@ -10,12 +10,12 @@ class Commit ...@@ -10,12 +10,12 @@ class Commit
# Used to prevent 500 error on huge commits by suppressing diff # Used to prevent 500 error on huge commits by suppressing diff
# #
# User can force display of diff above this size # User can force display of diff above this size
DIFF_SAFE_FILES = 100 DIFF_SAFE_FILES = 100 unless defined?(DIFF_SAFE_FILES)
DIFF_SAFE_LINES = 5000 DIFF_SAFE_LINES = 5000 unless defined?(DIFF_SAFE_LINES)
# Commits above this size will not be rendered in HTML # Commits above this size will not be rendered in HTML
DIFF_HARD_LIMIT_FILES = 1000 DIFF_HARD_LIMIT_FILES = 1000 unless defined?(DIFF_HARD_LIMIT_FILES)
DIFF_HARD_LIMIT_LINES = 50000 DIFF_HARD_LIMIT_LINES = 50000 unless defined?(DIFF_HARD_LIMIT_LINES)
class << self class << self
def decorate(commits) def decorate(commits)
......
...@@ -502,6 +502,6 @@ class Note < ActiveRecord::Base ...@@ -502,6 +502,6 @@ class Note < ActiveRecord::Base
end end
def editable? def editable?
!system !read_attribute(:system)
end end
end end
...@@ -5,7 +5,7 @@ class ProjectWiki ...@@ -5,7 +5,7 @@ class ProjectWiki
'Markdown' => :markdown, 'Markdown' => :markdown,
'RDoc' => :rdoc, 'RDoc' => :rdoc,
'AsciiDoc' => :asciidoc 'AsciiDoc' => :asciidoc
} } unless defined?(MARKUPS)
class CouldNotCreateWikiError < StandardError; end class CouldNotCreateWikiError < StandardError; end
......
...@@ -29,7 +29,9 @@ class Snippet < ActiveRecord::Base ...@@ -29,7 +29,9 @@ class Snippet < ActiveRecord::Base
validates :author, presence: true validates :author, presence: true
validates :title, presence: true, length: { within: 0..255 } validates :title, presence: true, length: { within: 0..255 }
validates :file_name, presence: true, length: { within: 0..255 } validates :file_name, presence: true, length: { within: 0..255 },
format: { with: Gitlab::Regex.path_regex,
message: Gitlab::Regex.path_regex_message }
validates :content, presence: true validates :content, presence: true
validates :visibility_level, inclusion: { in: Gitlab::VisibilityLevel.values } validates :visibility_level, inclusion: { in: Gitlab::VisibilityLevel.values }
...@@ -62,6 +64,10 @@ class Snippet < ActiveRecord::Base ...@@ -62,6 +64,10 @@ class Snippet < ActiveRecord::Base
file_name file_name
end end
def sanitized_file_name
file_name.gsub(/[^a-zA-Z0-9_\-\.]+/, '')
end
def mode def mode
nil nil
end end
...@@ -72,7 +78,7 @@ class Snippet < ActiveRecord::Base ...@@ -72,7 +78,7 @@ class Snippet < ActiveRecord::Base
def visibility_level_field def visibility_level_field
visibility_level visibility_level
end end
class << self class << self
def search(query) def search(query)
......
!!! 5 !!! 5
%html{ lang: "en"} %html{ lang: "en"}
= render "layouts/head", title: "Admin area" = render "layouts/head", title: "Admin area"
%body{class: "#{app_theme} admin", :'data-page' => body_data_page} %body{class: "#{app_theme} #{theme_type} admin", :'data-page' => body_data_page}
= render "layouts/broadcast" = render "layouts/broadcast"
= render "layouts/head_panel", title: "Admin area" = render "layouts/head_panel", title: "Admin area"
= render 'layouts/page', sidebar: 'layouts/nav/admin' = render 'layouts/page', sidebar: 'layouts/nav/admin'
!!! 5 !!! 5
%html{ lang: "en"} %html{ lang: "en"}
= render "layouts/head", title: "Dashboard" = render "layouts/head", title: "Dashboard"
%body{class: "#{app_theme} application", :'data-page' => body_data_page } %body{class: "#{app_theme} #{theme_type} application", :'data-page' => body_data_page }
= render "layouts/broadcast" = render "layouts/broadcast"
= render "layouts/head_panel", title: "Dashboard" = render "layouts/head_panel", title: "Dashboard"
= render 'layouts/page', sidebar: 'layouts/nav/dashboard' = render 'layouts/page', sidebar: 'layouts/nav/dashboard'
!!! 5 !!! 5
%html{ lang: "en"} %html{ lang: "en"}
= render "layouts/head", title: "Error" = render "layouts/head", title: "Error"
%body{class: "#{app_theme} application"} %body{class: "#{app_theme} #{theme_type} application"}
= render "layouts/head_panel", title: "" if current_user = render "layouts/head_panel", title: "" if current_user
.container.navless-container .container.navless-container
= render "layouts/flash" = render "layouts/flash"
......
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
!!! 5 !!! 5
%html{ lang: "en"} %html{ lang: "en"}
= render "layouts/head", title: page_title = render "layouts/head", title: page_title
%body{class: "#{app_theme} application", :'data-page' => body_data_page} %body{class: "#{app_theme} #{theme_type} application", :'data-page' => body_data_page}
= render "layouts/broadcast" = render "layouts/broadcast"
- if current_user - if current_user
= render "layouts/head_panel", title: page_title = render "layouts/head_panel", title: page_title
......
!!! 5 !!! 5
%html{ lang: "en"} %html{ lang: "en"}
= render "layouts/head", title: group_head_title = render "layouts/head", title: group_head_title
%body{class: "#{app_theme} application sidenav", :'data-page' => body_data_page} %body{class: "#{app_theme} #{theme_type} application", :'data-page' => body_data_page}
= render "layouts/broadcast" = render "layouts/broadcast"
= render "layouts/head_panel", title: @group.name = render "layouts/head_panel", title: @group.name
= render 'layouts/page', sidebar: 'layouts/nav/group' = render 'layouts/page', sidebar: 'layouts/nav/group'
!!! 5 !!! 5
%html{ lang: "en"} %html{ lang: "en"}
= render "layouts/head", title: @title = render "layouts/head", title: @title
%body{class: "#{app_theme} application", :'data-page' => body_data_page} %body{class: "#{app_theme} #{theme_type} application", :'data-page' => body_data_page}
= render "layouts/broadcast" = render "layouts/broadcast"
= render "layouts/head_panel", title: @title = render "layouts/head_panel", title: @title
.container.navless-container .container.navless-container
......
!!! 5 !!! 5
%html{ lang: "en"} %html{ lang: "en"}
= render "layouts/head", title: "Profile" = render "layouts/head", title: "Profile"
%body{class: "#{app_theme} profile", :'data-page' => body_data_page} %body{class: "#{app_theme} #{theme_type} profile", :'data-page' => body_data_page}
= render "layouts/broadcast" = render "layouts/broadcast"
= render "layouts/head_panel", title: "Profile" = render "layouts/head_panel", title: "Profile"
= render 'layouts/page', sidebar: 'layouts/nav/profile' = render 'layouts/page', sidebar: 'layouts/nav/profile'
!!! 5 !!! 5
%html{ lang: "en"} %html{ lang: "en"}
= render "layouts/head", title: @project.name_with_namespace = render "layouts/head", title: @project.name_with_namespace
%body{class: "#{app_theme} project", :'data-page' => body_data_page, :'data-project-id' => @project.id } %body{class: "#{app_theme} #{theme_type} project", :'data-page' => body_data_page, :'data-project-id' => @project.id }
= render "layouts/broadcast" = render "layouts/broadcast"
= render "layouts/head_panel", title: project_title(@project) = render "layouts/head_panel", title: project_title(@project)
= render "layouts/init_auto_complete" = render "layouts/init_auto_complete"
......
!!! 5 !!! 5
%html{ lang: "en"} %html{ lang: "en"}
= render "layouts/head", title: project_head_title = render "layouts/head", title: project_head_title
%body{class: "#{app_theme} project", :'data-page' => body_data_page, :'data-project-id' => @project.id } %body{class: "#{app_theme} #{theme_type} project", :'data-page' => body_data_page, :'data-project-id' => @project.id }
= render "layouts/broadcast" = render "layouts/broadcast"
= render "layouts/head_panel", title: project_title(@project) = render "layouts/head_panel", title: project_title(@project)
= render "layouts/init_auto_complete" = render "layouts/init_auto_complete"
......
!!! 5 !!! 5
%html{ lang: "en"} %html{ lang: "en"}
= render "layouts/head", title: group_head_title = render "layouts/head", title: group_head_title
%body{class: "#{app_theme} application", :'data-page' => body_data_page} %body{class: "#{app_theme} #{theme_type} application", :'data-page' => body_data_page}
= render "layouts/broadcast" = render "layouts/broadcast"
= render "layouts/public_head_panel", title: "group: #{@group.name}" = render "layouts/public_head_panel", title: "group: #{@group.name}"
= render 'layouts/page', sidebar: 'layouts/nav/group' = render 'layouts/page', sidebar: 'layouts/nav/group'
!!! 5 !!! 5
%html{ lang: "en"} %html{ lang: "en"}
= render "layouts/head", title: @project.name_with_namespace = render "layouts/head", title: @project.name_with_namespace
%body{class: "#{app_theme} application", :'data-page' => body_data_page} %body{class: "#{app_theme} #{theme_type} application", :'data-page' => body_data_page}
= render "layouts/broadcast" = render "layouts/broadcast"
= render "layouts/public_head_panel", title: project_title(@project) = render "layouts/public_head_panel", title: project_title(@project)
= render 'layouts/page', sidebar: 'layouts/nav/project' = render 'layouts/page', sidebar: 'layouts/nav/project'
!!! 5 !!! 5
%html{ lang: "en"} %html{ lang: "en"}
= render "layouts/head", title: @title = render "layouts/head", title: @title
%body{class: "#{app_theme} application", :'data-page' => body_data_page} %body{class: "#{app_theme} #{theme_type} application", :'data-page' => body_data_page}
= render "layouts/broadcast" = render "layouts/broadcast"
= render "layouts/public_head_panel", title: @title = render "layouts/public_head_panel", title: @title
= render 'layouts/page' = render 'layouts/page'
!!! 5 !!! 5
%html{ lang: "en"} %html{ lang: "en"}
= render "layouts/head", title: "Search" = render "layouts/head", title: "Search"
%body{class: "#{app_theme} application", :'data-page' => body_data_page} %body{class: "#{app_theme} #{theme_type} application", :'data-page' => body_data_page}
= render "layouts/broadcast" = render "layouts/broadcast"
= render "layouts/head_panel", title: "Search" = render "layouts/head_panel", title: "Search"
.container.navless-container .container.navless-container
......
// Remove body class for any previous theme, re-add current one // Remove body class for any previous theme, re-add current one
$('body').removeClass('ui_basic ui_mars ui_modern ui_gray ui_color') $('body').removeClass('ui_basic ui_mars ui_modern ui_gray ui_color light_theme dark_theme')
$('body').addClass('<%= app_theme %>') $('body').addClass('<%= app_theme %> <%= theme_type %>')
// Re-render the header to reflect the new theme // Re-render the header to reflect the new theme
$('header').html('<%= escape_javascript(render("layouts/head_panel", title: "Profile")) %>') $('header').html('<%= escape_javascript(render("layouts/head_panel", title: "Profile")) %>')
......
...@@ -14,17 +14,20 @@ ...@@ -14,17 +14,20 @@
.form-group.issuable-description .form-group.issuable-description
= f.label :description, 'Description', class: 'control-label' = f.label :description, 'Description', class: 'control-label'
.col-sm-10 .col-sm-10
= render 'projects/zen', f: f, attr: :description,
classes: 'description form-control' = render layout: 'projects/md_preview' do
.col-sm-12.hint = render 'projects/zen', f: f, attr: :description,
.pull-left classes: 'description form-control'
Parsed with .col-sm-12.hint
#{link_to 'GitLab Flavored Markdown', help_page_path('markdown', 'markdown'), target: '_blank'}. .pull-left
.pull-right Parsed with
Attach images (JPG, PNG, GIF) by dragging &amp; dropping #{link_to 'GitLab Flavored Markdown', help_page_path('markdown', 'markdown'), target: '_blank'}.
or #{link_to 'selecting them', '#', class: 'markdown-selector' }. .pull-right
.clearfix Attach images (JPG, PNG, GIF) by dragging &amp; dropping
.error-alert or #{link_to 'selecting them', '#', class: 'markdown-selector' }.
.clearfix
.error-alert
%hr %hr
.form-group .form-group
.issue-assignee .issue-assignee
......
%ul.nav.nav-tabs
%li.active
= link_to '#md-write-holder', class: 'js-md-write-button' do
Write
%li
= link_to '#md-preview-holder', class: 'js-md-preview-button',
data: { url: markdown_preview_project_path(@project) } do
Preview
%div
.md-write-holder
= yield
.md-preview-holder.hide
.js-md-preview
.btn-group.tree-btn-group .btn-group.tree-btn-group
-# only show edit link for text files = edit_blob_link(@project, @ref, @path)
- if @blob.text?
- if allowed_tree_edit?
= link_to 'Edit', project_edit_tree_path(@project, @id),
class: 'btn btn-small'
- else
%span.btn.btn-small.disabled Edit
= link_to 'Raw', project_raw_path(@project, @id), = link_to 'Raw', project_raw_path(@project, @id),
class: 'btn btn-small', target: '_blank' class: 'btn btn-small', target: '_blank'
-# only show normal/blame view links for text files -# only show normal/blame view links for text files
......
...@@ -16,7 +16,7 @@ ...@@ -16,7 +16,7 @@
= link_to title, '#' = link_to title, '#'
%ul.blob-commit-info.bs-callout.bs-callout-info.hidden-xs %ul.blob-commit-info.bs-callout.bs-callout-info.hidden-xs
- blob_commit = @repository.last_commit_for_path(@commit.id, @blob.path) - blob_commit = @repository.last_commit_for_path(@commit.id, blob.path)
= render blob_commit, project: @project = render blob_commit, project: @project
%div#tree-content-holder.tree-content-holder %div#tree-content-holder.tree-content-holder
......
...@@ -30,9 +30,9 @@ ...@@ -30,9 +30,9 @@
&nbsp; &nbsp;
- if @merge_request && @merge_request.source_project - if @merge_request && @merge_request.source_project
= link_to project_edit_tree_path(@merge_request.source_project, tree_join(@merge_request.source_branch, diff_file.new_path), from_merge_request_id: @merge_request.id), { class: 'btn btn-small' } do = edit_blob_link(@merge_request.source_project,
Edit @merge_request.source_branch, diff_file.new_path,
&nbsp; after: '&nbsp;', from_merge_request_id: @merge_request.id)
= view_file_btn(@commit.id, diff_file, project) = view_file_btn(@commit.id, diff_file, project)
......
...@@ -21,12 +21,13 @@ ...@@ -21,12 +21,13 @@
.form-group .form-group
.light .light
= f.label :description, "Description" = f.label :description, "Description"
= render 'projects/zen', f: f, attr: :description, = render layout: 'projects/md_preview' do
classes: 'description form-control' = render 'projects/zen', f: f, attr: :description,
.clearfix.hint classes: 'description form-control'
.pull-left Description is parsed with #{link_to "GitLab Flavored Markdown", help_page_path("markdown", "markdown"), target: '_blank'}. .clearfix.hint
.pull-right Attach images (JPG, PNG, GIF) by dragging & dropping or #{link_to "selecting them", '#', class: 'markdown-selector' }. .pull-left Description is parsed with #{link_to "GitLab Flavored Markdown", help_page_path("markdown", "markdown"), target: '_blank'}.
.error-alert .pull-right Attach images (JPG, PNG, GIF) by dragging & dropping or #{link_to "selecting them", '#', class: 'markdown-selector' }.
.error-alert
.form-group .form-group
.issue-assignee .issue-assignee
= f.label :assignee_id do = f.label :assignee_id do
......
...@@ -18,13 +18,14 @@ ...@@ -18,13 +18,14 @@
.col-sm-10 .col-sm-10
= f.text_field :title, maxlength: 255, class: "form-control" = f.text_field :title, maxlength: 255, class: "form-control"
%p.hint Required %p.hint Required
.form-group .form-group.milestone-description
= f.label :description, "Description", class: "control-label" = f.label :description, "Description", class: "control-label"
.col-sm-10 .col-sm-10
= render 'projects/zen', f: f, attr: :description, classes: 'description form-control' = render layout: 'projects/md_preview' do
.hint = render 'projects/zen', f: f, attr: :description, classes: 'description form-control'
.pull-left Milestones are parsed with #{link_to "GitLab Flavored Markdown", help_page_path("markdown", "markdown"), target: '_blank'}. .hint
.pull-left Attach images (JPG, PNG, GIF) by dragging & dropping or #{link_to "selecting them", '#', class: 'markdown-selector' }. .pull-left Milestones are parsed with #{link_to "GitLab Flavored Markdown", help_page_path("markdown", "markdown"), target: '_blank'}.
.pull-left Attach images (JPG, PNG, GIF) by dragging & dropping or #{link_to "selecting them", '#', class: 'markdown-selector' }.
.clearfix .clearfix
.error-alert .error-alert
.col-md-6 .col-md-6
......
...@@ -5,23 +5,13 @@ ...@@ -5,23 +5,13 @@
= f.hidden_field :noteable_id = f.hidden_field :noteable_id
= f.hidden_field :noteable_type = f.hidden_field :noteable_type
%ul.nav.nav-tabs = render layout: 'projects/md_preview' do
%li.active = render 'projects/zen', f: f, attr: :note,
= link_to '#note-write-holder', class: 'js-note-write-button' do classes: 'note_text js-note-text'
Write .light.clearfix
%li .pull-left Comments are parsed with #{link_to "GitLab Flavored Markdown", help_page_path("markdown", "markdown"),{ target: '_blank', tabindex: -1 }}
= link_to '#note-preview-holder', class: 'js-note-preview-button', data: { url: preview_project_notes_path(@project) } do .pull-right Attach images (JPG, PNG, GIF) by dragging &amp; dropping or #{link_to "selecting them", '#', class: 'markdown-selector', tabindex: -1 }.
Preview
%div
.note-write-holder
= render 'projects/zen', f: f, attr: :note,
classes: 'note_text js-note-text'
.light.clearfix
.pull-left Comments are parsed with #{link_to "GitLab Flavored Markdown", help_page_path("markdown", "markdown"),{ target: '_blank', tabindex: -1 }}
.pull-right Attach images (JPG, PNG, GIF) by dragging &amp; dropping or #{link_to "selecting them", '#', class: 'markdown-selector', tabindex: -1 }.
.note-preview-holder.hide
.js-note-preview
.note-form-actions .note-form-actions
.buttons .buttons
......
...@@ -40,7 +40,8 @@ ...@@ -40,7 +40,8 @@
.note-edit-form .note-edit-form
= form_for note, url: project_note_path(@project, note), method: :put, remote: true, authenticity_token: true do |f| = form_for note, url: project_note_path(@project, note), method: :put, remote: true, authenticity_token: true do |f|
= f.text_area :note, class: 'note_text js-note-text js-gfm-input turn-on' = render layout: 'projects/md_preview' do
= f.text_area :note, class: 'note_text js-note-text markdown-area js-gfm-input turn-on'
.form-actions.clearfix .form-actions.clearfix
= f.submit 'Save changes', class: "btn btn-primary btn-save js-comment-button" = f.submit 'Save changes', class: "btn btn-primary btn-save js-comment-button"
......
- if @project.errors[:namespace_id].present? :plain
:plain
$("#tab-transfer .errors-holder").replaceWith(errorMessage('#{escape_javascript(@project.errors[:namespace_id].first)}'));
$("#tab-transfer .form-actions input").removeAttr('disabled').removeClass('disabled');
- else
:plain
location.href = "#{edit_project_path(@project)}"; location.href = "#{edit_project_path(@project)}";
...@@ -186,16 +186,18 @@ Gitlab::Application.routes.draw do ...@@ -186,16 +186,18 @@ Gitlab::Application.routes.draw do
post :unarchive post :unarchive
post :upload_image post :upload_image
post :toggle_star post :toggle_star
get :markdown_preview
get :autocomplete_sources get :autocomplete_sources
end end
scope module: :projects do scope module: :projects do
resources :blob, only: [:show, :destroy], constraints: { id: /.+/ } do resources :blob, only: [:show, :destroy], constraints: { id: /.+/, format: false } do
get :diff, on: :member get :diff, on: :member
end end
resources :raw, only: [:show], constraints: {id: /.+/} resources :raw, only: [:show], constraints: {id: /.+/}
resources :tree, only: [:show], constraints: {id: /.+/, format: /(html|js)/ } resources :tree, only: [:show], constraints: {id: /.+/, format: /(html|js)/ }
resources :edit_tree, only: [:show, :update], constraints: { id: /.+/ }, path: 'edit' do resources :edit_tree, only: [:show, :update], constraints: { id: /.+/ }, path: 'edit' do
# Cannot be GET to differentiate from GET paths that end in preview.
post :preview, on: :member post :preview, on: :member
end end
resources :new_tree, only: [:show, :update], constraints: {id: /.+/}, path: 'new' resources :new_tree, only: [:show, :update], constraints: {id: /.+/}, path: 'new'
...@@ -329,10 +331,6 @@ Gitlab::Application.routes.draw do ...@@ -329,10 +331,6 @@ Gitlab::Application.routes.draw do
member do member do
delete :delete_attachment delete :delete_attachment
end end
collection do
post :preview
end
end end
end end
end end
......
...@@ -16,14 +16,13 @@ Gitlab::Seeder.quiet do ...@@ -16,14 +16,13 @@ Gitlab::Seeder.quiet do
(1..5).each do |i| (1..5).each do |i|
begin begin
User.seed(:id, [ User.seed do |s|
id: i + 10, s.username = "user#{i}"
username: "user#{i}", s.name = "User #{i}"
name: "User #{i}", s.email = "user#{i}@example.com"
email: "user#{i}@example.com", s.confirmed_at = DateTime.now
confirmed_at: DateTime.now, s.password = '12345678'
password: '12345678' end
])
print '.' print '.'
rescue ActiveRecord::RecordNotSaved rescue ActiveRecord::RecordNotSaved
print 'F' print 'F'
......
...@@ -23,6 +23,7 @@ ...@@ -23,6 +23,7 @@
- [Welcome message](customization/welcome_message.md) Add a custom welcome message to the sign-in page. - [Welcome message](customization/welcome_message.md) Add a custom welcome message to the sign-in page.
- [Issue closing](customization/issue_closing.md) Customize how to close an issue from commit messages. - [Issue closing](customization/issue_closing.md) Customize how to close an issue from commit messages.
- [Libravatar](customization/libravatar.md) Use Libravatar for user avatars. - [Libravatar](customization/libravatar.md) Use Libravatar for user avatars.
- [Operations](operations/README.md) Keeping GitLab up and running
## Contributor documentation ## Contributor documentation
......
# Guidelines for shell commands in the GitLab codebase # Guidelines for shell commands in the GitLab codebase
This document contains guidelines for working with processes and files in the GitLab codebase.
These guidelines are meant to make your code more reliable _and_ secure.
## References ## References
- [Google Ruby Security Reviewer's Guide](https://code.google.com/p/ruby-security/wiki/Guide) - [Google Ruby Security Reviewer's Guide](https://code.google.com/p/ruby-security/wiki/Guide)
...@@ -109,3 +112,63 @@ logs = IO.popen(%W(git log), chdir: repo_dir).read ...@@ -109,3 +112,63 @@ logs = IO.popen(%W(git log), chdir: repo_dir).read
``` ```
Note that unlike `Gitlab::Popen.popen`, `IO.popen` does not capture standard error. Note that unlike `Gitlab::Popen.popen`, `IO.popen` does not capture standard error.
## Avoid user input at the start of path strings
Various methods for opening and reading files in Ruby can be used to read the
standard output of a process instead of a file. The following two commands do
roughly the same:
```
`touch /tmp/pawned-by-backticks`
File.read('|touch /tmp/pawned-by-file-read')
```
The key is to open a 'file' whose name starts with a `|`.
Affected methods include Kernel#open, File::read, File::open, IO::open and IO::read.
You can protect against this behavior of 'open' and 'read' by ensuring that an
attacker cannot control the start of the filename string you are opening. For
instance, the following is sufficient to protect against accidentally starting
a shell command with `|`:
```
# we assume repo_path is not controlled by the attacker (user)
path = File.join(repo_path, user_input)
# path cannot start with '|' now.
File.read(path)
```
## Guard against path traversal
Path traversal is a security where the program (GitLab) tries to restrict user
access to a certain directory on disk, but the user manages to open a file
outside that directory by taking advantage of the `../` path notation.
```
# Suppose the user gave us a path and they are trying to trick us
user_input = '../other-repo.git/other-file'
# We look up the repo path somewhere
repo_path = 'repositories/user-repo.git'
# The intention of the code below is to open a file under repo_path, but
# because the user used '..' she can 'break out' into
# 'repositories/other-repo.git'
full_path = File.join(repo_path, user_input)
File.open(full_path) do # Oops!
```
A good way to protect against this is to compare the full path with its
'absolute path' according to Ruby's `File.absolute_path`.
```
full_path = File.join(repo_path, user_input)
if full_path != File.absolute_path(full_path)
raise "Invalid path: #{full_path.inspect}"
end
File.open(full_path) do # Etc.
```
A check like this could have avoided CVE-2013-4583.
...@@ -54,7 +54,7 @@ up-to-date and install it. ...@@ -54,7 +54,7 @@ up-to-date and install it.
Install the required packages (needed to compile Ruby and native extensions to Ruby gems): Install the required packages (needed to compile Ruby and native extensions to Ruby gems):
sudo apt-get install -y build-essential zlib1g-dev libyaml-dev libssl-dev libgdbm-dev libreadline-dev libncurses5-dev libffi-dev curl openssh-server redis-server checkinstall libxml2-dev libxslt-dev libcurl4-openssl-dev libicu-dev logrotate python-docutils pkg-config cmake sudo apt-get install -y build-essential zlib1g-dev libyaml-dev libssl-dev libgdbm-dev libreadline-dev libncurses5-dev libffi-dev curl openssh-server redis-server checkinstall libxml2-dev libxslt-dev libcurl4-openssl-dev libicu-dev logrotate python-docutils pkg-config cmake libkrb5-dev
Make sure you have the right version of Git installed Make sure you have the right version of Git installed
...@@ -181,9 +181,9 @@ We recommend using a PostgreSQL database. For MySQL check [MySQL setup guide](da ...@@ -181,9 +181,9 @@ We recommend using a PostgreSQL database. For MySQL check [MySQL setup guide](da
### Clone the Source ### Clone the Source
# Clone GitLab repository # Clone GitLab repository
sudo -u git -H git clone https://gitlab.com/gitlab-org/gitlab-ce.git -b 7-5-stable gitlab sudo -u git -H git clone https://gitlab.com/gitlab-org/gitlab-ce.git -b 7-6-stable gitlab
**Note:** You can change `7-5-stable` to `master` if you want the *bleeding edge* version, but never install master on a production server! **Note:** You can change `7-6-stable` to `master` if you want the *bleeding edge* version, but never install master on a production server!
### Configure It ### Configure It
...@@ -278,7 +278,7 @@ We recommend using a PostgreSQL database. For MySQL check [MySQL setup guide](da ...@@ -278,7 +278,7 @@ We recommend using a PostgreSQL database. For MySQL check [MySQL setup guide](da
GitLab Shell is an SSH access and repository management software developed specially for GitLab. GitLab Shell is an SSH access and repository management software developed specially for GitLab.
# Run the installation task for gitlab-shell (replace `REDIS_URL` if needed): # Run the installation task for gitlab-shell (replace `REDIS_URL` if needed):
sudo -u git -H bundle exec rake gitlab:shell:install[v2.2.0] REDIS_URL=unix:/var/run/redis/redis.sock RAILS_ENV=production sudo -u git -H bundle exec rake gitlab:shell:install[v2.4.0] REDIS_URL=unix:/var/run/redis/redis.sock RAILS_ENV=production
# By default, the gitlab-shell config is generated from your main GitLab config. # By default, the gitlab-shell config is generated from your main GitLab config.
# You can review (and modify) the gitlab-shell config as follows: # You can review (and modify) the gitlab-shell config as follows:
...@@ -383,15 +383,17 @@ NOTE: Supply `SANITIZE=true` environment variable to `gitlab:check` to omit proj ...@@ -383,15 +383,17 @@ NOTE: Supply `SANITIZE=true` environment variable to `gitlab:check` to omit proj
### Initial Login ### Initial Login
Visit YOUR_SERVER in your web browser for your first GitLab login. The setup has created an admin account for you. You can use it to log in: Visit YOUR_SERVER in your web browser for your first GitLab login. The setup has created a default admin account for you. You can use it to log in:
root root
5iveL!fe 5iveL!fe
**Important Note:** Please go over to your profile page and immediately change the password, so nobody can access your GitLab by using this login information later on. **Important Note:** Please login to the server before exposing it to the public internet. On login you'll be prompted to change the password.
**Enjoy!** **Enjoy!**
You can use `sudo service gitlab start` and `sudo service gitlab stop` to start and stop GitLab.
## Advanced Setup Tips ## Advanced Setup Tips
### Using HTTPS ### Using HTTPS
......
...@@ -7,6 +7,7 @@ OmniAuth does not prevent standard GitLab authentication or LDAP (if configured) ...@@ -7,6 +7,7 @@ OmniAuth does not prevent standard GitLab authentication or LDAP (if configured)
- [Initial OmniAuth Configuration](#initial-omniauth-configuration) - [Initial OmniAuth Configuration](#initial-omniauth-configuration)
- [Supported Providers](#supported-providers) - [Supported Providers](#supported-providers)
- [Enable OmniAuth for an Existing User](#enable-omniauth-for-an-existing-user) - [Enable OmniAuth for an Existing User](#enable-omniauth-for-an-existing-user)
- [OmniAuth configuration sample when using Omnibus GitLab](https://gitlab.com/gitlab-org/omnibus-gitlab/tree/master#omniauth-google-twitter-github-login)
## Initial OmniAuth Configuration ## Initial OmniAuth Configuration
......
...@@ -13,7 +13,7 @@ To enable the Twitter OmniAuth provider you must register your application with ...@@ -13,7 +13,7 @@ To enable the Twitter OmniAuth provider you must register your application with
something else descriptive. something else descriptive.
- Description: Create a description. - Description: Create a description.
- Website: The URL to your GitLab installation. 'https://gitlab.example.com' - Website: The URL to your GitLab installation. 'https://gitlab.example.com'
- Callback URL: 'https://gitlab.example.com/users/auth/github/callback' - Callback URL: 'https://gitlab.example.com/users/auth/twitter/callback'
- Agree to the "Rules of the Road." - Agree to the "Rules of the Road."
![Twitter App Details](twitter_app_details.png) ![Twitter App Details](twitter_app_details.png)
......
# GitLab operations
- [Sidekiq MemoryKiller](sidekiq_memory_killer.md)
# Sidekiq MemoryKiller
The GitLab Rails application code suffers from memory leaks. For web requests
this problem is made manageable using
[unicorn-worker-killer](https://github.com/kzk/unicorn-worker-killer) which
restarts Unicorn worker processes in between requests when needed. The Sidekiq
MemoryKiller applies the same approach to the Sidekiq processes used by GitLab
to process background jobs.
Unlike unicorn-worker-killer, which is enabled by default for all GitLab
installations since GitLab 6.4, the Sidekiq MemoryKiller is enabled by default
_only_ for Omnibus packages. The reason for this is that the MemoryKiller
relies on Runit to restart Sidekiq after a memory-induced shutdown and GitLab
installations from source do not all use Runit or an equivalent.
With the default settings, the MemoryKiller will cause a Sidekiq restart no
more often than once every 15 minutes, with the restart causing about one
minute of delay for incoming background jobs.
## Configuring the MemoryKiller
The MemoryKiller is controlled using environment variables.
- `SIDEKIQ_MEMORY_KILLER_MAX_RSS`: if this variable is set, and its value is
greater than 0, then after each Sidekiq job, the MemoryKiller will check the
RSS of the Sidekiq process that executed the job. If the RSS of the Sidekiq
process (expressed in kilobytes) exceeds SIDEKIQ_MEMORY_KILLER_MAX_RSS, a
delayed shutdown is triggered. The default value for Omnibus packages is set
[in the omnibus-gitlab
repository](https://gitlab.com/gitlab-org/omnibus-gitlab/blob/master/files/gitlab-cookbooks/gitlab/attributes/default.rb).
- `SIDEKIQ_MEMORY_KILLER_GRACE_TIME`: defaults 900 seconds (15 minutes). When
a shutdown is triggered, the Sidekiq process will keep working normally for
another 15 minutes.
- `SIDEKIQ_MEMORY_KILLER_SHUTDOWN_WAIT`: defaults to 30 seconds. When the grace
time has expired, the MemoryKiller tells Sidekiq to stop accepting new jobs.
Existing jobs get 30 seconds to finish. After that, the MemoryKiller tells
Sidekiq to shut down, and an external supervision mechanism (e.g. Runit) must
restart Sidekiq.
# Rake tasks
- [Backup restore](backup_restore.md) - [Backup restore](backup_restore.md)
- [Cleanup](cleanup.md) - [Cleanup](cleanup.md)
- [Features](features.md)
- [Maintenance](maintenance.md) and self-checks - [Maintenance](maintenance.md) and self-checks
- [User management](user_management.md) - [User management](user_management.md)
- [Web hooks](web_hooks.md) - [Web hooks](web_hooks.md)
......
...@@ -137,7 +137,7 @@ with the name of your bucket: ...@@ -137,7 +137,7 @@ with the name of your bucket:
Please be informed that a backup does not store your configuration files. Please be informed that a backup does not store your configuration files.
If you use an Omnibus package please see the [instructions in the readme to backup your configuration](https://gitlab.com/gitlab-org/omnibus-gitlab/blob/master/README.md#backup-and-restore-omnibus-gitlab-configuration). If you use an Omnibus package please see the [instructions in the readme to backup your configuration](https://gitlab.com/gitlab-org/omnibus-gitlab/blob/master/README.md#backup-and-restore-omnibus-gitlab-configuration).
If you have a cookbook installation there should be a copy of your configuration in Chef. If you have a cookbook installation there should be a copy of your configuration in Chef.
If you have a manual installation please consider backing up your gitlab.yml file and any SSL keys and certificates. If you have a manual installation please consider backing up your `gitlab.yml` file, any SSL keys and certificates, and your [SSH host keys](https://superuser.com/questions/532040/copy-ssh-keys-from-one-server-to-another-server/532079#532079).
## Restore a previously created backup ## Restore a previously created backup
......
...@@ -100,9 +100,9 @@ List any major changes here, so the user is aware of them before starting to upg ...@@ -100,9 +100,9 @@ List any major changes here, so the user is aware of them before starting to upg
- Web server changes - Web server changes
- File structure changes - File structure changes
#### 1. Make backup #### 1. Stop server
#### 2. Stop server #### 2. Make backup
#### 3. Do users need to update dependencies like `git`? #### 3. Do users need to update dependencies like `git`?
......
# From 6.x or 7.x to 7.5 # From 6.x or 7.x to 7.6
This allows you to upgrade any version of GitLab from 6.0 and up (including 7.0 and up) to 7.5. This allows you to upgrade any version of GitLab from 6.0 and up (including 7.0 and up) to 7.6.
## Global issue numbers ## Global issue numbers
...@@ -70,7 +70,7 @@ sudo -u git -H git checkout -- db/schema.rb # local changes will be restored aut ...@@ -70,7 +70,7 @@ sudo -u git -H git checkout -- db/schema.rb # local changes will be restored aut
For GitLab Community Edition: For GitLab Community Edition:
```bash ```bash
sudo -u git -H git checkout 7-5-stable sudo -u git -H git checkout 7-6-stable
``` ```
OR OR
...@@ -78,7 +78,7 @@ OR ...@@ -78,7 +78,7 @@ OR
For GitLab Enterprise Edition: For GitLab Enterprise Edition:
```bash ```bash
sudo -u git -H git checkout 7-5-stable-ee sudo -u git -H git checkout 7-6-stable-ee
``` ```
## 4. Install additional packages ## 4. Install additional packages
...@@ -119,7 +119,7 @@ sudo apt-get install pkg-config cmake ...@@ -119,7 +119,7 @@ sudo apt-get install pkg-config cmake
```bash ```bash
cd /home/git/gitlab-shell cd /home/git/gitlab-shell
sudo -u git -H git fetch sudo -u git -H git fetch
sudo -u git -H git checkout v2.2.0 sudo -u git -H git checkout v2.4.0
``` ```
## 7. Install libs, migrations, etc. ## 7. Install libs, migrations, etc.
...@@ -154,14 +154,14 @@ sudo cp lib/support/init.d/gitlab /etc/init.d/gitlab ...@@ -154,14 +154,14 @@ sudo cp lib/support/init.d/gitlab /etc/init.d/gitlab
TIP: to see what changed in `gitlab.yml.example` in this release use next command: TIP: to see what changed in `gitlab.yml.example` in this release use next command:
``` ```
git diff 6-0-stable:config/gitlab.yml.example 7-5-stable:config/gitlab.yml.example git diff 6-0-stable:config/gitlab.yml.example 7-6-stable:config/gitlab.yml.example
``` ```
* Make `/home/git/gitlab/config/gitlab.yml` the same as https://gitlab.com/gitlab-org/gitlab-ce/blob/7-5-stable/config/gitlab.yml.example but with your settings. * Make `/home/git/gitlab/config/gitlab.yml` the same as https://gitlab.com/gitlab-org/gitlab-ce/blob/7-6-stable/config/gitlab.yml.example but with your settings.
* Make `/home/git/gitlab/config/unicorn.rb` the same as https://gitlab.com/gitlab-org/gitlab-ce/blob/7-5-stable/config/unicorn.rb.example but with your settings. * Make `/home/git/gitlab/config/unicorn.rb` the same as https://gitlab.com/gitlab-org/gitlab-ce/blob/7-6-stable/config/unicorn.rb.example but with your settings.
* Make `/home/git/gitlab-shell/config.yml` the same as https://gitlab.com/gitlab-org/gitlab-shell/blob/v2.2.0/config.yml.example but with your settings. * Make `/home/git/gitlab-shell/config.yml` the same as https://gitlab.com/gitlab-org/gitlab-shell/blob/v2.4.0/config.yml.example but with your settings.
* HTTP setups: Make `/etc/nginx/sites-available/gitlab` the same as https://gitlab.com/gitlab-org/gitlab-ce/blob/7-5-stable/lib/support/nginx/gitlab but with your settings. * HTTP setups: Make `/etc/nginx/sites-available/gitlab` the same as https://gitlab.com/gitlab-org/gitlab-ce/blob/7-6-stable/lib/support/nginx/gitlab but with your settings.
* HTTPS setups: Make `/etc/nginx/sites-available/gitlab-ssl` the same as https://gitlab.com/gitlab-org/gitlab-ce/blob/7-5-stable/lib/support/nginx/gitlab-ssl but with your settings. * HTTPS setups: Make `/etc/nginx/sites-available/gitlab-ssl` the same as https://gitlab.com/gitlab-org/gitlab-ce/blob/7-6-stable/lib/support/nginx/gitlab-ssl but with your settings.
* Copy rack attack middleware config * Copy rack attack middleware config
```bash ```bash
......
...@@ -71,21 +71,10 @@ There are new configuration options available for gitlab.yml. View them with the ...@@ -71,21 +71,10 @@ There are new configuration options available for gitlab.yml. View them with the
git diff origin/7-4-stable:config/gitlab.yml.example origin/7-5-stable:config/gitlab.yml.example git diff origin/7-4-stable:config/gitlab.yml.example origin/7-5-stable:config/gitlab.yml.example
``` ```
#### Change timeout for unicorn #### Change Nginx settings
```
# set timeout to 60
sudo -u git -H editor config/unicorn.rb
```
#### Change nginx https settings
* HTTPS setups: Make `/etc/nginx/sites-available/gitlab-ssl` the same as https://gitlab.com/gitlab-org/gitlab-ce/blob/7-5-stable/lib/support/nginx/gitlab-ssl but with your setting
#### MySQL Databases: Update database.yml config file
* Add `collation: utf8_general_ci` to config/database.yml as seen in [config/database.yml.mysql](config/database.yml.mysql)
* HTTP setups: Make `/etc/nginx/sites-available/gitlab` the same as [`lib/support/nginx/gitlab`](/lib/support/nginx/gitlab) but with your settings
* HTTPS setups: Make `/etc/nginx/sites-available/gitlab-ssl` the same as [`lib/support/nginx/gitlab-ssl`](/lib/support/nginx/gitlab-ssl) but with your setting
### 6. Start application ### 6. Start application
...@@ -104,82 +93,6 @@ To make sure you didn't miss anything run a more thorough check with: ...@@ -104,82 +93,6 @@ To make sure you didn't miss anything run a more thorough check with:
If all items are green, then congratulations upgrade is complete! If all items are green, then congratulations upgrade is complete!
### 8. Optional optimizations for GitLab setups with MySQL databases
Only applies if running MySQL database created with GitLab 6.7 or earlier. If you are not experiencing any issues you may not need the following instructions however following them will bring your database in line with the latest recommended installation configuration and help avoid future issues. Be sure to follow these directions exactly. These directions should be safe for any MySQL instance but to be sure make a current MySQL database backup beforehand.
```
# Stop GitLab
sudo service gitlab stop
# Secure your MySQL installation (added in GitLab 6.2)
sudo mysql_secure_installation
# Login to MySQL
mysql -u root -p
# do not type the 'mysql>', this is part of the prompt
# Convert all tables to use the InnoDB storage engine (added in GitLab 6.8)
SELECT CONCAT('ALTER TABLE gitlabhq_production.', table_name, ' ENGINE=InnoDB;') AS 'Copy & run these SQL statements:' FROM information_schema.tables WHERE table_schema = 'gitlabhq_production' AND `ENGINE` <> 'InnoDB' AND `TABLE_TYPE` = 'BASE TABLE';
# If previous query returned results, copy & run all outputed SQL statements
# Convert all tables to correct character set
SET foreign_key_checks = 0;
SELECT CONCAT('ALTER TABLE gitlabhq_production.', table_name, ' CONVERT TO CHARACTER SET utf8 COLLATE utf8_general_ci;') AS 'Copy & run these SQL statements:' FROM information_schema.tables WHERE table_schema = 'gitlabhq_production' AND `TABLE_COLLATION` <> 'utf8_unicode_ci' AND `TABLE_TYPE` = 'BASE TABLE';
# If previous query returned results, copy & run all outputed SQL statements
# turn foreign key checks back on
SET foreign_key_checks = 1;
# Find MySQL users
mysql> SELECT user FROM mysql.user WHERE user LIKE '%git%';
# If git user exists and gitlab user does not exist
# you are done with the database cleanup tasks
mysql> \q
# If both users exist skip to Delete gitlab user
# Create new user for GitLab (changed in GitLab 6.4)
# change $password in the command below to a real password you pick
mysql> CREATE USER 'git'@'localhost' IDENTIFIED BY '$password';
# Grant the git user necessary permissions on the database
mysql> GRANT SELECT, INSERT, UPDATE, DELETE, CREATE, DROP, INDEX, ALTER, LOCK TABLES ON `gitlabhq_production`.* TO 'git'@'localhost';
# Delete the old gitlab user
mysql> DELETE FROM mysql.user WHERE user='gitlab';
# Quit the database session
mysql> \q
# Try connecting to the new database with the new user
sudo -u git -H mysql -u git -p -D gitlabhq_production
# Type the password you replaced $password with earlier
# You should now see a 'mysql>' prompt
# Quit the database session
mysql> \q
# Update database configuration details
# See config/database.yml.mysql for latest recommended configuration details
# Remove the reaping_frequency setting line if it exists (removed in GitLab 6.8)
# Set production -> pool: 10 (updated in GitLab 5.3)
# Set production -> username: git
# Set production -> password: the password your replaced $password with earlier
sudo -u git -H editor /home/git/gitlab/config/database.yml
# Run thorough check
sudo -u git -H bundle exec rake gitlab:check RAILS_ENV=production
```
## Things went south? Revert to previous version (7.4) ## Things went south? Revert to previous version (7.4)
### 1. Revert the code to the previous version ### 1. Revert the code to the previous version
......
# From 7.5 to 7.6 # From 7.5 to 7.6
**7.6 is not yet released. This is a preliminary upgrade guide.**
### 0. Stop server ### 0. Stop server
sudo service gitlab stop sudo service gitlab stop
...@@ -39,12 +37,14 @@ sudo -u git -H git checkout 7-6-stable-ee ...@@ -39,12 +37,14 @@ sudo -u git -H git checkout 7-6-stable-ee
```bash ```bash
cd /home/git/gitlab-shell cd /home/git/gitlab-shell
sudo -u git -H git fetch sudo -u git -H git fetch
sudo -u git -H git checkout v2.2.0 sudo -u git -H git checkout v2.4.0
``` ```
### 4. Install libs, migrations, etc. ### 4. Install libs, migrations, etc.
```bash ```bash
sudo apt-get install libkrb5-dev
cd /home/git/gitlab cd /home/git/gitlab
# MySQL installations (note: the line below states '--without ... postgres') # MySQL installations (note: the line below states '--without ... postgres')
......
...@@ -54,6 +54,29 @@ Triggered when you push to the repository except when pushing tags. ...@@ -54,6 +54,29 @@ Triggered when you push to the repository except when pushing tags.
} }
``` ```
## Tag events
Triggered when you create (or delete) tags to the repository.
**Request body:**
```json
{
"ref": "refs/tags/v1.0.0",
"before": "0000000000000000000000000000000000000000",
"after": "82b3d5ae55f7080f1e6022629cdb57bfae7cccc7",
"user_id": 1,
"user_name": "John Smith",
"project_id": 1,
"repository": {
"name": "jsmith",
"url": "ssh://git@example.com/jsmith/example.git",
"description": "",
"homepage": "http://example.com/jsmith/example"
}
}
```
## Issues events ## Issues events
Triggered when a new issue is created or an existing issue was updated/closed/reopened. Triggered when a new issue is created or an existing issue was updated/closed/reopened.
......
...@@ -2,16 +2,16 @@ FROM ubuntu:14.04 ...@@ -2,16 +2,16 @@ FROM ubuntu:14.04
# Install required packages # Install required packages
RUN apt-get update -q \ RUN apt-get update -q \
&& DEBIAN_FRONTEND=noninteractive apt-get install -qy \ && DEBIAN_FRONTEND=noninteractive apt-get install -qy --no-install-recommends \
ca-certificates \
openssh-server \ openssh-server \
wget \ wget
&& apt-get clean
# Download & Install GitLab # Download & Install GitLab
# If the Omnibus package version below is outdated please contribute a merge request to update it. # If the Omnibus package version below is outdated please contribute a merge request to update it.
# If you run GitLab Enterprise Edition point it to a location where you have downloaded it. # If you run GitLab Enterprise Edition point it to a location where you have downloaded it.
RUN TMP_FILE=$(mktemp); \ RUN TMP_FILE=$(mktemp); \
wget -q -O $TMP_FILE https://downloads-packages.s3.amazonaws.com/ubuntu-14.04/gitlab_7.5.2-omnibus.5.2.1.ci-1_amd64.deb \ wget -q -O $TMP_FILE https://downloads-packages.s3.amazonaws.com/ubuntu-14.04/gitlab_7.5.3-omnibus.5.2.1.ci-1_amd64.deb \
&& dpkg -i $TMP_FILE \ && dpkg -i $TMP_FILE \
&& rm -f $TMP_FILE && rm -f $TMP_FILE
......
...@@ -39,7 +39,7 @@ After creating this run GitLab: ...@@ -39,7 +39,7 @@ After creating this run GitLab:
sudo docker run --detach --name gitlab_app --publish 8080:80 --publish 2222:22 --volumes-from gitlab_data gitlab_image sudo docker run --detach --name gitlab_app --publish 8080:80 --publish 2222:22 --volumes-from gitlab_data gitlab_image
``` ```
It might take a while before the docker container is responding to queries. You can follow the configuration process with `docker logs -f gitlab`. It might take a while before the docker container is responding to queries. You can follow the configuration process with `docker logs -f gitlab_app`.
You can then go to `http://localhost:8080/` (or `http://192.168.59.103:8080/` if you use boot2docker). You can then go to `http://localhost:8080/` (or `http://192.168.59.103:8080/` if you use boot2docker).
You can login with username `root` and password `5iveL!fe`. You can login with username `root` and password `5iveL!fe`.
......
...@@ -16,12 +16,12 @@ Feature: Project Commits Comments ...@@ -16,12 +16,12 @@ Feature: Project Commits Comments
@javascript @javascript
Scenario: I can't preview without text Scenario: I can't preview without text
Given I haven't written any comment text Given I haven't written any comment text
Then I should not see the comment preview button Then The comment preview tab should say there is nothing to do
@javascript @javascript
Scenario: I can preview with text Scenario: I can preview with text
Given I write a comment like "Nice" Given I write a comment like ":+1: Nice"
Then I should see the comment preview button Then The comment preview tab should be display rendered Markdown
@javascript @javascript
Scenario: I preview a comment Scenario: I preview a comment
...@@ -32,7 +32,7 @@ Feature: Project Commits Comments ...@@ -32,7 +32,7 @@ Feature: Project Commits Comments
@javascript @javascript
Scenario: I can edit after preview Scenario: I can edit after preview
Given I preview a comment text like "Bug fixed :smile:" Given I preview a comment text like "Bug fixed :smile:"
Then I should see the comment edit button Then I should see the comment write tab
@javascript @javascript
Scenario: I have a reset form after posting from preview Scenario: I have a reset form after posting from preview
......
...@@ -58,13 +58,13 @@ Feature: Project Commits Diff Comments ...@@ -58,13 +58,13 @@ Feature: Project Commits Diff Comments
Scenario: I can't preview without text Scenario: I can't preview without text
Given I open a diff comment form Given I open a diff comment form
And I haven't written any diff comment text And I haven't written any diff comment text
Then I should not see the diff comment preview button Then The diff comment preview tab should say there is nothing to do
@javascript @javascript
Scenario: I can preview with text Scenario: I can preview with text
Given I open a diff comment form Given I open a diff comment form
And I write a diff comment like ":-1: I don't like this" And I write a diff comment like ":-1: I don't like this"
Then I should see the diff comment preview button Then The diff comment preview tab should display rendered Markdown
@javascript @javascript
Scenario: I preview a diff comment Scenario: I preview a diff comment
...@@ -75,7 +75,7 @@ Feature: Project Commits Diff Comments ...@@ -75,7 +75,7 @@ Feature: Project Commits Diff Comments
@javascript @javascript
Scenario: I can edit after preview Scenario: I can edit after preview
Given I preview a diff comment text like "Should fix it :smile:" Given I preview a diff comment text like "Should fix it :smile:"
Then I should see the diff comment edit button Then I should see the diff comment write tab
@javascript @javascript
Scenario: The form gets removed after posting Scenario: The form gets removed after posting
......
...@@ -159,3 +159,37 @@ Feature: Project Issues ...@@ -159,3 +159,37 @@ Feature: Project Issues
Given project "Shop" has "Tasks-closed" closed issue with task markdown Given project "Shop" has "Tasks-closed" closed issue with task markdown
When I visit issue page "Tasks-closed" When I visit issue page "Tasks-closed"
Then Task checkboxes should be disabled Then Task checkboxes should be disabled
# Issue description preview
@javascript
Scenario: I can't preview without text
Given I click link "New Issue"
And I haven't written any description text
Then The Markdown preview tab should say there is nothing to do
@javascript
Scenario: I can preview with text
Given I click link "New Issue"
And I write a description like ":+1: Nice"
Then The Markdown preview tab should display rendered Markdown
@javascript
Scenario: I preview an issue description
Given I click link "New Issue"
And I preview a description text like "Bug fixed :smile:"
Then I should see the Markdown preview
And I should not see the Markdown text field
@javascript
Scenario: I can edit after preview
Given I click link "New Issue"
And I preview a description text like "Bug fixed :smile:"
Then I should see the Markdown write tab
@javascript
Scenario: I can preview when editing an existing issue
Given I click link "Release 0.4"
And I click link "Edit" for the issue
And I preview a description text like "Bug fixed :smile:"
Then I should see the Markdown write tab
...@@ -187,3 +187,34 @@ Feature: Project Merge Requests ...@@ -187,3 +187,34 @@ Feature: Project Merge Requests
And I visit merge request page "MR-task-open" And I visit merge request page "MR-task-open"
And I click link "Close" And I click link "Close"
Then Task checkboxes should be disabled Then Task checkboxes should be disabled
# Description preview
@javascript
Scenario: I can't preview without text
Given I visit merge request page "Bug NS-04"
And I click link "Edit" for the merge request
And I haven't written any description text
Then The Markdown preview tab should say there is nothing to do
@javascript
Scenario: I can preview with text
Given I visit merge request page "Bug NS-04"
And I click link "Edit" for the merge request
And I write a description like ":+1: Nice"
Then The Markdown preview tab should display rendered Markdown
@javascript
Scenario: I preview a merge request description
Given I visit merge request page "Bug NS-04"
And I click link "Edit" for the merge request
And I preview a description text like "Bug fixed :smile:"
Then I should see the Markdown preview
And I should not see the Markdown text field
@javascript
Scenario: I can edit after preview
Given I visit merge request page "Bug NS-04"
And I click link "Edit" for the merge request
And I preview a description text like "Bug fixed :smile:"
Then I should see the Markdown write tab
class Spinach::Features::ProjectIssues < Spinach::FeatureSteps class Spinach::Features::ProjectIssues < Spinach::FeatureSteps
include SharedAuthentication include SharedAuthentication
include SharedIssuable
include SharedProject include SharedProject
include SharedNote include SharedNote
include SharedPaths include SharedPaths
......
class Spinach::Features::ProjectMergeRequests < Spinach::FeatureSteps class Spinach::Features::ProjectMergeRequests < Spinach::FeatureSteps
include SharedAuthentication include SharedAuthentication
include SharedIssuable
include SharedProject include SharedProject
include SharedNote include SharedNote
include SharedPaths include SharedPaths
......
...@@ -32,7 +32,7 @@ module SharedDiffNote ...@@ -32,7 +32,7 @@ module SharedDiffNote
click_diff_line(sample_commit.line_code) click_diff_line(sample_commit.line_code)
within("#{diff_file_selector} form[rel$='#{sample_commit.line_code}']") do within("#{diff_file_selector} form[rel$='#{sample_commit.line_code}']") do
fill_in "note[note]", with: "Should fix it :smile:" fill_in "note[note]", with: "Should fix it :smile:"
find(".js-note-preview-button").trigger("click") find('.js-md-preview-button').click
end end
end end
...@@ -41,7 +41,7 @@ module SharedDiffNote ...@@ -41,7 +41,7 @@ module SharedDiffNote
within("#{diff_file_selector} form[rel$='#{sample_commit.del_line_code}']") do within("#{diff_file_selector} form[rel$='#{sample_commit.del_line_code}']") do
fill_in "note[note]", with: "DRY this up" fill_in "note[note]", with: "DRY this up"
find(".js-note-preview-button").trigger("click") find('.js-md-preview-button').click
end end
end end
...@@ -71,9 +71,10 @@ module SharedDiffNote ...@@ -71,9 +71,10 @@ module SharedDiffNote
end end
end end
step 'I should not see the diff comment preview button' do step 'The diff comment preview tab should say there is nothing to do' do
within(diff_file_selector) do within(diff_file_selector) do
page.should have_css(".js-note-preview-button", visible: false) find('.js-md-preview-button').click
expect(find('.js-md-preview')).to have_content('Nothing to preview.')
end end
end end
...@@ -131,27 +132,28 @@ module SharedDiffNote ...@@ -131,27 +132,28 @@ module SharedDiffNote
step 'I should see the diff comment preview' do step 'I should see the diff comment preview' do
within("#{diff_file_selector} form") do within("#{diff_file_selector} form") do
page.should have_css(".js-note-preview", visible: false) expect(page).to have_css('.js-md-preview', visible: true)
end end
end end
step 'I should see the diff comment edit button' do step 'I should see the diff comment write tab' do
within(diff_file_selector) do within(diff_file_selector) do
page.should have_css(".js-note-write-button", visible: true) expect(page).to have_css('.js-md-write-button', visible: true)
end end
end end
step 'I should see the diff comment preview button' do step 'The diff comment preview tab should display rendered Markdown' do
within(diff_file_selector) do within(diff_file_selector) do
page.should have_css(".js-note-preview-button", visible: true) find('.js-md-preview-button').click
expect(find('.js-md-preview')).to have_css('img.emoji', visible: true)
end end
end end
step 'I should see two separate previews' do step 'I should see two separate previews' do
within(diff_file_selector) do within(diff_file_selector) do
page.should have_css(".js-note-preview", visible: true, count: 2) expect(page).to have_css('.js-md-preview', visible: true, count: 2)
page.should have_content("Should fix it") expect(page).to have_content('Should fix it')
page.should have_content("DRY this up") expect(page).to have_content('DRY this up')
end end
end end
......
module SharedIssuable
include Spinach::DSL
def edit_issuable
find('.issue-btn-group').click_link 'Edit'
end
step 'I click link "Edit" for the merge request' do
edit_issuable
end
step 'I click link "Edit" for the issue' do
edit_issuable
end
end
...@@ -54,4 +54,49 @@ EOT ...@@ -54,4 +54,49 @@ EOT
'div.description li.task-list-item input[type="checkbox"]:disabled' 'div.description li.task-list-item input[type="checkbox"]:disabled'
) )
end end
step 'I should not see the Markdown preview' do
expect(find('.gfm-form .js-md-preview')).not_to be_visible
end
step 'The Markdown preview tab should say there is nothing to do' do
within('.gfm-form') do
find('.js-md-preview-button').click
expect(find('.js-md-preview')).to have_content('Nothing to preview.')
end
end
step 'I should not see the Markdown text field' do
expect(find('.gfm-form textarea')).not_to be_visible
end
step 'I should see the Markdown write tab' do
expect(find('.gfm-form')).to have_css('.js-md-write-button', visible: true)
end
step 'I should see the Markdown preview' do
expect(find('.gfm-form')).to have_css('.js-md-preview', visible: true)
end
step 'The Markdown preview tab should display rendered Markdown' do
within('.gfm-form') do
find('.js-md-preview-button').click
expect(find('.js-md-preview')).to have_css('img.emoji', visible: true)
end
end
step 'I write a description like ":+1: Nice"' do
find('.gfm-form').fill_in 'Description', with: ':+1: Nice'
end
step 'I preview a description text like "Bug fixed :smile:"' do
within('.gfm-form') do
fill_in 'Description', with: 'Bug fixed :smile:'
find('.js-md-preview-button').click
end
end
step 'I haven\'t written any description text' do
find('.gfm-form').fill_in 'Description', with: ''
end
end end
...@@ -23,7 +23,7 @@ module SharedNote ...@@ -23,7 +23,7 @@ module SharedNote
step 'I preview a comment text like "Bug fixed :smile:"' do step 'I preview a comment text like "Bug fixed :smile:"' do
within(".js-main-target-form") do within(".js-main-target-form") do
fill_in "note[note]", with: "Bug fixed :smile:" fill_in "note[note]", with: "Bug fixed :smile:"
find(".js-note-preview-button").trigger("click") find('.js-md-preview-button').click
end end
end end
...@@ -33,9 +33,9 @@ module SharedNote ...@@ -33,9 +33,9 @@ module SharedNote
end end
end end
step 'I write a comment like "Nice"' do step 'I write a comment like ":+1: Nice"' do
within(".js-main-target-form") do within(".js-main-target-form") do
fill_in "note[note]", with: "Nice" fill_in 'note[note]', with: ':+1: Nice'
end end
end end
...@@ -51,13 +51,14 @@ module SharedNote ...@@ -51,13 +51,14 @@ module SharedNote
step 'I should not see the comment preview' do step 'I should not see the comment preview' do
within(".js-main-target-form") do within(".js-main-target-form") do
page.should have_css(".js-note-preview", visible: false) expect(find('.js-md-preview')).not_to be_visible
end end
end end
step 'I should not see the comment preview button' do step 'The comment preview tab should say there is nothing to do' do
within(".js-main-target-form") do within(".js-main-target-form") do
page.should have_css(".js-note-preview-button", visible: false) find('.js-md-preview-button').click
expect(find('.js-md-preview')).to have_content('Nothing to preview.')
end end
end end
...@@ -79,21 +80,22 @@ module SharedNote ...@@ -79,21 +80,22 @@ module SharedNote
end end
end end
step 'I should see the comment edit button' do step 'I should see the comment write tab' do
within(".js-main-target-form") do within(".js-main-target-form") do
page.should have_css(".js-note-write-button", visible: true) expect(page).to have_css('.js-md-write-button', visible: true)
end end
end end
step 'I should see the comment preview' do step 'The comment preview tab should be display rendered Markdown' do
within(".js-main-target-form") do within(".js-main-target-form") do
page.should have_css(".js-note-preview", visible: true) find('.js-md-preview-button').click
expect(find('.js-md-preview')).to have_css('img.emoji', visible: true)
end end
end end
step 'I should see the comment preview button' do step 'I should see the comment preview' do
within(".js-main-target-form") do within(".js-main-target-form") do
page.should have_css(".js-note-preview-button", visible: true) expect(page).to have_css('.js-md-preview', visible: true)
end end
end end
......
...@@ -19,5 +19,19 @@ module Gitlab ...@@ -19,5 +19,19 @@ module Gitlab
return themes[id] return themes[id]
end end
def self.type_css_class_by_id(id)
types = {
BASIC => 'light_theme',
MARS => 'dark_theme',
MODERN => 'dark_theme',
GRAY => 'dark_theme',
COLOR => 'dark_theme'
}
id ||= Gitlab.config.gitlab.default_theme
types[id]
end
end end
end end
...@@ -17,15 +17,19 @@ namespace :gitlab do ...@@ -17,15 +17,19 @@ namespace :gitlab do
# Clone if needed # Clone if needed
unless File.directory?(target_dir) unless File.directory?(target_dir)
sh(*%W(git clone #{args.repo} #{target_dir})) system(*%W(git clone -- #{args.repo} #{target_dir}))
end end
# Make sure we're on the right tag # Make sure we're on the right tag
Dir.chdir(target_dir) do Dir.chdir(target_dir) do
# First try to checkout without fetching # First try to checkout without fetching
# to avoid stalling tests if the Internet is down. # to avoid stalling tests if the Internet is down.
reset = "git reset --hard $(git describe #{args.tag} || git describe origin/#{args.tag})" reseted = reset_to_commit(args)
sh "#{reset} || git fetch origin && #{reset}"
unless reseted
system(*%W(git fetch origin))
reset_to_commit(args)
end
config = { config = {
user: user, user: user,
...@@ -54,7 +58,7 @@ namespace :gitlab do ...@@ -54,7 +58,7 @@ namespace :gitlab do
File.open("config.yml", "w+") {|f| f.puts config.to_yaml} File.open("config.yml", "w+") {|f| f.puts config.to_yaml}
# Launch installation process # Launch installation process
sh "bin/install" system(*%W(bin/install))
end end
# Required for debian packaging with PKGR: Setup .ssh/environment with # Required for debian packaging with PKGR: Setup .ssh/environment with
...@@ -118,5 +122,16 @@ namespace :gitlab do ...@@ -118,5 +122,16 @@ namespace :gitlab do
puts "Quitting...".red puts "Quitting...".red
exit 1 exit 1
end end
def reset_to_commit(args)
tag, status = Gitlab::Popen.popen(%W(git describe -- #{args.tag}))
unless status.zero?
tag, status = Gitlab::Popen.popen(%W(git describe -- origin/#{args.tag}))
end
tag = tag.strip
system(*%W(git reset --hard #{tag}))
end
end end
...@@ -5,10 +5,14 @@ FactoryGirl.define do ...@@ -5,10 +5,14 @@ FactoryGirl.define do
Faker::Lorem.sentence Faker::Lorem.sentence
end end
sequence :name, aliases: [:file_name] do sequence :name do
Faker::Name.name Faker::Name.name
end end
sequence :file_name do
Faker::Internet.user_name
end
sequence(:url) { Faker::Internet.uri('http') } sequence(:url) { Faker::Internet.uri('http') }
factory :user, aliases: [:author, :assignee, :owner, :creator] do factory :user, aliases: [:author, :assignee, :owner, :creator] do
...@@ -18,7 +22,7 @@ FactoryGirl.define do ...@@ -18,7 +22,7 @@ FactoryGirl.define do
password "12345678" password "12345678"
password_confirmation { password } password_confirmation { password }
confirmed_at { Time.now } confirmed_at { Time.now }
confirmation_token { nil } confirmation_token { nil }
trait :admin do trait :admin do
admin true admin true
......
...@@ -19,8 +19,9 @@ describe 'Comments' do ...@@ -19,8 +19,9 @@ describe 'Comments' do
it 'should be valid' do it 'should be valid' do
should have_css(".js-main-target-form", visible: true, count: 1) should have_css(".js-main-target-form", visible: true, count: 1)
find(".js-main-target-form input[type=submit]").value.should == "Add Comment" find(".js-main-target-form input[type=submit]").value.should == "Add Comment"
within(".js-main-target-form") { should_not have_link("Cancel") } within('.js-main-target-form') do
within(".js-main-target-form") { should have_css(".js-note-preview-button", visible: false) } expect(page).not_to have_link('Cancel')
end
end end
describe "with text" do describe "with text" do
...@@ -31,8 +32,10 @@ describe 'Comments' do ...@@ -31,8 +32,10 @@ describe 'Comments' do
end end
it 'should have enable submit button and preview button' do it 'should have enable submit button and preview button' do
within(".js-main-target-form") { should_not have_css(".js-comment-button[disabled]") } within('.js-main-target-form') do
within(".js-main-target-form") { should have_css(".js-note-preview-button", visible: true) } expect(page).not_to have_css('.js-comment-button[disabled]')
expect(page).to have_css('.js-md-preview-button', visible: true)
end
end end
end end
end end
...@@ -41,15 +44,17 @@ describe 'Comments' do ...@@ -41,15 +44,17 @@ describe 'Comments' do
before do before do
within(".js-main-target-form") do within(".js-main-target-form") do
fill_in "note[note]", with: "This is awsome!" fill_in "note[note]", with: "This is awsome!"
find(".js-note-preview-button").trigger("click") find('.js-md-preview-button').click
click_button "Add Comment" click_button "Add Comment"
end end
end end
it 'should be added and form reset' do it 'should be added and form reset' do
should have_content("This is awsome!") should have_content("This is awsome!")
within(".js-main-target-form") { should have_no_field("note[note]", with: "This is awesome!") } within('.js-main-target-form') do
within(".js-main-target-form") { should have_css(".js-note-preview", visible: false) } expect(page).to have_no_field('note[note]', with: 'This is awesome!')
expect(page).to have_css('.js-md-preview', visible: :hidden)
end
within(".js-main-target-form") { should have_css(".js-note-text", visible: true) } within(".js-main-target-form") { should have_css(".js-note-text", visible: true) }
end end
end end
...@@ -172,11 +177,11 @@ describe 'Comments' do ...@@ -172,11 +177,11 @@ describe 'Comments' do
# add two separate texts and trigger previews on both # add two separate texts and trigger previews on both
within("tr[id='#{line_code}'] + .js-temp-notes-holder") do within("tr[id='#{line_code}'] + .js-temp-notes-holder") do
fill_in "note[note]", with: "One comment on line 7" fill_in "note[note]", with: "One comment on line 7"
find(".js-note-preview-button").trigger("click") find('.js-md-preview-button').click
end end
within("tr[id='#{line_code_2}'] + .js-temp-notes-holder") do within("tr[id='#{line_code_2}'] + .js-temp-notes-holder") do
fill_in "note[note]", with: "Another comment on line 10" fill_in "note[note]", with: "Another comment on line 10"
find(".js-note-preview-button").trigger("click") find('.js-md-preview-button').click
end end
end end
end end
......
...@@ -53,13 +53,14 @@ shared_examples "RESTful project resources" do ...@@ -53,13 +53,14 @@ shared_examples "RESTful project resources" do
end end
end end
# projects POST /projects(.:format) projects#create # projects POST /projects(.:format) projects#create
# new_project GET /projects/new(.:format) projects#new # new_project GET /projects/new(.:format) projects#new
# files_project GET /:id/files(.:format) projects#files # files_project GET /:id/files(.:format) projects#files
# edit_project GET /:id/edit(.:format) projects#edit # edit_project GET /:id/edit(.:format) projects#edit
# project GET /:id(.:format) projects#show # project GET /:id(.:format) projects#show
# PUT /:id(.:format) projects#update # PUT /:id(.:format) projects#update
# DELETE /:id(.:format) projects#destroy # DELETE /:id(.:format) projects#destroy
# markdown_preview_project GET /:id/markdown_preview(.:format) projects#markdown_preview
describe ProjectsController, "routing" do describe ProjectsController, "routing" do
it "to #create" do it "to #create" do
post("/projects").should route_to('projects#create') post("/projects").should route_to('projects#create')
...@@ -88,6 +89,12 @@ describe ProjectsController, "routing" do ...@@ -88,6 +89,12 @@ describe ProjectsController, "routing" do
it "to #destroy" do it "to #destroy" do
delete("/gitlab/gitlabhq").should route_to('projects#destroy', id: 'gitlab/gitlabhq') delete("/gitlab/gitlabhq").should route_to('projects#destroy', id: 'gitlab/gitlabhq')
end end
it 'to #markdown_preview' do
get('/gitlab/gitlabhq/markdown_preview').should(
route_to('projects#markdown_preview', id: 'gitlab/gitlabhq')
)
end
end end
# pages_project_wikis GET /:project_id/wikis/pages(.:format) projects/wikis#pages # pages_project_wikis GET /:project_id/wikis/pages(.:format) projects/wikis#pages
...@@ -387,15 +394,10 @@ describe Projects::IssuesController, "routing" do ...@@ -387,15 +394,10 @@ describe Projects::IssuesController, "routing" do
end end
end end
# preview_project_notes POST /:project_id/notes/preview(.:format) notes#preview
# project_notes GET /:project_id/notes(.:format) notes#index # project_notes GET /:project_id/notes(.:format) notes#index
# POST /:project_id/notes(.:format) notes#create # POST /:project_id/notes(.:format) notes#create
# project_note DELETE /:project_id/notes/:id(.:format) notes#destroy # project_note DELETE /:project_id/notes/:id(.:format) notes#destroy
describe Projects::NotesController, "routing" do describe Projects::NotesController, "routing" do
it "to #preview" do
post("/gitlab/gitlabhq/notes/preview").should route_to('projects/notes#preview', project_id: 'gitlab/gitlabhq')
end
it_behaves_like "RESTful project resources" do it_behaves_like "RESTful project resources" do
let(:actions) { [:index, :create, :destroy] } let(:actions) { [:index, :create, :destroy] }
let(:controller) { 'notes' } let(:controller) { 'notes' }
...@@ -415,6 +417,7 @@ describe Projects::BlobController, "routing" do ...@@ -415,6 +417,7 @@ describe Projects::BlobController, "routing" do
it "to #show" do it "to #show" do
get("/gitlab/gitlabhq/blob/master/app/models/project.rb").should route_to('projects/blob#show', project_id: 'gitlab/gitlabhq', id: 'master/app/models/project.rb') get("/gitlab/gitlabhq/blob/master/app/models/project.rb").should route_to('projects/blob#show', project_id: 'gitlab/gitlabhq', id: 'master/app/models/project.rb')
get("/gitlab/gitlabhq/blob/master/app/models/compare.rb").should route_to('projects/blob#show', project_id: 'gitlab/gitlabhq', id: 'master/app/models/compare.rb') get("/gitlab/gitlabhq/blob/master/app/models/compare.rb").should route_to('projects/blob#show', project_id: 'gitlab/gitlabhq', id: 'master/app/models/compare.rb')
get("/gitlab/gitlabhq/blob/master/app/models/diff.js").should route_to('projects/blob#show', project_id: 'gitlab/gitlabhq', id: 'master/app/models/diff.js')
get("/gitlab/gitlabhq/blob/master/files.scss").should route_to('projects/blob#show', project_id: 'gitlab/gitlabhq', id: 'master/files.scss') get("/gitlab/gitlabhq/blob/master/files.scss").should route_to('projects/blob#show', project_id: 'gitlab/gitlabhq', id: 'master/files.scss')
end end
end end
...@@ -427,6 +430,26 @@ describe Projects::TreeController, "routing" do ...@@ -427,6 +430,26 @@ describe Projects::TreeController, "routing" do
end end
end end
describe Projects::EditTreeController, 'routing' do
it 'to #show' do
get('/gitlab/gitlabhq/edit/master/app/models/project.rb').should(
route_to('projects/edit_tree#show',
project_id: 'gitlab/gitlabhq',
id: 'master/app/models/project.rb'))
get('/gitlab/gitlabhq/edit/master/app/models/project.rb/preview').should(
route_to('projects/edit_tree#show',
project_id: 'gitlab/gitlabhq',
id: 'master/app/models/project.rb/preview'))
end
it 'to #preview' do
post('/gitlab/gitlabhq/edit/master/app/models/project.rb/preview').should(
route_to('projects/edit_tree#preview',
project_id: 'gitlab/gitlabhq',
id: 'master/app/models/project.rb'))
end
end
# project_compare_index GET /:project_id/compare(.:format) compare#index {id: /[^\/]+/, project_id: /[^\/]+/} # project_compare_index GET /:project_id/compare(.:format) compare#index {id: /[^\/]+/, project_id: /[^\/]+/}
# POST /:project_id/compare(.:format) compare#create {id: /[^\/]+/, project_id: /[^\/]+/} # POST /:project_id/compare(.:format) compare#create {id: /[^\/]+/, project_id: /[^\/]+/}
# project_compare /:project_id/compare/:from...:to(.:format) compare#show {from: /.+/, to: /.+/, id: /[^\/]+/, project_id: /[^\/]+/} # project_compare /:project_id/compare/:from...:to(.:format) compare#show {from: /.+/, to: /.+/, id: /[^\/]+/, project_id: /[^\/]+/}
......
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