diff --git a/.travis.yml b/.travis.yml index c137aec907c..f56311bb5a2 100644 --- a/.travis.yml +++ b/.travis.yml @@ -9,7 +9,6 @@ env: - TASK=jasmine:ci before_install: - sudo apt-get install libicu-dev -y - - gem install charlock_holmes -v="0.6.9" branches: only: - 'master' diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index d1fdd93850a..293688331cd 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -9,6 +9,10 @@ This guide details how to use issues and pull requests to improve GitLab. If you want to know how the GitLab team handles contributions have a look at [the GitLab contributing process](PROCESS.md). +## Contributor license agreement + +By submitting code as an individual you agree to the [individual contributor license agreement](doc/legal/individual_contributor_license_agreement.md). By submitting code as an entity you agree to the [corporate contributor license agreement](doc/legal/corporate_contributor_license_agreement.md). + ## Closing policy for issues and pull requests GitLab is a popular open source project and the capacity to deal with issues and pull requests is limited. Out of respect for our volunteers, issues and pull requests not in line with the guidelines listed in this document may be closed without notice. diff --git a/README.md b/README.md index 64e40fdc51a..5cc3081dcb9 100644 --- a/README.md +++ b/README.md @@ -64,9 +64,10 @@ If you want to contribute, please first read our [Contributing Guidelines](https * [Installation guides](https://github.com/gitlabhq/gitlab-public-wiki/wiki/Unofficial-Installation-Guides) public wiki with unofficial guides to install GitLab on different operating systems. -* [BitNami one-click installers](http://bitnami.com/stack/gitlab) -* [TurnKey Linux virtual appliance](http://www.turnkeylinux.org/gitlab) +* [Digital Ocean 1-Click Application Install](https://www.digitalocean.com/) Have a new server up in 55 seconds. Digital Ocean uses SSD disks which is great for an IO intensive app as GitLab. Look for GitLab under 'Select Image' => 'Applications' when creating a droplet. + +* [BitNami one-click installers](http://bitnami.com/stack/gitlab) Get an image with GitLab and GitLab CI preinstalled for Amazon Web Services, Azure, VMware or your local server. ### New versions and upgrading diff --git a/app/assets/javascripts/notes.js b/app/assets/javascripts/notes.js index 5225623c1f0..defbf81f580 100644 --- a/app/assets/javascripts/notes.js +++ b/app/assets/javascripts/notes.js @@ -233,10 +233,12 @@ var NoteList = { form.show(); var textarea = form.find("textarea"); - var p = $("

").text(textarea.val()); - var hidden_div = $('
').append(p); - form.append(hidden_div); - hidden_div.hide(); + if (form.find(".note-original-content").length === 0) { + var p = $("

