Añade el plugin Redmine Git Hosting 5.0.0

This commit is contained in:
Manuel Cillero 2021-03-20 13:29:16 +01:00
parent cfa0d58b18
commit a3bddad233
458 changed files with 30396 additions and 1 deletions

View file

@ -0,0 +1,26 @@
production:
adapter: mysql2
database: redmine
host: 127.0.0.1
port: 3306
username: root
password:
encoding: utf8mb4
development:
adapter: mysql2
database: redmine
port: 3306
host: 127.0.0.1
username: root
password:
encoding: utf8mb4
test:
adapter: mysql2
database: redmine
port: 3306
host: 127.0.0.1
username: root
password:
encoding: utf8mb4

View file

@ -0,0 +1,23 @@
production:
adapter: postgresql
host: localhost
database: redmine
username: postgres
password: postgres
encoding: utf8
development:
adapter: postgresql
host: localhost
database: redmine
username: postgres
password: postgres
encoding: utf8
test:
adapter: postgresql
host: localhost
database: redmine
username: postgres
password: postgres
encoding: utf8

View file

@ -0,0 +1,103 @@
require 'digest/sha1'
module GitHosting
class Config
IGNORE_PARAMS = %w[redmineurl projectid debugmode asyncmode repositorykey].freeze
REDMINE_PARAMS = %w[redminegitolite.redmineurl
redminegitolite.projectid
redminegitolite.repositoryid
redminegitolite.repositorykey
redminegitolite.debugmode
redminegitolite.asyncmode].freeze
attr_reader :config
def initialize
@config = {}
load_gitolite_vars
end
def valid?
config_errors.nil?
end
def project_url
"#{redmine_url}/#{project_name}"
end
def redmine_url
config['redmineurl']
end
def project_name
config['projectid']
end
def repository_name
if config.key?('repositoryid') && !config['repositoryid'].empty?
"#{project_name}/#{config['repositoryid']}"
else
project_name
end
end
def repository_key
config['repositorykey']
end
def debug_mode?
config['debugmode'] == 'true'
end
def loglevel
if debug_mode?
'debug'
else
'info'
end
end
def post_data
post_data = {}
post_data['clear_time'] = clear_time
post_data['encoded_time'] = auth_token
config.each_key do |key|
post_data[key] = config[key] unless IGNORE_PARAMS.include?(key)
end
post_data
end
def clear_time
@clear_time ||= Time.new.utc.to_i.to_s
end
def auth_token
Digest::SHA1.hexdigest(clear_time.to_s + repository_key)
end
# Detect blank params in config.
# Allow blank repositoryid (as default).
#
def config_errors
config.detect { |k, v| k != 'repositoryid' && v == '' }
end
private
def load_gitolite_vars
REDMINE_PARAMS.each do |var_name|
var_value = get_gitolite_config(var_name)
var_name = sanitize(var_name)
@config[var_name] = var_value
end
end
def get_gitolite_config(var_name)
(%x[git config #{var_name}]).chomp.strip
end
def sanitize(var_name)
var_name.gsub(/^.*\./, '')
end
end
end

View file

@ -0,0 +1,89 @@
module GitHosting
class CustomHook
attr_reader :repo_path, :refs, :git_config
def initialize(repo_path, refs)
@repo_path = repo_path
@refs = refs
@git_config = Config.new
end
def exec
## Execute extra hooks
extra_hooks = get_extra_hooks
return if extra_hooks.nil? || extra_hooks.none?
logger.info 'Calling additional post-receive hooks...'
call_extra_hooks extra_hooks
logger.info ''
end
private
def get_extra_hooks
# Get global extra hooks
logger.debug('Looking for additional global post-receive hooks...')
global_extra_hooks = get_executables('hooks/post-receive.d')
if global_extra_hooks.empty?
logger.debug(' - No global hooks found')
else
logger.debug(" - Global hooks found : #{global_extra_hooks}")
end
logger.debug('')
# Get local extra hooks
logger.debug('Looking for additional local post-receive hooks...')
local_extra_hooks = get_executables('hooks/post-receive.local.d')
if local_extra_hooks.empty?
logger.debug(' - No local hooks found')
else
logger.debug(" - Local hooks found : #{local_extra_hooks}")
end
logger.debug('')
global_extra_hooks + local_extra_hooks
end
def get_executables(directory)
executables = []
if File.directory?(directory)
Dir.foreach(directory) do |item|
next if item == '.' || item == '..'
# Use full relative path
path = "#{directory}/#{item}"
# Test if the file is executable
if File.executable?(path)
# Remember it, if so
executables.push(path)
end
end
end
executables
end
def call_extra_hooks(extra_hooks)
# Call each exectuble found with the parameters we got
extra_hooks.each do |extra_hook|
logger.info(" - Executing extra hook '#{extra_hook}'")
IO.popen(extra_hook.to_s, 'w+') do |pipe|
begin
pipe.puts refs
pipe.close_write
logger.info pipe.read.to_s
rescue => e
logger.error "Error while executing hook #{extra_hook}"
logger.error e.message.to_s
end
end
end
end
def logger
@logger ||= GitHosting::HookLogger.new(loglevel: git_config.loglevel)
end
end
end

View file

@ -0,0 +1,29 @@
module GitHosting
class HookLogger
attr_reader :loglevel
def initialize(opts = {})
@loglevel = opts.delete(:loglevel) { 'info' }
end
def debug(message)
write(message) if loglevel == 'debug'
end
def info(message)
write(message)
end
def error(message)
write(message)
end
private
def write(message)
$stdout.sync = true
$stdout.puts "\e[1G#{message}"
$stdout.flush
end
end
end

View file

@ -0,0 +1,114 @@
require 'json'
require 'net/http'
require 'net/https'
require 'uri'
module GitHosting
module HttpHelper
def http_post(url, opts = {}, &block)
http, request = build_post_request url, opts
send_http_request http, request, &block
end
def http_get(url, opts = {}, &block)
http, request = build_get_request url, opts
send_http_request http, request, &block
end
def valid_url?(url)
uri = URI.parse url
uri.is_a?(URI::HTTP)
rescue URI::InvalidURIError
false
end
def serialize_params(params)
params.map do |key, value|
if value.instance_of?(Array)
value.map { |e| "#{urlencode(key.to_s)}=#{urlencode(e.to_s)}" }.join('&')
else
"#{urlencode(key.to_s)}=#{urlencode(value.to_s)}"
end
end.join('&')
end
private
def urlencode(string)
URI.encode(string, /[^a-zA-Z0-9_.\-]/)
end
def build_post_request(url, opts = {})
# Get params
params = opts.delete(:params) { {} }
# Build request
uri, http = build_http_request url, opts
request = Net::HTTP::Post.new uri.request_uri
# Set request
request.body = serialize_params params
request.content_type = 'application/x-www-form-urlencoded'
[http, request]
end
def build_get_request(url, opts = {})
# Get params
params = opts.delete(:params) { {} }
params = serialize_params params
# Build request
uri, http = build_http_request url, opts
request = Net::HTTP::Get.new uri.request_uri
[http, request]
end
def build_http_request(url, opts = {})
# Get HTTP options
open_timeout = opts.delete(:open_timeout) { 5 }
read_timeout = opts.delete(:read_timeout) { 10 }
uri = URI(url)
http = Net::HTTP.new(uri.host, uri.port)
if uri.scheme == 'https'
http.use_ssl = true
http.verify_mode = OpenSSL::SSL::VERIFY_NONE
end
# Set HTTP options
http.open_timeout = open_timeout
http.read_timeout = read_timeout
[uri, http]
end
def send_http_request(http, request)
if block_given?
yield(http, request)
else
one_shot_request(http, request)
end
end
def one_shot_request(http, request)
message = ''
begin
res = http.start { |openhttp| openhttp.request request }
if !res.is_a?(Net::HTTPSuccess)
message = "Return code : #{res.code} (#{res.message})."
failed = true
else
message = res.body
failed = false
end
rescue StandardError => e
message = "Exception : #{e.message}"
failed = true
end
[failed, message]
end
end
end

View file

@ -0,0 +1,61 @@
module GitHosting
class PostReceive
include HttpHelper
attr_reader :repo_path, :refs, :git_config
def initialize(repo_path, refs)
@repo_path = repo_path
@refs = refs
@git_config = Config.new
end
def exec
notify_redmine if git_config.valid?
end
private
def notify_redmine
logger.info('')
logger.info("Notifying Redmine about changes to this repository : '#{git_config.repository_name}' ...")
http_post(git_config.project_url, { params: http_post_data }) do |http, request|
begin
http.request(request) { |response| check_response(response) }
rescue => e
logger.error("HTTP_ERROR : #{e.message}")
end
end
logger.info('')
end
def http_post_data
git_config.post_data.merge('refs[]' => parsed_refs)
end
def parsed_refs
parsed = []
refs.split("\n").each do |line|
r = line.chomp.strip.split
parsed << [r[0].to_s, r[1].to_s, r[2].to_s].join(',')
end
parsed
end
def check_response(response)
if response.code.to_i == 200
response.read_body do |body_frag|
body_frag.split("\n").each { |line| logger.info(line) }
end
else
logger.error(" - Error while notifying Redmine ! (status code: #{response.code})")
end
end
def logger
@logger ||= GitHosting::HookLogger.new(loglevel: git_config.loglevel)
end
end
end

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,35 @@
#! /usr/bin/env python
import sys
import os
import git_multimail
# It is possible to modify the output templates here; e.g.:
git_multimail.FOOTER_TEMPLATE = """\
-- \n\
This email was generated by the wonderful git-multimail tool from JBox Web.
"""
# Specify which "git config" section contains the configuration for
# git-multimail:
config = git_multimail.Config('multimailhook')
# check if hook is enabled
enabled = config.get_bool('enabled')
if enabled:
# Select the type of environment:
environment = git_multimail.GitoliteEnvironment(config=config)
# Choose the method of sending emails based on the git config:
mailer = git_multimail.choose_mailer(config, environment)
# Read changes from stdin and send notification emails:
git_multimail.run_as_post_receive_hook(environment, mailer)
else:
print(" multimailhook is disabled")

View file

@ -0,0 +1,19 @@
#!/usr/bin/env ruby
# This file was placed here by Redmine Git Hosting. It makes sure that your pushed commits
# will be processed properly.
refs = ARGF.read
repo_path = Dir.pwd
require_relative 'lib/git_hosting/http_helper'
require_relative 'lib/git_hosting/hook_logger'
require_relative 'lib/git_hosting/config'
require_relative 'lib/git_hosting/post_receive'
require_relative 'lib/git_hosting/custom_hook'
if GitHosting::PostReceive.new(repo_path, refs).exec && GitHosting::CustomHook.new(repo_path, refs).exec
exit 0
else
exit 1
end

View file

@ -0,0 +1,7 @@
stdout_redirect '/home/redmine/redmine/log/puma.stderr.log', '/home/redmine/redmine/log/puma.stdout.log'
on_worker_boot do
ActiveSupport.on_load(:active_record) do
ActiveRecord::Base.establish_connection
end
end

View file

@ -0,0 +1,36 @@
#!/bin/sh
### BEGIN INIT INFO
# Provides: redmine
# Required-Start: $local_fs $remote_fs $network $mysql $named
# Required-Stop: $local_fs $remote_fs $network $mysql $named
# Default-Start: 2 3 4 5
# Default-Stop: 0 1 6
# Short-Description: Redmine projects manager
# Description: This file should be used to start and stop Redmine.
### END INIT INFO
[ -f /etc/default/rcS ] && . /etc/default/rcS
. /lib/lsb/init-functions
REDMINE_USER="redmine"
WEBSERVER="server_puma"
WORKER1="sidekiq_git_hosting"
case "$1" in
start)
su - $REDMINE_USER -c "${WEBSERVER}.sh start"
su - $REDMINE_USER -c "${WORKER1}.sh start"
;;
stop)
su - $REDMINE_USER -c "${WEBSERVER}.sh stop"
su - $REDMINE_USER -c "${WORKER1}.sh stop"
;;
restart)
su - $REDMINE_USER -c "${WEBSERVER}.sh restart"
su - $REDMINE_USER -c "${WORKER1}.sh restart"
;;
*)
echo "Usage : /etc/init.d/redmine {start|stop|restart}"
;;
esac

