Elimina el plugin Redmine Git Hosting

Finalmente se descarta por los problemas de configuración y potencial
brecha de seguridad al requerir acceso global al puerto ssh.
This commit is contained in:
Manuel Cillero 2020-12-06 11:46:44 +01:00
parent bdd66d941f
commit 0edadcfed8
494 changed files with 0 additions and 36768 deletions

View file

@ -1,8 +0,0 @@
.*.swp
Gemfile.lock
settings.yml
/tmp
/rdoc
/coverage
/junit
custom_hooks.rb

View file

@ -1,60 +0,0 @@
require:
- rubocop-rspec
- rubocop-performance
Rails:
Enabled: true
AllCops:
TargetRubyVersion: 2.5
TargetRailsVersion: 5.2
Include:
- '**/*.ruby'
- '**/*.rake'
- '**/*.rb'
- '**/*.rsb'
- '**/Rakefile'
- '**/Gemfile'
Metrics/AbcSize:
Max: 65
Metrics/BlockLength:
Max: 60
Metrics/ClassLength:
Enabled: false
Metrics/CyclomaticComplexity:
Max: 20
Metrics/LineLength:
Max: 140
Metrics/MethodLength:
Max: 60
Metrics/ModuleLength:
Enabled: false
Metrics/PerceivedComplexity:
Max: 25
Rails/SkipsModelValidations:
Enabled: false
Rails/CreateTableWithTimestamps:
Enabled: false
# app/model/application_record.rb is missing in redmine, we can't use ApplicationRecord
Rails/ApplicationRecord:
Enabled: false
Style/FrozenStringLiteralComment:
Enabled: false
Style/AutoResourceCleanup:
Enabled: true
Style/Documentation:
Enabled: false

View file

@ -1,42 +0,0 @@
language: ruby
sudo: required
cache: bundler
rvm:
- 2.6
- 2.5
gemfile:
- Gemfile
services:
- mysql
- postgresql
env:
global:
- REDMINE_LANG=en
- MYSQL_DATABASE=redmine
- MYSQL_HOST=127.0.0.1
- MYSQL_PORT=3306
- MYSQL_USER=root
- MYSQL_PASSWORD=
- POSTGRES_DATABASE=redmine
- POSTGRES_USER=postgres
matrix:
- REDMINE_VERSION=4.0-stable DATABASE_ADAPTER=mysql USE_SVN=true
- REDMINE_VERSION=4.0-stable DATABASE_ADAPTER=postgresql USE_SVN=true
before_install:
- cd ../..
- sudo apt-get update -qq
- ./jbox-web/redmine_git_hosting/contrib/travis/install_redmine.sh
- cd redmine
- echo $(pwd)
- export BUNDLE_GEMFILE=$PWD/Gemfile
before_script:
- echo $(pwd)
- mysql -e 'create database redmine;'
- psql -c 'create database redmine;' -U postgres
- bundle exec rake generate_secret_token
- bundle exec rake db:migrate
- bundle exec rake redmine:load_default_data
- bundle exec rake redmine:plugins:migrate
- bundle exec rake db:test:prepare
script:
- bundle exec rake redmine_git_hosting:ci:all

View file

@ -1,66 +0,0 @@
Aaron Fellin <aaron@tingar.uni.cx>
Alexander Meindl <a.meindl@alphanodes.com>
allen-t <kex.allen13@gmail.com>
Andrea Piccinelli <frasten@gmail.com>
Boris Bera <Boris.Bera@wolterskluwer.com>
bullshit <oskar@biglan.at>
ciaranj <ciaranj@gmail.com>
Clemens Hammacher <hammacher@cs.uni-saarland.de>
crocket <crockabiscuit@gmail.com>
Daniel Dehennin <daniel.dehennin@baby-gnu.org>
Daniel Stoeckel <dstoeckel@bioinf.uni-sb.de>
danomatika <danomatika@gmail.com>
David Cramer <dcramer@gmail.com>
DFYX <dfyx@wecallit42.de>
Eric Bishop <ericpaulbishop@gmail.com>
Evgeny Generalov <e.generalov@gmail.com>
Federico Ramallo <framallo@gmail.com>
fjuan <fjuan@splendeo.es>
Gartz <gabriel@intuicom.com.br>
Geoffroy Desvernay <dgeo@centrale-marseille.fr>
Greg Cymbalski <cymbalski@gmail.com>
Greg Thornton <xdissent@gmail.com>
hboyet <hugo.david-boyet@savoirfairelinux.com>
IceArmy <roejames12@hotmail.com>
Jan Schulz-Hofen <yeah@yeahrock.de>
Jean-Sébastien Bour <jsb@zenexity.com>
John Axel Eriksson <john@insane.se>
John Kubiatowicz <kubitron@cs.berkeley.edu>
Joshua Hogendorn <jhogendorn@gmail.com>
Kovalev Vladimir <kovalev@em.mos.ru>
Ludovic Schoepps <ludovic.schoepps@gmail.com>
Lukas Mika <lukas.mika@web.de>
Marco Nenciarini <marco.nenciarini@devise.it>
Mario Werner <m.werner@student.tugraz.at>
Mathieu Marache <mathieu@marache.com>
Matthew Meng <Matthew@Lorraine.local>
Matt Meng <maximusstrife@gmail.com>
nicesw123 <nicesw123@users.noreply.github.com>
Nicholas Clark <nick4jesus@gmail.com>
Nicolas Rodriguez <nrodriguez@jbox-web.com>
Nils Rokita <0rokita@informatik.uni-hamburg.de>
Patrick Naubert <patrickn@xelerance.com>
Patrick Roberts <Patrick@silentbluesystems.com>
Pedro Algarvio <pedro@algarvio.me>
Petter Uvesten <petter@everichon.com>
Philip Schiffer <philip.schiffer@gmail.com>
Rocket Rentals <contact@rocket-rentals.de>
root <root@cori-celesti.org>
root <root@hanzo.(none)>
rposborne <russosborn@gmail.com>
Ryan Thompson <rct@thompsonclan.org>
Sebastian Harl <sh@teamix.net>
Simon Peeters <peeters.simon@gmail.com>
Slotos <slotos@gmail.com>
Soeren Helbig <soerenhelbig@gmail.com>
Strnadj <jan.strnadek@gmail.com>
takahashim <maki@rubycolor.org>
Thomas Debesse <thomas.debesse@rcf.fr>
Tom Kazimiers <tom@voodoo-arts.net>
U-catsby\oddpoet <oddpoet@catsby.(none)>
Untoldwind <landru@untoldwind.net>
Warren Volz <warren@warrenvolz.com>
wilsoc5 <wilsoc5@users.noreply.github.com>
Yarema <yds@CoolRat.org>
Yunsang Choi <oddpoet@gmail.com>
Zsolt Parragi <dutow@mentalstatic.info>

View file

