From dfb8ac4853ce2a16ecaeca8dcd2a37fa0b3ecf03 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Oliver=20G=C3=BCnther?=
Date: Wed, 19 Aug 2015 09:08:26 +0200
Subject: [PATCH] Add basic checkout instructions
This commit adds very basic checkout instructions similar
to `openproject-checkout` to repositories.
Issues:
* Uses table style for checkout component, as exact styling is unclear
* Adds compressed table style with less padding
* Checkout settings are best organized in a Hash with keys per SCM
* vendor. Using default settings, a lot of new setting values would be
introduced
* Checks for Hash in SettingsController
* Currently can't use SettingsHelper, as it requires single setting
values
---
app/assets/javascripts/settings.js.erb | 16 +-
app/assets/stylesheets/content/_forms.lsg | 19 +++
app/assets/stylesheets/content/_forms.sass | 6 +
app/controllers/repositories_controller.rb | 5 +
app/controllers/settings_controller.rb | 2 +
app/models/repository.rb | 4 +
.../scm/checkout_instructions_service.rb | 142 ++++++++++++++++++
.../_checkout_instructions.html.erb | 29 ++++
app/views/repositories/empty.html.erb | 1 +
app/views/repositories/show.html.erb | 1 +
app/views/settings/_repositories.html.erb | 4 +-
.../settings/_repositories_checkout.html.erb | 36 +++++
config/locales/en.yml | 16 +-
config/settings.yml | 13 ++
lib/open_project/scm/adapters/base.rb | 2 +
.../scm/adapters/checkout_instructions.rb | 79 ++++++++++
lib/open_project/scm/adapters/git.rb | 4 +
lib/open_project/scm/adapters/subversion.rb | 8 +
lib/open_project/scm/manageable_repository.rb | 2 -
19 files changed, 383 insertions(+), 6 deletions(-)
create mode 100644 app/services/scm/checkout_instructions_service.rb
create mode 100644 app/views/repositories/_checkout_instructions.html.erb
create mode 100644 app/views/settings/_repositories_checkout.html.erb
create mode 100644 lib/open_project/scm/adapters/checkout_instructions.rb
diff --git a/app/assets/javascripts/settings.js.erb b/app/assets/javascripts/settings.js.erb
index 3ce327fae6e..49394ba32e9 100644
--- a/app/assets/javascripts/settings.js.erb
+++ b/app/assets/javascripts/settings.js.erb
@@ -36,7 +36,7 @@ See doc/COPYRIGHT.rdoc for more details.
/** Sync SCM vendor select when enabled SCMs are changed */
- $('[name="settings[enabled_scm][]"]').change(function () {
+ $('[name="settings[enabled_scm][]"]').change(function() {
var wasDisabled = !this.checked,
vendor = this.value,
select = $('#settings_repositories_automatic_managed_vendor'),
@@ -51,7 +51,19 @@ See doc/COPYRIGHT.rdoc for more details.
if (wasDisabled && option.prop('selected')) {
select.val('');
}
-
});
+
+ /** Toggle repository checkout fieldsets required when option is disabled */
+ $('.settings-repositories--checkout-toggle').change(function() {
+ var wasChecked = this.checked,
+ fieldset = $(this).closest('fieldset');
+
+ fieldset
+ .find('input,select,textarea')
+ .filter(':not([type=checkbox])')
+ .filter(':not([type=hidden])')
+ .removeAttr('required') // Rails 4.0 still seems to use attribute
+ .prop('required', wasChecked);
+ })
});
}(jQuery));
diff --git a/app/assets/stylesheets/content/_forms.lsg b/app/assets/stylesheets/content/_forms.lsg
index 26236c83744..86c7022e6b9 100644
--- a/app/assets/stylesheets/content/_forms.lsg
+++ b/app/assets/stylesheets/content/_forms.lsg
@@ -38,6 +38,25 @@
```
+## Forms: Bordered compressed style (less padding)
+
+```
+
+```
+
## Forms: Standard layout
```
diff --git a/app/assets/stylesheets/content/_forms.sass b/app/assets/stylesheets/content/_forms.sass
index 04d4e0ef25e..49e2df66f66 100644
--- a/app/assets/stylesheets/content/_forms.sass
+++ b/app/assets/stylesheets/content/_forms.sass
@@ -58,6 +58,9 @@ $form--field-types: (text-field, text-area, select, check-box, radio-button, ran
background-color: $content-form-bg-color
border: $content-form-border
+ &.-compressed
+ padding: 10px 20px 0 20px
+
.form--separator
border: 0
border-bottom: 1px solid $content-form-separator-color
@@ -328,6 +331,9 @@ fieldset.form--fieldset
@extend %form--field-after-container
font-style: italic
+ &.-no-italic
+ font-style: normal
+
.form--field-extra-actions
@extend %form--field-after-container
@include grid-visible-overflow
diff --git a/app/controllers/repositories_controller.rb b/app/controllers/repositories_controller.rb
index 9105aaef755..17d0889a780 100644
--- a/app/controllers/repositories_controller.rb
+++ b/app/controllers/repositories_controller.rb
@@ -308,6 +308,11 @@ class RepositoriesController < ApplicationController
@repository = @project.repository
(render_404; return false) unless @repository
+ # Prepare checkout instructions
+ # available on all pages (even empty!)
+ @instructions = ::Scm::CheckoutInstructionsService.new(@repository)
+
+ # Asserts repository availability, or renders an appropriate error
@repository.scm.check_availability!
@path = params[:path] || ''
diff --git a/app/controllers/settings_controller.rb b/app/controllers/settings_controller.rb
index 20ac62df270..2405e90eafb 100644
--- a/app/controllers/settings_controller.rb
+++ b/app/controllers/settings_controller.rb
@@ -48,6 +48,8 @@ class SettingsController < ApplicationController
if value.is_a?(Array)
# remove blank values in array settings
value.delete_if(&:blank?)
+ elsif value.is_a?(Hash)
+ value.delete_if { |_, v| v.blank? }
else
value = value.strip
end
diff --git a/app/models/repository.rb b/app/models/repository.rb
index fb4e671ca4d..4bcd18b904f 100644
--- a/app/models/repository.rb
+++ b/app/models/repository.rb
@@ -129,6 +129,10 @@ class Repository < ActiveRecord::Base
false
end
+ def supports_checkout_info?
+ true
+ end
+
def entry(path = nil, identifier = nil)
scm.entry(path, identifier)
end
diff --git a/app/services/scm/checkout_instructions_service.rb b/app/services/scm/checkout_instructions_service.rb
new file mode 100644
index 00000000000..94b7615fee5
--- /dev/null
+++ b/app/services/scm/checkout_instructions_service.rb
@@ -0,0 +1,142 @@
+#-- encoding: UTF-8
+#-- copyright
+# OpenProject is a project management system.
+# Copyright (C) 2012-2015 the OpenProject Foundation (OPF)
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License version 3.
+#
+# OpenProject is a fork of ChiliProject, which is a fork of Redmine. The copyright follows:
+# Copyright (C) 2006-2013 Jean-Philippe Lang
+# Copyright (C) 2010-2013 the ChiliProject Team
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+#
+# See doc/COPYRIGHT.rdoc for more details.
+#++
+
+##
+# Implements a repository service for building checkout instructions if supported
+class Scm::CheckoutInstructionsService
+ attr_reader :repository, :user
+
+ def initialize(repository, user = User.current)
+ @repository = repository
+ @user = user
+ end
+
+ ##
+ # Retrieve the checkout URL using the repository vendor information
+ # It may additionally set a path parameter, if the repository supports subtree checkout
+ def checkout_url(path = nil)
+ repository.scm.checkout_url(repository, checkout_base_url, path)
+ end
+
+ ##
+ # Returns the checkout command from SCM adapter
+ # (e.g., `git clone`)
+ def checkout_command
+ repository.scm.checkout_command
+ end
+
+ ##
+ # Returns the checkout base URL as defined in settings.
+ def checkout_base_url
+ checkout_settings['base_url']
+ end
+
+ ##
+ # Returns the instructions defined in the settings.
+ def instructions
+ checkout_settings['text']
+ end
+
+ ##
+ # Returns true when the checkout URL may target a subtree of the repository.
+ def subtree_checkout?
+ repository.scm.subtree_checkout?
+ end
+
+ ##
+ # Returns whether the repository supports showing checkout information
+ # and has been configured for it.
+ def available?
+ checkout_enabled? &&
+ repository.supports_checkout_info? &&
+ checkout_base_url.present?
+ end
+
+ def checkout_enabled?
+ checkout_settings['enabled'].to_i > 0
+ end
+
+ ##
+ # Determines whether permissions for the given repository
+ # are available.
+ def permission?
+ repository.managed?
+ end
+
+ ##
+ # Returns one of the following permission symbols for the given user
+ #
+ # - :readwrite: When user is allowed to read and commit (:commit_access)
+ # - :read: When user is allowed to checkout the repository, but not commit (:browse_repository)
+ # - :none: Otherwise
+ #
+ # Note that this information is only applicable when the repository is managed,
+ # because otherwise OpenProject does not control the repository permissions.
+ # Use +permission?+ to check whether this is the case.
+ #
+ def permission
+ project = repository.project
+ if user.allowed_to?(:commit_access, project)
+ :readwrite
+ elsif user.allowed_to?(:browse_repository, project)
+ :read
+ else
+ :none
+ end
+ end
+
+ ##
+ # Returns whether the given user may checkout the repository
+ #
+ # Note that this information is only applicable when the repository is managed,
+ # because otherwise OpenProject does not control the repository permissions.
+ # Use +permission?+ to check whether this is the case.
+ def may_checkout?
+ [:readwrite, :read].include?(permission)
+ end
+
+ ##
+ # Returns whether the given user may commit to the repository
+ #
+ # Note that this information is only applicable when the repository is managed,
+ # because otherwise OpenProject does not control the repository permissions.
+ # Use +permission?+ to check whether this is the case.
+ def may_commit?
+ permission == :readwrite
+ end
+
+ private
+
+ def checkout_settings
+ @settings ||= begin
+ hash = Setting.repository_checkout_data[repository.vendor.to_s]
+ hash.presence || {}
+ end
+ end
+end
diff --git a/app/views/repositories/_checkout_instructions.html.erb b/app/views/repositories/_checkout_instructions.html.erb
new file mode 100644
index 00000000000..26d0ccae779
--- /dev/null
+++ b/app/views/repositories/_checkout_instructions.html.erb
@@ -0,0 +1,29 @@
+<% if instructions.present? && instructions.available? %>
+
+<% end %>
diff --git a/app/views/repositories/empty.html.erb b/app/views/repositories/empty.html.erb
index 71eb1c26c5f..9712c827c3c 100644
--- a/app/views/repositories/empty.html.erb
+++ b/app/views/repositories/empty.html.erb
@@ -33,6 +33,7 @@ See doc/COPYRIGHT.rdoc for more details.
message: l('repositories.errors.empty_repository')) %>