View file

@ -0,0 +1,75 @@
#!/bin/bash
# You should place this script in user's home bin dir like :
# /home/redmine/bin/server_puma.sh
#
# Normally the user's bin directory should be in the PATH.
# If not, add this in /home/redmine/.profile :
#
# ------------------>8
# #set PATH so it includes user's private bin if it exists
# if [ -d "$HOME/bin" ] ; then
# PATH="$HOME/bin:$PATH"
# fi
# ------------------>8
#
#
# This script *must* be run by the Redmine user so
# switch user *before* running the script :
# root$ su - redmine
#
# Then :
# redmine$ server_puma.sh start
# redmine$ server_puma.sh stop
# redmine$ server_puma.sh restart
SERVER_NAME="redmine"
RAILS_ENV="production"
REDMINE_PATH="$HOME/redmine"
CONFIG_FILE="$HOME/etc/puma.rb"
PID_FILE="$REDMINE_PATH/tmp/pids/puma.pid"
SOCK_FILE="$REDMINE_PATH/tmp/sockets/redmine.sock"
BIND_URI="unix://$SOCK_FILE"
THREADS="0:8"
WORKERS=2
function start () {
echo "Start Puma Server..."
puma --daemon --preload --bind $BIND_URI \
--environment $RAILS_ENV --dir $REDMINE_PATH \
--workers $WORKERS --threads $THREADS \
--pidfile $PID_FILE --tag $SERVER_NAME \
--config $CONFIG_FILE
echo "Done"
}
function stop () {
echo "Stop Puma Server..."
if [ -f $PID_FILE ] ; then
kill $(cat $PID_FILE) 2>/dev/null
rm -f $PID_FILE
rm -f $SOCK_FILE
fi
echo "Done"
}
case "$1" in
start)
start
;;
stop)
stop
;;
restart)
stop
start
;;
*)
echo "Usage : server_puma.sh {start|stop|restart}"
;;
esac

