Añade el plugin Redmine Git Server 0.4

This commit is contained in:
Manuel Cillero 2021-05-14 16:45:54 +02:00
parent 525527a55b
commit 4b46a7472e
30 changed files with 485 additions and 0 deletions

View file

@ -0,0 +1,21 @@
The MIT License (MIT)
Copyright (c) 2016 Jean-Baptiste Barth
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.

View file

@ -0,0 +1 @@
gem 'deface', '1.5.3'

View file

@ -0,0 +1,36 @@
Redmine base_deface plugin
======================
Integrate with the deface gem to manage view modifications in plugins
Installation
------------
This plugin is compatible with Redmine 2.1.0+.
Please apply general instructions for plugins [here](http://www.redmine.org/wiki/redmine/Plugins).
First download the source or clone the plugin and put it in the "plugins/" directory of your redmine instance. Note that this is crucial that the directory is named redmine_base_deface !
Then execute from redmine root directory:
$ bundle install
$ rake redmine:plugins
And finally restart your Redmine instance.
Contributing
------------
1. Fork it
2. Create your feature branch (`git checkout -b my-new-feature`)
3. Commit your changes (`git commit -am 'Add some feature'`)
4. Push to the branch (`git push origin my-new-feature`)
5. Create new Pull Request
License
-------
This project is released under the MIT license, see LICENSE file.

View file

@ -0,0 +1 @@
This directory is only here to ensure the plugin works through unit tests. It is automatically added to Rails.application.paths["app/overrides"]

View file

@ -0,0 +1,20 @@
Redmine::Plugin.register :redmine_base_deface do
name 'Redmine Base Deface plugin'
author 'Jean-Baptiste BARTH'
description 'This is a plugin for Redmine'
version '1.5.3'
url 'https://github.com/jbbarth/redmine_base_deface'
author_url 'jeanbaptiste.barth@gmail.com'
#doesn't work since redmine evaluates dependencies as it loads, and loads in lexical order
#TODO: see if it works in Redmine 2.6.x or 3.x when they're released
# requires_redmine_plugin :redmine_base_rspec, :version_or_higher => '0.0.3' if Rails.env.test?
end
# Little hack for deface in redmine:
# - redmine plugins are not railties nor engines, so deface overrides are not detected automatically
# - deface doesn't support direct loading anymore ; it unloads everything at boot so that reload in dev works
# - hack consists in adding "app/overrides" path of all plugins in Redmine's main #paths
Rails.application.paths["app/overrides"] ||= []
Dir.glob("#{Rails.root}/plugins/*/app/overrides").each do |dir|
Rails.application.paths["app/overrides"] << dir unless Rails.application.paths["app/overrides"].include?(dir)
end

View file

@ -0,0 +1,10 @@
require "spec_helper"
describe "DefacePaths" do
it "should app overrides paths" do
overrides_paths = Rails.application.paths["app/overrides"]
this_plugin_paths = Rails.root.join("plugins/redmine_base_deface/app/overrides")
assert overrides_paths.include?(this_plugin_paths.to_s),
"The init.rb of this very plugin should add every plugins' app/overrides to rails paths for app/overrides"
end
end

View file

@ -0,0 +1 @@
gem 'grack', '0.1.1'

View file

@ -0,0 +1,21 @@
MIT License
Copyright (c) 2020 Romain Lalaut
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

View file

@ -0,0 +1,52 @@
Redmine plugin - Git Server
============
This Redmine plugin lets your users pull and push to/from your git repositories hosted on Redmine with HTTP - without any complex setup.
Under the hood, it relies on [Grack](https://github.com/grackorg/grack), a Ruby/Rack Git Smart HTTP Server Handler.
Screenshot
------------
![redmine_git_server example](assets/images/screenshot.png)
Installation
------------
This plugin is tested with Redmine 4.1+ (but it could be compatible with other versions).
Please apply general instructions for plugins [here](http://www.redmine.org/wiki/redmine/Plugins).
Note that this plugin depends on this other plugin:
* **redmine_base_deface** [here](https://github.com/jbbarth/redmine_base_deface)
First download the source or clone the plugin and put it in the "plugins/" directory of your redmine instance. Note that this is crucial that the directory is named 'redmine_git_server'!
Then execute:
$ bundle install
$ rake redmine:plugins
And finally restart your Redmine instance.
Permissions
-----------
* *Git Server > Enable git server* : allows a user to enable/disable the project module "Git Server"
* *(Redmine built-in) Repository > View changesets* : allows a user to fetch changesets (pull) from a repository
* *(Redmine built-in) Repository > Commit access* : allows a user to push to a repository
Alternatives
------------
* [redmine_git_hosting](http://redmine-git-hosting.io/) - based on Gitolite, this plugin offer a **lot** more features but it is also more complex to setup.
Knowns issues
-------------
Puma 3.7 which is currently bundled with Redmine has an issue with chunked uploads. You can upgrade to Puma 4.3 or configure git locally to avoid chunked uploads (eg. `git config --global http.postBuffer 524288000`)

View file

@ -0,0 +1,50 @@
class GitServerController < ApplicationController
skip_before_action :verify_authenticity_token
skip_before_action :check_if_login_required
before_action do
begin
authenticate_or_request_with_http_basic do |username, password|
@user = User.try_to_login(username, password, false)
if @user.nil? or @user.new_record? or !@user.active?
logger.info "(Git Server) Authentication failed from #{request.remote_ip} at #{Time.now.utc}"
false
else
logger.info "(Git Server) Successful authentication for '#{@user.login}' from #{request.remote_ip} at #{Time.now.utc}"
true
end
end
next false unless @user
project = Project.find(params[:id])
unless project.module_enabled?("git_server")
logger.warn "(Git Server) project '#{project.identifier}' doesn't have the git_server module enabled"
render_404
next false
end
repository = project.repositories.find_by_identifier_param(params[:repository_id])
unless repository
render_404
next false
end
@grack_app = RedmineGitServer::GrackApp.new \
request: request,
repository_path: repository.url,
allow_push: @user.allowed_to?(:commit_access, project),
allow_pull: @user.allowed_to?(:view_changesets, project)
rescue ActiveRecord::RecordNotFound
render_404
end
end
Grack::App::ROUTES.collect{|o| o[2] }.uniq.each do |action|
define_method action do
path = request.params["path"]
params = action == :info_refs ? [] : [path]
rack_response = @grack_app.send(action, *params)
self.response = ActionDispatch::Response.new(*rack_response)
response.sending!
end
end
end

View file

@ -0,0 +1,5 @@
Deface::Override.new virtual_path: 'repositories/show',
name: 'insert_clone_button',
insert_bottom: 'div.contextual',
partial: 'repositories/clone_button'

View file

@ -0,0 +1,14 @@
<% user = User.current %>
<% write_access = user.allowed_to?(:commit_access, @project) %>
<% read_access = user.allowed_to?(:view_changesets, @project) %>
<% if @project.module_enabled?("git_server") and read_access %>
|
<%= content_tag :div, class: 'drdn clone-wrapper' do %>
<%= button_tag l(:clone), type: 'button', class: 'drdn-trigger clone-button' %>
<%= content_tag :div, class: 'drdn-content clone-dropdown' do %>
<% protocol = Setting['protocol'] %>
<h4><%= l(:clone_with_protocol, protocol: protocol.upcase) %></h4>
<%= render 'clone_form' %>
<% end %>
<% end %>
<% end %>

View file

@ -0,0 +1,28 @@
<% user = User.current %>
<% write_access = user.allowed_to?(:commit_access, @project) %>
<% read_access = user.allowed_to?(:view_changesets, @project) %>
<%= content_tag :div, class: 'clone-form' do %>
<% protocol = Setting['protocol'] %>
<p>
<%= l(:use_git_with_this_web_url) %>
<% if write_access %>
<%= l(:git_read_write_access) %>
<% else %>
<%= l(:git_read_only_access) %>
<% end %>
</p>
<%= content_tag :code, class: 'clone-input-group' do %>
<% url = url_for(
controller: 'repositories',
action: 'show',
id: @project.identifier,
repository_id: @repository.identifier,
user: User.current.login,
password: '',
only_path: false,
protocol: protocol).sub(':@', '@') %>
<%= text_field_tag 'url', url, readonly: true %>
<%= button_tag image_tag('../plugin_assets/redmine_git_server/images/copy-to-clipboard.png') %>
<% end %>
<div class="flash notice"><%= l(:url_copied) %></div>
<% end %>

View file

@ -0,0 +1,10 @@
<% user = User.current %>
<% write_access = user.allowed_to?(:commit_access, @project) %>
<% read_access = user.allowed_to?(:view_changesets, @project) %>
<div class="flash warning">
<%= l(:empty_repository) %>
</div>
<div class="empty-clone-form">
<%= render 'clone_form' %>
</div>

Binary file not shown.

After

Width:  |  Height:  |  Size: 543 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 21 KiB

View file

@ -0,0 +1,15 @@
$(() => {
$('body.controller-repositories.action-show code.clone-input-group input').click(function() {
$(this).select()
})
$('body.controller-repositories.action-show code.clone-input-group button').click(function() {
const $this = $(this)
$this.siblings('input').click()
document.execCommand("copy")
const $flash = $this.parent().siblings('.flash.notice')
$flash.show()
setTimeout(function() {
$flash.hide("fast")
}, 1000)
})
})

View file

@ -0,0 +1,47 @@
.clone-wrapper {
display: inline-block;
margin-left: O!important;
}
.clone-button {
background-color: #fff;
background-image: url(../../../images/arrow_down.png);
background-repeat: no-repeat;
background-position: calc(100% - 7px) 50%;
padding-right: 20px;
font-size: 0.9em;
}
.clone-dropdown {
top: 28px!important;
padding: 1em;
width: 350px;
}
.clone-input-group {
display: flex;
flex-direction: row;
}
.clone-input-group > * {
height: 26px!important;
}
.clone-input-group input {
flex: 1;
font-size: 1.2em;
font-family: inherit;
}
.clone-input-group button {
flex: none;
margin-left: 0.5em;
}
.clone-input-group button img {
vertical-align: middle;
}
.clone-form .flash.notice {
display: none;
position: absolute;
padding-right: 1em;
right: .5em;
margin-top: 1.5em;
}
.empty-clone-form {
max-width: 600px;
position: relative;
}

View file

@ -0,0 +1,9 @@
en:
project_module_git_server: Git Server
clone: Clone
clone_with_protocol: Clone with %{protocol}
use_git_with_this_web_url: Use Git with this web URL.
url_copied: URL copied to the clipboard
git_read_write_access: Read/write access.
git_read_only_access: Read only access.
empty_repository: This repository is empty.

View file

@ -0,0 +1,10 @@
fr:
project_module_git_server: Serveur Git
clone: Cloner
clone_with_protocol: Cloner via %{protocol}
use_git_with_this_web_url: Utilisez Git avec cette URL.
url_copied: URL copiée dans le presse-papiers
git_read_write_access: Accès en lecture/écriture.
git_read_only_access: Accès en lecture seule.
empty_repository: Ce dépôt est vide.

View file

@ -0,0 +1,15 @@
Grack::App::ROUTES.each do |grack_route|
regex = grack_route[0]
method = grack_route[1].downcase.to_sym
action = grack_route[2]
match 'projects/:id/repository/:repository_id/*path',
controller: 'git_server',
action: action,
via: method,
format: false,
constraints: -> (request) {
regex.match(request.path)
}
end

View file

@ -0,0 +1,21 @@
Redmine::Plugin.register :redmine_git_server do
name 'Redmine Git Server plugin'
author 'Romain Lalaut'
description 'This is a plugin for Redmine allowing to serve the git repositories through the http connection'
url 'https://github.com/voondo/redmine_git_server'
version '0.4'
author_url 'https://github.com/voondo'
project_module :git_server do
permission :enable_git_server, {}
end
end
require_dependency 'redmine_git_server/hooks'
app = Rails.application
app.config.to_prepare do
plugin = Redmine::Plugin.find(:redmine_git_server)
plugin.requires_redmine_plugin :redmine_base_rspec, :version_or_higher => '0.0.4' if Rails.env.test?
plugin.requires_redmine_plugin :redmine_base_deface, :version_or_higher => '0.0.1'
require_dependency 'redmine_git_server/patches/repositories_controller_patch'
end

View file

@ -0,0 +1,15 @@
module RedmineGitServer
class GrackApp < Grack::App
def initialize opts
@request = opts.fetch(:request, nil)
@env = @request.env
@git = RedmineGitServer::GrackGitAdapter.new Redmine::Scm::Adapters::GitAdapter::GIT_BIN
@git.repository_path = opts.fetch(:repository_path, nil)
@allow_push = opts.fetch(:allow_push, nil)
@allow_pull = opts.fetch(:allow_pull, nil)
@request_verb = @request.method
end
end
end

View file

@ -0,0 +1,26 @@
module RedmineGitServer
class GrackGitAdapter < Grack::GitAdapter
def command(cmd, args, io_in, io_out, dir = nil)
cmd = [git_path, cmd] + args
opts = {:err => :close}
opts[:chdir] = dir unless dir.nil?
cmd << opts
IO.popen(cmd, 'r+b') do |pipe|
while !io_in.nil? and !io_in.closed? and !io_in.eof? do
chunk = io_in.read(READ_SIZE)
pipe.write(chunk)
end
pipe.close_write
while !pipe.eof? do
chunk = pipe.read(READ_SIZE)
unless io_out.nil?
io_out.write(chunk)
end
end
end
end
end
end

View file

@ -0,0 +1,11 @@
module RedmineGitServer
class Hooks < Redmine::Hook::ViewListener
# Add our css/js on each page
def view_layouts_base_html_head(context)
tags = stylesheet_link_tag('git_server.css', plugin: 'redmine_git_server')
tags += javascript_include_tag('git_server.js', plugin: 'redmine_git_server')
end
end
end

View file

@ -0,0 +1,12 @@
require_dependency 'repositories_controller'
module RepositoriesControllerWithGitServerSupport
def show_error_not_found
return super if params[:action] != 'show'
render action: 'empty'
end
end
RepositoriesController.send(:prepend, RepositoriesControllerWithGitServerSupport)

View file

@ -0,0 +1,16 @@
require "spec_helper"
describe GitServerController, :type => :controller do
fixtures :roles, :users
before do
@request.session[:user_id] = 1 # Admin
User.current = User.find(1)
Setting.default_language = 'en'
end
it "should be tested (FIXME)" do
end
end

View file

@ -0,0 +1,8 @@
require 'spec_helper'
describe GitServerHelper, type: :helper do
it "should be tested (FIXME)" do
end
end

View file

@ -0,0 +1,4 @@
# for travis debugging
# config.logger = Logger.new(STDOUT)
# config.logger.level = Logger::INFO
# config.log_level = :info

View file

@ -0,0 +1,6 @@
test:
adapter: postgresql
encoding: unicode
pool: 5
database: travis_ci_test
user: postgres