").text(textarea.val()); + var hidden_div = $('
').append(p); + form.append(hidden_div); + hidden_div.hide(); + } textarea.focus(); }, @@ -532,6 +534,8 @@ var NoteList = { note_text.html(response.note).show(); var note_form = note_li.find(".note-edit-form"); + var original_content = note_form.find(".note-original-content"); + original_content.remove(); note_form.hide(); note_form.find(".btn-save").enableButton(); diff --git a/app/assets/javascripts/project.js.coffee b/app/assets/javascripts/project.js.coffee index bdb18574b6d..b12f045e375 100644 --- a/app/assets/javascripts/project.js.coffee +++ b/app/assets/javascripts/project.js.coffee @@ -40,3 +40,8 @@ $ -> # Ref switcher $('.project-refs-select').on 'change', -> $(@).parents('form').submit() + + $('.hide-no-ssh-message').on 'click', (e) -> + $.cookie('hide_no_ssh_message', 'false') + $(@).parents('.no-ssh-key-message').hide() + e.preventDefault() diff --git a/app/assets/stylesheets/common.scss b/app/assets/stylesheets/common.scss index dbd50b4dcc8..8cb8e1b3276 100644 --- a/app/assets/stylesheets/common.scss +++ b/app/assets/stylesheets/common.scss @@ -220,7 +220,6 @@ li.note { .error-message { padding: 10px; background: #C67; - padding-left: 20px; margin: 0; color: #FFF; @@ -228,8 +227,18 @@ li.note { color: #fff; text-decoration: underline; } - &.centered { - text-align: center; +} + +.no-ssh-key-message { + padding: 10px 0; + background: #C67; + margin: 0; + color: #FFF; + text-align: center; + + a { + color: #fff; + text-decoration: underline; } } diff --git a/app/contexts/files/create_context.rb b/app/contexts/files/create_context.rb index e1554c47bd6..ae73b11bd54 100644 --- a/app/contexts/files/create_context.rb +++ b/app/contexts/files/create_context.rb @@ -33,11 +33,10 @@ module Files return error("Your changes could not be commited, because file with such name exists") end - new_file_action = Gitlab::Satellite::NewFileAction.new(current_user, project, ref, path) + new_file_action = Gitlab::Satellite::NewFileAction.new(current_user, project, ref, file_path) created_successfully = new_file_action.commit!( params[:content], - params[:commit_message], - file_name, + params[:commit_message] ) if created_successfully diff --git a/app/contexts/files/update_context.rb b/app/contexts/files/update_context.rb index 000d3d02f12..f40c7496994 100644 --- a/app/contexts/files/update_context.rb +++ b/app/contexts/files/update_context.rb @@ -24,8 +24,7 @@ module Files new_file_action = Gitlab::Satellite::EditFileAction.new(current_user, project, ref, path) created_successfully = new_file_action.commit!( params[:content], - params[:commit_message], - params[:last_commit] + params[:commit_message] ) if created_successfully diff --git a/app/mailers/emails/groups.rb b/app/mailers/emails/groups.rb index 2e9d28981e3..1c8ae122c46 100644 --- a/app/mailers/emails/groups.rb +++ b/app/mailers/emails/groups.rb @@ -5,7 +5,7 @@ module Emails @group = @membership.group mail(to: @membership.user.email, - subject: subject("access to group was granted")) + subject: subject("Access to group was granted")) end end end diff --git a/app/mailers/emails/issues.rb b/app/mailers/emails/issues.rb index 6eda88c7921..5abdf99529c 100644 --- a/app/mailers/emails/issues.rb +++ b/app/mailers/emails/issues.rb @@ -3,14 +3,14 @@ module Emails def new_issue_email(recipient_id, issue_id) @issue = Issue.find(issue_id) @project = @issue.project - mail(to: recipient(recipient_id), subject: subject("new issue ##{@issue.iid}", @issue.title)) + mail(to: recipient(recipient_id), subject: subject("New issue ##{@issue.iid}", @issue.title)) end def reassigned_issue_email(recipient_id, issue_id, previous_assignee_id) @issue = Issue.find(issue_id) @previous_assignee = User.find_by_id(previous_assignee_id) if previous_assignee_id @project = @issue.project - mail(to: recipient(recipient_id), subject: subject("changed issue ##{@issue.iid}", @issue.title)) + mail(to: recipient(recipient_id), subject: subject("Changed issue ##{@issue.iid}", @issue.title)) end def closed_issue_email(recipient_id, issue_id, updated_by_user_id) @@ -27,7 +27,7 @@ module Emails @project = @issue.project @updated_by = User.find updated_by_user_id mail(to: recipient(recipient_id), - subject: subject("changed issue ##{@issue.iid}", @issue.title)) + subject: subject("Changed issue ##{@issue.iid}", @issue.title)) end end end diff --git a/app/mailers/emails/merge_requests.rb b/app/mailers/emails/merge_requests.rb index 57c1925fa47..67544f2a331 100644 --- a/app/mailers/emails/merge_requests.rb +++ b/app/mailers/emails/merge_requests.rb @@ -2,24 +2,24 @@ module Emails module MergeRequests def new_merge_request_email(recipient_id, merge_request_id) @merge_request = MergeRequest.find(merge_request_id) - mail(to: recipient(recipient_id), subject: subject("new merge request !#{@merge_request.iid}", @merge_request.title)) + mail(to: recipient(recipient_id), subject: subject("New merge request ##{@merge_request.iid}", @merge_request.title)) end def reassigned_merge_request_email(recipient_id, merge_request_id, previous_assignee_id) @merge_request = MergeRequest.find(merge_request_id) @previous_assignee = User.find_by_id(previous_assignee_id) if previous_assignee_id - mail(to: recipient(recipient_id), subject: subject("changed merge request !#{@merge_request.iid}", @merge_request.title)) + mail(to: recipient(recipient_id), subject: subject("Changed merge request ##{@merge_request.iid}", @merge_request.title)) end def closed_merge_request_email(recipient_id, merge_request_id, updated_by_user_id) @merge_request = MergeRequest.find(merge_request_id) @updated_by = User.find updated_by_user_id - mail(to: recipient(recipient_id), subject: subject("Closed merge request !#{@merge_request.iid}", @merge_request.title)) + mail(to: recipient(recipient_id), subject: subject("Closed merge request ##{@merge_request.iid}", @merge_request.title)) end def merged_merge_request_email(recipient_id, merge_request_id) @merge_request = MergeRequest.find(merge_request_id) - mail(to: recipient(recipient_id), subject: subject("Accepted merge request !#{@merge_request.iid}", @merge_request.title)) + mail(to: recipient(recipient_id), subject: subject("Accepted merge request ##{@merge_request.iid}", @merge_request.title)) end end diff --git a/app/mailers/emails/notes.rb b/app/mailers/emails/notes.rb index ba4f0dd862c..e967cf6dc73 100644 --- a/app/mailers/emails/notes.rb +++ b/app/mailers/emails/notes.rb @@ -4,27 +4,27 @@ module Emails @note = Note.find(note_id) @commit = @note.noteable @project = @note.project - mail(to: recipient(recipient_id), subject: subject("note for commit #{@commit.short_id}", @commit.title)) + mail(to: recipient(recipient_id), subject: subject("Note for commit #{@commit.short_id}", @commit.title)) end def note_issue_email(recipient_id, note_id) @note = Note.find(note_id) @issue = @note.noteable @project = @note.project - mail(to: recipient(recipient_id), subject: subject("note for issue ##{@issue.iid}")) + mail(to: recipient(recipient_id), subject: subject("Note for issue ##{@issue.iid}")) end def note_merge_request_email(recipient_id, note_id) @note = Note.find(note_id) @merge_request = @note.noteable @project = @note.project - mail(to: recipient(recipient_id), subject: subject("note for merge request ##{@merge_request.iid}")) + mail(to: recipient(recipient_id), subject: subject("Note for merge request ##{@merge_request.iid}")) end def note_wall_email(recipient_id, note_id) @note = Note.find(note_id) @project = @note.project - mail(to: recipient(recipient_id), subject: subject("note on wall")) + mail(to: recipient(recipient_id), subject: subject("Note on wall")) end end end diff --git a/app/mailers/emails/projects.rb b/app/mailers/emails/projects.rb index 4d5fe9ef614..0e40450bfee 100644 --- a/app/mailers/emails/projects.rb +++ b/app/mailers/emails/projects.rb @@ -4,14 +4,14 @@ module Emails @users_project = UsersProject.find user_project_id @project = @users_project.project mail(to: @users_project.user.email, - subject: subject("access to project was granted")) + subject: subject("Access to project was granted")) end def project_was_moved_email(project_id, user_id) @user = User.find user_id @project = Project.find project_id mail(to: @user.email, - subject: subject("project was moved")) + subject: subject("Project was moved")) end end end diff --git a/app/models/issue.rb b/app/models/issue.rb index f3ec322126f..d350b237d37 100644 --- a/app/models/issue.rb +++ b/app/models/issue.rb @@ -21,6 +21,8 @@ class Issue < ActiveRecord::Base include Issuable include InternalId + ActsAsTaggableOn.strict_case_match = true + belongs_to :project validates :project, presence: true diff --git a/app/models/project.rb b/app/models/project.rb index 0b32c90f09b..73aa237013e 100644 --- a/app/models/project.rb +++ b/app/models/project.rb @@ -27,6 +27,8 @@ class Project < ActiveRecord::Base include Gitlab::ShellAdapter extend Enumerize + + ActsAsTaggableOn.strict_case_match = true attr_accessible :name, :path, :description, :issues_tracker, :label_list, :issues_enabled, :wall_enabled, :merge_requests_enabled, :snippets_enabled, :issues_tracker_id, diff --git a/app/views/notify/_note_message.html.haml b/app/views/notify/_note_message.html.haml index 88c4df55b7f..9e329af2d47 100644 --- a/app/views/notify/_note_message.html.haml +++ b/app/views/notify/_note_message.html.haml @@ -1,6 +1,6 @@ %p %strong #{@note.author_name} - left next message: + wrote: %cite{style: 'color: #666'} = markdown(@note.note) diff --git a/app/views/notify/new_merge_request_email.html.haml b/app/views/notify/new_merge_request_email.html.haml index 6b2782ebb0b..321f9418ded 100644 --- a/app/views/notify/new_merge_request_email.html.haml +++ b/app/views/notify/new_merge_request_email.html.haml @@ -1,5 +1,5 @@ %p - = "New Merge Request !#{@merge_request.iid}" + = "New Merge Request ##{@merge_request.iid}" %p = link_to_gfm truncate(@merge_request.title, length: 40), project_merge_request_url(@merge_request.target_project, @merge_request) %p diff --git a/app/views/notify/new_merge_request_email.text.erb b/app/views/notify/new_merge_request_email.text.erb index 2d27350486e..16be4bb619f 100644 --- a/app/views/notify/new_merge_request_email.text.erb +++ b/app/views/notify/new_merge_request_email.text.erb @@ -1,4 +1,4 @@ -New Merge Request <%= @merge_request.iid %> +New Merge Request #<%= @merge_request.iid %> <%= url_for(project_merge_request_url(@merge_request.target_project, @merge_request)) %> diff --git a/app/views/notify/reassigned_merge_request_email.html.haml b/app/views/notify/reassigned_merge_request_email.html.haml index 3a615f86e69..d2d82d36c48 100644 --- a/app/views/notify/reassigned_merge_request_email.html.haml +++ b/app/views/notify/reassigned_merge_request_email.html.haml @@ -1,5 +1,5 @@ %p - = "Reassigned Merge Request !#{@merge_request.iid}" + = "Reassigned Merge Request ##{@merge_request.iid}" = link_to_gfm truncate(@merge_request.title, length: 30), project_merge_request_url(@merge_request.target_project, @merge_request) %p Assignee changed diff --git a/app/views/notify/reassigned_merge_request_email.text.erb b/app/views/notify/reassigned_merge_request_email.text.erb index eecf055ff6f..87a7847e06d 100644 --- a/app/views/notify/reassigned_merge_request_email.text.erb +++ b/app/views/notify/reassigned_merge_request_email.text.erb @@ -1,4 +1,4 @@ -Reassigned Merge Request <%= @merge_request.iid %> +Reassigned Merge Request #<%= @merge_request.iid %> <%= url_for(project_merge_request_url(@merge_request.target_project, @merge_request)) %> diff --git a/app/views/shared/_no_ssh.html.haml b/app/views/shared/_no_ssh.html.haml index 6d363807d62..2a365ce4f63 100644 --- a/app/views/shared/_no_ssh.html.haml +++ b/app/views/shared/_no_ssh.html.haml @@ -1,3 +1,6 @@ -- if current_user.require_ssh_key? && alert.blank? && notice.blank? - %p.error-message.centered - You won't be able to pull or push project code via SSH until you #{link_to 'add an SSH key', new_profile_key_path} to your profile +- if cookies[:hide_no_ssh_message].blank? && current_user.require_ssh_key? + .no-ssh-key-message + .container + You won't be able to pull or push project code via SSH until you #{link_to 'add an SSH key', new_profile_key_path} to your profile + = link_to '#', class: 'pull-right hide-no-ssh-message' do + %i.icon-remove diff --git a/config/application.rb b/config/application.rb index d85bcab7885..82e74e7250d 100644 --- a/config/application.rb +++ b/config/application.rb @@ -78,7 +78,6 @@ module Gitlab # # config.relative_url_root = "/gitlab" - # Uncomment to enable rack attack middleware - # config.middleware.use Rack::Attack + config.middleware.use Rack::Attack end end diff --git a/config/gitlab.yml.example b/config/gitlab.yml.example index 163af226aaa..7ed8493a8d5 100644 --- a/config/gitlab.yml.example +++ b/config/gitlab.yml.example @@ -59,7 +59,7 @@ production: &base # If a commit message matches this regular expression, all issues referenced from the matched text will be closed. # This happends when the commit is pushed or merged into the default branch of a project. # When not specified the default issue_closing_pattern as specified below will be used. - # issue_closing_pattern: ([Cc]loses|[Ff]ixes) +#\d+ + # issue_closing_pattern: ([Cc]lose[sd]|[Ff]ixe[sd]) +#\d+ ## Default project features settings default_projects_features: diff --git a/config/initializers/rack_attack.rb.example b/config/initializers/rack_attack.rb.example index 76fa7ad282e..c6d3605dc5a 100644 --- a/config/initializers/rack_attack.rb.example +++ b/config/initializers/rack_attack.rb.example @@ -1,9 +1,5 @@ -# To enable rack-attack for your GitLab instance do the following: -# 1. In config/application.rb find and uncomment the following line: -# config.middleware.use Rack::Attack -# 2. Rename this file to rack_attack.rb -# 3. Review the paths_to_be_protected and add any other path you need protecting -# 4. Restart GitLab instance +# 1. Rename this file to rack_attack.rb +# 2. Review the paths_to_be_protected and add any other path you need protecting # paths_to_be_protected = [ diff --git a/doc/api/repositories.md b/doc/api/repositories.md index 2769c22d6aa..9ec6ba74125 100644 --- a/doc/api/repositories.md +++ b/doc/api/repositories.md @@ -368,4 +368,32 @@ GET /projects/:id/repository/archive Parameters: + `id` (required) - The ID of a project -+ `sha` (optional) - The commit sha to download defaults to the tip of the default branch \ No newline at end of file ++ `sha` (optional) - The commit sha to download defaults to the tip of the default branch + + +## Create new file in repository + +``` +POST /projects/:id/repository/files +``` + +Parameters: + ++ `file_name` (required) - The name of new file. Ex. class.rb ++ `file_path` (optional) - The path to new file. Ex. lib/ ++ `branch_name` (required) - The name of branch ++ `content` (required) - File content ++ `commit_message` (required) - Commit message + +## Update existing file in repository + +``` +PUT /projects/:id/repository/files +``` + +Parameters: + ++ `file_path` (required) - Full path to file. Ex. lib/class.rb ++ `branch_name` (required) - The name of branch ++ `content` (required) - New file content ++ `commit_message` (required) - Commit message diff --git a/doc/install/installation.md b/doc/install/installation.md index c573727f608..fe59033513a 100644 --- a/doc/install/installation.md +++ b/doc/install/installation.md @@ -227,10 +227,6 @@ You can change `6-2-stable` to `master` if you want the *bleeding edge* version, # Copy the example Rack attack config sudo -u git -H cp config/initializers/rack_attack.rb.example config/initializers/rack_attack.rb - # Enable rack attack middleware - # Find and uncomment the line 'config.middleware.use Rack::Attack' - sudo -u git -H editor config/application.rb - # Configure Git global settings for git user, useful when editing via web # Edit user.email according to what is set in gitlab.yml sudo -u git -H git config --global user.name "GitLab" @@ -265,8 +261,6 @@ Make sure to edit both `gitlab.yml` and `unicorn.rb` to match your setup. cd /home/git/gitlab - sudo gem install charlock_holmes --version '0.6.9.4' - # For MySQL (note, the option says "without ... postgres") sudo -u git -H bundle install --deployment --without development test postgres aws diff --git a/doc/legal/corporate_contributor_license_agreement.md b/doc/legal/corporate_contributor_license_agreement.md new file mode 100644 index 00000000000..bbc274f3b0c --- /dev/null +++ b/doc/legal/corporate_contributor_license_agreement.md @@ -0,0 +1,25 @@ +You accept and agree to the following terms and conditions for Your present and future Contributions submitted to GitLab.com. Except for the license granted herein to GitLab.com and recipients of software distributed by GitLab.com, You reserve all right, title, and interest in and to Your Contributions. + +1. Definitions. + + "You" (or "Your") shall mean the copyright owner or legal entity authorized by the copyright owner that is making this Agreement with GitLab.com. For legal entities, the entity making a Contribution and all other entities that control, are controlled by, or are under common control with that entity are considered to be a single Contributor. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. + + "Contribution" shall mean the code, documentation or other original works of authorship expressly identified in Schedule B, as well as any original work of authorship, including any modifications or additions to an existing work, that is intentionally submitted by You to GitLab.com for inclusion in, or documentation of, any of the products owned or managed by GitLab.com (the "Work"). For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to GitLab.com or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, GitLab.com for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by You as "Not a Contribution." + +2. Grant of Copyright License. Subject to the terms and conditions of this Agreement, You hereby grant to GitLab.com and to recipients of software distributed by GitLab.com a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare derivative works of, publicly display, publicly perform, sublicense, and distribute Your Contributions and such derivative works. + +3. Grant of Patent License. Subject to the terms and conditions of this Agreement, You hereby grant to GitLab.com and to recipients of software distributed by GitLab.com a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by You that are necessarily infringed by Your Contribution(s) alone or by combination of Your Contribution(s) with the Work to which such Contribution(s) was submitted. If any entity institutes patent litigation against You or any other entity (including a cross-claim or counterclaim in a lawsuit) alleging that your Contribution, or the Work to which you have contributed, constitutes direct or contributory patent infringement, then any patent licenses granted to that entity under this Agreement for that Contribution or Work shall terminate as of the date such litigation is filed. + +4. You represent that You are legally entitled to grant the above license. You represent further that each employee of the Corporation designated on Schedule A below (or in a subsequent written modification to that Schedule) is authorized to submit Contributions on behalf of the Corporation. + +5. You represent that each of Your Contributions is Your original creation (see section 7 for submissions on behalf of others). + +6. You are not expected to provide support for Your Contributions, except to the extent You desire to provide support. You may provide support for free, for a fee, or not at all. Unless required by applicable law or agreed to in writing, You provide Your Contributions on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. + +7. Should You wish to submit work that is not Your original creation, You may submit it to GitLab.com separately from any Contribution, identifying the complete details of its source and of any license or other restriction (including, but not limited to, related patents, trademarks, and license agreements) of which you are personally aware, and conspicuously marking the work as "Submitted on behalf of a third-party: [named here]". + +8. It is your responsibility to notify GitLab.com when any change is required to the list of designated employees authorized to submit Contributions on behalf of the Corporation, or to the Corporation's Point of Contact with GitLab.com. + +--------------------------------------- + +This text is licensed under the [Creative Commons Attribution 3.0 License](http://creativecommons.org/licenses/by/3.0/) and the original source is the Google Open Source Programs Office. diff --git a/doc/legal/individual_contributor_license_agreement.md b/doc/legal/individual_contributor_license_agreement.md new file mode 100644 index 00000000000..eaf5812ca4c --- /dev/null +++ b/doc/legal/individual_contributor_license_agreement.md @@ -0,0 +1,25 @@ +You accept and agree to the following terms and conditions for Your present and future Contributions submitted to GitLab.com. Except for the license granted herein to GitLab.com and recipients of software distributed by GitLab.com, You reserve all right, title, and interest in and to Your Contributions. + +1. Definitions. + + "You" (or "Your") shall mean the copyright owner or legal entity authorized by the copyright owner that is making this Agreement with GitLab.com. For legal entities, the entity making a Contribution and all other entities that control, are controlled by, or are under common control with that entity are considered to be a single Contributor. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. + + "Contribution" shall mean any original work of authorship, including any modifications or additions to an existing work, that is intentionally submitted by You to GitLab.com for inclusion in, or documentation of, any of the products owned or managed by GitLab.com (the "Work"). For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to GitLab.com or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, GitLab.com for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by You as "Not a Contribution." + +2. Grant of Copyright License. Subject to the terms and conditions of this Agreement, You hereby grant to GitLab.com and to recipients of software distributed by GitLab.com a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare derivative works of, publicly display, publicly perform, sublicense, and distribute Your Contributions and such derivative works. + +3. Grant of Patent License. Subject to the terms and conditions of this Agreement, You hereby grant to GitLab.com and to recipients of software distributed by GitLab.com a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by You that are necessarily infringed by Your Contribution(s) alone or by combination of Your Contribution(s) with the Work to which such Contribution(s) was submitted. If any entity institutes patent litigation against You or any other entity (including a cross-claim or counterclaim in a lawsuit) alleging that your Contribution, or the Work to which you have contributed, constitutes direct or contributory patent infringement, then any patent licenses granted to that entity under this Agreement for that Contribution or Work shall terminate as of the date such litigation is filed. + +4. You represent that you are legally entitled to grant the above license. If your employer(s) has rights to intellectual property that you create that includes your Contributions, you represent that you have received permission to make Contributions on behalf of that employer, that your employer has waived such rights for your Contributions to GitLab.com, or that your employer has executed a separate Corporate CLA with GitLab.com. + +5. You represent that each of Your Contributions is Your original creation (see section 7 for submissions on behalf of others). You represent that Your Contribution submissions include complete details of any third-party license or other restriction (including, but not limited to, related patents and trademarks) of which you are personally aware and which are associated with any part of Your Contributions. + +6. You are not expected to provide support for Your Contributions, except to the extent You desire to provide support. You may provide support for free, for a fee, or not at all. Unless required by applicable law or agreed to in writing, You provide Your Contributions on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON- INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. + +7. Should You wish to submit work that is not Your original creation, You may submit it to GitLab.com separately from any Contribution, identifying the complete details of its source and of any license or other restriction (including, but not limited to, related patents, trademarks, and license agreements) of which you are personally aware, and conspicuously marking the work as "Submitted on behalf of a third-party: [[]named here]". + +8. You agree to notify GitLab.com of any facts or circumstances of which you become aware that would make these representations inaccurate in any respect. + +--------------------------------------- + +This text is licensed under the [Creative Commons Attribution 3.0 License](http://creativecommons.org/licenses/by/3.0/) and the original source is the Google Open Source Programs Office. diff --git a/lib/api/api.rb b/lib/api/api.rb index 4db81f42b4c..45efcc8cd47 100644 --- a/lib/api/api.rb +++ b/lib/api/api.rb @@ -39,5 +39,6 @@ module API mount DeployKeys mount ProjectHooks mount Services + mount Files end end diff --git a/lib/api/files.rb b/lib/api/files.rb new file mode 100644 index 00000000000..e467b0f8e9a --- /dev/null +++ b/lib/api/files.rb @@ -0,0 +1,73 @@ +module API + # Projects API + class Files < Grape::API + before { authenticate! } + before { authorize! :push_code, user_project } + + resource :projects do + # Create new file in repository + # + # Parameters: + # file_name (required) - The name of new file. Ex. class.rb + # file_path (optional) - The path to new file. Ex. lib/ + # branch_name (required) - The name of branch + # content (required) - File content + # commit_message (required) - Commit message + # + # Example Request: + # POST /projects/:id/repository/files + # + post ":id/repository/files" do + required_attributes! [:file_name, :branch_name, :content, :commit_message] + attrs = attributes_for_keys [:file_name, :file_path, :branch_name, :content, :commit_message] + branch_name = attrs.delete(:branch_name) + file_path = attrs.delete(:file_path) + result = ::Files::CreateContext.new(user_project, current_user, attrs, branch_name, file_path).execute + + if result[:status] == :success + status(201) + + { + file_name: attrs[:file_name], + file_path: file_path, + branch_name: branch_name + } + else + render_api_error!(result[:error], 400) + end + end + + # Update existing file in repository + # + # Parameters: + # file_name (required) - The name of new file. Ex. class.rb + # file_path (optional) - The path to new file. Ex. lib/ + # branch_name (required) - The name of branch + # content (required) - File content + # commit_message (required) - Commit message + # + # Example Request: + # PUT /projects/:id/repository/files + # + put ":id/repository/files" do + required_attributes! [:file_path, :branch_name, :content, :commit_message] + attrs = attributes_for_keys [:file_path, :branch_name, :content, :commit_message] + branch_name = attrs.delete(:branch_name) + file_path = attrs.delete(:file_path) + result = ::Files::UpdateContext.new(user_project, current_user, attrs, branch_name, file_path).execute + + if result[:status] == :success + status(200) + + { + file_path: file_path, + branch_name: branch_name + } + else + render_api_error!(result[:error], 400) + end + end + end + end +end + diff --git a/lib/api/helpers.rb b/lib/api/helpers.rb index edc662eaaab..b0f8d5a6da9 100644 --- a/lib/api/helpers.rb +++ b/lib/api/helpers.rb @@ -6,19 +6,23 @@ module API SUDO_PARAM = :sudo def current_user - @current_user ||= User.find_by_authentication_token(params[PRIVATE_TOKEN_PARAM] || env[PRIVATE_TOKEN_HEADER]) + private_token = (params[PRIVATE_TOKEN_PARAM] || env[PRIVATE_TOKEN_HEADER]).to_s + @current_user ||= User.find_by_authentication_token(private_token) identifier = sudo_identifier() + # If the sudo is the current user do nothing if (identifier && !(@current_user.id == identifier || @current_user.username == identifier)) render_api_error!('403 Forbidden: Must be admin to use sudo', 403) unless @current_user.is_admin? @current_user = User.by_username_or_id(identifier) not_found!("No user id or username for: #{identifier}") if @current_user.nil? end + @current_user end def sudo_identifier() identifier ||= params[SUDO_PARAM] ||= env[SUDO_HEADER] + # Regex for integers if (!!(identifier =~ /^[0-9]+$/)) identifier.to_i @@ -29,6 +33,7 @@ module API def set_current_user_for_thread Thread.current[:current_user] = current_user + begin yield ensure diff --git a/lib/gitlab/satellite/files/edit_file_action.rb b/lib/gitlab/satellite/files/edit_file_action.rb index 72e12fb077c..3747c6afc48 100644 --- a/lib/gitlab/satellite/files/edit_file_action.rb +++ b/lib/gitlab/satellite/files/edit_file_action.rb @@ -10,9 +10,7 @@ module Gitlab # Returns false if committing the change fails # Returns false if pushing from the satellite to Gitolite failed or was rejected # Returns true otherwise - def commit!(content, commit_message, last_commit) - return false unless can_edit?(last_commit) - + def commit!(content, commit_message) in_locked_and_timed_satellite do |repo| prepare_satellite!(repo) diff --git a/lib/gitlab/satellite/files/file_action.rb b/lib/gitlab/satellite/files/file_action.rb index 4ac53c2cd5a..7c08e292192 100644 --- a/lib/gitlab/satellite/files/file_action.rb +++ b/lib/gitlab/satellite/files/file_action.rb @@ -8,13 +8,6 @@ module Gitlab @file_path = file_path @ref = ref end - - protected - - def can_edit?(last_commit) - current_last_commit = Gitlab::Git::Commit.last_for_path(@project.repository, ref, file_path).sha - last_commit == current_last_commit - end end end end diff --git a/lib/gitlab/satellite/files/new_file_action.rb b/lib/gitlab/satellite/files/new_file_action.rb index 9fe5a38eb80..97b19809c8d 100644 --- a/lib/gitlab/satellite/files/new_file_action.rb +++ b/lib/gitlab/satellite/files/new_file_action.rb @@ -9,7 +9,7 @@ module Gitlab # Returns false if committing the change fails # Returns false if pushing from the satellite to Gitolite failed or was rejected # Returns true otherwise - def commit!(content, commit_message, file_name) + def commit!(content, commit_message) in_locked_and_timed_satellite do |repo| prepare_satellite!(repo) @@ -17,7 +17,7 @@ module Gitlab repo.git.checkout({raise: true, timeout: true, b: true}, ref, "origin/#{ref}") # update the file in the satellite's working dir - file_path_in_satellite = File.join(repo.working_dir, file_path, file_name) + file_path_in_satellite = File.join(repo.working_dir, file_path) File.open(file_path_in_satellite, 'w') { |f| f.write(content) } # add new file diff --git a/spec/mailers/notify_spec.rb b/spec/mailers/notify_spec.rb index 666c6ccefff..d287239cfe3 100644 --- a/spec/mailers/notify_spec.rb +++ b/spec/mailers/notify_spec.rb @@ -110,7 +110,7 @@ describe Notify do it_behaves_like 'an assignee email' it 'has the correct subject' do - should have_subject /#{project.name} \| new issue ##{issue.iid} \| #{issue.title}/ + should have_subject /#{project.name} \| New issue ##{issue.iid} \| #{issue.title}/ end it 'contains a link to the new issue' do @@ -126,7 +126,7 @@ describe Notify do it_behaves_like 'a multiple recipients email' it 'has the correct subject' do - should have_subject /changed issue ##{issue.iid} \| #{issue.title}/ + should have_subject /Changed issue ##{issue.iid} \| #{issue.title}/ end it 'contains the name of the previous assignee' do @@ -148,7 +148,7 @@ describe Notify do subject { Notify.issue_status_changed_email(recipient.id, issue.id, status, current_user) } it 'has the correct subject' do - should have_subject /changed issue ##{issue.iid} \| #{issue.title}/i + should have_subject /Changed issue ##{issue.iid} \| #{issue.title}/i end it 'contains the new status' do @@ -175,7 +175,7 @@ describe Notify do it_behaves_like 'an assignee email' it 'has the correct subject' do - should have_subject /new merge request !#{merge_request.iid}/ + should have_subject /New merge request ##{merge_request.iid}/ end it 'contains a link to the new merge request' do @@ -199,7 +199,7 @@ describe Notify do it_behaves_like 'a multiple recipients email' it 'has the correct subject' do - should have_subject /changed merge request !#{merge_request.iid}/ + should have_subject /Changed merge request ##{merge_request.iid}/ end it 'contains the name of the previous assignee' do @@ -224,7 +224,7 @@ describe Notify do subject { Notify.project_was_moved_email(project.id, user.id) } it 'has the correct subject' do - should have_subject /project was moved/ + should have_subject /Project was moved/ end it 'contains name of project' do @@ -244,7 +244,7 @@ describe Notify do user: user) } subject { Notify.project_access_granted_email(users_project.id) } it 'has the correct subject' do - should have_subject /access to project was granted/ + should have_subject /Access to project was granted/ end it 'contains name of project' do should have_body_text /#{project.name}/ @@ -302,7 +302,7 @@ describe Notify do it_behaves_like 'a note email' it 'has the correct subject' do - should have_subject /note for commit #{commit.short_id}/ + should have_subject /Note for commit #{commit.short_id}/ end it 'contains a link to the commit' do @@ -320,7 +320,7 @@ describe Notify do it_behaves_like 'a note email' it 'has the correct subject' do - should have_subject /note for merge request ##{merge_request.iid}/ + should have_subject /Note for merge request ##{merge_request.iid}/ end it 'contains a link to the merge request note' do @@ -338,7 +338,7 @@ describe Notify do it_behaves_like 'a note email' it 'has the correct subject' do - should have_subject /note for issue ##{issue.iid}/ + should have_subject /Note for issue ##{issue.iid}/ end it 'contains a link to the issue note' do @@ -356,7 +356,7 @@ describe Notify do subject { Notify.group_access_granted_email(membership.id) } it 'has the correct subject' do - should have_subject /access to group was granted/ + should have_subject /Access to group was granted/ end it 'contains name of project' do @@ -367,4 +367,28 @@ describe Notify do should have_body_text /#{membership.human_access}/ end end + + describe 'confirmation if email changed' do + let(:example_site_path) { root_path } + let(:user) { create(:user, email: 'old-email@mail.com') } + + before do + user.email = "new-email@mail.com" + user.save + end + + subject { ActionMailer::Base.deliveries.last } + + it 'is sent to the new user' do + should deliver_to 'new-email@mail.com' + end + + it 'has the correct subject' do + should have_subject "Confirmation instructions" + end + + it 'includes a link to the site' do + should have_body_text /#{example_site_path}/ + end + end end diff --git a/spec/requests/api/files_spec.rb b/spec/requests/api/files_spec.rb new file mode 100644 index 00000000000..345f2bae65a --- /dev/null +++ b/spec/requests/api/files_spec.rb @@ -0,0 +1,81 @@ +require 'spec_helper' + +describe API::API do + include ApiHelpers + before(:each) { ActiveRecord::Base.observers.enable(:user_observer) } + after(:each) { ActiveRecord::Base.observers.disable(:user_observer) } + + let(:user) { create(:user) } + let!(:project) { create(:project_with_code, namespace: user.namespace ) } + before { project.team << [user, :developer] } + + describe "POST /projects/:id/repository/files" do + let(:valid_params) { + { + file_name: 'newfile.rb', + branch_name: 'master', + content: 'puts 8', + commit_message: 'Added newfile' + } + } + + it "should create a new file in project repo" do + Gitlab::Satellite::NewFileAction.any_instance.stub( + commit!: true, + ) + + post api("/projects/#{project.id}/repository/files", user), valid_params + response.status.should == 201 + json_response['file_name'].should == 'newfile.rb' + end + + it "should return a 400 bad request if no params given" do + post api("/projects/#{project.id}/repository/files", user) + response.status.should == 400 + end + + it "should return a 400 if satellite fails to create file" do + Gitlab::Satellite::NewFileAction.any_instance.stub( + commit!: false, + ) + + post api("/projects/#{project.id}/repository/files", user), valid_params + response.status.should == 400 + end + end + + describe "PUT /projects/:id/repository/files" do + let(:valid_params) { + { + file_path: 'spec/spec_helper.rb', + branch_name: 'master', + content: 'puts 8', + commit_message: 'Changed file' + } + } + + it "should update existing file in project repo" do + Gitlab::Satellite::EditFileAction.any_instance.stub( + commit!: true, + ) + + put api("/projects/#{project.id}/repository/files", user), valid_params + response.status.should == 200 + json_response['file_path'].should == 'spec/spec_helper.rb' + end + + it "should return a 400 bad request if no params given" do + put api("/projects/#{project.id}/repository/files", user) + response.status.should == 400 + end + + it "should return a 400 if satellite fails to create file" do + Gitlab::Satellite::EditFileAction.any_instance.stub( + commit!: false, + ) + + put api("/projects/#{project.id}/repository/files", user), valid_params + response.status.should == 400 + end + end +end diff --git a/spec/support/test_env.rb b/spec/support/test_env.rb index 16e10b1a62b..5dbdffe4102 100644 --- a/spec/support/test_env.rb +++ b/spec/support/test_env.rb @@ -45,6 +45,7 @@ module TestEnv def disable_mailer NotificationService.any_instance.stub(mailer: double.as_null_object) end + def enable_mailer NotificationService.any_instance.unstub(:mailer) end