View file

@ -0,0 +1,169 @@
#!/bin/bash
# You should place this script in user's home bin dir like :
# /home/redmine/bin/sidekiq_git_hosting.sh
#
# Normally the user's bin directory should be in the PATH.
# If not, add this in /home/redmine/.profile :
#
# ------------------>8
# #set PATH so it includes user's private bin if it exists
# if [ -d "$HOME/bin" ] ; then
# PATH="$HOME/bin:$PATH"
# fi
# ------------------>8
#
#
# This script *must* be run by the Redmine user so
# switch user *before* running the script :
# root$ su - redmine
#
# Then :
# redmine$ sidekiq_git_hosting.sh start
# redmine$ sidekiq_git_hosting.sh stop
# redmine$ sidekiq_git_hosting.sh restart
# WORKER_NAME is used to identify the worker among the processus list
# Example : sidekiq 3.2.1 redmine_git_hosting [0 of 1 busy]
WORKER_NAME="redmine_git_hosting"
# The Rails environment, default : production
RAILS_ENV=${RAILS_ENV:-production}
# The absolute path to Redmine
REDMINE_PATH=${REDMINE_PATH:-$HOME/redmine}
# The start detection timeout
TIMEOUT=${TIMEOUT:-15}
DESC="Sidekiq worker '$WORKER_NAME'"
LOG_DIR="$REDMINE_PATH/log"
PID_DIR="$REDMINE_PATH/tmp/pids"
LOG_FILE="$LOG_DIR/worker_${WORKER_NAME}.log"
PID_FILE="$PID_DIR/worker_${WORKER_NAME}.pid"
# Do not change these values !
# See here for more details :
# https://github.com/jbox-web/redmine_git_hosting/wiki/Configuration-notes#sidekiq--concurrency
CONCURRENCY=1
QUEUE="redmine_git_hosting,1"
if [ "$RAILS_ENV" = "production" ] ; then
DAEMON_OPTS="--daemon --logfile $LOG_FILE --pidfile $PID_FILE"
else
DAEMON_OPTS=
fi
if [ ! -d $PID_DIR ] ; then
mkdir $PID_DIR
fi
RETVAL=0
################################
success() {
echo -e "\t\t[ \e[32mOK\e[0m ]"
}
failure() {
echo -e "\t\t[ \e[31mFailure\e[0m ]"
}
start () {
pid=$(get_pid)
if [ $pid -gt 1 ] ; then
echo "$DESC is already running (pid $pid)"
RETVAL=1
return $RETVAL
fi
echo -n "Starting $DESC ..."
sidekiq $DAEMON_OPTS --verbose --concurrency $CONCURRENCY \
--environment $RAILS_ENV --require $REDMINE_PATH \
--queue $QUEUE --tag $WORKER_NAME
if [ ! -z "$DAEMON_OPTS" ] ; then
for ((i=1; i<=TIMEOUT; i++)) ; do
pid=$(get_pid)
if [ $pid -gt 1 ] ; then
break
fi
echo -n '.' && sleep 1
done
echo -n " "
pid=$(get_pid)
if [ $pid -gt 1 ] ; then
success
RETVAL=0
else
failure
RETVAL=1
fi
fi
}
stop () {
echo -n "Shutting down $DESC ..."
kill $(cat $PID_FILE 2>/dev/null) >/dev/null 2>&1
RETVAL=$?
[ $RETVAL -eq 0 ] && success || failure
rm -f $PID_FILE >/dev/null 2>&1
}
status () {
# show status
pid=$(get_pid)
if [ $pid -gt 1 ] ; then
echo "$DESC is running (pid $pid)"
else
echo "$DESC is stopped"
fi
RETVAL=0
}
get_pid () {
# get status
pid=$(ps axo pid,command | grep sidekiq | grep $WORKER_NAME | awk '{print $1}')
if [ -z $pid ] ; then
rc=1
else
rc=$pid
fi
echo $rc
}
################################
case "$1" in
start)
start
;;
stop)
stop
;;
restart)
stop
sleep 1
start
;;
status)
status
;;
*)
echo "Usage: $0 {start|stop|restart|status}"
exit 1
;;
esac
exit $RETVAL