@ -1,585 +0,0 @@
## CHANGELOG
### 4.0.0
* compatible with Redmine 4 (drop Redmine 3.x support)
* drop redmine_bootstrap_kit required plugin
* requires additionals plugin for latest fontawesome, slim and deface support -> and better maintenance
* switch from haml to slim templates (because this is already used in additionals plugin)
* libraries high_charts and bootstrap are moved to this plugin (TODO: high_charts should be migrationed to charts.js, which comes with Redmine 4. Bootstrap should be drop to vanila redmine, to get better theme support)
### 1.2.3 - 2017-07-17
* Merge [#640](https://github.com/jbox-web/redmine_git_hosting/pull/640) ([Views] Fix typo while rendering partial repositories/download_revision)
* Merge [#646](https://github.com/jbox-web/redmine_git_hosting/pull/646) (Fix compatibility with Redmine 3.3)
* Merge [#663](https://github.com/jbox-web/redmine_git_hosting/pull/663) ([Core] Fix installation of Gitolite3 hooks)
* Improve custom Gitolite hook loading (see `custom_hooks.rb.example` at the root of the project)
* Fix plugin icon with Redmine 3.4.x
* Fix author url in sub-uri mode
* Check if hook's permissions has changed
* Catch Errno::ENOENT exceptions when installing custom hooks
* Add logs for well installed Gitolite hooks
### 1.2.2 - 2016-12-31
* Fix [#472](https://github.com/jbox-web/redmine_git_hosting/issues/472) ([Views] 404 on the "My public keys" link in the user panel)
* Fix [#526](https://github.com/jbox-web/redmine_git_hosting/issues/526) ([Core] Plugin breaks if gitolite user == redmine user)
* Fix [#551](https://github.com/jbox-web/redmine_git_hosting/issues/551) ([Core] Make Sidekiq truly optional)
* Fix [#576](https://github.com/jbox-web/redmine_git_hosting/issues/576) ([Models] Can't add Git Config Key)
* Fix [#630](https://github.com/jbox-web/redmine_git_hosting/issues/630) ([Core] Use "gitolite query-rc" to get Gitolite variables)
* Fix [#632](https://github.com/jbox-web/redmine_git_hosting/issues/632) ([Core] Mirroring does not work on git push)
* Merge [#581](https://github.com/jbox-web/redmine_git_hosting/pull/581) (Fix [#472](https://github.com/jbox-web/redmine_git_hosting/issues/472) by amelentjev)
* Merge [#621](https://github.com/jbox-web/redmine_git_hosting/pull/621) ([Routes] Mount grack under http_server_subdir)
* Merge [#624](https://github.com/jbox-web/redmine_git_hosting/pull/624) ([Translations] Add Spanish translation)
* Merge [#634](https://github.com/jbox-web/redmine_git_hosting/pull/634) ([Views] Added missing mandatory param for partial repositories/download_revision)
* Merge [#636](https://github.com/jbox-web/redmine_git_hosting/pull/636) ([Doc] "Remove user ID from Gitolite identifier" requires a restart)
* Fix repo url in Gitolite hooks
* Fix nil data case when loading custom settings from empty file
* Allow to load plugin settings from a file in Redmine root (should ease deployment and upgrades)
* Fix wrong Repository Git objects count
* Add Russian translation
* Rename `redmine_git_hosting:restore_defaults` task to `redmine_git_hosting:update_settings`
* Add Rake task `redmine_git_hosting:dump_settings` to dump plugin settings in console
### 1.2.1 - 2016-07-25
* Fix [#524](https://github.com/jbox-web/redmine_git_hosting/issues/524) ([DB] Index too long)
* Fix [#533](https://github.com/jbox-web/redmine_git_hosting/issues/533) ([Views] About readme.md preview feature)
* Fix [#541](https://github.com/jbox-web/redmine_git_hosting/issues/541) ([Core] SSH/Gitolite server host on 1.2)
* Fix [#553](https://github.com/jbox-web/redmine_git_hosting/issues/553) ([Controllers] Protected branches user list never updated. Mass-assign warning.)
* Fix [#569](https://github.com/jbox-web/redmine_git_hosting/issues/569) ([Core] Connection refused when sshd doesn't listen on default port)
* Merge [#583](https://github.com/jbox-web/redmine_git_hosting/pull/583) ([Core] force UTF-8 encoding for tags and branches)
* Merge [#600](https://github.com/jbox-web/redmine_git_hosting/pull/600) ([Core] Improve performance)
### 1.2.0 - 2015-11-18
* Enhance protected branches permissions support : [#389](https://github.com/jbox-web/redmine_git_hosting/issues/389), [#414](https://github.com/jbox-web/redmine_git_hosting/issues/414)
* Add support for [Gitolite options](https://gitolite.com/gitolite/options.html) : [#415](https://github.com/jbox-web/redmine_git_hosting/issues/415)
* Enhance global repository access : [#465](https://github.com/jbox-web/redmine_git_hosting/issues/465). You can now choose if Redmine has RW access on all repositories.
* Improve validation of plugin settings. Validation errors are now displayed in the view.
* Use our own Rack implementation to render Gitolite hooks
* Fix [push over HTTP](http://redmine-git-hosting.io/troubleshooting/#hook-errors-while-pushing-over-https)
* Cleanup code/API
* Improve coding style
* Display contributors in plugins info page ;)
### 1.1.5 - 2015-11-18
* Fix wrong behavior of GoRedirectorController when project is private
* Update Redcarpet to latest version (3.3.2)
### 1.1.4 - 2015-10-01
* Merge [#505](https://github.com/jbox-web/redmine_git_hosting/pull/505) ([Core] Added an error message in case that something as broken the temp directory)
* Fix #<TypeError: no implicit conversion of nil into String> when triggers are enabled on PostReceiveUrls and pushing on a non-triggering branch
* Fix #<TypeError: no implicit conversion of nil into String> when triggers (refspec) are enabled on RepositoryMirrors and pushing on a non-triggering branch
### 1.1.3 - 2015-08-30
* Merge [#350](https://github.com/jbox-web/redmine_git_hosting/pull/350) ([Core] return [] if error occured on branches or tags check)
* Fix [#472](https://github.com/jbox-web/redmine_git_hosting/issues/472) ([Views] 404 on the "My public keys" link in the user panel when Redmine is installed in a subpath)
* Fix [#484](https://github.com/jbox-web/redmine_git_hosting/issues/484) ([Core] Error 500 on repository creation & edit)
* Fix [#501](https://github.com/jbox-web/redmine_git_hosting/issues/501) ([Controllers] Download Git Revision Archive for Anonymous user redirect to login page)
* Fix [#502](https://github.com/jbox-web/redmine_git_hosting/issues/502) ([Core] Issues with Git 1.7.1)
### 1.1.2 - 2015-08-21
* Fix [#459](https://github.com/jbox-web/redmine_git_hosting/issues/459) ([Install] Undefined method `urls_order' for #RepositoryGitExtra during migrations)
* Merge [#491](https://github.com/jbox-web/redmine_git_hosting/pull/491) ([Views] Fix css spacer bug for compatibility with core css)
### 1.1.1 - 2015-06-29
* Display Rugged infos in Config test tab
* Display Rugged features status (present/absent) in Config test tab
* Bump gitolite-rugged to v1.1.1 (Use HTTPs instead of Git protocol to download rugged gem)
* Add [#464](https://github.com/jbox-web/redmine_git_hosting/pull/464) ([Views] Fix display of git_annex urls)
* Add [#466](https://github.com/jbox-web/redmine_git_hosting/pull/466) ([Core] In case of git command failure, log the actual command line)
### 1.1.0 - 2015-06-06
* Add [#417](https://github.com/jbox-web/redmine_git_hosting/issues/417) ([Views] Define order of repository urls)
* Add [#426](https://github.com/jbox-web/redmine_git_hosting/issues/426) ([Views] Direct link to repository settings page on sidebar)
* Add [#427](https://github.com/jbox-web/redmine_git_hosting/issues/427) ([Views] Back to settings/repositories on repositories/edit page)
* Add [#431](https://github.com/jbox-web/redmine_git_hosting/issues/431) ([Core] Add support for Redmine/Gitolite splitted configuration)
* Add ```resync_ssh_keys``` Rake command (thx Hugodby)
* Use ```Etc``` Ruby module to find out Gitolite user home dir (instead of doing ```eval``` with sudo)
* Rework mirroring key installation
* Flush internal cached variables when settings change
* Add a jump box to switch repositories in edit view
* Fix RepositoryMirror regex (allow dashes in user name part)
* Bump gitolite-rugged to v1.1.0 (bundled with rugged and libgit2 in version 0.22.2)
* Remove temp directory when Gitolite settings change (it will be recloned with the right settings)
* Add 'Move repository' feature : you can now move repositories accross projects
* Add unique index on fingerprint field
* Various small fixes
### 1.0.7 - 2015-06-06
* Fix [#450](https://github.com/jbox-web/redmine_git_hosting/issues/450) (Github webhook return 404 error)
* Display Rugged infos in Config test tab
### 1.0.6 - 2015-06-04
* Validate that people don't reuse Gitolite Admin key
### 1.0.5 - 2015-05-31
* Fix [#418](https://github.com/jbox-web/redmine_git_hosting/issues/418) ([Rugged] On delete deploy key: Rugged::NetworkError)
* Fix [#430](https://github.com/jbox-web/redmine_git_hosting/issues/430) ([User] Error when trying to update user details)
### 1.0.4 - 2015-04-10
* Fix [#404](https://github.com/jbox-web/redmine_git_hosting/issues/404) ([Git cache] "Until next commit" param is broken for Redis adapter)
* Fix [#406](https://github.com/jbox-web/redmine_git_hosting/issues/406) ([Protected Branch] Protected Branch Name Must be Unique Across Projects)
* Fix [#407](https://github.com/jbox-web/redmine_git_hosting/issues/407) ([Protected Branch] 500 Error rearranging protected branches)
* Fix [#413](https://github.com/jbox-web/redmine_git_hosting/issues/413) ([Repository view] Missing repo source in repo instructions)
* Add [#410](https://github.com/jbox-web/redmine_git_hosting/issues/410) ([Protected Branch] Gray protected branches if not enabled by repo flag)
### 1.0.3 - 2015-04-01
* Fix [#322](https://github.com/jbox-web/redmine_git_hosting/issues/322) ([Statistics view] PG::GroupingError: ERROR: column "changesets.id" must appear in the GROUP BY clause)
* Fix [#334](https://github.com/jbox-web/redmine_git_hosting/issues/334) ([Translations] English locale file still contains French messages)
* Fix [#383](https://github.com/jbox-web/redmine_git_hosting/issues/383) ([Statistics view] Mysql2::Error: Unknown column 'changes.commit_date' in 'order clause')
* Fix [#384](https://github.com/jbox-web/redmine_git_hosting/issues/384) (```rake redmine_git_hosting:fetch_changesets``` doesn't clear cache)
* Fix [#385](https://github.com/jbox-web/redmine_git_hosting/issues/385) ([Statistics view] Commits and changes lines are shifted)
* Fix [#401](https://github.com/jbox-web/redmine_git_hosting/issues/401) ([Git cache] "Until next commit" param is broken)
* DRY controllers
* Improve permissions checking
* Improve tests on controllers
* DRY views
* Rework Repository URLs rendering
* Extract some views helpers to Redmine Bootstrap Kit plugin
* Fix TagIt loading for ProtectedBranches
* Add the '@all' repository in ```gitolite.conf``` when auto create README file is enabled (from [#338](https://github.com/jbox-web/redmine_git_hosting/issues/338))
* Remove useless ```:gitolite_log_split``` params
* Improve GitCache lookup performance (for Database and Redis adapters)
* Improve Statistics rendering performance
* Test the plugin with Redmine latest stable branch to prevent/anticipate [this kind of bug](https://github.com/jbox-web/redmine_git_hosting/issues/387)
* Update install doc
* Update migration doc
**Notes :**
* Before update Redmine Git Hosting plugin you **must** update Redmine Bootstrap Kit plugin to version **0.2.3** :
```sh
# Update Redmine Bootstrap Kit
redmine$ cd REDMINE_ROOT/plugins/redmine_bootstrap_kit
redmine$ git fetch -p
redmine$ git checkout 0.2.3
# Cleanup plugins assets dir
redmine$ cd REDMINE_ROOT/public/plugin_assets
redmine$ rm -rf *
```
* Deployment keys permissions has been renamed (from ```*_deployment_keys``` to ```*_repository_deployment_credentials```) so you will have to restore these permissions in *Administration -> Roles*.
### 1.0.2 - 2015-03-14
* Merge [#348](https://github.com/jbox-web/redmine_git_hosting/pull/348) (Use Redmine setting for Git command)
* Fix [#345](https://github.com/jbox-web/redmine_git_hosting/issues/345) (HTTPS Push, Popen : wrong number of arguments, Ruby 1.9 compatibility)
* Fix [#351](https://github.com/jbox-web/redmine_git_hosting/issues/351) (undefined method `split' for nil:NilClass)
* Fix [#354](https://github.com/jbox-web/redmine_git_hosting/issues/354) (Input string is longer than NAMEDATALEN / index too long)
* Fix [#358](https://github.com/jbox-web/redmine_git_hosting/issues/358) (undefined method `join' for nil:NilClass)
* Fix [#364](https://github.com/jbox-web/redmine_git_hosting/issues/364) (Gitolite hook silently fails on HTTP redirect)
* Fix [#368](https://github.com/jbox-web/redmine_git_hosting/issues/368) ("My public keys" link is still missing the subpath)
* Fix [#375](https://github.com/jbox-web/redmine_git_hosting/issues/375) (SmartHTTP link is not properly generated when Redmine is installed in a sub-path)
* Fix [#377](https://github.com/jbox-web/redmine_git_hosting/issues/377) ("Git user is able to sudo to Redmine user?" fails with non-login shell)
* Fix "undefined method `identifier' for nil:NilClass" when migrating to v1
* Add Redmine 3.x compatibility
* Update Redmine installer script for Travis builds
* Use Redmine Bootstrap Kit - TagIt helper
* Use Redmine Bootstrap Kit - BootstrapSwitch helper
**Notes :**
* Depending on your Redmine version (2.x/3.x) you'll have to comment/uncomment the right lines in the plugin's ```Gemfile```
* Before update Redmine Git Hosting plugin you **must** update Redmine Bootstrap Kit plugin to version **0.2.2** :
```sh
# Update Redmine Bootstrap Kit
redmine$ cd REDMINE_ROOT/plugins/redmine_bootstrap_kit
redmine$ git fetch -p
redmine$ git checkout 0.2.2
# Cleanup plugins assets dir
redmine$ cd REDMINE_ROOT/public/plugin_assets
redmine$ rm -rf *
```
* Since [support of Ruby 1.9.x has ended](https://www.ruby-lang.org/en/news/2014/01/10/ruby-1-9-3-will-end-on-2015/), **we won't support Ruby 1.9.x anymore**.
We highly recommend that you upgrade to Ruby 2.1 or 2.0.0 as soon as possible.
### 1.0.1 - 2015-02-23
* Fix archive name in DownloadGitRevision
* Fix [#331](https://github.com/jbox-web/redmine_git_hosting/issues/331) (Internal Server Error on user details)
* Fix [#335](https://github.com/jbox-web/redmine_git_hosting/issues/335) (gitolite-rugged can handle subdirectories for config file, just pass them)
* Fix [#336](https://github.com/jbox-web/redmine_git_hosting/issues/336) (TypeError no implicit conversion of nil into Array, fix 404/500 errors in repository views)
* Fix [#340](https://github.com/jbox-web/redmine_git_hosting/issues/340) (Invalid public key link)
* Fix [#344](https://github.com/jbox-web/redmine_git_hosting/issues/344) (Add a warning if Repository::Xitolite is disabled on repository auto-create)
* Add link to repositories in Project overview
### 1.0.0 - 2015-01-26
This new version is the first one of the v1.0 branch!
For this version the major part of the code has be rewritten to be cleaner and easier to debug.
It also brings some new features and fixes a lot of bugs.
There are some major changes that should solve a lot of issues :
* The plugin doesn't override ```Repository::Git``` object anymore. Instead it introduces a new type of repository in Redmine : ```Gitolite``` repositories.
That means that you can have standard Redmine Git repositories as before and Gitolite repositories in the **same time**.
*Note that only Gitolite repositories have advanced features (mirrors, post urls, etc...).*
* The second major change concerns the Storage strategy already discussed [here](https://github.com/jbox-web/redmine_git_hosting/issues/199).
```unique_repo_identifier``` and ```hierarchical_organisation``` are now combined in a single param : ```hierarchical_organisation```.
* And finally the third major change is the switch to [gitolite-rugged](https://github.com/oliverguenther/gitolite-rugged) thanks to Oliver Günther.
**Changes :**
* Big refactoring of GitoliteWrapper (thanks Oliver Günther)
* Switch to Gitlab Grack to provide Git SmartHTTP feature
* Add SSH key fingerprint field in database
**New features :**
* Export developer public ssh keys in Redmine REST API
* Export repository extras (mirrors, post receive urls, etc...) in Redmine REST API
* Add "go get" support for GoLang
* GitolitePlugins Sweepers and Extenders : to execute some actions after repository create/update/delete
* new GitCache adapters : Memcached and Redis (faster than the current database adapter)
* GitoliteHooks DSL to install your own Gitolite hooks globally
* Support for GitAnnex repositories
* [Support for branch permission / protected branches](https://github.com/jbox-web/redmine_git_hosting/issues/86)
* Add rake tasks for a fully automated install [#303](https://github.com/jbox-web/redmine_git_hosting/issues/303)
**Fixes :**
* Hooks URL should be configurable
* Fix [#223](https://github.com/jbox-web/redmine_git_hosting/pull/223) (fix https:// notifications if TLSvX is mandatory)
* Fix [#240](https://github.com/jbox-web/redmine_git_hosting/issues/240) (Allow modification of the gitolite-admin repository from a different location)
* Fix [#286](https://github.com/jbox-web/redmine_git_hosting/issues/286) (Link to "my public keys" is shown even if right is not granted)
* Fix [#310](https://github.com/jbox-web/redmine_git_hosting/issues/310) (compatibility with redmine_scm_creator plugin)
* Fix [#311](https://github.com/jbox-web/redmine_git_hosting/issues/311) (mirror repository URLs should permit dots in repository path)
* Purge RecycleBin on fetch_changesets ([Configuration notes]({{ site.baseurl }}/configuration/notes/#empty-recycle-bin-periodically))
**Other :**
* Bump to last version of Git Multimail hook
* Bump ZeroClipboard to version v2.1.1
* Bump Highcharts to version 4.0.3
**Notes :**
Thanks to the work of Oliver Günther (really thank you), the plugin is now a lot more simple in many ways :
* the plugin is scriptless : no more need of ```gitolite_scripts_dir``` and shell scripts to wrap calls to sudo. Now, the only required dir is the ```gitolite_temp_dir``` to clone the Gitolite admin repository.
* SSH keys are stored in Gitolite in a directory tree under ```ssh_keys```. No more need of timestamped key name :)
Example :
```sh
gitolite-admin.git/
├── conf
│ └── gitolite.conf
└── keydir
├── redmine_git_hosting
│ ├── redmine_admin_1
│ │ └── redmine_my_key
│ │ └── redmine_admin_1.pub
│ └── redmine_admin_1_deploy_key_1
│ └── redmine_deploy_key_1
│ └── redmine_admin_1_deploy_key_1.pub
└── redmine_gitolite_admin_id_rsa.pub
```
### 0.7.10 - 2015-01-26
* Fix [#324](https://github.com/jbox-web/redmine_git_hosting/issues/324) (Unable to flag repository as Main)
* Fix [#326](https://github.com/jbox-web/redmine_git_hosting/issues/326) (Error occurred while loading the routes definition)
* Fix [#329](https://github.com/jbox-web/redmine_git_hosting/issues/329) ("internal Error" when trying to edit a newly created repo)
**Notes :**
**Important !**
This is the last version of the v0.7 branch. **There won't be new releases under this branch**.
That means that everyone should migrate to the new 1.0 version :)
**Important !**
Before migrating to the new 1.0 you **MUST** migrate to this version (0.7.10).
It includes a Rake task that prepare the migration to 1.0, so **don't miss that step!**
### 0.7.9 - 2014-12-29
* Fix [#218](https://github.com/jbox-web/redmine_git_hosting/issues/218) (I18n warnings)
* Fix [#288](https://github.com/jbox-web/redmine_git_hosting/issues/288) (wrong deployment key identifier attribution that may lead to a security issue)
* Fix [#317](https://github.com/jbox-web/redmine_git_hosting/issues/317) (inconsistent url's of hierarchical repositories in sub-projects)
* gitolite-admin is a forbiden repository identifier
* Fix ActiveRecord translations
* Better handling of errors on git commit
* Add Rake task to prepare migration to V1.0
### 0.7.8 - 2014-11-08
* Fix collision in method name with Redmine Jenkins Plugin
* Backport patch from [pull #266](https://github.com/jbox-web/redmine_git_hosting/pull/266)
* Fix [#246](https://github.com/jbox-web/redmine_git_hosting/issues/246) (init.rb - config values not taken)
* Fix [#258](https://github.com/jbox-web/redmine_git_hosting/issues/258) (wrong hook installation place on gitolite 3.x)
* Fix [#289](https://github.com/jbox-web/redmine_git_hosting/issues/289) (url to wiki goes nowhere)
**Notes :**
**Important !**
As explained in [Gitolite documentation](https://gitolite.com/gitolite/non-core.html#localcode) hooks should be installed in a separate directory.
This new version fixes Gitolite hooks install path for Gitolite v3.
Hooks are now stored by default in ```<gitolite user home dir>/local```. You can override this in the plugin settings.
Note that the directory must be **a relative path** to the Gitolite user home directory.
You'll also have to update your ```.gitolite.rc``` accordingly :
LOCAL_CODE => "$ENV{HOME}/local"
### 0.7.7 - 2014-09-10
* Merge [#259](https://github.com/jbox-web/redmine_git_hosting/pull/259) (Some (very old) repositories have been indentified as empty)
* Merge [#223](https://github.com/jbox-web/redmine_git_hosting/pull/223) (Fix https:// notifications if TLSvX is mandatory #223)
* Bump to jbox-gitolite 1.2.6 which depends on [gitlab-grit 2.7.1](https://github.com/gitlabhq/grit/blob/master/History.txt)
**Notes :**
Until this version, the plugin silently failed when pushing data to Gitolite Admin. Now when an error happens on push, you should get this in the log :
```sh
2014-09-10 19:02:25 +0200 INFO [GitHosting] User 'admin' created a new repository 'test/blof'
2014-09-10 19:02:25 +0200 INFO [GitWorker] Using Gitolite configuration file : 'gitolite.conf'
2014-09-10 19:02:26 +0200 INFO [GitWorker] add_repository : repository 'test/blof' does not exist in Gitolite, create it ...
2014-09-10 19:02:26 +0200 INFO [GitWorker] add_repository : commiting to Gitolite...
2014-09-10 19:02:26 +0200 INFO [GitWorker] add_repository : let Gitolite create empty repository 'repositories/test/blof.git'
2014-09-10 19:02:26 +0200 INFO [GitWorker] add_repository : pushing to Gitolite...
2014-09-10 19:02:26 +0200 ERROR [GitWorker] Command failed [1]: /usr/bin/git --git-dir=/tmp/redmine_git_hosting/git/gitolite-admin.git/.git --work-tree=/tmp/redmine_git_hosting/git/gitolite-admin.git push origin master
[GitWorker]
[GitWorker]To ssh://git@localhost:22/gitolite-admin.git
[GitWorker] ! [rejected] master -> master (fetch first)
[GitWorker]error: failed to push some refs to 'ssh://git@localhost:22/gitolite-admin.git'
[GitWorker]hint: Updates were rejected because the remote contains work that you do
[GitWorker]hint: not have locally. This is usually caused by another repository pushing
[GitWorker]hint: to the same ref. You may want to first integrate the remote changes
[GitWorker]hint: (e.g., 'git pull ...') before pushing again.
[GitWorker]hint: See the 'Note about fast-forwards' in 'git push --help' for details.
[GitWorker]
```
### 0.7.6 - 2014-07-17
* Bump to jbox-gitolite 1.2.3 which depends on [gitlab-grit 2.7.0](https://github.com/gitlabhq/grit/blob/master/History.txt)
* Fix [#207](https://github.com/jbox-web/redmine_git_hosting/issues/207) (gitolite-admin does not sync anymore) and his brothers
### 0.7.5 - 2014-07-14
* Fix [#226](https://github.com/jbox-web/redmine_git_hosting/issues/226) (unable to download revision if branch has a '/' in the name)
* Fix [#230](https://github.com/jbox-web/redmine_git_hosting/issues/230) (Unwanted access to gitolite-admin repository)
### 0.7.4 - 2014-07-04
* Fix [#184](https://github.com/jbox-web/redmine_git_hosting/issues/184 ) (truncated Bootstrap Switches)
* Fix [#211](https://github.com/jbox-web/redmine_git_hosting/issues/211) (mixed up dates in contributors statistics graph)
* Fix [#215](https://github.com/jbox-web/redmine_git_hosting/issues/215) (application.css conflicts)
* Fix [#225](https://github.com/jbox-web/redmine_git_hosting/issues/225) (unable to set new repository deployment credentials)
* Set extra_info field when auto-creating repo with project
### 0.7.3 - 2014-06-11
* Fix [#144](https://github.com/jbox-web/redmine_git_hosting/issues/144) (redcarpet dependency)
* Bump to jbox-gitolite 1.2.2
* Fix files changements in Github payload (files added, deleted, modified)
* Use repository name in Github payload
* Add pusher informations in Github payload
* Show Redmine fields in repository/edit
* Fix [#186](https://github.com/jbox-web/redmine_git_hosting/issues/186) (post-receive doesn't pass multiple lines through from STDIN)
* Fetch changesets after repository creation/restore
* Fix repository content overwrite on repo creation with README file and repository not empty
**Notes :**
You're invited to take a look at this [post](https://github.com/jbox-web/redmine_git_hosting/issues/199).
### 0.7.2 - 2014-04-16
* Fix [#160](https://github.com/jbox-web/redmine_git_hosting/issues/160)
* Fix [#169](https://github.com/jbox-web/redmine_git_hosting/issues/169)
### 0.7.1 - 2014-04-14
* Remove ENV['HOME'] dependency
* Remove Git config file dependency
* Remove SSH config file dependency
* Fix log redirection on Automatic Repository Initialization
* Fix plugin portability (use env instead of export)
* Fix layout bug in header navigation ([#162](https://github.com/jbox-web/redmine_git_hosting/pull/162)) (thanks soeren-helbig)
* Fix projects update on locking/unlocking user
* Various small fixes
* Use last version of [jbox-gitolite](http://rubygems.org/gems/jbox-gitolite) gem (1.1.11)
### 0.7.0 - 2014-04-02
* remove Redmine 1.x support
* remove Rails 2.x support
* remove Ruby 1.8.x support
* replace Rails Observers by Active Record Callbacks
* replace 'Gitolite home made interface' by Gitolite gem (https://github.com/jbox-web/gitolite)
* lots of code cleanup
* lots of bug fixes
* add [Sidekiq async jobs]({{ site.baseurl }}/features/#sidekiq-asynchronous-jobs)
* add [Git mailing lists]({{ site.baseurl }}/features/#git-mailing-lists)
* add [Default branch selection]({{ site.baseurl }}/features/#default-branch-selection)
* add [Automatic Repository Initialization]({{ site.baseurl }}/features/#automatic-repository-initialization)
* add [Git Revision Download]({{ site.baseurl }}/features/#git-revision-download)
* add [README preview]({{ site.baseurl }}/features/#readme-preview)
* add [Repository “config” keys management]({{ site.baseurl }}/features/#git-config-keys-management)
* add [Improved Repository Statistics]({{ site.baseurl }}/features/#improved-repository-statistics)
* add [Github Issues Sync]({{ site.baseurl }}/features/#github-issues-sync)
* add [Browse Archived Repositories]({{ site.baseurl }}/features/#browse-archived-repositories)
* add Bootstrap CSS
* add Font Awesome icons
### 0.6.3 - 2014-02-23
This is a bugfix release.
This is the last release of the 0.6.x branch.
The 'v0.6' is kept as archive and will be no longer supported.
### 0.6.2 - 2013-07-29
This is a security and bugfix release.
This releases fixes a high risk vulnerability, allowing an attacker to gain shell access to the server (CVE-2013-4663).
We strongly advise you to update your plugin!
### 0.6.1 - 2013-04-05
This is a bugfix release.
### 0.6.0 - 2013-03-25
This is a compatibility release.
The plugin is now compatible with Redmine 2.x (and Redmine 1.x).
### 0.5.2 - 2012-12-25
This is a bug-fix release.
* Fixed a migration problem with PostGreSQL (for uninstalling).
* Fix to allow validations to fail properly on Project creation for Redmine < 1.4
* Fix to prevent repository creation from stealing preexisting repositories in gitolite (which could happen under specialized circumstances).
* Fix to handle old versions of sudo (< 1.7.3) during repair of the administrative key
* Fix to preserve other administrative keys in the gitolite configuration file. Previously, the plugin would delete all but the first one. This fix is useful for people who want to have separate administrative keys for access to the gitolite config file.
* Fixed weird behavior on Repository page when using multiple repos/project. Showed up when on non-default repo when trying to switch to branch other than master. Would switch back to default repository.
### 0.5.1 - 2012-10-31
This is a bug-fix release.
* Post-Receive URLs should now work with SSL (i.e. URLs of the form "https://xxx")
* Additional patches for backward compatibility with ChiliProject/Redmine < 1.4. In this category was a problem with editing Git repo parameters as well as a minor bug that caused problems with adding members to projects that didn't have a Git repo.
* Additional patches to support Ruby 1.9.x. Includes fix to post-receive hook and change in meaning of Module#instance_methods.
* Patched installation so that can install Redmine from *scratch* (i.e. run `rake db:migrate` on empty DB) with plugin already in place.
* Latest migration should now work with PostGreSQL. This was broken in 0.5.0x.
### 0.5.0 - 2012-10-03
This is a feature release.
* New : Compatibility with Redmine 1.4
* Fix : Uninstall of plugin should work properly now.
* Fix : Problems with patching on some installations should be fixed now (introduced in a recent revision).
### 0.4.6 - 2012-08-22
This is a feature release.
* New: Added Deployment Credentials, which are public keys associated directly with a repository rather
than through a user. These credentials can be created directly from the repository settings page. Since
they are named (like other public keys), they can be reused for other repositories, if desired. Note
that only **managers** (or **administrators**) can create deployment credentials (or deployment keys). Further, deployment keys and credentials are owned by the original creator and appear in their "my account" page.
* New : Key validation and uniqueness. The format, properties, and uniqueness of keys are validated before allowing them to be saved. Note that actual keys must be unique across a whole gitolite installation (otherwise the access control mechanism doesn't work). At the moment, this validation allows keys of type "ssh-rsa" and "ssh-dss".
* New : Ability to utilize alternate gitolite configuration file.
* New : handle archiving of projects. Archived projects stay in the gitolite repository but are deactivated in the gitolite config file. All Redmine keys are removed and replaced with a token key called "redmine_archived_project".
* New : Post-receive URLs configured from a repository settings page. When commits occur, configured URLs will be POSTed with json information about the commit, roughly in the same format as github commits. The POSTed payload is described here: http://help.github.com/post-receive-hooks/.
* New : Repository mirrors have more configuration options. Rather than forcing the remote repository to be a complete mirror of the local repository (i.e. --mirror), repository mirrors can now specific an explicit reference specification for which branches to update and/or select whether to force update or require nothing more than a fast-forward.
* Fix : Change in login name on User settings screen properly changes keys in keydir.
* Fix : Fixed cases in which delete of user from project ACL and delete of user didn't clean up gitolite.conf
* Fix : Fixed problem with failed validation in user settings screen.
* Fix : Remove extra control characters (such as line breaks) as well as leading and trailing whitespace in public keys
* Fix : Validations for public keys now reflected back to the user interface.
* Fix : Deselection of repository module now has same effect as archiving project. The repository is marked in gitolite.conf as "redmine_disabled_project". When project repository module is re-enabled, the repository is reconnected automatically.
Prior to this, repository module deselection was treated inconsistently.
### 0.4.5 - 2012-04-23
* Fixed missed case for compatibility with Redmine 1.1-Stable. This patch allows the mirror functionality to work.
* Fixed bad interaction between cron cleanup of /tmp and access to gitolite-admin repository in /tmp. Behavior could cause user keys to appear to be deleted, even though they remain in the redmine database. This behavior has likely been a part of this plugin since before this branch was forked (pre 0.4.2).
### 0.4.4 - 2012-04-01
This release includes feature enhancements and bug fixes.
Compatibility with Redmine 1.1-Stable. A couple of patches were included to permit this plugin to work with older Redmine releases.
* New settings to configure the /tmp and /bin directories (**gitTemporaryDir** and **gitScriptDir** respectively).
* New settings for the default "Daemon Mode" (**gitDaemonDefault**), "SmartHTTP mode" (**gitHttpDefault**), and "Notify CIA mode" (**gitNotifyCIADefault**) for new repositories.
* Better script support for installing scripts in the /bin directory.
* Updated installation instructions in the README.
* Better recovery from loss of administrative key in gitolite -- assuming use of gitolite version >= 2.0.3.
* Fix : Improvements to repository mirror support.
* Fix : Support '@' in user names for http access (externally converted to '%40').
* Fix : Syntax fixes to allow use of Ruby 1.9.
* Fix : Support for git-daemon now working correctly. The "daemon" key was not being removed correctly and projectgs with "daemon" support were not being deleted.
* Fix : Better handling of null-buffer condition in smart-http.
* Fix : Fixed language tags in localization files.
### 0.4.3 - 2012-02-01
This release includes feature enhancements and bug fixes.
This release includes a complete rewrite of the update_repository() functionality with an eye toward better resilience.
This code will automatically recover from a variety of weird failure modes which originally could occur.
Further, execution of fetch_changesets will resynchronize the gitolite.conf file, fixing any inconsistencies that might have crept into this file.
Co-existence of Redmine-managed and non-redmine-managed repositories in the gitolite.conf file is supported. Some specific things that will be resynched :
* Missing keys will be added and unused keys will be removed from the keydir directory.
* Entries in gitolite.conf will be updated with new path information as necessary.
* If proper setting is selected, orphan repo entries will be removed from gitolite.conf file, and the repositories themselves will be moved to the new recycle bin in the gitolite homedirectory.
* Hooks will be checked and repaired as necessary.
This code is now explicitly compatible with Redmine 1.3-stable.
* Added user-edit screen to allow administrator to examine and edit users keys.
* Git Server parameter now supports a port specification.
* Other bug fuxes: mirrors now report status properly.
### 0.4.2 - 2011-12-01
This release includes feature enhancements and bug fixes.
* One of the most important aspects of this release is a fix for the performance problems that plagued earlier versions of the plugin for post 1.2 Redmine. Fetch_changesets operations should now be possible.
* A second aspect is support for selinux. Scripts have been placed into a separate /bin directory which is placed at the root of the plugin (i.e. REDMINE_ROOT/vendor/plugins/redmine_git_hosting/bin). A set of rake tasks have been added to assist in installing selinux tags and pre-building scripts in the bin directory.

View file

@ -1,57 +0,0 @@
# Gitolite Admin repository management
gem 'gitolite-rugged', git: 'https://github.com/jbox-web/gitolite-rugged.git', tag: '1.2.0'
# Ruby/Rack Git Smart-HTTP Server Handler
gem 'gitlab-grack', '~> 2.0.0', git: 'https://github.com/jbox-web/grack.git', require: 'grack', branch: 'fix_gemfile'
# Memcached client for GitCache
gem 'dalli'
# Redis client for GitCache
gem 'redis'
gem 'hiredis'
# Markdown rendering
gem 'escape_utils'
gem 'html-pipeline'
gem 'rinku'
# Syntaxic coloration
gem 'github-markup'
gem 'RedCloth'
gem 'org-ruby'
gem 'creole'
gem 'asciidoctor'
# Rack parser for Hrack
gem 'rack-parser', require: 'rack/parser'
# temp autoloading fix
gem 'sidekiq'
gem 'sshkey'
group :development, :test do
gem 'rspec'
gem 'rspec-rails', '~> 3.5', '>= 3.5.2'
gem 'rails-controller-testing'
gem 'shoulda', '~> 3.5.0'
gem 'shoulda-context'
gem 'shoulda-matchers', '~> 2.7.0'
gem 'database_cleaner'
gem 'factory_bot_rails', '< 5.0'
gem 'rubocop', require: false
gem 'rubocop-rspec'
# Publish to CodeClimate
gem 'codeclimate-test-reporter', require: false
end
group :development do
gem 'brakeman'
gem 'bullet'
gem 'spring'
gem 'spring-commands-rspec'
end

View file

@ -1,19 +0,0 @@
The MIT License (MIT)
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

@ -1,30 +0,0 @@
## ![logo](https://raw.github.com/jbox-web/redmine_git_hosting/gh-pages/images/git_logo.png) Redmine Git Hosting Plugin
[![GitHub license](https://img.shields.io/github/license/jbox-web/redmine_git_hosting.svg)](https://github.com/jbox-web/redmine_git_hosting/blob/master/LICENSE)
[![GitHub release](https://img.shields.io/github/release/jbox-web/redmine_git_hosting.svg)](https://github.com/jbox-web/redmine_git_hosting/releases/latest)
[![Code Climate](https://codeclimate.com/github/jbox-web/redmine_git_hosting.png)](https://codeclimate.com/github/jbox-web/redmine_git_hosting)
[![Build Status](https://travis-ci.com/jbox-web/redmine_git_hosting.svg?branch=master)](https://travis-ci.com/jbox-web/redmine_git_hosting)
### A Redmine plugin which makes configuring your own Git hosting easy ;)
This plugin allows straightforward management of Gitolite within Redmine.
Looking for maintainers, mail me if you're interested.
## Installation
The installation guide is [here](http://redmine-git-hosting.io/get_started/). The migration guide is [here](http://redmine-git-hosting.io/how-to/migrate/).
Read the documentation and more on the [project's website](http://redmine-git-hosting.io/).
## Contributors
A big thank to [them](https://github.com/jbox-web/redmine_git_hosting/blob/master/AUTHORS) for their contribution!
## Contribute
You can contribute to this plugin in many ways such as :
* Helping with documentation
* Contributing code (features or bugfixes)
* Reporting a bug
* Submitting translations

View file

@ -1,16 +0,0 @@
class ArchivedRepositoriesController < RepositoriesController
skip_before_action :authorize
skip_before_action :find_project_repository, only: :index
before_action :can_view_archived_projects
def index
@archived_projects = Project.where("status = #{Project::STATUS_ARCHIVED}").includes(:repositories)
end
private
def can_view_archived_projects
render_403 unless User.current.admin?
end
end

View file

@ -1,31 +0,0 @@
module XitoliteRepositoryFinder
extend ActiveSupport::Concern
def find_xitolite_repository
begin
@repository = Repository::Xitolite.find(find_repository_param)
rescue ActiveRecord::RecordNotFound => e
render_404
else
@project = @repository.project
render_404 if @project.nil?
end
end
def find_xitolite_repository_by_path
repo_path = params[:repo_path] + '.git'
repository = Repository::Xitolite.find_by_path(repo_path, loose: true)
if repository.nil?
RedmineGitHosting.logger.error("GoRedirector : repository not found at path : '#{repo_path}', exiting !")
render_404
elsif !repository.go_access_available?
RedmineGitHosting.logger.error("GoRedirector : GoAccess is disabled for this repository '#{repository.gitolite_repository_name}', exiting !")
render_403
else
RedmineGitHosting.logger.info("GoRedirector : access granted for repository '#{repository.gitolite_repository_name}'")
@repository = repository
end
end
end

View file

@ -1,57 +0,0 @@
class DownloadGitRevisionController < ApplicationController
include XitoliteRepositoryFinder
before_action :find_xitolite_repository
before_action :can_download_git_revision
before_action :set_download
before_action :validate_download
helper :bootstrap_kit
def index
begin
send_data(@download.content, filename: @download.filename, type: @download.content_type)
rescue => e
flash.now[:error] = l(:git_archive_timeout, timeout: e.output)
render_404
end
end
private
def find_repository_param
params[:id]
end
def can_download_git_revision
render_403 unless User.current.allowed_to_download?(@repository)
end
def set_download
@download = Repositories::DownloadRevision.new(@repository, download_revision, download_format)
end
def download_revision
@download_revision ||= (params[:rev] || 'master')
end
def download_format
@download_format ||= (params[:download_format] || 'tar')
end
def validate_download
if !@download.valid_commit?
flash.now[:error] = l(:error_download_revision_no_such_commit, commit: download_revision)
render_404
end
end
end

View file

@ -1,88 +0,0 @@
class GitolitePublicKeysController < ApplicationController
include RedmineGitHosting::GitoliteAccessor::Methods
before_action :require_login
before_action :find_user
before_action :find_gitolite_public_key, only: [:destroy]
helper :gitolite_public_keys
helper :bootstrap_kit
def index
@gitolite_user_keys = @user.gitolite_public_keys.user_key.order('title ASC, created_at ASC')
@gitolite_deploy_keys = @user.gitolite_public_keys.deploy_key.order('title ASC, created_at ASC')
end
def create
if params[:create_button]
@gitolite_public_key = @user.gitolite_public_keys.new
@gitolite_public_key.safe_attributes = params[:gitolite_public_key]
if @gitolite_public_key.save
create_ssh_key(@gitolite_public_key)
flash[:notice] = l(:notice_public_key_created, title: view_context.keylabel(@gitolite_public_key))
else
flash[:error] = @gitolite_public_key.errors.full_messages.to_sentence
end
redirect_to @redirect_url
else
redirect_to @cancel_url
end
end
def destroy
return unless request.delete?
if @gitolite_public_key.user == @user || @user.admin?
if @gitolite_public_key.destroy
destroy_ssh_key(@gitolite_public_key)
flash[:notice] = l(:notice_public_key_deleted, title: view_context.keylabel(@gitolite_public_key))
end
redirect_to @redirect_url
else
render_403
end
end
private
def find_user
if params[:user_id]
set_user_from_params
else
set_user_from_current_user
end
end
def set_user_from_params
@user = params[:user_id] == 'current' ? User.current : User.find_by(id: params[:user_id])
if @user
@cancel_url = @redirect_url = url_for(controller: 'users', action: 'edit', id: params[:user_id], tab: 'keys')
else
render_404
end
end
def set_user_from_current_user
if User.current.allowed_to_create_ssh_keys?
@user = User.current
@redirect_url = url_for(controller: 'gitolite_public_keys', action: 'index')
@cancel_url = url_for(controller: 'my', action: 'account')
else
render_403
end
end
def find_gitolite_public_key
@gitolite_public_key = @user.gitolite_public_keys.find(params[:id])
rescue ActiveRecord::RecordNotFound
render_404
end
def create_ssh_key(ssh_key)
gitolite_accessor.create_ssh_key(ssh_key)
end
def destroy_ssh_key(ssh_key)
gitolite_accessor.destroy_ssh_key(ssh_key)
end
end

View file

@ -1,14 +0,0 @@
class GoRedirectorController < ApplicationController
include XitoliteRepositoryFinder
# prevents login action to be filtered by check_if_login_required application scope filter
skip_before_action :check_if_login_required, :verify_authenticity_token
before_action :find_xitolite_repository_by_path
def index
end
end

View file

@ -1,72 +0,0 @@
class RedmineGitHostingController < ApplicationController
include XitoliteRepositoryFinder
before_action :require_login
before_action :find_xitolite_repository
before_action :check_required_permissions
before_action :set_current_tab
layout(proc { |controller| controller.request.xhr? ? false : 'base' })
helper :bootstrap_kit
def show
respond_to do |format|
format.api
end
end
def edit; end
private
def find_repository_param
params[:repository_id]
end
def check_required_permissions
return render_403 unless @project.module_enabled?(:repository)
return true if User.current.admin?
return render_403 unless User.current.allowed_to_manage_repository?(@repository)
end
def check_xitolite_permissions
case action_name
when 'index', 'show'
perm = "view_#{controller_name}".to_sym
render_403 unless User.current.git_allowed_to?(perm, @repository)
when 'new', 'create'
perm = "create_#{controller_name}".to_sym
render_403 unless User.current.git_allowed_to?(perm, @repository)
when 'edit', 'update', 'destroy'
perm = "edit_#{controller_name}".to_sym
render_403 unless User.current.git_allowed_to?(perm, @repository)
end
end
def render_with_api
respond_to do |format|
format.html { render layout: false }
format.api
end
end
def render_js_redirect
respond_to do |format|
format.js { render js: "window.location = #{success_url.to_json};" }
format.html do
redirect_to success_url
end
end
end
def success_url
url_for(controller: 'repositories', action: 'edit', id: @repository.id, tab: @tab)
end
def call_use_case_and_redirect(opts = {})
# Update Gitolite repository
call_use_case(opts)
render_js_redirect
end
end

View file

@ -1,123 +0,0 @@
class RepositoryDeploymentCredentialsController < RedmineGitHostingController
include RedmineGitHosting::GitoliteAccessor::Methods
before_action :check_xitolite_permissions
before_action :find_deployment_credential, only: %i[edit update destroy]
before_action :find_key, only: %i[edit update destroy]
before_action :find_all_keys, only: %i[index new create]
helper :gitolite_public_keys
def index
@repository_deployment_credentials = @repository.deployment_credentials.all
render layout: false
end
def edit; end
def show
render_404
end
def new
@credential = @repository.deployment_credentials.new
end
def create
@credential = build_new_credential
return unless @credential.save
flash[:notice] = l(:notice_deployment_credential_created)
call_use_case_and_redirect
end
def update
@credential.safe_attributes = params[:repository_deployment_credential]
return unless @credential.save
flash[:notice] = l(:notice_deployment_credential_updated)
call_use_case_and_redirect
end
def destroy
will_delete_key = @key.deploy_key? && @key.delete_when_unused && @key.repository_deployment_credentials.count == 1
@credential.destroy
if will_delete_key && @key.repository_deployment_credentials.empty?
# Key no longer used -- delete it!
@key.destroy
flash[:notice] = l(:notice_deployment_credential_deleted_with_key)
else
flash[:notice] = l(:notice_deployment_credential_deleted)
end
call_use_case_and_redirect
end
private
def set_current_tab
@tab = 'repository_deployment_credentials'
end
def find_deployment_credential
credential = @repository.deployment_credentials.find(params[:id])
rescue ActiveRecord::RecordNotFound
render_404
else
if credential.user && (User.current.admin? || credential.user == User.current)
@credential = credential
else
render_403
end
end
def find_key
key = @credential.gitolite_public_key
if key&.user && (User.current.admin? || key.user == User.current)
@key = key
elsif key
render_403
else
render_404
end
end
def find_all_keys
# display create_with_key view. Find preexisting keys to offer to user
@user_keys = User.current.gitolite_public_keys.deploy_key.order('title ASC')
@disabled_keys = @repository.deployment_credentials.map(&:gitolite_public_key)
@other_keys = []
# Admin can use other's deploy keys as well
@other_keys = other_deployment_keys if User.current.admin?
end
def other_deployment_keys
users_allowed_to_create_deployment_keys.map { |user| user.gitolite_public_keys.deploy_key.order('title ASC') }.flatten
end
def users_allowed_to_create_deployment_keys
@project.users.select { |user| user != User.current && user.git_allowed_to?(:create_repository_deployment_credentials, @repository) }
end
def call_use_case(opts = {})
options = opts.merge(message: "Update deploy keys for repository : '#{@repository.gitolite_repository_name}'")
gitolite_accessor.update_repository(@repository, options)
end
def build_new_credential
credential = @repository.deployment_credentials.new
credential.safe_attributes = params[:repository_deployment_credential]
key = GitolitePublicKey.find_by(id: params[:repository_deployment_credential][:gitolite_public_key_id])
credential.gitolite_public_key = key unless key.nil?
# If admin, let credential be owned by owner of key...
if User.current.admin?
credential.user = key.user unless key.nil?
else
credential.user = User.current
end
credential
end
end

View file

@ -1,73 +0,0 @@
class RepositoryGitConfigKeysController < RedmineGitHostingController
include RedmineGitHosting::GitoliteAccessor::Methods
before_action :check_xitolite_permissions
before_action :find_repository_git_config_key, except: %i[index new create]
accept_api_auth :index, :show
def index
@repository_git_config_keys = @repository.git_config_keys.all
@repository_git_option_keys = @repository.git_option_keys.all
render_with_api
end
def new
@git_config_key = @repository.send(key_type).new
end
def create
@git_config_key = @repository.send(key_type).new
@git_config_key.safe_attributes = params[:repository_git_config_key]
return unless @git_config_key.save
flash[:notice] = l(:notice_git_config_key_created)
call_use_case_and_redirect
end
def update
@git_config_key.safe_attributes = params[:repository_git_config_key]
return unless @git_config_key.save
flash[:notice] = l(:notice_git_config_key_updated)
options = @git_config_key.key_has_changed? ? { delete_git_config_key: @git_config_key.old_key } : {}
call_use_case_and_redirect(options)
end
def destroy
return unless @git_config_key.destroy
flash[:notice] = l(:notice_git_config_key_deleted)
options = { delete_git_config_key: @git_config_key.key }
call_use_case_and_redirect(options)
end
private
def key_type
type = params[:type] || params[:repository_git_config_key][:type]
case type
when 'RepositoryGitConfigKey::GitConfig', 'git_config'
:git_config_keys
when 'RepositoryGitConfigKey::Option', 'git_option'
:git_option_keys
else
:git_keys
end
end
def set_current_tab
@tab = 'repository_git_config_keys'
end
def find_repository_git_config_key
@git_config_key = @repository.git_keys.find(params[:id])
rescue ActiveRecord::RecordNotFound
render_404
end
def call_use_case(opts = {})
options = opts.merge(message: "Rebuild Git config keys respository : '#{@repository.gitolite_repository_name}'")
gitolite_accessor.update_repository(@repository, options)
end
end

View file

@ -1,47 +0,0 @@
class RepositoryGitExtrasController < RedmineGitHostingController
include RedmineGitHosting::GitoliteAccessor::Methods
skip_before_action :set_current_tab
helper :extend_repositories
def update
@git_extra = @repository.extra
@git_extra.safe_attributes = params[:repository_git_extra]
if @git_extra.save
flash.now[:notice] = l(:notice_gitolite_extra_updated)
gitolite_accessor.update_repository(@repository, update_default_branch: @git_extra.default_branch_has_changed?)
else
flash.now[:error] = l(:notice_gitolite_extra_update_failed)
end
end
def sort_urls
@git_extra = @repository.extra
return unless request.post?
if @git_extra.update(urls_order: params[:repository_git_extra])
flash.now[:notice] = l(:notice_gitolite_extra_updated)
else
flash.now[:error] = l(:notice_gitolite_extra_update_failed)
end
end
def move
@move_repository_form = MoveRepositoryForm.new(@repository)
return unless request.post?
@move_repository_form = MoveRepositoryForm.new(@repository)
return unless @move_repository_form.submit(params[:repository_mover])
redirect_to settings_project_path(@repository.project, tab: 'repositories')
end
private
def set_git_extra
@git_extra = @repository.extra
end
end

View file

@ -1,66 +0,0 @@
class RepositoryMirrorsController < RedmineGitHostingController
before_action :check_xitolite_permissions
before_action :find_repository_mirror, except: %i[index new create]
accept_api_auth :index, :show
helper :additionals_clipboardjs
def index
@repository_mirrors = @repository.mirrors.all
render_with_api
end
def new
@mirror = @repository.mirrors.new
end
def create
@mirror = @repository.mirrors.new
@mirror.safe_attributes = params[:repository_mirror]
return unless @mirror.save
flash[:notice] = l(:notice_mirror_created)
render_js_redirect
end
def update
@mirror.safe_attributes = params[:repository_mirror]
return unless @mirror.save
flash[:notice] = l(:notice_mirror_updated)
render_js_redirect
end
def destroy
return unless @mirror.destroy
flash[:notice] = l(:notice_mirror_deleted)
render_js_redirect
end
def push
@push_failed, @shellout = RepositoryMirrors::Push.call(@mirror)
render layout: false
end
private
def set_current_tab
@tab = 'repository_mirrors'
end
def find_repository_mirror
@mirror = @repository.mirrors.find(params[:id])
rescue ActiveRecord::RecordNotFound
render_404
end
def check_xitolite_permissions
if action_name == 'push'
render_403 unless User.current.git_allowed_to?(:push_repository_mirrors, @repository)
else
super
end
end
end

View file

@ -1,51 +0,0 @@
class RepositoryPostReceiveUrlsController < RedmineGitHostingController
before_action :check_xitolite_permissions
before_action :find_repository_post_receive_url, except: %i[index new create]
accept_api_auth :index, :show
def index
@repository_post_receive_urls = @repository.post_receive_urls.all
render_with_api
end
def new
@post_receive_url = @repository.post_receive_urls.new
end
def create
@post_receive_url = @repository.post_receive_urls.new
@post_receive_url.safe_attributes = params[:repository_post_receive_url]
return unless @post_receive_url.save
flash[:notice] = l(:notice_post_receive_url_created)
render_js_redirect
end
def update
@post_receive_url.safe_attributes = params[:repository_post_receive_url]
return unless @post_receive_url.save
flash[:notice] = l(:notice_post_receive_url_updated)
render_js_redirect
end
def destroy
return unless @post_receive_url.destroy
flash[:notice] = l(:notice_post_receive_url_deleted)
render_js_redirect
end
private
def set_current_tab
@tab = 'repository_post_receive_urls'
end
def find_repository_post_receive_url
@post_receive_url = @repository.post_receive_urls.find(params[:id])
rescue ActiveRecord::RecordNotFound
render_404
end
end

View file

@ -1,80 +0,0 @@
class RepositoryProtectedBranchesController < RedmineGitHostingController
include RedmineGitHosting::GitoliteAccessor::Methods
before_action :check_xitolite_permissions
before_action :find_repository_protected_branch, except: %i[index new create sort]
accept_api_auth :index, :show
def index
@repository_protected_branches = @repository.protected_branches.all
render_with_api
end
def new
@protected_branch = @repository.protected_branches.new
end
def create
@protected_branch = @repository.protected_branches.new
@protected_branch.safe_attributes = params[:repository_protected_branche]
return unless @protected_branch.save
check_members
flash[:notice] = l(:notice_protected_branch_created)
call_use_case_and_redirect
end
def update
@protected_branch.safe_attributes = params[:repository_protected_branche]
return unless @protected_branch.save
check_members
flash[:notice] = l(:notice_protected_branch_updated)
call_use_case_and_redirect
end
def destroy
return unless @protected_branch.destroy
flash[:notice] = l(:notice_protected_branch_deleted)
call_use_case_and_redirect
end
def clone
@protected_branch = RepositoryProtectedBranche.clone_from(params[:id])
render 'new'
end
def sort
params[:protected_branch].each_with_index do |id, index|
@repository.protected_branches.where(id: id).update_all(position: index + 1)
end
# Update Gitolite repository
call_use_case
head :ok
end
private
def set_current_tab
@tab = 'repository_protected_branches'
end
def find_repository_protected_branch
@protected_branch = @repository.protected_branches.find(params[:id])
rescue ActiveRecord::RecordNotFound
render_404
end
def call_use_case(opts = {})
options = opts.merge(message: "Update branch permissions for repository : '#{@repository.gitolite_repository_name}'")
gitolite_accessor.update_repository(@repository, options)
end
def check_members
member_manager = RepositoryProtectedBranches::MemberManager.new(@protected_branch)
member_manager.add_users(params[:user_ids])
member_manager.add_groups(params[:group_ids])
end
end

View file

@ -1,26 +0,0 @@
module BaseForm
extend ActiveSupport::Concern
included do
include ActiveModel::Validations
include ActiveModel::Validations::Callbacks
include ActiveModel::Conversion
extend ActiveModel::Naming
end
def persisted?
false
end
def submit(attributes = {})
attributes.each do |name, value|
send("#{name}=", value)
end
if valid?
valid_form_submitted if respond_to?(:valid_form_submitted)
true
else
false
end
end
end

View file

@ -1,39 +0,0 @@
class MoveRepositoryForm
include BaseForm
attr_reader :repository
attr_accessor :project_id
validates_presence_of :project_id
validate :repository_is_movable
validate :target_project
validate :repository_uniqueness
def initialize(repository)
@repository = repository
end
def project
@project ||= Project.find_by_id(project_id)
end
def valid_form_submitted
repository.update_attribute(:project_id, project.id)
RedmineGitHosting::GitoliteAccessor.move_repository(repository)
end
private
def repository_is_movable
errors.add(:base, :identifier_empty) unless repository.movable?
end
def target_project
errors.add(:base, :wrong_target_project) if repository.project == project
end
def repository_uniqueness
new_repo = project.repositories.find_by_identifier(repository.identifier)
errors.add(:base, :identifier_taken) unless new_repo.nil?
end
end

View file

@ -1,59 +0,0 @@
class PluginSettingsForm
class << self
def add_accessor(*args)
@accessors ||= []
args.each do |accessor|
@accessors << accessor
attr_accessor accessor
end
end
def all_accessors
@accessors
end
end
include BaseForm
include PluginSettingsValidation::CacheConfig
include PluginSettingsValidation::GitoliteAccessConfig
include PluginSettingsValidation::GitoliteConfig
include PluginSettingsValidation::HooksConfig
include PluginSettingsValidation::MailingListConfig
include PluginSettingsValidation::RedmineConfig
include PluginSettingsValidation::SshConfig
include PluginSettingsValidation::StorageConfig
attr_reader :plugin
def initialize(plugin)
@plugin = plugin
end
def params
Hash[self.class.all_accessors.map { |v| [v, send(v)] }]
end
private
def current_setting(setting)
Setting.plugin_redmine_git_hosting[setting]
end
def strip_value(value)
return '' if value.nil?
value.strip
end
def filter_email_list(list)
list.select(&:present?).select { |m| valid_email?(m) }
end
def valid_email?(email)
RedmineGitHosting::Validators.valid_email?(email)
end
def convert_time(time)
(time.to_f * 10).to_i / 10.0
end
end

View file

@ -1,18 +0,0 @@
module PluginSettingsValidation
module CacheConfig
extend ActiveSupport::Concern
included do
# Gitolite Cache Config
add_accessor :gitolite_cache_max_time,
:gitolite_cache_max_size,
:gitolite_cache_max_elements,
:gitolite_cache_adapter
validates :gitolite_cache_max_time, presence: true, numericality: { only_integer: true }
validates :gitolite_cache_max_size, presence: true, numericality: { only_integer: true }
validates :gitolite_cache_max_elements, presence: true, numericality: { only_integer: true }
validates :gitolite_cache_adapter, presence: true, inclusion: { in: GitCache.adapters }
end
end
end

View file

@ -1,39 +0,0 @@
module PluginSettingsValidation
module GitoliteAccessConfig
extend ActiveSupport::Concern
included do
# Gitolite Access Config
add_accessor :ssh_server_domain,
:http_server_domain,
:https_server_domain,
:http_server_subdir,
:show_repositories_url,
:gitolite_daemon_by_default,
:gitolite_http_by_default
before_validation do
self.ssh_server_domain = strip_value(ssh_server_domain)
self.http_server_domain = strip_value(http_server_domain)
self.https_server_domain = strip_value(https_server_domain)
self.http_server_subdir = strip_value(http_server_subdir)
end
validates :ssh_server_domain, presence: true, format: { with: RedmineGitHosting::Validators::DOMAIN_REGEX }
validates :http_server_domain, presence: true, format: { with: RedmineGitHosting::Validators::DOMAIN_REGEX }
validates :https_server_domain, format: { with: RedmineGitHosting::Validators::DOMAIN_REGEX }, allow_blank: true
validates :show_repositories_url, presence: true, inclusion: { in: RedmineGitHosting::Validators::BOOLEAN_FIELDS }
validates :gitolite_daemon_by_default, presence: true, inclusion: { in: RedmineGitHosting::Validators::BOOLEAN_FIELDS }
validates :gitolite_http_by_default, presence: true, inclusion: { in: %w[0 1 2 3] }, numericality: { only_integer: true }
validate :http_server_subdir_is_relative
end
private
def http_server_subdir_is_relative
errors.add(:http_server_subdir, 'must be relative') if http_server_subdir.starts_with?('/')
end
end
end

View file

@ -1,61 +0,0 @@
module PluginSettingsValidation
module GitoliteConfig
extend ActiveSupport::Concern
included do
# Gitolite Config File
add_accessor :gitolite_config_file,
:gitolite_identifier_prefix,
:gitolite_identifier_strip_user_id
# Gitolite Global Config
add_accessor :gitolite_temp_dir,
:gitolite_recycle_bin_expiration_time,
:gitolite_log_level,
:git_config_username,
:git_config_email
before_validation do
self.gitolite_config_file = strip_value(gitolite_config_file)
self.gitolite_identifier_prefix = strip_value(gitolite_identifier_prefix)
self.gitolite_temp_dir = strip_value(gitolite_temp_dir)
self.git_config_username = strip_value(git_config_username)
self.git_config_email = strip_value(git_config_email)
self.gitolite_recycle_bin_expiration_time = strip_value(gitolite_recycle_bin_expiration_time)
end
# Validates Gitolite Config File
validates :gitolite_identifier_strip_user_id, presence: true, inclusion: { in: RedmineGitHosting::Validators::BOOLEAN_FIELDS }
# Validates Gitolite Global Config
validates :gitolite_temp_dir, presence: true
validates :gitolite_recycle_bin_expiration_time, presence: true, numericality: true
validates :gitolite_log_level, presence: true, inclusion: { in: RedmineGitHosting::Logger::LOG_LEVELS }
validates :git_config_username, presence: true
validates :git_config_email, presence: true, format: { with: URI::MailTo::EMAIL_REGEXP }
validate :gitolite_config_file_is_relative
validate :tmp_dir_is_absolute
after_validation do
self.gitolite_recycle_bin_expiration_time = convert_time(gitolite_recycle_bin_expiration_time)
if gitolite_config_file == RedmineGitHosting::Config::GITOLITE_DEFAULT_CONFIG_FILE
self.gitolite_identifier_strip_user_id = 'false'
self.gitolite_identifier_prefix = RedmineGitHosting::Config::GITOLITE_IDENTIFIER_DEFAULT_PREFIX
end
end
end
private
def gitolite_config_file_is_relative
errors.add(:gitolite_config_file, 'must be relative') if gitolite_config_file.starts_with?('/')
end
def tmp_dir_is_absolute
errors.add(:gitolite_temp_dir, 'must be absolute') unless gitolite_temp_dir.starts_with?('/')
end
end
end

View file

@ -1,22 +0,0 @@
module PluginSettingsValidation
module HooksConfig
extend ActiveSupport::Concern
included do
# Gitolite Hooks Config
add_accessor :gitolite_overwrite_existing_hooks,
:gitolite_hooks_are_asynchronous,
:gitolite_hooks_debug,
:gitolite_hooks_url
before_validation do
self.gitolite_hooks_url = strip_value(gitolite_hooks_url)
end
validates :gitolite_overwrite_existing_hooks, presence: true, inclusion: { in: RedmineGitHosting::Validators::BOOLEAN_FIELDS }
validates :gitolite_hooks_are_asynchronous, presence: true, inclusion: { in: RedmineGitHosting::Validators::BOOLEAN_FIELDS }
validates :gitolite_hooks_debug, presence: true, inclusion: { in: RedmineGitHosting::Validators::BOOLEAN_FIELDS }
validates :gitolite_hooks_url, presence: true, format: { with: URI::regexp(%w[http https]) }
end
end
end

View file

@ -1,34 +0,0 @@
module PluginSettingsValidation
module MailingListConfig
extend ActiveSupport::Concern
included do
# Git Mailing List Config
add_accessor :gitolite_notify_by_default,
:gitolite_notify_global_prefix,
:gitolite_notify_global_sender_address,
:gitolite_notify_global_include,
:gitolite_notify_global_exclude
before_validation do
self.gitolite_notify_global_include = filter_email_list(gitolite_notify_global_include)
self.gitolite_notify_global_exclude = filter_email_list(gitolite_notify_global_exclude)
end
validates :gitolite_notify_by_default, presence: true, inclusion: { in: RedmineGitHosting::Validators::BOOLEAN_FIELDS }
validates :gitolite_notify_global_sender_address, presence: true, format: { with: URI::MailTo::EMAIL_REGEXP }
validate :git_notifications_intersection
end
private
# Validate intersection of global_include/global_exclude
#
def git_notifications_intersection
intersection = gitolite_notify_global_include & gitolite_notify_global_exclude
return unless intersection.count.positive?
errors.add(:base, 'duplicated entries detected in gitolite_notify_global_include and gitolite_notify_global_exclude')
end
end
end

View file

@ -1,55 +0,0 @@
module PluginSettingsValidation
module RedmineConfig
extend ActiveSupport::Concern
included do
# Redmine Config
add_accessor :redmine_has_rw_access_on_all_repos,
:all_projects_use_git,
:init_repositories_on_create,
:delete_git_repositories,
:download_revision_enabled,
:gitolite_use_sidekiq
# This params work together!
# When hierarchical_organisation = true, unique_repo_identifier MUST be false
# When hierarchical_organisation = false, unique_repo_identifier MUST be true
add_accessor :hierarchical_organisation, :unique_repo_identifier
# hierarchical_organisation and unique_repo_identifier are now combined
#
before_validation do
self.unique_repo_identifier = if Additionals.true? hierarchical_organisation
'false'
else
'true'
end
## If we don't auto-create repository, we cannot create README file
self.init_repositories_on_create = 'false' unless Additionals.true? all_projects_use_git
end
validates :redmine_has_rw_access_on_all_repos, presence: true, inclusion: { in: RedmineGitHosting::Validators::BOOLEAN_FIELDS }
validates :all_projects_use_git, presence: true, inclusion: { in: RedmineGitHosting::Validators::BOOLEAN_FIELDS }
validates :init_repositories_on_create, presence: true, inclusion: { in: RedmineGitHosting::Validators::BOOLEAN_FIELDS }
validates :delete_git_repositories, presence: true, inclusion: { in: RedmineGitHosting::Validators::BOOLEAN_FIELDS }
validates :download_revision_enabled, presence: true, inclusion: { in: RedmineGitHosting::Validators::BOOLEAN_FIELDS }
validates :gitolite_use_sidekiq, presence: true, inclusion: { in: RedmineGitHosting::Validators::BOOLEAN_FIELDS }
validates :hierarchical_organisation, presence: true, inclusion: { in: RedmineGitHosting::Validators::BOOLEAN_FIELDS }
validates :unique_repo_identifier, presence: true, inclusion: { in: RedmineGitHosting::Validators::BOOLEAN_FIELDS }
validate :check_for_duplicated_repo
end
private
# Check duplication if we are switching from a mode to another
#
def check_for_duplicated_repo
return if Additionals.true?(hierarchical_organisation)
return unless Repository::Xitolite.have_duplicated_identifier?
errors.add(:base, 'Detected non-unique repository identifiers. Cannot switch to flat mode')
end
end
end

View file

@ -1,33 +0,0 @@
module PluginSettingsValidation
module SshConfig
extend ActiveSupport::Concern
included do
# Gitolite SSH Config
add_accessor :gitolite_user,
:gitolite_server_host,
:gitolite_server_port,
:gitolite_ssh_private_key,
:gitolite_ssh_public_key
before_validation do
self.gitolite_user = strip_value(gitolite_user)
self.gitolite_server_host = strip_value(gitolite_server_host)
self.gitolite_server_port = strip_value(gitolite_server_port)
self.gitolite_ssh_private_key = strip_value(gitolite_ssh_private_key)
self.gitolite_ssh_public_key = strip_value(gitolite_ssh_public_key)
end
validates :gitolite_user, presence: true
validates :gitolite_server_host, presence: true
validates :gitolite_server_port, presence: true, numericality: { only_integer: true, greater_than_or_equal_to: 1, less_than_or_equal_to: 65_536 }
validates :gitolite_ssh_private_key, presence: true
validates :gitolite_ssh_public_key, presence: true
validates_each :gitolite_ssh_private_key, :gitolite_ssh_public_key do |record, attr, value|
record.errors.add(attr, 'must exists on filesystem') unless File.exists?(value)
end
end
end
end

View file

@ -1,26 +0,0 @@
module PluginSettingsValidation
module StorageConfig
extend ActiveSupport::Concern
PATHS_TO_VALIDATE = %i[gitolite_global_storage_dir gitolite_redmine_storage_dir gitolite_recycle_bin_dir].freeze
included do
# Gitolite Storage Config
add_accessor :gitolite_global_storage_dir,
:gitolite_redmine_storage_dir,
:gitolite_recycle_bin_dir
before_validation do
self.gitolite_global_storage_dir = strip_value(gitolite_global_storage_dir)
self.gitolite_redmine_storage_dir = strip_value(gitolite_redmine_storage_dir)
self.gitolite_recycle_bin_dir = strip_value(gitolite_recycle_bin_dir)
end
validates_presence_of :gitolite_global_storage_dir, :gitolite_recycle_bin_dir
validates_each PATHS_TO_VALIDATE do |record, attr, value|
record.errors.add(attr, 'must be relative') if value.starts_with?('/')
end
end
end
end

View file

@ -1,14 +0,0 @@
module ArchivedRepositoriesHelper
def link_to_revision2(revision, repository, options = {})
repository = repository.repository if repository.is_a?(Project)
text = options.delete(:text) { format_revision(revision) }
rev = revision.respond_to?(:identifier) ? revision.identifier : revision
link_to(
h(text),
{ controller: 'archived_repositories', action: 'revision', id: repository.project, repository_id: repository.identifier_param, rev: rev },
title: l(:label_revision_id, format_revision(revision))
)
end
end

View file

@ -1,33 +0,0 @@
module BootstrapKit::AjaxHelper
def render_flash_messages_as_js(target = '#flash-messages', opts = {})
js_render(target, render_flash_messages, opts).html_safe
end
def js_render_template(target, template, opts = {})
locals = opts.delete(:locals) { {} }
content = render(template: template, locals: locals)
js_render(target, content, opts)
end
def js_render_partial(target, partial, opts = {})
locals = opts.delete(:locals) { {} }
content = render(partial: partial, locals: locals)
js_render(target, content, opts)
end
def js_render(target, content, opts = {})
method = opts.delete(:method) { :inject }
"$('#{target}').#{js_rendering_method(method)}(\"#{escape_javascript(content)}\");\n".html_safe
end
def js_rendering_method(method)
case method
when :append
'append'
when :inject
'html'
when :replace
'replaceWith'
end
end
end

View file

@ -1,8 +0,0 @@
module BootstrapKit::PresenterHelper
def present(object, klass = nil, *args)
klass ||= "#{object.class.base_class}Presenter".constantize
presenter = klass.new(object, self, *args)
yield presenter if block_given?
presenter
end
end

View file

@ -1,59 +0,0 @@
module BootstrapKitHelper
include BootstrapKit::AjaxHelper
include BootstrapKit::PresenterHelper
def bootstrap_load_base
stylesheet_link_tag('bootstrap_custom', plugin: 'redmine_git_hosting') +
bs_include_css('bootstrap_custom')
end
def bootstrap_load_module(bs_module)
method = "load_bs_module_#{bs_module}"
send(method)
end
def checked_image_with_exclamation(checked = true)
checked ? image_tag('toggle_check.png') : image_tag('exclamation.png')
end
private
def bs_include_js(js)
javascript_include_tag "bootstrap/#{js}", plugin: 'redmine_git_hosting'
end
def bs_include_css(css)
stylesheet_link_tag "bootstrap/#{css}", plugin: 'redmine_git_hosting'
end
def load_bs_module_alerts
bs_include_js('bootstrap_alert') +
bs_include_js('bootstrap_alert_helper') +
bs_include_js('bootstrap_transitions') +
bs_include_css('bootstrap_alert') +
bs_include_css('bootstrap_animations') +
bs_include_css('bootstrap_close')
end
def load_bs_module_label
bs_include_css('bootstrap_label')
end
def load_bs_module_modals
bs_include_js('bootstrap_modal')
end
def load_bs_module_sortable
bs_include_js('bootstrap_sortable_helper')
end
def load_bs_module_tables
bs_include_css('bootstrap_tables')
end
def load_bs_module_tooltip
bs_include_js('bootstrap_tooltip') +
bs_include_js('bootstrap_tooltip_helper') +
bs_include_css('bootstrap_tooltip')
end
end

View file

@ -1,81 +0,0 @@
module ExtendProjectsHelper
def render_feature(repository, feature)
method = "#{feature}_feature"
label, css_class, enabled = send(method, repository)
# Get css class
base_class = ['icon-git']
base_class << css_class
base_class << 'icon-git-disabled' unless enabled
# Get label
base_label = []
base_label << label
base_label << "(#{l(:label_disabled)})" unless enabled
content_tag(:i, '', title: base_label.join(' '), class: base_class)
end
def deployment_credentials_feature(repository)
label = l(:label_deployment_credentials)
css_class = 'fas fa-lock'
enabled = repository.deployment_credentials.active.any?
[label, css_class, enabled]
end
def post_receive_urls_feature(repository)
label = l(:label_post_receive_urls)
css_class = 'fas fa-external-link-alt'
enabled = repository.post_receive_urls.active.any?
[label, css_class, enabled]
end
def mirrors_feature(repository)
label = l(:label_repository_mirrors)
css_class = 'fas fa-cloud-upload-alt'
enabled = repository.mirrors.active.any?
[label, css_class, enabled]
end
def git_daemon_feature(repository)
label = l(:label_git_daemon)
css_class = 'fab fa-git'
enabled = repository.git_access_available?
[label, css_class, enabled]
end
def git_http_feature(repository)
label = l(:label_smart_http)
css_class = 'fas fa-cloud-download-alt'
enabled = repository.smart_http_enabled?
[label, css_class, enabled]
end
def git_notify_feature(repository)
label = l(:label_git_notify)
css_class = 'fas fa-bullhorn'
enabled = repository.git_notification_enabled?
[label, css_class, enabled]
end
def protected_branch_feature(repository)
label = l(:label_protected_branch)
css_class = 'fas fa-shield-alt'
enabled = repository.protected_branches_available?
[label, css_class, enabled]
end
def git_annex_feature(repository)
label = l(:label_git_annex)
css_class = 'fas fa-cloud-upload-alt'
enabled = repository.git_annex_enabled?
[label, css_class, enabled]
end
def public_repo_feature(repository)
label = l(:label_public_repo)
css_class = 'fas fa-users'
enabled = repository.public_repo?
[label, css_class, enabled]
end
end

View file

@ -1,67 +0,0 @@
module ExtendRepositoriesHelper
def encoding_field(form, repository)
content_tag(:p) do
form.select(
:path_encoding, [nil] + Setting::ENCODINGS,
label: l(:field_scm_path_encoding)
) + '<br />'.html_safe + l(:text_scm_path_encoding_note)
end
end
def available_download_format(repository, rev = nil)
%w[zip tar tar.gz].map { |f| [f, download_git_revision_repository_path(repository, rev: rev, download_format: f)] }
end
def create_readme_field(form, repository)
return unless repository.new_record?
content_tag(:p) do
hidden_field_tag('repository[create_readme]', 'false', id: '') +
content_tag(:label, l(:label_init_repo_with_readme), for: 'repository_create_readme') +
check_box_tag('repository[create_readme]', 'true', RedmineGitHosting::Config.init_repositories_on_create?)
end
end
def enable_git_annex_field(form, repository)
return unless repository.new_record?
content_tag(:p) do
hidden_field_tag('repository[enable_git_annex]', 'false', id: '') +
content_tag(:label, l(:label_init_repo_with_git_annex), for: 'repository_enable_git_annex') +
check_box_tag('repository[enable_git_annex]', 'true')
end
end
def repository_branches_list(branches)
options_for_select branches.collect { |b| [b.to_s, b.to_s] }, selected: branches.find(&:is_default).to_s
end
def render_repository_quick_jump(repository)
options = repository.project.repositories.map { |r| [r.redmine_name, edit_repository_path(r)] }
select_tag('repository_quick_jump_box',
options_for_select(options, selected: edit_repository_path(repository)),
onchange: 'if (this.value != \'\') { window.location = this.value; }')
end
def link_to_repository(repo, current_repo)
css_class = ['repository', (repo == current_repo ? 'selected' : ''), current_repo.type.split('::')[1].downcase].join(' ')
link_to h(repo.name),
{ controller: 'repositories', action: 'show', id: @project, repository_id: repo.identifier_param, rev: nil, path: nil },
class: css_class
end
def icon_for_url_type(url_type)
font_awesome_icon(RepositoryGitExtra::URLS_ICONS[url_type][:icon])
end
def label_for_url_type(url_type)
RepositoryGitExtra::URLS_ICONS[url_type][:label]
end
def render_options_for_move_repo_select_box(project)
projects = Project.active
.where(Project.allowed_to_condition(User.current, :manage_repository))
.where.not(id: project.id)
project_tree_options_for_select(projects, selected: project) if projects.any?
end
end

View file

@ -1,6 +0,0 @@
module GitHostingUsersHelper
def user_settings_tabs
tabs = super
tabs << { name: 'keys', partial: 'gitolite_public_keys/view', label: :label_public_keys }
end
end

View file

@ -1,102 +0,0 @@
module GitolitePluginSettingsHelper
def render_gitolite_params_status(params)
content_tag(:ul, class: 'list-unstyled') do
content = ''
params.each do |param, installed|
content << content_tag(:li, style: 'padding: 2px;') do
image_tag(image_for_param(installed), style: 'vertical-align: bottom; padding-right: 5px;') +
content_tag(:em, label_for_param(param, installed))
end
end
content.html_safe
end
end
def label_for_param(param, install_status)
install_status == 2 ? "#{param} (#{l(:label_gitolite_hook_untouched)})" : param
end
def image_for_param(install_status)
case install_status
when 0, true
'true.png'
when 1, false
'exclamation.png'
else
'warning.png'
end
end
def render_gitolite_version(version)
if version.nil?
css_class = 'label label-important'
label = l(:label_unknown_gitolite_version)
else
css_class = 'label label-success'
label = version
end
content_tag(:span, label, class: css_class)
end
def render_temp_dir_writeable(state, label)
css_class = state ? 'label label-success' : 'label label-important'
content_tag(:span, label, class: css_class)
end
def gitolite_plugin_settings_tabs
[
{ name: 'gitolite_config_ssh', partial: 'settings/redmine_git_hosting/gitolite_config_ssh', label: :label_tab_ssh },
{ name: 'gitolite_config_storage', partial: 'settings/redmine_git_hosting/gitolite_config_storage', label: :label_tab_storage },
{ name: 'gitolite_config_file', partial: 'settings/redmine_git_hosting/gitolite_config_file', label: :label_tab_config_file },
{ name: 'gitolite_config_global', partial: 'settings/redmine_git_hosting/gitolite_config_global', label: :label_tab_global },
{ name: 'gitolite_config_access', partial: 'settings/redmine_git_hosting/gitolite_config_access', label: :label_tab_access },
{ name: 'gitolite_config_hooks', partial: 'settings/redmine_git_hosting/gitolite_config_hooks', label: :label_tab_hooks },
{ name: 'gitolite_config_cache', partial: 'settings/redmine_git_hosting/gitolite_config_cache', label: :label_tab_cache },
{ name: 'gitolite_config_notify', partial: 'settings/redmine_git_hosting/gitolite_config_notify', label: :label_tab_notify },
{ name: 'gitolite_redmine_config', partial: 'settings/redmine_git_hosting/redmine_config', label: :label_tab_redmine },
{ name: 'gitolite_sidekiq_interface', partial: 'settings/redmine_git_hosting/sidekiq_interface', label: :label_tab_sidekiq_interface },
{ name: 'gitolite_config_test', partial: 'settings/redmine_git_hosting/gitolite_config_test', label: :label_tab_config_test },
{ name: 'gitolite_recycle_bin', partial: 'settings/redmine_git_hosting/gitolite_recycle_bin', label: :label_tab_gitolite_recycle_bin },
{ name: 'gitolite_rescue', partial: 'settings/redmine_git_hosting/gitolite_rescue', label: :label_tab_gitolite_rescue }
]
end
def git_cache_options
[
['Cache Disabled', '0'],
['Until next commit', '-1'],
['1 Minute or until next commit', '60'],
['15 Minutes or until next commit', '900'],
['1 Hour or until next commit', '3600'],
['1 Day or until next commit', '86400']
]
end
def log_level_options
RedmineGitHosting::Logger::LOG_LEVELS.map { |level| [l("label_#{level}"), level] }
end
def render_rugged_mandatory_features
content = ''
RedmineGitHosting::Config.rugged_mandatory_features.each do |feature|
opts = if RedmineGitHosting::Config.rugged_features.include?(feature)
{ class: 'label label-success' }
else
{ class: 'label label-important' }
end
content << content_tag(:span, feature, opts) + "\n"
end
content.html_safe
end
def render_rugged_optional_features
content = ''
RedmineGitHosting::Config.rugged_features.each do |feature|
unless RedmineGitHosting::Config.rugged_mandatory_features.include?(feature)
opts = { class: 'label label-success' }
content << content_tag(:span, feature, opts)
end
end
content.html_safe
end
end

View file

@ -1,16 +0,0 @@
module GitolitePublicKeysHelper
def keylabel(key)
key.user == User.current ? "#{key.title}" : "#{key.user.login}@#{key.title}"
end
def can_create_deployment_keys_for_some_project(theuser = User.current)
return true if theuser.admin?
theuser.projects_by_role.each_key do |role|
return true if role.allowed_to?(:create_repository_deployment_credentials)
end
return false
end
end

View file

@ -1,19 +0,0 @@
module RepositoryDeploymentCredentialsHelper
def build_list_of_keys(user_keys, other_keys, disabled_keys)
option_array = [[l(:label_deployment_credential_select_deploy_key), -1]]
option_array += user_keys.map { |key| [keylabel(key), key.id] }
if !other_keys.empty?
option_array2 = other_keys.map { |key| [keylabel(key), key.id] }
maxlen = (option_array + option_array2).map { |x| x.first.length }.max
extra = ([maxlen - l(:select_other_keys).length - 2, 6].max) / 2
option_array += [[('-' * extra) + ' ' + l(:select_other_keys) + ' ' + ('-' * extra), -2]]
option_array += option_array2
end
options_for_select(option_array, selected: -1, disabled: [-2] + disabled_keys.map(&:id))
end
end

View file

@ -1,10 +0,0 @@
module RepositoryGitConfigKeysHelper
def git_config_key_options
[
[l(:label_git_key_type_config), 'RepositoryGitConfigKey::GitConfig'],
[l(:label_git_key_type_option), 'RepositoryGitConfigKey::Option']
]
end
end

View file

@ -1,45 +0,0 @@
module RepositoryMirrorsHelper
# Mirror Mode
def mirror_mode(mirror)
[l(:label_mirror_full_mirror), l(:label_mirror_forced_update), l(:label_mirror_fast_forward)][mirror.push_mode]
end
# Refspec for mirrors
def refspec(mirror, max_refspec = 0)
if mirror.mirror_mode?
l(:all_references)
else
result = []
result << l(:all_branches) if mirror.include_all_branches
result << l(:all_tags) if mirror.include_all_tags
result << mirror.explicit_refspec if (max_refspec == 0) || ((1..max_refspec) === mirror.explicit_refspec.length)
result << l(:explicit) if (max_refspec > 0) && (mirror.explicit_refspec.length > max_refspec)
result.join(',<br />')
end
end
def mirrors_options
[
[l(:label_mirror_full_mirror), 0],
[l(:label_mirror_forced_update), 1],
[l(:label_mirror_fast_forward), 2]
]
end
def render_push_state(mirror, error)
if error
status = l(:label_mirror_push_fail)
status_css = 'important'
else
status = l(:label_mirror_push_sucess)
status_css = 'success'
end
l(:label_mirror_push_info_html, mirror_url: mirror.url, status: status, status_css: status_css).html_safe
end
end

View file

@ -1,15 +0,0 @@
module RepositoryPostReceiveUrlsHelper
# Post-receive Mode
def post_receive_mode(prurl)
label = []
if prurl.github_mode?
label << l(:label_github_post)
label << "(#{l(:label_split_payloads)})" if prurl.split_payloads?
else
label << l(:label_empty_get)
end
label.join(' ')
end
end

View file

@ -1,13 +0,0 @@
module Gitolitable
extend ActiveSupport::Concern
include Gitolitable::Authorizations
include Gitolitable::Cache
include Gitolitable::Config
include Gitolitable::Features
include Gitolitable::Notifications
include Gitolitable::Paths
include Gitolitable::Permissions
include Gitolitable::Urls
include Gitolitable::Users
include Gitolitable::Validations
end

View file

@ -1,89 +0,0 @@
module Gitolitable
module Authorizations
extend ActiveSupport::Concern
# These are for repository Gitolite configuration
def git_daemon_available?
User.anonymous.allowed_to?(:view_changesets, project) && git_daemon_enabled?
end
def git_web_available?
User.anonymous.allowed_to?(:browse_repository, project) && smart_http_enabled?
end
def protected_branches_available?
protected_branches_enabled? && project.active? && protected_branches.any?
end
def clonable_via_http?
User.anonymous.allowed_to?(:view_changesets, project) || smart_http_enabled?
end
def pushable_via_http?
https_access_enabled?
end
def git_notification_available?
git_notification_enabled? && !mailing_list.empty?
end
# These are for repository URLs
def urls_are_viewable?
RedmineGitHosting::Config.show_repositories_url? && User.current.allowed_to?(:view_changesets, project)
end
def ssh_access_available?
git_ssh_enabled? && !git_annex_enabled? && User.current.allowed_to_commit?(self)
end
def https_access_available?
https_access_enabled?
end
def http_access_available?
http_access_enabled?
end
def git_access_available?
(public_project? || public_repo?) && git_daemon_enabled?
end
def go_access_available?
(public_project? || public_repo?) && smart_http_enabled? && git_go_enabled?
end
def git_annex_access_available?
git_annex_enabled?
end
def downloadable?
git_annex_enabled? ? false : User.current.allowed_to_download?(self)
end
def deletable?
RedmineGitHosting::Config.delete_git_repositories?
end
def movable?
!identifier.nil? && !identifier.empty?
end
end
end

View file

@ -1,90 +0,0 @@
module Gitolitable
module Cache
extend ActiveSupport::Concern
included do
class << self
# Are repositories identifier unique?
#
def repo_ident_unique?
RedmineGitHosting::Config.unique_repo_identifier?
end
# Translate repository path into a unique ID for use in caching of git commands.
#
def repo_path_to_git_cache_id(repo_path)
repo = find_by_path(repo_path, loose: true)
repo ? repo.git_cache_id : nil
end
# Parse a path of the form <proj1>/<proj2>/<proj3>/<repo> and return the specified
# repository. If either 'repo_ident_unique?' is true or the <repo> is a project
# identifier, just return the last component. Otherwise,
# use the immediate parent (<proj3>) to try to identify the repo.
#
# Flags:
# :loose => true : Try to identify corresponding repo even if path is not quite correct
#
# Note that the :loose flag is used when interpreting the contents of the
# repository. If switching back and forth between the "repo_ident_unique?"
# form, it will still identify the repository (as long as there are not more than
# one repo with the same identifier.
#
# Example of data captured by regex :
# <MatchData "test/test2/test3/test4/test5.git" 1:"test4/" 2:"test4" 3:"test5" 4:".git">
# <MatchData "blabla2.git" 1:nil 2:nil 3:"blabla2" 4:".git">
#
def find_by_path(path, flags = {})
parseit = path.match(/\A.*?(([^\/]+)\/)?([^\/]+?)(\.git)?\z/)
return nil if parseit.nil?
project = Project.find_by_identifier(parseit[3])
# return default or first repo with blank identifier (or first Git repo--very rare?)
if project
project.repository || project.repo_blank_ident || project.gitolite_repos.first
elsif repo_ident_unique? || flags[:loose] && parseit[2].nil?
find_by_identifier(parseit[3])
elsif parseit[2]
project = Project.find_by_identifier(parseit[2])
if project.nil?
find_by_identifier(parseit[3])
else
find_by_identifier_and_project_id(parseit[3], project.id) || (flags[:loose] && find_by_identifier(parseit[3]))
end
end
end
end
end
# If repositories identifiers are unique, identifier forms a unique label,
# else use directory notation: <project identifier>/<repo identifier>
#
def git_cache_id
if identifier.blank?
# Should only happen with one repo/project (the default)
project.identifier
elsif self.class.repo_ident_unique?
identifier
else
"#{project.identifier}/#{identifier}"
end
end
# Note: RedmineGitHosting::Cache doesn't know about repository object, it only knows *git_cache_id*.
#
def empty_cache!
RedmineGitHosting::Cache.clear_cache_for_repository(git_cache_id)
end
end
end

View file

@ -1,85 +0,0 @@
module Gitolitable
module Config
extend ActiveSupport::Concern
def git_config
repo_conf = {}
# This is needed for all Redmine repositories
repo_conf['redminegitolite.projectid'] = project.identifier.to_s
repo_conf['redminegitolite.repositoryid'] = identifier || ''
repo_conf['redminegitolite.repositorykey'] = gitolite_hook_key
if project.active?
repo_conf['http.uploadpack'] = clonable_via_http?.to_s
repo_conf['http.receivepack'] = pushable_via_http?.to_s
if git_notification_available?
repo_conf['multimailhook.enabled'] = 'true'
repo_conf['multimailhook.mailinglist'] = mailing_list.join(', ')
repo_conf['multimailhook.from'] = sender_address
repo_conf['multimailhook.emailPrefix'] = email_prefix
else
repo_conf['multimailhook.enabled'] = 'false'
end
git_config_keys.each do |git|
repo_conf[git.key] = git.value
end if git_config_keys.any?
else
# Disable repository
repo_conf['http.uploadpack'] = 'false'
repo_conf['http.receivepack'] = 'false'
repo_conf['multimailhook.enabled'] = 'false'
end
repo_conf
end
def gitolite_options
repo_conf = {}
git_option_keys.each do |option|
repo_conf[option.key] = option.value
end if git_option_keys.any?
repo_conf
end
def owner
{ name: Setting['app_title'], email: Setting['mail_from'] }
end
def github_payload
{
repository: {
owner: owner,
description: project.description,
fork: false,
forks: 0,
homepage: project.homepage,
name: redmine_name,
open_issues: project.issues.open.length,
watchers: 0,
private: !project.is_public,
url: repository_url
},
pusher: owner,
}
end
def repository_url
Rails.application.routes.url_helpers.url_for(
controller: 'repositories', action: 'show',
id: project, repository_id: identifier_param,
only_path: false, host: Setting['host_name'], protocol: Setting['protocol']
)
end
end
end

View file

@ -1,97 +0,0 @@
module Gitolitable
module Features
extend ActiveSupport::Concern
# Always true to force repository fetch_changesets.
def report_last_commit
true
end
# Always true to force repository fetch_changesets.
def extra_report_last_commit
true
end
def git_default_branch
extra[:default_branch]
end
def gitolite_hook_key
extra[:key]
end
def git_daemon_enabled?
extra[:git_daemon]
end
def git_annex_enabled?
extra[:git_annex]
end
def git_notification_enabled?
extra[:git_notify]
end
def git_ssh_enabled?
extra[:git_ssh]
end
def git_go_enabled?
extra[:git_go]
end
def https_access_enabled?
extra[:git_https]
end
def http_access_enabled?
extra[:git_http]
end
def smart_http_enabled?
https_access_enabled? || http_access_enabled?
end
def only_https_access_enabled?
https_access_enabled? && !http_access_enabled?
end
def only_http_access_enabled?
http_access_enabled? && !https_access_enabled?
end
def protected_branches_enabled?
extra[:protected_branch]
end
def public_project?
project.is_public?
end
def public_repo?
extra[:public_repo]
end
def urls_order
extra[:urls_order]
end
end
end

View file

@ -1,43 +0,0 @@
module Gitolitable
module Notifications
extend ActiveSupport::Concern
def mailing_list
default_list + global_include_list - global_exclude_list
end
def default_list
watcher_users.map(&:email_address).map(&:address)
end
def global_include_list
RedmineGitHosting::Config.gitolite_notify_global_include
end
def global_exclude_list
RedmineGitHosting::Config.gitolite_notify_global_exclude
end
def sender_address
if extra.notification_sender.nil? || extra.notification_sender.empty?
RedmineGitHosting::Config.gitolite_notify_global_sender_address
else
extra.notification_sender
end
end
def email_prefix
if extra.notification_prefix.nil? || extra.notification_prefix.empty?
RedmineGitHosting::Config.gitolite_notify_global_prefix
else
extra.notification_prefix
end
end
end
end

View file

@ -1,94 +0,0 @@
module Gitolitable
module Paths
extend ActiveSupport::Concern
# This is the repository path from Redmine point of view.
# It is used to build HTTP(s) urls (including GoLang url).
# It doesn't contain references to internal directories like *gitolite_global_storage_dir* or *gitolite_redmine_storage_dir*
# to stay abstract from the real repository location.
# In this case, the real repository path is deduced from the path given thanks to the *find_by_path* method.
#
# Example : blabla/test-blabla/uuuuuuuuuuu/oooooo
#
# Call File.expand_path to add then remove heading /
#
def redmine_repository_path
File.expand_path(File.join('./', get_full_parent_path, git_cache_id), '/')[1..-1]
end
# This is the Gitolite repository identifier as it should appear in Gitolite config file.
# Example : redmine/blabla/test-blabla/uuuuuuuuuuu/oooooo
# (with 'redmine' a subdir of the Gitolite storage directory)
#
# Call File.expand_path to add then remove heading /
#
def gitolite_repository_name
File.expand_path(File.join('./', RedmineGitHosting::Config.gitolite_redmine_storage_dir, get_full_parent_path, git_cache_id), '/')[1..-1]
end
# The Gitolite repository identifier with the .git extension.
# Example : redmine/blabla/test-blabla/uuuuuuuuuuu/oooooo.git
#
def gitolite_repository_name_with_extension
"#{gitolite_repository_name}.git"
end
# This is the relative path to the Gitolite repository.
# Example : repositories/redmine/blabla/test-blabla/uuuuuuuuuuu/oooooo.git
# (with 'repositories' the Gitolite storage directory).
#
def gitolite_repository_path
File.join(RedmineGitHosting::Config.gitolite_global_storage_dir, gitolite_repository_name_with_extension)
end
# This is the full absolute path to the Gitolite repository.
# Example : /home/git/repositories/redmine/blabla/test-blabla/uuuuuuuuuuu/oooooo.git
#
def gitolite_full_repository_path
File.join(RedmineGitHosting::Config.gitolite_home_dir, gitolite_repository_path)
end
# A syntaxic sugar used to move repository from a location to an other
# Example : repositories/blabla/test-blabla/uuuuuuuuuuu/oooooo
#
def new_repository_name
gitolite_repository_name
end
# Used to move repository from a location to an other.
# At this point repository url still points to the old location but
# it contains the Gitolite storage directory in its path and the '.git' extension.
# Strip them to get the old repository name.
# Example :
# before : repositories/redmine/blabla/test-blabla/uuuuuuuuuuu/oooooo.git
# after : redmine/blabla/test-blabla/uuuuuuuuuuu/oooooo
#
def old_repository_name
url.gsub(RedmineGitHosting::Config.gitolite_global_storage_dir, '').gsub('.git', '')
end
private
def get_full_parent_path
return '' if !RedmineGitHosting::Config.hierarchical_organisation?
parent_parts = []
p = project
while p.parent
parent_id = p.parent.identifier.to_s
parent_parts.unshift(parent_id)
p = p.parent
end
parent_parts.join('/')
end
end
end

View file

@ -1,66 +0,0 @@
module Gitolitable
module Permissions
extend ActiveSupport::Concern
def build_gitolite_permissions(old_perms = {})
permissions_builder.build(self, gitolite_users, old_perms)
end
# We assume here that ':gitolite_config_file' is different than 'gitolite.conf'
# like 'redmine.conf' with 'include "redmine.conf"' in 'gitolite.conf'.
# This way, we know that all repos in this file are managed by Redmine so we
# don't need to backup users
#
def backup_gitolite_permissions(current_permissions)
if protected_branches_available? || RedmineGitHosting::Config.gitolite_identifier_prefix == ''
{}
else
extract_permissions(current_permissions)
end
end
private
def permissions_builder
if protected_branches_available?
PermissionsBuilder::ProtectedBranches
else
PermissionsBuilder::Standard
end
end
SKIP_USERS = ['gitweb', 'daemon', 'DUMMY_REDMINE_KEY', 'REDMINE_ARCHIVED_PROJECT', 'REDMINE_CLOSED_PROJECT']
def extract_permissions(current_permissions)
old_permissions = {}
current_permissions.each do |perm, branch_settings|
old_permissions[perm] = {}
branch_settings.each do |branch, user_list|
next if user_list.empty?
new_user_list = []
user_list.each do |user|
# ignore these users
next if SKIP_USERS.include?(user)
# backup users that are not Redmine users
new_user_list.push(user) if !user.include?(RedmineGitHosting::Config.gitolite_identifier_prefix)
end
old_permissions[perm][branch] = new_user_list if new_user_list.any?
end
end
old_permissions
end
end
end

View file

@ -1,122 +0,0 @@
module Gitolitable
module Urls
extend ActiveSupport::Concern
def http_user_login
User.current.anonymous? ? '' : "#{User.current.login}@"
end
def git_access_path
gitolite_repository_name_with_extension
end
def http_access_path
"#{RedmineGitHosting::Config.http_server_subdir}#{redmine_repository_path}.git"
end
def go_access_path
"go/#{redmine_repository_path}"
end
def ssh_url
"ssh://#{RedmineGitHosting::Config.gitolite_user}@#{RedmineGitHosting::Config.ssh_server_domain}/#{git_access_path}"
end
def git_url
"git://#{RedmineGitHosting::Config.ssh_server_domain}/#{git_access_path}"
end
def http_url
"http://#{http_user_login}#{RedmineGitHosting::Config.http_root_url}/#{http_access_path}"
end
def https_url
"https://#{http_user_login}#{RedmineGitHosting::Config.https_root_url}/#{http_access_path}"
end
def git_annex_url
"#{RedmineGitHosting::Config.gitolite_user}@#{RedmineGitHosting::Config.ssh_server_domain}:#{git_access_path}"
end
# This is the url used by Go to clone repository
#
def go_access_url
return '' if !smart_http_enabled?
return https_url if https_access_available?
return http_url if http_access_available?
end
# This is the url to add in Go files
#
def go_url
return '' if !smart_http_enabled?
return "#{RedmineGitHosting::Config.https_root_url}/#{go_access_path}" if https_access_available?
return "#{RedmineGitHosting::Config.http_root_url}/#{go_access_path}" if http_access_available?
end
def ssh_access
{ url: ssh_url, committer: User.current.allowed_to_commit?(self).to_s }
end
## Unsecure channels (clear password), commit is disabled
def http_access
{ url: http_url, committer: 'false' }
end
def https_access
{ url: https_url, committer: User.current.allowed_to_commit?(self).to_s }
end
def git_access
{ url: git_url, committer: 'false' }
end
def git_annex_access
{ url: git_annex_url, committer: User.current.allowed_to_commit?(self).to_s }
end
def go_access
{ url: go_url, committer: 'false' }
end
def available_urls
hash = {}
hash[:ssh] = ssh_access if ssh_access_available?
hash[:https] = https_access if https_access_available?
hash[:http] = http_access if http_access_available?
hash[:git] = git_access if git_access_available?
hash[:go] = go_access if go_access_available?
hash[:git_annex] = git_annex_access if git_annex_access_available?
hash
end
def available_urls_sorted
return available_urls if urls_order.nil? || urls_order.empty?
hash = {}
urls_order.each do |url|
next if !available_urls[url.to_sym]
hash[url.to_sym] = available_urls[url.to_sym]
end
hash
end
end
end

View file

@ -1,109 +0,0 @@
module Gitolitable
module Users
extend ActiveSupport::Concern
def gitolite_users
if project.active?
users_for_active_project
elsif project.archived?
users_for_archived_project
else
users_for_closed_project
end
end
def users_for_active_project
data = {}
data[:rewind_users] = rewind_users + rewind_deploy_users
data[:write_users] = write_users
data[:read_users] = read_users + read_deploy_users
data[:developer_team] = developer_team
data[:all_read] = all_users
# Add other users
data[:read_users] << 'DUMMY_REDMINE_KEY' if read_users.empty? && write_users.empty? && rewind_users.empty?
data[:read_users] << 'gitweb' if git_web_available?
data[:read_users] << 'daemon' if git_daemon_available?
# Return users
data
end
def users_for_archived_project
data = {}
data[:read_users] = ['REDMINE_ARCHIVED_PROJECT']
data
end
def users_for_closed_project
data = {}
data[:read_users] = all_users
data[:read_users] << 'REDMINE_CLOSED_PROJECT'
data
end
def users
project.users_available
end
def rewind_users
@rewind_users ||= users.select { |u| u.allowed_to?(:manage_repository, project) }.map { |u| u.gitolite_identifier }.sort
end
def write_users
@write_users ||= users.select { |u| u.allowed_to?(:commit_access, project) }.map { |u| u.gitolite_identifier }.sort - rewind_users
end
def read_users
@read_users ||= users.select { |u| u.allowed_to?(:view_changesets, project) }.map { |u| u.gitolite_identifier }.sort - rewind_users - write_users
end
def developer_team
@developer_team ||= (rewind_users + write_users).sort
end
def all_users
@all_users ||= (rewind_users + write_users + read_users).sort
end
def rewind_deploy_users
deploy_users_for_keys(rewind_deploy_keys)
end
def read_deploy_users
deploy_users_for_keys(read_deploy_keys)
end
def rewind_deploy_keys
deploy_keys_by_perm('RW+')
end
def read_deploy_keys
deploy_keys_by_perm('R')
end
def deploy_keys_by_perm(perm)
deployment_credentials.active.select { |cred| cred.perm == perm }
end
def deploy_users_for_keys(keys)
keys.map { |cred| cred.gitolite_public_key.owner }
end
end
end

View file

@ -1,122 +0,0 @@
module Gitolitable
module Validations
extend ActiveSupport::Concern
included do
# Set URL ourself as relative path.
#
before_validation :set_git_urls
# Make sure that identifier does not match Gitolite Admin repository
#
validates_exclusion_of :identifier, in: %w(gitolite-admin)
# Place additional constraints on repository identifiers
# because of multi repos
#
validate :additional_constraints_on_identifier
validate :identifier_dont_change
validate :default_repository_has_identifier
class << self
# Build a hash of repository identifier :
# <repo_1_identifier> => 1
# <repo_2_identifier> => 1
# etc...
# If the same repository identifier is found many times, increment the corresponding counter.
# Repository identifiers are unique if all values of the hash are 1.
#
def identifiers_to_hash
self.all.map(&:identifier).inject(Hash.new(0)) do |h, x|
h[x] += 1 unless x.blank?
h
end
end
def have_duplicated_identifier?
(identifiers_to_hash.values.max || 0) > 1
end
end
end
def exists_in_gitolite?
RedmineGitHosting::Commands.sudo_dir_exists?(gitolite_repository_path)
end
def empty_in_gitolite?
RedmineGitHosting::Commands.sudo_repository_empty?(gitolite_repository_path)
end
def git_objects_count
RedmineGitHosting::Commands.sudo_git_objects_count(File.join(gitolite_repository_path, 'objects'))
end
def empty?
extra_info.nil? || (!extra_info.has_key?('heads') && !extra_info.has_key?('branches'))
end
def data_for_destruction
{
repo_name: gitolite_repository_name,
repo_path: gitolite_full_repository_path,
delete_repository: deletable?,
git_cache_id: git_cache_id
}
end
private
# Set up git urls for new repositories
#
def set_git_urls
self.url = gitolite_repository_path if self.url.blank?
self.root_url = self.url if self.root_url.blank?
end
# Check several aspects of repository identifier (only for Redmine 1.4+)
# 1) cannot equal identifier of any project
# 2) if repo_ident_unique? make sure that repo identifier is globally unique
# 3) cannot make this repo the default if there will be some other repo with blank identifier
#
def additional_constraints_on_identifier
if !identifier.blank? && (new_record? || identifier_changed?)
errors.add(:identifier, :cannot_equal_project) if Project.find_by_identifier(identifier)
# See if a repo for another project has the same identifier (existing validations already check for current project)
errors.add(:identifier, :taken) if self.class.repo_ident_unique? && Repository.where("identifier = ? and project_id <> ?", identifier, project.id).any?
end
end
# Make sure identifier hasn't changed. Allow null and blank
# Note that simply using identifier_changed doesn't seem to work
# if the identifier was "NULL" but the new identifier is ""
#
def identifier_dont_change
return if new_record?
errors.add(:identifier, :cannot_change) if (identifier_was.blank? && !identifier.blank?) || (!identifier_was.blank? && identifier_changed?)
end
# Need to make sure that we don't take the default slot away from a sibling repo with blank identifier
#
def default_repository_has_identifier
if project && (is_default? || set_as_default?)
possibles = Repository.where("project_id = ? and (identifier = '' or identifier is null)", project.id)
errors.add(:base, :blank_default_exists) if possibles.any? && (new_record? || possibles.detect { |x| x.id != id })
end
end
end
end

View file

@ -1,21 +0,0 @@
class GitCache < ActiveRecord::Base
include Redmine::SafeAttributes
CACHE_ADAPTERS = [%w[Database database],
%w[Memcached memcached],
%w[Redis redis]].freeze
## Attributes
safe_attributes 'repo_identifier', 'command', 'command_output'
## Validations
validates :repo_identifier, presence: true
validates :command, presence: true
validates :command_output, presence: true
class << self
def adapters
CACHE_ADAPTERS.map(&:last)
end
end
end

View file

@ -1,9 +0,0 @@
class GithubComment < ActiveRecord::Base
## Relations
belongs_to :journal
## Validations
validates :github_id, presence: true
validates :journal_id, presence: true, uniqueness: { scope: :github_id }
end

View file

@ -1,9 +0,0 @@
class GithubIssue < ActiveRecord::Base
## Relations
belongs_to :issue
## Validations
validates :github_id, presence: true
validates :issue_id, presence: true, uniqueness: { scope: :github_id }
end

View file

@ -1,202 +0,0 @@
class GitolitePublicKey < ActiveRecord::Base
include Redmine::SafeAttributes
TITLE_LENGTH_LIMIT = 60
KEY_TYPE_USER = 0
KEY_TYPE_DEPLOY = 1
## Attributes
safe_attributes 'title', 'key', 'key_type', 'delete_when_unused'
## Relations
belongs_to :user
has_many :repository_deployment_credentials, dependent: :destroy
## Validations
validates :user_id, presence: true
validates :title, presence: true, uniqueness: { case_sensitive: false, scope: :user_id },
length: { maximum: TITLE_LENGTH_LIMIT }, format: /\A[a-z0-9_\-]*\z/i
validates :identifier, presence: true, uniqueness: { case_sensitive: false, scope: :user_id }
validates :key, presence: true
validates :key_type, presence: true, numericality: { only_integer: true },
inclusion: { in: [KEY_TYPE_USER, KEY_TYPE_DEPLOY] }
validate :has_not_been_changed
validate :key_correctness
validate :key_not_admin
validate :key_uniqueness
## Scopes
scope :user_key, -> { where(key_type: KEY_TYPE_USER) }
scope :deploy_key, -> { where(key_type: KEY_TYPE_DEPLOY) }
## Callbacks
before_validation :strip_whitespace
before_validation :remove_control_characters
before_validation :set_identifier
before_validation :set_fingerprint
def key_type_as_string
user_key? ? 'user_key' : 'deploy_key'
end
def to_s
title
end
def data_for_destruction
{ title: identifier, key: key, location: location, owner: owner }
end
# Returns the path to this key under the gitolite keydir
# resolves to <user.gitolite_identifier>/<location>/<owner>.pub
#
# tile: test-key
# identifier: redmine_admin_1@redmine_test_key
# identifier: redmine_admin_1@redmine_deploy_key_1
#
#
# keydir/
# ├── redmine_git_hosting
# │   └── redmine_admin_1
# │   ├── redmine_test_key
# │   │   └── redmine_admin_1.pub
# │   ├── redmine_deploy_key_1
# │   │   └── redmine_admin_1.pub
# │   └── redmine_deploy_key_2
# │   └── redmine_admin_1.pub
# └── redmine_gitolite_admin_id_rsa.pub
#
#
# The root folder for this user is the user's identifier
# for logical grouping of their keys, which are organized
# by their title in subfolders.
#
# This is due to the new gitolite multi-keys organization
# using folders. See https://gitolite.com/gitolite/users.html
def gitolite_path
File.join('keydir', RedmineGitHosting::Config.gitolite_key_subdir, user.gitolite_identifier, location, owner) + '.pub'
end
# Make sure that current identifier is consistent with current user login.
# This method explicitly overrides the static nature of the identifier
def reset_identifiers(opts = {})
# Fix identifier
self.identifier = nil
self.fingerprint = nil
self.identifier = GitolitePublicKeys::GenerateIdentifier.call(self, user, opts)
set_fingerprint
# Need to override the "never change identifier" constraint
save(validate: false)
end
# Key type checking functions
def user_key?
key_type == KEY_TYPE_USER
end
def deploy_key?
key_type == KEY_TYPE_DEPLOY
end
def owner
identifier.split('@')[0]
end
def location
identifier.split('@')[1]
end
def type
key.split(' ')[0]
end
def blob
key.split(' ')[1]
end
def email
key.split(' ')[2]
end
private
# Strip leading and trailing whitespace
# Don't mess with existing keys (since cannot change key text anyway)
#
def strip_whitespace
return unless new_record?
self.title = title.strip rescue ''
self.key = key.strip rescue ''
end
# Remove control characters from key
# Don't mess with existing keys (since cannot change key text anyway)
#
def remove_control_characters
return unless new_record?
self.key = RedmineGitHosting::Utils::Ssh.sanitize_ssh_key(key)
end
# Returns the unique identifier for this key based on the key_type
#
# For user public keys, this simply is the user's gitolite_identifier.
# For deployment keys, we use an incrementing number.
#
def set_identifier
return nil if user_id.nil?
self.identifier ||= GitolitePublicKeys::GenerateIdentifier.call(self, user)
end
def set_fingerprint
self.fingerprint = RedmineGitHosting::Utils::Ssh.ssh_fingerprint(key)
rescue RedmineGitHosting::Error::InvalidSshKey => e
errors.add(:key, :corrupted)
end
def has_not_been_changed
return if new_record?
%w[identifier key user_id key_type title fingerprint].each do |attribute|
method = "#{attribute}_changed?"
errors.add(attribute, :cannot_change) if send(method)
end
end
# Test correctness of fingerprint from output
# and general ssh-(r|d|ecd)sa <key> <id> structure
#
def key_correctness
return false if key.nil?
key.match(/^(\S+)\s+(\S+)/) && (fingerprint =~ /^(\w{2}:?)+$/i)
end
def key_not_admin
errors.add(:key, :taken_by_gitolite_admin) if fingerprint == RedmineGitHosting::Config.gitolite_ssh_public_key_fingerprint
end
def key_uniqueness
return unless new_record?
existing = GitolitePublicKey.find_by_fingerprint(fingerprint)
return unless existing
if existing.user == User.current
errors.add(:key, :taken_by_you, name: existing.title)
elsif User.current.admin?
errors.add(:key, :taken_by_other, login: existing.user.login, name: existing.title)
else
errors.add(:key, :taken_by_someone)
end
end
end

View file

@ -1,24 +0,0 @@
class ProtectedBranchesMember < ActiveRecord::Base
include Redmine::SafeAttributes
## Attributes
safe_attributes 'principal_id', 'inherited_by'
## Relations
belongs_to :protected_branch, class_name: 'RepositoryProtectedBranche'
belongs_to :principal
## Callbacks
after_destroy :remove_dependent_objects
private
def remove_dependent_objects
return unless principal.class.name == 'Group'
principal.users.each do |user|
member = self.class.find_by_principal_id_and_inherited_by(user.id, principal.id)
member.destroy! unless member.nil?
end
end
end

View file

@ -1,74 +0,0 @@
require_dependency 'redmine/scm/adapters/xitolite_adapter'
class Repository::Xitolite < Repository::Git
# Include Gitolitable concern
include Gitolitable
# Virtual attributes
attr_accessor :create_readme
attr_accessor :enable_git_annex
# Redmine uses safe_attributes on Repository, so we need to declare our virtual attributes.
safe_attributes 'create_readme', 'enable_git_annex'
# Relations
has_one :extra, dependent: :destroy, foreign_key: 'repository_id', class_name: 'RepositoryGitExtra'
has_many :mirrors, dependent: :destroy, foreign_key: 'repository_id', class_name: 'RepositoryMirror'
has_many :post_receive_urls, dependent: :destroy, foreign_key: 'repository_id', class_name: 'RepositoryPostReceiveUrl'
has_many :deployment_credentials, dependent: :destroy, foreign_key: 'repository_id', class_name: 'RepositoryDeploymentCredential'
has_many :git_keys, dependent: :destroy, foreign_key: 'repository_id', class_name: 'RepositoryGitConfigKey'
has_many :git_config_keys, dependent: :destroy, foreign_key: 'repository_id', class_name: 'RepositoryGitConfigKey::GitConfig'
has_many :git_option_keys, dependent: :destroy, foreign_key: 'repository_id', class_name: 'RepositoryGitConfigKey::Option'
has_many :protected_branches, dependent: :destroy, foreign_key: 'repository_id', class_name: 'RepositoryProtectedBranche'
# Additionnal validations
validate :valid_repository_options, on: :create
acts_as_watchable
class << self
def scm_adapter_class
Redmine::Scm::Adapters::XitoliteAdapter
end
def scm_name
'Gitolite'
end
end
def sti_name
'Repository::Xitolite'
end
# Override the original method to accept options hash
# which may contain *bypass_cache* flag.
#
def diff(path, rev, rev_to, opts = {})
scm.diff(path, rev, rev_to, opts)
end
def rev_list(revision, args = [])
scm.rev_list(revision, args)
end
def rev_parse(revision)
scm.rev_parse(revision)
end
def archive(revision, format = 'tar')
scm.archive(revision, format)
end
def mirror_push(url, branch, args = [])
scm.mirror_push(url, branch, args)
end
private
def valid_repository_options
return unless Additionals.true? create_readme
return unless Additionals.true? enable_git_annex
errors.add(:base, :invalid_options)
end
end

View file

@ -1,55 +0,0 @@
class RepositoryDeploymentCredential < ActiveRecord::Base
include Redmine::SafeAttributes
VALID_PERMS = ['R', 'RW+'].freeze
DEFAULT_PERM = 'RW+'.freeze
## Attributes
safe_attributes 'perm', 'active', 'gitolite_public_key_id'
## Relations
belongs_to :repository
belongs_to :gitolite_public_key
belongs_to :user
## Validations
validates :repository_id, presence: true,
uniqueness: { scope: :gitolite_public_key_id }
validates :gitolite_public_key_id, presence: true
validates :user_id, presence: true
validates :perm, presence: true,
inclusion: { in: VALID_PERMS }
validates_associated :repository
validates_associated :gitolite_public_key
validates_associated :user
validate :correct_key_type
validate :owner_matches_key
## Scopes
scope :active, -> { where(active: true) }
scope :inactive, -> { where(active: false) }
def to_s
"#{repository.identifier}-#{gitolite_public_key.identifier} : #{perm}"
end
# Deployment Credentials ignored unless created by someone who still has permission to create them
def honored?
user.admin? || user.allowed_to?(:create_repository_deployment_credentials, repository.project)
end
private
def correct_key_type
errors.add(:base, :invalid_key) if gitolite_public_key && gitolite_public_key.key_type_as_string != 'deploy_key'
end
def owner_matches_key
return if user.nil? || gitolite_public_key.nil?
errors.add(:base, :invalid_user) if user != gitolite_public_key.user
end
end

View file

@ -1,42 +0,0 @@
class RepositoryGitConfigKey < ActiveRecord::Base
include Redmine::SafeAttributes
## Attributes
safe_attributes 'type', 'key', 'value'
## Relations
belongs_to :repository
## Validations
validates :repository_id, presence: true
validates :type, presence: true, inclusion: { in: ['RepositoryGitConfigKey::GitConfig', 'RepositoryGitConfigKey::Option'] }
validates :value, presence: true
## Callbacks
after_save :check_if_key_changed
## Virtual attribute
attr_accessor :key_has_changed
attr_accessor :old_key
# Syntaxic sugar
def key_has_changed?
key_has_changed
end
private
# This is Rails method : <attribute>_changed?
# However, the value is cleared before passing the object to the controller.
# We need to save it in virtual attribute to trigger Gitolite resync if changed.
#
def check_if_key_changed
if key_changed?
self.key_has_changed = true
self.old_key = key_change[0]
else
self.key_has_changed = false
self.old_key = ''
end
end
end

View file

@ -1,9 +0,0 @@
class RepositoryGitConfigKey::GitConfig < RepositoryGitConfigKey
VALID_CONFIG_KEY_REGEX = /\A[a-zA-Z0-9]+\.[a-zA-Z0-9.]+\z/
validates :key, presence: true,
uniqueness: { case_sensitive: false, scope: [:type, :repository_id] },
format: { with: VALID_CONFIG_KEY_REGEX }
end

View file

@ -1,6 +0,0 @@
class RepositoryGitConfigKey::Option < RepositoryGitConfigKey
validates :key, presence: true,
uniqueness: { case_sensitive: false, scope: [:type, :repository_id] }
end

View file

@ -1,115 +0,0 @@
class RepositoryGitExtra < ActiveRecord::Base
include Redmine::SafeAttributes
SMART_HTTP_OPTIONS = [[l(:label_disabled), '0'],
[l(:label_http_only), '3'],
[l(:label_https_only), '1'],
[l(:label_https_and_http), '2']].freeze
ALLOWED_URLS = %w[ssh http https go git git_annex].freeze
URLS_ICONS = { go: { label: 'Go', icon: 'fab_google' },
http: { label: 'HTTP', icon: 'fas_external-link-alt' },
https: { label: 'HTTPS', icon: 'fas_external-link-alt' },
ssh: { label: 'SSH', icon: 'fas_shield-alt' },
git: { label: 'Git', icon: 'fab_git' },
git_annex: { label: 'GitAnnex', icon: 'fab_git' } }.freeze
## Attributes
safe_attributes 'git_http', 'git_https', 'git_ssh', 'git_go', 'git_daemon', 'git_notify', 'git_annex', 'default_branch',
'protected_branch', 'public_repo', 'key', 'urls_order', 'notification_sender', 'notification_prefix'
## Relations
belongs_to :repository
## Validations
validates :repository_id, presence: true, uniqueness: true
validates :default_branch, presence: true
validates :key, presence: true
validates :notification_sender, format: { with: URI::MailTo::EMAIL_REGEXP, allow_blank: true }
validate :validate_urls_order
## Serializations
serialize :urls_order, Array
## Callbacks
before_save :check_urls_order_consistency
after_save :check_if_default_branch_changed
## Virtual attribute
attr_accessor :default_branch_has_changed
# Syntaxic sugar
def default_branch_has_changed?
default_branch_has_changed
end
private
def validate_urls_order
urls_order.each do |url|
errors.add(:urls_order, :invalid) unless ALLOWED_URLS.include?(url)
end
end
# This is Rails method : <attribute>_changed?
# However, the value is cleared before passing the object to the controller.
# We need to save it in virtual attribute to trigger Gitolite resync if changed.
#
def check_if_default_branch_changed
self.default_branch_has_changed = if default_branch_changed?
true
else
false
end
end
def check_urls_order_consistency
check_ssh_url
check_git_http_urls
check_go_url
check_git_url
check_git_annex_url
end
def check_ssh_url
git_ssh? ? add_url('ssh') : remove_url('ssh')
end
def check_git_http_urls
if git_http? && git_https?
add_url('http')
add_url('https')
elsif git_http?
add_url('http')
remove_url('https')
elsif git_https?
add_url('https')
remove_url('http')
else
remove_url('http')
remove_url('https')
end
end
def check_go_url
git_go? ? add_url('go') : remove_url('go')
end
def check_git_annex_url
git_annex? ? add_url('git_annex') : remove_url('git_annex')
end
def check_git_url
git_daemon? ? add_url('git') : remove_url('git')
end
def remove_url(url)
urls_order.delete(url)
end
def add_url(url)
urls_order.push(url).uniq!
end
end

View file

@ -1,106 +0,0 @@
class RepositoryMirror < ActiveRecord::Base
include Redmine::SafeAttributes
PUSHMODE_MIRROR = 0
PUSHMODE_FORCE = 1
PUSHMODE_FAST_FORWARD = 2
## Attributes
safe_attributes 'url', 'push_mode', 'include_all_branches', 'include_all_tags',
'explicit_refspec', 'active'
## Relations
belongs_to :repository
## Validations
validates :repository_id, presence: true
## Only allow SSH format
## ssh://git@redmine.example.org/project1/project2/project3/project4.git
## ssh://git@redmine.example.org:2222/project1/project2/project3/project4.git
validates :url, presence: true,
uniqueness: { case_sensitive: false, scope: :repository_id },
format: { with: RedmineGitHosting::Validators::GIT_SSH_URL_REGEX }
validates :push_mode, presence: true,
numericality: { only_integer: true },
inclusion: { in: [PUSHMODE_MIRROR, PUSHMODE_FORCE, PUSHMODE_FAST_FORWARD] }
## Additional validations
validate :mirror_configuration
## Scopes
scope :active, -> { where(active: true) }
scope :inactive, -> { where(active: false) }
scope :has_explicit_refspec, -> { where(push_mode: '> 0') }
## Callbacks
before_validation :strip_whitespace
def mirror_mode?
push_mode == PUSHMODE_MIRROR
end
def force_mode?
push_mode == PUSHMODE_FORCE
end
def push_mode_to_s
case push_mode
when 0
'mirror'
when 1
'force'
when 2
'fast_forward'
end
end
private
# Strip leading and trailing whitespace
def strip_whitespace
self.url = url.strip rescue ''
self.explicit_refspec = explicit_refspec.strip rescue ''
end
def mirror_configuration
if mirror_mode?
reset_fields
elsif include_all_branches? && include_all_tags?
mutual_exclusion_error
elsif explicit_refspec.present?
if include_all_branches?
errors.add(:explicit_refspec, "cannot be used with #{l(:label_mirror_include_all_branches)}.")
else
validate_refspec
end
elsif !include_all_branches? && !include_all_tags?
errors.add(:base, :nothing_to_push)
end
end
# Check format of refspec
#
def validate_refspec
RedmineGitHosting::Validators.valid_git_refspec_path?(explicit_refspec)
rescue RedmineGitHosting::Error::InvalidRefspec::BadFormat => e
errors.add(:explicit_refspec, :bad_format)
rescue RedmineGitHosting::Error::InvalidRefspec::NullComponent => e
errors.add(:explicit_refspec, :have_null_component)
end
def reset_fields
# clear out all extra parameters.. (we use javascript to hide them anyway)
self.include_all_branches = false
self.include_all_tags = false
self.explicit_refspec = ''
end
def mutual_exclusion_error
errors.add(:base, "Cannot #{l(:label_mirror_include_all_branches)} and #{l(:label_mirror_include_all_tags)} at the same time.")
return if explicit_refspec.blank?
errors.add(:explicit_refspec, "cannot be used with #{l(:label_mirror_include_all_branches)} or #{l(:label_mirror_include_all_tags)}")
end
end

View file

@ -1,56 +0,0 @@
require 'uri'
class RepositoryPostReceiveUrl < ActiveRecord::Base
include Redmine::SafeAttributes
## Attributes
safe_attributes 'url', 'mode', 'active', 'use_triggers', 'triggers', 'split_payloads'
## Relations
belongs_to :repository
## Validations
validates :repository_id, presence: true
# Only allow HTTP(s) format
validates :url, presence: true,
uniqueness: { case_sensitive: false, scope: :repository_id },
format: { with: URI::regexp(%w[http https]) }
validates :mode, presence: true, inclusion: { in: %i[github get] }
## Serializations
serialize :triggers, Array
## Scopes
scope :active, -> { where(active: true) }
scope :inactive, -> { where(active: false) }
## Callbacks
before_validation :strip_whitespace
before_validation :remove_blank_triggers
def mode
self[:mode].to_sym
end
def mode=(value)
self[:mode] = value.to_s
end
def github_mode?
mode == :github
end
private
# Strip leading and trailing whitespace
def strip_whitespace
self.url = url.strip rescue ''
end
# Remove blank entries in triggers
def remove_blank_triggers
self.triggers = triggers.select(&:present?)
end
end

View file

@ -1,47 +0,0 @@
class RepositoryProtectedBranche < ActiveRecord::Base
include Redmine::SafeAttributes
VALID_PERMS = ['RW+', 'RW', 'R', '-'].freeze
DEFAULT_PERM = 'RW+'.freeze
acts_as_positioned
## Attributes
safe_attributes 'path', 'permissions', 'position'
## Relations
belongs_to :repository
has_many :protected_branches_members, foreign_key: :protected_branch_id, dependent: :destroy
has_many :members, through: :protected_branches_members, source: :principal
## Validations
validates :repository_id, presence: true
validates :path, presence: true, uniqueness: { scope: %i[permissions repository_id] }
validates :permissions, presence: true, inclusion: { in: VALID_PERMS }
## Scopes
default_scope { order(position: :asc) }
class << self
def clone_from(parent)
parent = find_by(id: parent) unless parent.is_a? RepositoryProtectedBranche
copy = new
copy.attributes = parent.attributes
copy.repository = parent.repository
copy
end
end
# Accessors
#
def users
members.select { |m| m.class.name == 'User' }.uniq
end
def groups
members.select { |m| m.class.name == 'Group' }.uniq
end
def allowed_users
users.map(&:gitolite_identifier).sort
end
end

View file

@ -1,5 +0,0 @@
Deface::Override.new virtual_path: 'repositories/_navigation',
name: 'show-repositories-hook-navigation',
insert_before: 'erb[loud]:contains("label_statistics")',
original: '88f120e99075ba3246901c6e970ca671d7166855',
text: '<%= call_hook(:view_repositories_navigation, repository: @repository) %>'

View file

@ -1,11 +0,0 @@
Deface::Override.new virtual_path: 'repositories/show',
name: 'show-repositories-hook-bottom',
insert_before: 'erb[silent]:contains("other_formats_links")',
original: 'f302d110cd10675a0a952f5f3e1ecfe57ebd38be',
text: '<%= call_hook(:view_repositories_show_bottom, repository: @repository) %>'
Deface::Override.new virtual_path: 'repositories/show',
name: 'show-repositories-hook-sidebar',
insert_before: 'erb[silent]:contains("html_title")',
original: '2a0a09659d76066b896016c72527d479c69463ec',
partial: 'hooks/show_repositories_sidebar'

View file

@ -1,77 +0,0 @@
class RepositoryPresenter < SimpleDelegator
attr_reader :repository
def initialize(repository, template)
super(template)
@repository = repository
end
def link_to_repository
link_to repository.name,
controller: 'repositories',
action: 'show',
id: repository.project,
repository_id: repository.identifier_param,
rev: nil,
path: nil
end
def git_urls_box
content_tag(:div, class: 'git_url_box', id: urls_container_id) do
render_git_urls +
render_git_url_text +
render_permissions +
render_clipboard_button
end
end
private
def render_git_urls
content_tag(:ul, render_url_list, class: 'git_url_list')
end
def render_url_list
s = ''
repository.available_urls_sorted.each do |key, value|
s << content_tag(:li, link_to(key.upcase, 'javascript:void(0)').html_safe, options_for_git_url(key, value))
end
s.html_safe
end
def options_for_git_url(key, value)
{ class: 'git_url', data: { url: value[:url], target: element_name, committer: committer_label(value) } }
end
def render_git_url_text
content_tag(:input, '', class: 'git_url_text', id: url_text_container_id, readonly: 'readonly')
end
def render_permissions
content_tag(:div, content_tag(:span, '', id: permissions_container_id), class: 'git_url_permissions')
end
def render_clipboard_button
clipboardjs_button_for(url_text_container_id)
end
def committer_label(value)
Additionals.true?(value[:committer]) ? l(:label_read_write_permission) : l(:label_read_only_permission)
end
def element_name
"repository_#{repository.id}"
end
def urls_container_id
"git_url_box_#{element_name}"
end
def permissions_container_id
"git_url_permissions_#{element_name}"
end
def url_text_container_id
"git_url_text_#{element_name}"
end
end

View file

@ -1,13 +0,0 @@
class ReportBase
include Redmine::I18n
include ReportHelper
include ReportQuery
attr_reader :repository
def initialize(repository)
@repository = repository
end
end

View file

@ -1,44 +0,0 @@
module ReportHelper
def date_to
User.current.today
end
def week_day_hash
{ day_name(1) => 0,
day_name(2) => 0,
day_name(3) => 0,
day_name(4) => 0,
day_name(5) => 0,
day_name(6) => 0,
day_name(0) => 0 }
end
def hours
(0..23).step(1).map { |h| "#{h}h" }
end
def months
(1..12).map { |m| l('date.month_names')[m].capitalize }
end
def get_hour_from_date(date)
return nil unless date
time = date.to_time
zone = User.current.time_zone
local = zone ? time.in_time_zone(zone) : (time.utc? ? time.localtime : time)
local.hour
end
def total_by_month_for(method)
total = [0] * 12
send(method).each { |c| total[(date_to.month - c.first.to_date.month) % 12] += c.last }
total
end
def total_by_hour_for(method)
total = [0] * 24
send(method).each { |c| total[get_hour_from_date(c)] += 1 }
total
end
end

View file

@ -1,47 +0,0 @@
module ReportQuery
private
def all_changesets
@all_changesets ||= Changeset.where(repository_id: repository.id)
end
def all_changes
@all_changes ||= Change.joins(:changeset).where("#{Changeset.table_name}.repository_id = ?", repository.id)
end
def all_commits_by_day
@all_commits_by_day ||= all_changesets.group(:commit_date)
end
def all_changes_by_day
@all_changes_by_day ||= all_changes.group(:commit_date)
end
def redmine_committers
@redmine_committers ||= all_changesets.where.not(user_id: nil).distinct.count(:user_id)
end
def external_committers
@external_committers ||= all_changesets.where(user_id: nil).distinct.count(:committer)
end
def commits_by_day
@commits_by_day ||= all_commits_by_day.count
end
def changes_by_day
@changes_by_day ||= all_changes_by_day.count
end
def commits_by_hour
@commits_by_hour ||= all_changesets.map(&:committed_on)
end
def commits_by_author
@commits_by_author ||= all_changesets.group(:committer).count
end
def changes_by_author
@changes_by_author ||= all_changes.group(:committer).count
end
end

View file

@ -1,91 +0,0 @@
class RepositoryCommitsStats < ReportBase
def commits_per_month
data = {}
data[:categories] = months.reverse
data[:series] = []
data[:series] << { name: l(:label_commit_plural), data: total_commits_by_month[0..11].reverse }
data[:series] << { name: l(:label_change_plural), data: total_changes_by_month[0..11].reverse }
data
end
def commits_per_day
data = {}
data[:categories] = total_commits_by_day.keys
data[:series] = []
data[:series] << { name: l(:label_commit_plural), data: total_commits_by_day.values }
data[:series] << { name: l(:label_change_plural), data: total_changes_by_day.values }
data
end
def commits_per_hours
data = {}
data[:categories] = hours
data[:series] = []
data[:series] << { name: l(:label_commit_plural), data: total_commits_by_hour }
data
end
def commits_per_weekday
data = {}
data[:name] = l(:label_commit_plural)
data[:data] = []
total_commits_by_weekday.each do |key, value|
data[:data] << [key, value]
end
[data]
end
private
def total_commits_by_month
total_by_month_for(:commits_by_day)
end
def total_changes_by_month
total_by_month_for(:changes_by_day)
end
def total_commits_by_day
@total_commits_by_day ||= all_commits_by_day.order(:commit_date).count
end
def total_changes_by_day
return @total_changes_by_day unless @total_changes_by_day.nil?
@total_changes_by_day = nil
changes = {}
Changeset.where('repository_id = ?', repository.id).includes(:filechanges).order(:commit_date).each do |changeset|
changes[changeset.commit_date] = 0 unless changes.key?(changeset.commit_date)
changes[changeset.commit_date] += changeset.filechanges.size
end
@total_changes_by_day = changes
@total_changes_by_day
end
def total_commits_by_hour
total_by_hour_for(:commits_by_hour)
end
def total_commits_by_weekday
week_day = week_day_hash
commits_by_day.each do |commit_date, commit_count|
case commit_date.to_date.wday
when 0
week_day[day_name(0)] += commit_count
when 1
week_day[day_name(1)] += commit_count
when 2
week_day[day_name(2)] += commit_count
when 3
week_day[day_name(3)] += commit_count
when 4
week_day[day_name(4)] += commit_count
when 5
week_day[day_name(5)] += commit_count
when 6
week_day[day_name(6)] += commit_count
end
end
week_day
end
end

View file

@ -1,107 +0,0 @@
class RepositoryContributorsStats < ReportBase
def initialize(repository)
super
@changes_for_committer = {}
end
def commits_per_author
data = []
sorted_commits_per_author_with_aliases.each do |committer_hash|
commits = {}
committer_hash[:committers].each do |committer|
commits = commits.merge(count_changes_for_committer(committer)) { |key, oldval, newval| newval + oldval }
end
commits = Hash[commits.sort]
commits_data = {}
commits_data[:author_name] = committer_hash[:name]
commits_data[:author_mail] = committer_hash[:mail]
commits_data[:total_commits] = committer_hash[:commits]
commits_data[:categories] = commits.keys
commits_data[:series] = []
commits_data[:series] << { name: l(:label_commit_plural), data: commits.values }
data.push(commits_data)
end
data
end
def commits_per_author_global
merged = commits_per_author_with_aliases
data = {}
data[:categories] = merged.map { |x| x[:name] }
data[:series] = []
data[:series] << { name: l(:label_commit_plural), data: merged.map { |x| x[:commits] } }
data[:series] << { name: l(:label_change_plural), data: merged.map { |x| x[:changes] } }
data
end
private
# Generate mappings from the registered users to the comitters
# user_committer_mapping = { name => [comitter, ...] }
# registered_committers = [ committer,... ]
#
def commits_per_author_with_aliases
return @commits_per_author_with_aliases if !@commits_per_author_with_aliases.nil?
@commits_per_author_with_aliases = nil
registered_committers = []
user_committer_mapping = {}
Changeset.select('changesets.committer, changesets.user_id')
.where('repository_id = ? and user_id IS NOT NULL', repository.id)
.group(:committer, :user_id)
.includes(:user).each do |x|
name = "#{x.user.firstname} #{x.user.lastname}"
registered_committers << x.committer
user_committer_mapping[[name, x.user.mail]] ||= []
user_committer_mapping[[name, x.user.mail]] << x.committer
end
merged = []
commits_by_author.each do |committer, count|
# skip all registered users
next if registered_committers.include?(committer)
name = committer.gsub(%r{<.+@.+>}, '').strip
mail = committer[/<(.+@.+)>/, 1]
merged << { name: name, mail: mail, commits: count, changes: changes_by_author[committer] || 0, committers: [committer] }
end
user_committer_mapping.each do |identity, committers|
count = 0
changes = 0
committers.each do |c|
count += commits_by_author[c] || 0
changes += changes_by_author[c] || 0
end
merged << { name: identity[0], mail: identity[1], commits: count, changes: changes, committers: committers }
end
# sort by name
merged.sort! { |x, y| x[:name] <=> y[:name] }
# merged = merged + [{name:"",commits:0,changes:0}]*(10 - merged.length) if merged.length < 10
@commits_per_author_with_aliases = merged
@commits_per_author_with_aliases
end
def sorted_commits_per_author_with_aliases
@committers ||= commits_per_author_with_aliases.sort! { |x, y| y[:commits] <=> x[:commits] }
end
def count_changes_for_committer(committer)
return @changes_for_committer[committer] if !@changes_for_committer[committer].nil?
@changes_for_committer[committer] ||= Changeset.where('repository_id = ? AND committer = ?', repository.id, committer).group(:commit_date).order(:commit_date).count
@changes_for_committer[committer]
end
end

View file

@ -1,43 +0,0 @@
class RepositoryGlobalStats < ReportBase
def build
data = {}
data[l(:label_total_commits)] = total_commits
data[l(:label_total_contributors)] = committers
data[l(:label_first_commit_date)] = format_date(first_commit.commit_date)
data[l(:label_latest_commit_date)] = format_date(last_commit.commit_date)
data[l(:label_active_for)] = "#{active_for} #{l(:days, active_for)}"
data[l(:label_average_commit_per_day)] = average_commit_per_day
data[l(:label_average_contributor_commits)] = average_contributor_commits
data
end
private
def total_commits
@total_commits ||= all_changesets.count
end
def committers
@committers ||= redmine_committers + external_committers
end
def first_commit
@first_commit ||= all_changesets.order(commit_date: :asc).first
end
def last_commit
@last_commit ||= all_changesets.order(commit_date: :asc).last
end
def active_for
@active_for ||= (last_commit.commit_date - first_commit.commit_date).to_i
end
def average_commit_per_day
@average_commit_per_day ||= total_commits.fdiv(active_for).round(2)
end
def average_contributor_commits
@average_contributor_commits ||= total_commits.fdiv(committers).round(2)
end
end

View file

@ -1,38 +0,0 @@
module PermissionsBuilder
class Base
attr_reader :repository
attr_reader :gitolite_users
attr_reader :old_permissions
def initialize(repository, gitolite_users, old_permissions = {})
@repository = repository
@gitolite_users = gitolite_users
@old_permissions = old_permissions
end
class << self
def build(repository, gitolite_users, old_permissions = {})
new(repository, gitolite_users, old_permissions).build
end
end
def build
raise NotImplementedError
end
private
def has_no_users?(type)
gitolite_users[type].nil? || gitolite_users[type].empty?
end
end
end

View file

@ -1,29 +0,0 @@
module PermissionsBuilder
class ProtectedBranches < Base
attr_reader :permissions
def initialize(*args)
super
@permissions = []
end
def build
build_protected_branch_permissions
permissions
end
def build_protected_branch_permissions
repository.protected_branches.each do |branch|
perms = {}
perms[branch.permissions] = {}
perms[branch.permissions][branch.path] = branch.allowed_users unless branch.allowed_users.empty?
permissions.push(perms)
end
end
end
end

View file

@ -1,71 +0,0 @@
module PermissionsBuilder
class Standard < Base
attr_reader :permissions
def initialize(*args)
super
@permissions = {}
@permissions['RW+'] = {}
@permissions['RW'] = {}
@permissions['R'] = {}
end
def build
# Build permissions
build_permissions
# Return them
[merge_permissions(permissions, old_permissions)]
end
private
def build_permissions
@permissions['RW+'][''] = gitolite_users[:rewind_users] unless has_no_users?(:rewind_users)
@permissions['RW'][''] = gitolite_users[:write_users] unless has_no_users?(:write_users)
@permissions['R'][''] = gitolite_users[:read_users] unless has_no_users?(:read_users)
end
def merge_permissions(current_permissions, old_permissions)
merge_permissions = {}
merge_permissions['RW+'] = {}
merge_permissions['RW'] = {}
merge_permissions['R'] = {}
current_permissions.each do |perm, branch_settings|
branch_settings.each do |branch, user_list|
if user_list.any?
if !merge_permissions[perm].has_key?(branch)
merge_permissions[perm][branch] = []
end
merge_permissions[perm][branch] += user_list
end
end
end
old_permissions.each do |perm, branch_settings|
branch_settings.each do |branch, user_list|
if user_list.any?
if !merge_permissions[perm].has_key?(branch)
merge_permissions[perm][branch] = []
end
merge_permissions[perm][branch] += user_list
end
end
end
merge_permissions.each do |perm, branch_settings|
merge_permissions.delete(perm) if merge_permissions[perm].empty?
end
merge_permissions
end
end
end

View file

@ -1,70 +0,0 @@
module RedmineHooks
class Base
attr_reader :object
attr_reader :payloads
def initialize(object, payloads = {})
@object = object
@payloads = payloads
end
class << self
def call(object, payloads = {})
new(object, payloads).call
end
end
def call
raise NotImplementedError
end
def start_message
raise NotImplementedError
end
private
def logger
RedmineGitHosting.logger
end
def success_message
" [success]\n"
end
def failure_message
" [failure]\n"
end
def log_hook_succeeded
logger.info('Succeeded!')
end
def log_hook_failed
logger.error('Failed!')
end
def execute_hook(&block)
y = ''
logger.info(start_message)
y << " - #{start_message} ... "
yield y
y
end
end
end

View file

@ -1,118 +0,0 @@
module RedmineHooks
class CallWebservices < Base
include HttpHelper
attr_reader :payloads_to_send
def initialize(*args)
super
@payloads_to_send = []
set_payloads_to_send
end
def call
execute_hook do |out|
if needs_push?
out << call_webservice
else
out << "#{skip_message}\n"
logger.info(skip_message)
end
end
end
def post_receive_url
object
end
def needs_push?
return false if payloads.empty?
return true unless use_triggers?
return false if post_receive_url.triggers.empty?
return !payloads_to_send.empty?
end
def start_message
"Notifying #{post_receive_url.url}"
end
def skip_message
"This url doesn't need to be notified"
end
private
def set_payloads_to_send
if use_triggers?
@payloads_to_send = extract_payloads
else
@payloads_to_send = payloads
end
end
def extract_payloads
new_payloads = []
payloads.each do |payload|
data = RedmineGitHosting::Utils::Git.parse_refspec(payload[:ref])
if data[:type] == 'heads' && post_receive_url.triggers.include?(data[:name])
new_payloads << payload
end
end
new_payloads
end
def use_method
post_receive_url.mode == :github ? :http_post : :http_get
end
def use_triggers?
post_receive_url.use_triggers?
end
def split_payloads?
post_receive_url.split_payloads?
end
def call_webservice
if use_method == :http_post && split_payloads?
y = ''
payloads_to_send.each do |payload|
y << do_call_webservice(payload)
end
y
else
do_call_webservice(payloads_to_send)
end
end
def do_call_webservice(payload)
post_failed, post_message = self.send(use_method, post_receive_url.url, { data: { payload: payload } })
if post_failed
logger.error('Failed!')
logger.error(post_message)
(split_payloads? ? failure_message.gsub("\n", '') : failure_message)
else
log_hook_succeeded
(split_payloads? ? success_message.gsub("\n", '') : success_message)
end
end
end
end

View file

@ -1,38 +0,0 @@
module RedmineHooks
class FetchChangesets < Base
def call
repository.empty_cache!
execute_hook do |out|
out << fetch_changesets
end
end
def repository
object
end
def start_message
"Fetching changesets for '#{repository.redmine_name}' repository"
end
private
def fetch_changesets
begin
repository.fetch_changesets
log_hook_succeeded
success_message
rescue ::Redmine::Scm::Adapters::CommandFailed => e
log_hook_failed
logger.error("Error during fetching changesets : #{e.message}")
failure_message
end
end
end
end

View file

@ -1,152 +0,0 @@
require 'json'
module RedmineHooks
class GithubIssuesSync < Base
include HttpHelper
def call
sync_with_github
end
def project
object
end
def params
payloads
end
private
def github_issue
GithubIssue.find_by_github_id(params[:issue][:id])
end
def redmine_issue
Issue.find_by_subject(params[:issue][:title])
end
def sync_with_github
create_relation = false
## We don't have stored relation
if github_issue.nil?
## And we don't have issue in Redmine
if redmine_issue.nil?
create_relation = true
redmine_issue = create_redmine_issue
else
## Create relation and update issue
create_relation = true
redmine_issue = update_redmine_issue(redmine_issue)
end
else
## We have one relation, update issue
redmine_issue = update_redmine_issue(github_issue.issue)
end
if create_relation
github_issue = GithubIssue.new
github_issue.github_id = params[:issue][:id]
github_issue.issue_id = redmine_issue.id
github_issue.save!
end
if params.has_key?(:comment)
issue_journal = GithubComment.find_by_github_id(params[:comment][:id])
if issue_journal.nil?
issue_journal = create_issue_journal(github_issue.issue)
github_comment = GithubComment.new
github_comment.github_id = params[:comment][:id]
github_comment.journal_id = issue_journal.id
github_comment.save!
end
end
end
def create_redmine_issue
logger.info('Github Issues Sync : create new issue')
issue = project.issues.new
issue.tracker_id = project.trackers.first.try(:id)
issue.subject = params[:issue][:title].chomp[0, 255]
issue.description = params[:issue][:body]
issue.updated_on = params[:issue][:updated_at]
issue.created_on = params[:issue][:created_at]
## Get user mail
user = find_user(params[:issue][:user][:url])
issue.author = user
issue.save!
return issue
end
def create_issue_journal(issue)
logger.info("Github Issues Sync : create new journal for issue '##{issue.id}'")
journal = Journal.new
journal.journalized_id = issue.id
journal.journalized_type = 'Issue'
journal.notes = params[:comment][:body]
journal.created_on = params[:comment][:created_at]
## Get user mail
user = find_user(params[:comment][:user][:url])
journal.user_id = user.id
journal.save!
return journal
end
def update_redmine_issue(issue)
logger.info("Github Issues Sync : update issue '##{issue.id}'")
if params[:issue][:state] == 'closed'
issue.status_id = 5
else
issue.status_id = 1
end
issue.subject = params[:issue][:title].chomp[0, 255]
issue.description = params[:issue][:body]
issue.updated_on = params[:issue][:updated_at]
issue.save!
return issue
end
def find_user(url)
post_failed, user_data = http_get(url)
user_data = JSON.parse(user_data)
user = User.find_by_mail(user_data['email'])
if user.nil?
logger.info("Github Issues Sync : cannot find user '#{user_data['email']}' in Redmine, use anonymous")
user = User.anonymous
user.mail = user_data['email']
user.firstname = user_data['name']
user.lastname = user_data['login']
end
return user
end
end
end

View file

@ -1,14 +0,0 @@
module RedmineHooks
module HttpHelper
def http_post(url, opts = {})
RedmineGitHosting::Utils::Http.http_post(url, opts)
end
def http_get(url, opts = {})
RedmineGitHosting::Utils::Http.http_get(url, opts)
end
end
end

View file

@ -1,71 +0,0 @@
module RedmineHooks
class UpdateMirrors < Base
def call
execute_hook do |out|
if needs_push?
out << call_mirror
else
out << "#{skip_message}\n"
logger.info(skip_message)
end
end
end
def mirror
object
end
# If we have an explicit refspec, check it against incoming payloads
# Special case: if we do not pass in any payloads, return true
def needs_push?
return true if payloads.empty?
return true if mirror.mirror_mode?
return check_ref_spec
end
def start_message
"Pushing changes to #{mirror.url}"
end
def skip_message
"This mirror doesn't need to be updated"
end
private
def check_ref_spec
refspec_parse = RedmineGitHosting::Validators.valid_git_refspec?(mirror.explicit_refspec)
payloads.each do |payload|
if splitpath = RedmineGitHosting::Utils::Git.parse_refspec(payload[:ref])
return true if payload[:ref] == refspec_parse[1] # Explicit Reference Spec complete path
return true if splitpath[:name] == refspec_parse[1] # Explicit Reference Spec no type
return true if mirror.include_all_branches? && splitpath[:type] == 'heads'
return true if mirror.include_all_tags? && splitpath[:type] == 'tags'
end
end
false
end
def call_mirror
push_failed, push_message = RepositoryMirrors::Push.call(mirror)
if push_failed
log_hook_failed
logger.error(push_message)
failure_message
else
log_hook_succeeded
success_message
end
end
end
end

View file

@ -1,72 +0,0 @@
module GitolitePublicKeys
class GenerateIdentifier
DEPLOY_PSEUDO_USER = 'deploy_key'
attr_reader :public_key
attr_reader :user
attr_reader :skip_auto_increment
def initialize(public_key, user, opts = {})
@public_key = public_key
@user = user
@skip_auto_increment = opts.delete(:skip_auto_increment) { false }
end
class << self
def call(public_key, user, opts = {})
new(public_key, user, opts).call
end
end
# Returns the unique identifier for this key based on the key_type
#
# For user public keys, this simply is the user's gitolite_identifier.
# For deployment keys, we use an incrementing number.
#
def call
if public_key.user_key?
set_identifier_for_user_key
elsif public_key.deploy_key?
set_identifier_for_deploy_key
end
end
private
def set_identifier_for_user_key
tag = public_key.title.gsub(/[^0-9a-zA-Z]/, '_')
[user.gitolite_identifier, '@', 'redmine_', tag].join
end
# Fix https://github.com/jbox-web/redmine_git_hosting/issues/288
# Getting user deployment keys count is not sufficient to assure uniqueness of
# deployment key identifier. So we need an 'external' counter to increment the global count
# while a key with this identifier exists.
#
def set_identifier_for_deploy_key
count = 0
begin
key_id = generate_deploy_key_identifier(count)
count += 1
end while user.gitolite_public_keys.deploy_key.map(&:owner).include?(key_id.split('@')[0])
key_id
end
def generate_deploy_key_identifier(count)
key_count = 1 + count
key_count += user.gitolite_public_keys.deploy_key.length unless skip_auto_increment
[user.gitolite_identifier, '_', DEPLOY_PSEUDO_USER, '_', key_count, '@', 'redmine_', DEPLOY_PSEUDO_USER, '_', key_count].join
end
end
end

View file

@ -1,30 +0,0 @@
module Projects
class Base
include RedmineGitHosting::GitoliteAccessor::Methods
attr_reader :project
attr_reader :options
def initialize(project, opts = {})
@project = project
@options = opts
end
class << self
def call(project, opts = {})
new(project, opts).call
end
end
def call
raise NotImplementedError
end
end
end

View file

@ -1,32 +0,0 @@
module Projects
class CreateRepository < Base
def call
create_project_repository
end
private
def create_project_repository
# Create new repository
repository = Repository.factory('Xitolite')
repository.is_default = true
repository.extra_info = {}
repository.extra_info['extra_report_last_commit'] = '1'
# Save it to database
project.repositories << repository
# Create it in Gitolite
Repositories::Create.call(repository, creation_options)
end
def creation_options
{ create_readme_file: RedmineGitHosting::Config.init_repositories_on_create? }
end
end
end

View file

@ -1,38 +0,0 @@
module Projects
class ExecuteHooks
attr_reader :project
attr_reader :hook_type
attr_reader :params
def initialize(project, hook_type, params = {})
@project = project
@hook_type = hook_type
@params = params
end
class << self
def call(project, hook_type, params = {})
new(project, hook_type, params).call
end
end
def call
self.send("execute_#{hook_type}_hook")
end
private
def execute_github_hook
RedmineHooks::GithubIssuesSync.call(project, params)
end
end
end

View file

@ -1,29 +0,0 @@
module Projects
class Update < Base
def call
# Adjust daemon status
disable_git_daemon_if_not_public
resync
end
private
def disable_git_daemon_if_not_public
# Go through all gitolite repos and disable Git daemon if necessary
project.gitolite_repos.each do |repository|
repository.extra[:git_daemon] = false if repository.git_daemon_enabled? && !project.is_public
# Save GitExtra in all cases to trigger urls order consistency checks
repository.extra.save
end
end
def resync
gitolite_accessor.update_projects([project.id], options)
end
end
end

View file

@ -1,40 +0,0 @@
module Repositories
class Base
include RedmineGitHosting::GitoliteAccessor::Methods
attr_reader :repository
attr_reader :options
attr_reader :project
def initialize(repository, opts = {})
@repository = repository
@options = opts
@project = repository.project
end
class << self
def call(repository, opts = {})
new(repository, opts).call
end
end
def call
raise NotImplementedError
end
private
def logger
RedmineGitHosting.logger
end
end
end

View file

@ -1,91 +0,0 @@
module Repositories
class BuildPayload < Base
def initialize(*args)
super
@payloads = []
end
def call
build_payloads
end
def refs
options
end
private
# Returns an array of GitHub post-receive hook style hashes
# http://help.github.com/post-receive-hooks/
#
def build_payloads
refs.each do |ref|
# Get revisions range
range = get_revisions_from_ref(ref)
next if range.nil?
@payloads << build_payload(ref, range)
end
@payloads
end
def get_revisions_from_ref(ref)
oldhead, newhead, refname = ref.split(',')
# Only pay attention to branch updates
return nil if !refname.match(/refs\/heads\//)
# Get branch name
branch_name = refname.gsub('refs/heads/', '')
if newhead.match(/\A0{40}\z/)
# Deleting a branch
logger.info("Deleting branch '#{branch_name}'")
range = nil
elsif oldhead.match(/\A0{40}\z/)
# Creating a branch
logger.info("Creating branch '#{branch_name}'")
range = newhead
else
range = "#{oldhead}..#{newhead}"
end
range
end
def build_payload(ref, range)
revisions_in_range = get_revisions_in_range(range)
logger.debug("Revisions in range : #{revisions_in_range.join(' ')}")
# Get refs
oldhead, newhead, refname = ref.split(',')
# Build payload hash
repository.github_payload
.merge({ before: oldhead, after: newhead, ref: refname, commits: build_commits_list(revisions_in_range) })
end
def build_commits_list(revisions_in_range)
commits_list = []
revisions_in_range.each do |rev|
changeset = repository.find_changeset_by_name(rev)
next if changeset.nil?
commits_list << changeset.github_payload
end
commits_list
end
def get_revisions_in_range(range)
repository.rev_list(range, ['--reverse'])
end
end
end

View file

@ -1,71 +0,0 @@
module Repositories
class Create < Base
def call
set_repository_extra
create_repository
end
private
def set_repository_extra
extra = repository.build_extra(default_extra_options)
extra.save!
end
def default_extra_options
enable_git_annex? ? git_annex_repository_options : standard_repository_options
end
def enable_git_annex?
options[:enable_git_annex]
end
def standard_repository_options
{
git_daemon: RedmineGitHosting::Config.gitolite_daemon_by_default?,
git_notify: RedmineGitHosting::Config.gitolite_notify_by_default?,
git_annex: false,
default_branch: 'master',
key: RedmineGitHosting::Utils::Crypto.generate_secret(64)
}.merge(smart_http_options)
end
def smart_http_options
case RedmineGitHosting::Config.gitolite_http_by_default?
when '1' # HTTPS only
{ git_https: true }
when '2' # HTTPS and HTTP
{ git_http: true, git_https: true }
when '3' # HTTP only
{ git_http: true }
else
{}
end
end
def git_annex_repository_options
{
git_http: 0,
git_daemon: false,
git_notify: false,
git_annex: true,
default_branch: 'git-annex',
key: RedmineGitHosting::Utils::Crypto.generate_secret(64)
}
end
def create_repository
gitolite_accessor.create_repository(repository, options)
end
end
end

View file

@ -1,93 +0,0 @@
module Repositories
class DownloadRevision
attr_reader :repository
attr_reader :revision
attr_reader :format
attr_reader :gitolite_repository_path
attr_reader :commit_id
attr_reader :content_type
attr_reader :filename
def initialize(repository, revision, format)
@repository = repository
@revision = revision
@format = format
@gitolite_repository_path = repository.gitolite_repository_path
@valid_commit = false
@commit_id = nil
@content_type = ''
@filename = ''
validate_revision
fill_data
end
def content
repository.archive(commit_id, format)
end
def valid_commit?
@valid_commit
end
private
def validate_revision
commit = nil
# is the revision a branch?
repository.branches.each do |x|
if x.to_s == revision
commit = x.revision
break
end
end
# is the revision a tag?
if commit.nil?
repository.tags.each do |x|
if x == revision
commit = repository.rev_list(revision).first
break
end
end
end
# well, let check if this is a valid commit
commit = revision if commit.nil?
commit = repository.rev_parse(commit)
if commit == ''
@valid_commit = false
else
@valid_commit = true
@commit_id = commit
end
end
def fill_data
case format
when 'tar.gz' then
extension = 'tar.gz'
@content_type = 'application/x-gzip'
when 'zip' then
extension = 'zip'
@content_type = 'application/x-zip'
else
extension = 'tar'
@content_type = 'application/x-tar'
end
@filename = "#{repository.redmine_name}-#{revision}.#{extension}"
end
end
end

View file

@ -1,79 +0,0 @@
module Repositories
class ExecuteHooks
attr_reader :repository
attr_reader :hook_type
attr_reader :payloads
def initialize(repository, hook_type, payloads = {})
@repository = repository
@hook_type = hook_type
@payloads = payloads
end
class << self
def call(repository, hook_type, payloads = {})
new(repository, hook_type, payloads).call
end
end
def call
self.send("execute_#{hook_type}_hook")
end
private
def logger
RedmineGitHosting.logger
end
def execute_fetch_changesets_hook
RedmineHooks::FetchChangesets.call(repository)
end
def execute_update_mirrors_hook
message = 'Notifying mirrors about changes to this repository :'
y = ''
## Post to each post-receive URL
if repository.mirrors.active.any?
logger.info(message)
y << "\n#{message}\n"
repository.mirrors.active.each do |mirror|
y << RedmineHooks::UpdateMirrors.call(mirror, payloads)
end
end
y
end
def execute_call_webservices_hook
message = 'Notifying post receive urls about changes to this repository :'
y = ''
## Post to each post-receive URL
if repository.post_receive_urls.active.any?
logger.info(message)
y << "\n#{message}\n"
repository.post_receive_urls.active.each do |post_receive_url|
y << RedmineHooks::CallWebservices.call(post_receive_url, payloads)
end
end
y
end
end
end

View file

@ -1,28 +0,0 @@
module RepositoryMirrors
class Base
attr_reader :mirror
attr_reader :repository
def initialize(mirror)
@mirror = mirror
@repository = mirror.repository
end
class << self
def call(mirror)
new(mirror).call
end
end
def call
raise NotImplementedError
end
end
end

View file

@ -1,55 +0,0 @@
module RepositoryMirrors
class Push < Base
def call
push!
end
def push!
begin
push_message = repository.mirror_push(*command)
push_failed = false
rescue RedmineGitHosting::Error::GitoliteCommandException => e
push_message = e.output
push_failed = true
end
return push_failed, push_message
end
def command
[mirror.url, branch, push_args]
end
private
def push_args
mirror.mirror_mode? ? ['--mirror'] : mirror_args
end
def mirror_args
push_args = []
push_args << '--force' if mirror.force_mode?
push_args << '--all' if mirror.include_all_branches?
push_args << '--tags' if mirror.include_all_tags?
push_args
end
def branch
"#{dequote(mirror.explicit_refspec)}" unless mirror.explicit_refspec.blank?
end
# Put backquote in front of crucial characters
def dequote(in_string)
in_string.gsub(/[$,"\\\n]/) { |x| "\\" + x }
end
end
end

View file

@ -1,91 +0,0 @@
module RepositoryProtectedBranches
class MemberManager
attr_reader :protected_branch
def initialize(protected_branch)
@protected_branch = protected_branch
end
def current_user_ids
protected_branch.users.map(&:id)
end
def current_group_ids
protected_branch.groups.map(&:id)
end
def current_members
protected_branch.protected_branches_members
end
def users_by_group_id(id)
current_members.select { |pbm| pbm.principal.class.name == 'User' && pbm.inherited_by == id }.map(&:principal)
end
def add_users(ids)
create_user_member(ids, current_user_ids)
end
def add_groups(ids)
create_group_member(ids, current_group_ids) do |group|
ids = group.users.map(&:id)
current_ids = users_by_group_id(group.id).map(&:id)
create_user_member(ids, current_ids, inherited_by: group.id, destroy: false)
end
end
def create_user_member(ids, current_ids, opts = {}, &block)
create_member(ids, current_ids, 'User', opts, &block)
end
def create_group_member(ids, current_ids, opts = {}, &block)
create_member(ids, current_ids, 'Group', opts, &block)
end
def add_user_from_group(user, group_id)
ids = users_by_group_id(group_id).push(user).map(&:id)
current_ids = users_by_group_id(group_id).map(&:id)
create_user_member(ids, current_ids, inherited_by: group_id, destroy: false)
end
def remove_user_from_group(user, group_id)
return unless users_by_group_id(group_id).include?(user)
member = current_members.find_by_protected_branch_id_and_principal_id_and_inherited_by(protected_branch.id, user.id, group_id)
member.destroy! unless member.nil?
end
def create_member(ids, current_ids, klass, opts = {}, &block)
destroy = opts.fetch(:destroy, true)
inherited_by = opts.fetch(:inherited_by, nil)
ids = (ids || []).collect(&:to_i) - [0]
new_ids = ids - current_ids
new_ids.each do |id|
object = klass.constantize.find_by_id(id)
next if object.nil?
current_members.create(principal_id: object.id, inherited_by: inherited_by)
yield object if block_given?
end
if destroy
member_to_destroy = current_members.select { |m| m.principal.class.name == klass && !ids.include?(m.principal.id) }
member_to_destroy.each(&:destroy) if member_to_destroy.any?
end
end
end
end

Some files were not shown because too many files have changed in this diff Show more