diff --git a/CHANGELOG b/CHANGELOG index d538bb42992f6e745fd46bf0286e956b695d23cf..4ada5df5bc159311a8b4ff7da8710a47a783b5a3 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -2,6 +2,7 @@ Please view this file on the master branch, on stable branches it's out of date. v 7.13.0 (unreleased) - Fix redirection to home page URL for unauthorized users (Daniel Gerhardt) + - Add branch switching support for graphs (Daniel Gerhardt) - Fix external issue tracker hook/test for HTTPS URLs (Daniel Gerhardt) - Remove link leading to a 404 error in Deploy Keys page (Stan Hu) - Add support for unlocking users in admin settings (Stan Hu) @@ -19,6 +20,7 @@ v 7.13.0 (unreleased) - Update maintenance documentation to explain no need to recompile asssets for omnibus installations (Stan Hu) - Support commenting on diffs in side-by-side mode (Stan Hu) - Fix JavaScript error when clicking on the comment button on a diff line that has a comment already (Stan Hu) + - Return 40x error codes if branch could not be deleted in UI (Stan Hu) - Remove project visibility icons from dashboard projects list - Rename "Design" profile settings page to "Preferences". - Allow users to customize their default Dashboard page. @@ -51,6 +53,8 @@ v 7.12.1 - Fix closed merge request scope at milestone page (Dmitriy Zaporozhets) - Revert merge request states renaming - Fix hooks for web based events with external issue references (Daniel Gerhardt) + - Improve performance for issue and merge request pages + - Compress database dumps to reduce backup size v 7.12.0 - Fix Error 500 when one user attempts to access a personal, internal snippet (Stan Hu) diff --git a/app/controllers/projects/branches_controller.rb b/app/controllers/projects/branches_controller.rb index 696011b94b9bb23d7d563ac85736f20d15f62480..117ae3aaa3d469e1260f5f6f9dd3639d4b9ab21c 100644 --- a/app/controllers/projects/branches_controller.rb +++ b/app/controllers/projects/branches_controller.rb @@ -32,7 +32,7 @@ def create end def destroy - DeleteBranchService.new(project, current_user).execute(params[:id]) + status = DeleteBranchService.new(project, current_user).execute(params[:id]) @branch_name = params[:id] respond_to do |format| @@ -40,7 +40,7 @@ def destroy redirect_to namespace_project_branches_path(@project.namespace, @project) end - format.js + format.js { render status: status[:return_code] } end end end diff --git a/app/controllers/projects/graphs_controller.rb b/app/controllers/projects/graphs_controller.rb index a060ea6f9989d448fd8e48d05d05cf5a69a2f8e2..0b6f7f5c91e565379a597d6b12297b90be65dec6 100644 --- a/app/controllers/projects/graphs_controller.rb +++ b/app/controllers/projects/graphs_controller.rb @@ -1,6 +1,9 @@ class Projects::GraphsController < Projects::ApplicationController + include ExtractsPath + # Authorize before_action :require_non_empty_project + before_action :assign_ref_vars before_action :authorize_download_code! def show @@ -13,7 +16,7 @@ def show end def commits - @commits = @project.repository.commits(nil, nil, 2000, 0, true) + @commits = @project.repository.commits(@ref, nil, 2000, 0, true) @commits_graph = Gitlab::Graphs::Commits.new(@commits) @commits_per_week_days = @commits_graph.commits_per_week_days @commits_per_time = @commits_graph.commits_per_time @@ -23,7 +26,7 @@ def commits private def fetch_graph - @commits = @project.repository.commits(nil, nil, 6000, 0, true) + @commits = @project.repository.commits(@ref, nil, 6000, 0, true) @log = [] @commits.each do |commit| diff --git a/app/controllers/projects/refs_controller.rb b/app/controllers/projects/refs_controller.rb index 01ca1537c0e66316229fa9df52f7bed145d19b20..d83561cf32af3bf10776eca0a175ba2003fa4338 100644 --- a/app/controllers/projects/refs_controller.rb +++ b/app/controllers/projects/refs_controller.rb @@ -8,17 +8,21 @@ class Projects::RefsController < Projects::ApplicationController def switch respond_to do |format| format.html do - new_path = if params[:destination] == "tree" - namespace_project_tree_path(@project.namespace, @project, - (@id)) - elsif params[:destination] == "blob" - namespace_project_blob_path(@project.namespace, @project, - (@id)) - elsif params[:destination] == "graph" - namespace_project_network_path(@project.namespace, @project, @id, @options) - else - namespace_project_commits_path(@project.namespace, @project, @id) - end + new_path = + case params[:destination] + when "tree" + namespace_project_tree_path(@project.namespace, @project, @id) + when "blob" + namespace_project_blob_path(@project.namespace, @project, @id) + when "graph" + namespace_project_network_path(@project.namespace, @project, @id, @options) + when "graphs" + namespace_project_graph_path(@project.namespace, @project, @id) + when "graphs_commits" + commits_namespace_project_graph_path(@project.namespace, @project, @id) + else + namespace_project_commits_path(@project.namespace, @project, @id) + end redirect_to new_path end diff --git a/app/views/projects/graphs/commits.html.haml b/app/views/projects/graphs/commits.html.haml index 254a76e108baecbf4cd96093d4bfc05515c579fa..141acbdcf722478d55368bc37f059ba3c0966e17 100644 --- a/app/views/projects/graphs/commits.html.haml +++ b/app/views/projects/graphs/commits.html.haml @@ -1,9 +1,11 @@ - page_title "Commit statistics" +.tree-ref-holder + = render 'shared/ref_switcher', destination: 'graphs_commits' = render 'head' %p.lead Commit statistics for - %strong #{@repository.root_ref} + %strong #{@ref} #{@commits_graph.start_date.strftime('%b %d')} - #{@commits_graph.end_date.strftime('%b %d')} .row diff --git a/app/views/projects/graphs/show.html.haml b/app/views/projects/graphs/show.html.haml index 3a8dc89f84cc3c25b8dbf90f2eeeaf33a645a416..ecdd0eaf52fbedeafcdd7f2cca1bd54ba7385980 100644 --- a/app/views/projects/graphs/show.html.haml +++ b/app/views/projects/graphs/show.html.haml @@ -1,5 +1,8 @@ - page_title "Contributor statistics" +.tree-ref-holder + = render 'shared/ref_switcher', destination: 'graphs' = render 'head' + .loading-graph .center %h3.page-title @@ -11,7 +14,7 @@ .header.clearfix %h3#date_header.page-title %p.light - Commits to #{@project.default_branch}, excluding merge commits. Limited by 6,000 commits + Commits to #{@ref}, excluding merge commits. Limited by 6,000 commits %input#brush_change{:type => "hidden"} .graphs #contributors-master @@ -35,4 +38,3 @@ $(".stat-graph").fadeIn(); $(".loading-graph").hide(); dataType: "json" - diff --git a/doc/api/README.md b/doc/api/README.md index ca58c184543e526a1a0841b529ab22c99170a03f..b474e0ea38902e2a24f597ae3213286570495c33 100644 --- a/doc/api/README.md +++ b/doc/api/README.md @@ -20,6 +20,7 @@ - [System Hooks](system_hooks.md) - [Groups](groups.md) - [Namespaces](namespaces.md) +- [Settings](settings.md) ## Clients diff --git a/doc/api/settings.md b/doc/api/settings.md new file mode 100644 index 0000000000000000000000000000000000000000..d1b93a09c02b40d927a8b158687f8826e677c89d --- /dev/null +++ b/doc/api/settings.md @@ -0,0 +1,88 @@ +# Application settings + +This API allows you to read and modify GitLab instance application settings. + + +## Get current application settings: + +``` +GET /application/settings +``` + +```json +{ + "id": 1, + "default_projects_limit": 10, + "signup_enabled": true, + "signin_enabled": true, + "gravatar_enabled": true, + "sign_in_text": "", + "created_at": "2015-06-12T15:51:55.432Z", + "updated_at": "2015-06-30T13:22:42.210Z", + "home_page_url": "", + "default_branch_protection": 2, + "twitter_sharing_enabled": true, + "restricted_visibility_levels": [], + "max_attachment_size": 10, + "session_expire_delay": 10080, + "default_project_visibility": 0, + "default_snippet_visibility": 0, + "restricted_signup_domains": [], + "user_oauth_applications": true, + "after_sign_out_path": "" +} +``` + +## Change application settings: + + + +``` +PUT /application/settings +``` + +Parameters: + +- `default_projects_limit` - project limit per user +- `signup_enabled` - enable registration +- `signin_enabled` - enable login via GitLab account +- `gravatar_enabled` - enable gravatar +- `sign_in_text` - text on login page +- `home_page_url` - redirect to this URL when not logged in +- `default_branch_protection` - determine if developers can push to master +- `twitter_sharing_enabled` - allow users to share project creation in twitter +- `restricted_visibility_levels` - restrict certain visibility levels +- `max_attachment_size` - limit attachment size +- `session_expire_delay` - session lifetime +- `default_project_visibility` - what visibility level new project receives +- `default_snippet_visibility` - what visibility level new snippet receives +- `restricted_signup_domains` - force people to use only corporate emails for signup +- `user_oauth_applications` - allow users to create oauth applicaitons +- `after_sign_out_path` - where redirect user after logout + +All parameters are optional. You can send only one that you want to change. + + +```json +{ + "id": 1, + "default_projects_limit": 10, + "signup_enabled": true, + "signin_enabled": true, + "gravatar_enabled": true, + "sign_in_text": "", + "created_at": "2015-06-12T15:51:55.432Z", + "updated_at": "2015-06-30T13:22:42.210Z", + "home_page_url": "", + "default_branch_protection": 2, + "twitter_sharing_enabled": true, + "restricted_visibility_levels": [], + "max_attachment_size": 10, + "session_expire_delay": 10080, + "default_project_visibility": 0, + "default_snippet_visibility": 0, + "restricted_signup_domains": [], + "user_oauth_applications": true, + "after_sign_out_path": "" +} +``` diff --git a/doc/update/mysql_to_postgresql.md b/doc/update/mysql_to_postgresql.md index 2c43cf59c1f6029351731db32531d7f2a01ec407..8ef3e0d55cc9d3b9ca095a94fdc83df00b3a4fd5 100644 --- a/doc/update/mysql_to_postgresql.md +++ b/doc/update/mysql_to_postgresql.md @@ -57,12 +57,15 @@ sudo -u git -H git clone https://github.com/gitlabhq/mysql-postgresql-converter. sudo -u git -H mkdir db sudo -u git -H python mysql-postgresql-converter/db_converter.py gitlabhq_production.mysql db/database.sql +# Compress database backup +sudo -u git -H gzip db/database.sql + # Replace the MySQL dump in TIMESTAMP_gitlab_backup.tar. # Warning: if you forget to replace TIMESTAMP below, tar will create a new file # 'TIMESTAMP_gitlab_backup.tar' without giving an error. -sudo -u git -H tar rf TIMESTAMP_gitlab_backup.tar db/database.sql +sudo -u git -H tar rf TIMESTAMP_gitlab_backup.tar db/database.sql.gz # Done! TIMESTAMP_gitlab_backup.tar can now be restored into a Postgres GitLab # installation. Remember to recreate the indexes after the import. diff --git a/lib/api/api.rb b/lib/api/api.rb index d2a35c78fc18b2ccf5226f3344dc46d4b887ff9b..eebd44ea5b66c108fa9fd70c41ee4a121239f10d 100644 --- a/lib/api/api.rb +++ b/lib/api/api.rb @@ -49,5 +49,6 @@ class API < Grape::API mount Namespaces mount Branches mount Labels + mount Settings end end diff --git a/lib/api/entities.rb b/lib/api/entities.rb index 14a8f929d76ac125c99782863e4d7d612767cc50..31202fa8c1fbd04f0d23a7ba260efaaa2bb79b8f 100644 --- a/lib/api/entities.rb +++ b/lib/api/entities.rb @@ -277,5 +277,27 @@ class Contributor < Grape::Entity class BroadcastMessage < Grape::Entity expose :message, :starts_at, :ends_at, :color, :font end + + class ApplicationSetting < Grape::Entity + expose :id + expose :default_projects_limit + expose :signup_enabled + expose :signin_enabled + expose :gravatar_enabled + expose :sign_in_text + expose :created_at + expose :updated_at + expose :home_page_url + expose :default_branch_protection + expose :twitter_sharing_enabled + expose :restricted_visibility_levels + expose :max_attachment_size + expose :session_expire_delay + expose :default_project_visibility + expose :default_snippet_visibility + expose :restricted_signup_domains + expose :user_oauth_applications + expose :after_sign_out_path + end end end diff --git a/lib/api/settings.rb b/lib/api/settings.rb new file mode 100644 index 0000000000000000000000000000000000000000..c885fcd7ea34abe2d8417b7e8fc0eb62e27a8545 --- /dev/null +++ b/lib/api/settings.rb @@ -0,0 +1,35 @@ +module API + class Settings < Grape::API + before { authenticated_as_admin! } + + helpers do + def current_settings + @current_setting ||= + (ApplicationSetting.current || ApplicationSetting.create_from_defaults) + end + end + + # Get current applicaiton settings + # + # Example Request: + # GET /application/settings + get "application/settings" do + present current_settings, with: Entities::ApplicationSetting + end + + # Modify applicaiton settings + # + # Example Request: + # PUT /application/settings + put "application/settings" do + attributes = current_settings.attributes.keys - ["id"] + attrs = attributes_for_keys(attributes) + + if current_settings.update_attributes(attrs) + present current_settings, with: Entities::ApplicationSetting + else + render_validation_error!(current_settings) + end + end + end +end diff --git a/lib/backup/database.rb b/lib/backup/database.rb index 9ab6aca276da7a274b464b404efafc62878c7605..f677f8def2b142de204c2430c4ea7f36185e8a6d 100644 --- a/lib/backup/database.rb +++ b/lib/backup/database.rb @@ -22,9 +22,19 @@ def dump end report_success(success) abort 'Backup failed' unless success + + $progress.print 'Compressing database ... ' + success = system('gzip', db_file_name) + report_success(success) + abort 'Backup failed: compress error' unless success end def restore + $progress.print 'Decompressing database ... ' + success = system('gzip', '-d', db_file_name_gz) + report_success(success) + abort 'Restore failed: decompress error' unless success + success = case config["adapter"] when /^mysql/ then $progress.print "Restoring MySQL database #{config['database']} ... " @@ -48,6 +58,10 @@ def db_file_name File.join(db_dir, 'database.sql') end + def db_file_name_gz + File.join(db_dir, 'database.sql.gz') + end + def mysql_args args = { 'host' => '--host', diff --git a/spec/controllers/branches_controller_spec.rb b/spec/controllers/branches_controller_spec.rb index db3b64babcd26fc409b1b93ac483bfa3a81dcd52..bd4c946b64b8700bf82d83849adf9eefb09bcd42 100644 --- a/spec/controllers/branches_controller_spec.rb +++ b/spec/controllers/branches_controller_spec.rb @@ -55,4 +55,30 @@ it { is_expected.to render_template('new') } end end + + describe "POST destroy" do + render_views + + before do + post :destroy, + format: :js, + id: branch, + namespace_id: project.namespace.to_param, + project_id: project.to_param + end + + context "valid branch name, valid source" do + let(:branch) { "feature" } + + it { expect(response.status).to eq(200) } + it { expect(subject).to render_template('destroy') } + end + + context "invalid branch name, valid ref" do + let(:branch) { "no-branch" } + + it { expect(response.status).to eq(404) } + it { expect(subject).to render_template('destroy') } + end + end end diff --git a/spec/requests/api/settings_spec.rb b/spec/requests/api/settings_spec.rb new file mode 100644 index 0000000000000000000000000000000000000000..c815a8e1d738696832cacb1236f2d5c5bbd2bf26 --- /dev/null +++ b/spec/requests/api/settings_spec.rb @@ -0,0 +1,29 @@ +require 'spec_helper' + +describe API::API, 'Settings', api: true do + include ApiHelpers + + let(:user) { create(:user) } + let(:admin) { create(:admin) } + + + describe "GET /application/settings" do + it "should return application settings" do + get api("/application/settings", admin) + expect(response.status).to eq(200) + expect(json_response).to be_an Hash + expect(json_response['default_projects_limit']).to eq(42) + expect(json_response['signin_enabled']).to be_truthy + end + end + + describe "PUT /application/settings" do + it "should update application settings" do + put api("/application/settings", admin), + default_projects_limit: 3, signin_enabled: false + expect(response.status).to eq(200) + expect(json_response['default_projects_limit']).to eq(3) + expect(json_response['signin_enabled']).to be_falsey + end + end +end