release: Merge default into stable for release preparation

This commit is contained in:
Marcin Kuzminski 2016-08-12 12:28:59 +00:00
commit 0bf319bc22
393 changed files with 21780 additions and 9081 deletions

View file

@ -1,5 +1,5 @@
[bumpversion]
current_version = 4.2.1
current_version = 4.3.0
message = release: Bump version {current_version} to {new_version}
[bumpversion:file:rhodecode/VERSION]

View file

@ -25,6 +25,7 @@ syntax: regexp
^build/
^coverage\.xml$
^data$
^\.eggs/
^configs/data$
^dev.ini$
^acceptance_tests/dev.*\.ini$

View file

@ -4,27 +4,22 @@ done = false
[task:bump_version]
done = true
[task:rc_tools_pinned]
done = true
[task:fixes_on_stable]
done = true
[task:pip2nix_generated]
done = true
[task:changelog_updated]
done = true
[task:generate_api_docs]
done = true
[release]
state = prepared
version = 4.2.1
[task:updated_translation]
[release]
state = in_progress
version = 4.3.0
[task:rc_tools_pinned]
[task:generate_js_routes]
[task:updated_trial_license]

View file

@ -20,6 +20,7 @@ module.exports = function(grunt) {
'<%= dirs.js.src %>/moment.js',
'<%= dirs.js.src %>/appenlight-client-0.4.1.min.js',
'<%= dirs.js.src %>/i18n_utils.js',
'<%= dirs.js.src %>/deform.js',
// Plugins
'<%= dirs.js.src %>/plugins/jquery.pjax.js',
@ -31,6 +32,7 @@ module.exports = function(grunt) {
'<%= dirs.js.src %>/plugins/jquery.mark.js',
'<%= dirs.js.src %>/plugins/jquery.timeago.js',
'<%= dirs.js.src %>/plugins/jquery.timeago-extension.js',
'<%= dirs.js.src %>/plugins/toastr.js',
// Select2
'<%= dirs.js.src %>/select2/select2.js',
@ -56,12 +58,14 @@ module.exports = function(grunt) {
'<%= dirs.js.src %>/rhodecode/utils/colorgenerator.js',
'<%= dirs.js.src %>/rhodecode/utils/ie.js',
'<%= dirs.js.src %>/rhodecode/utils/os.js',
'<%= dirs.js.src %>/rhodecode/utils/topics.js',
// Rhodecode widgets
'<%= dirs.js.src %>/rhodecode/widgets/multiselect.js',
// Rhodecode components
'<%= dirs.js.src %>/rhodecode/init.js',
'<%= dirs.js.src %>/rhodecode/connection_controller.js',
'<%= dirs.js.src %>/rhodecode/codemirror.js',
'<%= dirs.js.src %>/rhodecode/comments.js',
'<%= dirs.js.src %>/rhodecode/constants.js',
@ -76,6 +80,7 @@ module.exports = function(grunt) {
'<%= dirs.js.src %>/rhodecode/select2_widgets.js',
'<%= dirs.js.src %>/rhodecode/tooltips.js',
'<%= dirs.js.src %>/rhodecode/users.js',
'<%= dirs.js.src %>/rhodecode/utils/notifications.js',
'<%= dirs.js.src %>/rhodecode/appenlight.js',
// Rhodecode main module

View file

@ -10,8 +10,10 @@ permission notice:
file:
Copyright (c) 2008-2011 - msgpack-python
file:licenses/msgpack_license.txt
Copyright (c) 2009 - tornado
file:licenses/tornado_license.txt
Both licensed under the Apache License, Version 2.0 (the "License");
All licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

View file

@ -2,20 +2,20 @@
include test.ini
include MANIFEST.in
include README.rst
include CHANGES.rst
include LICENSE.txt
include rhodecode/VERSION
# docs
recursive-include docs *
# init.d
recursive-include init.d *
# all config files
recursive-include configs *
# translations
recursive-include rhodecode/i18n *
# bin stuff
recursive-include rhodecode/bin *
# hook templates
recursive-include rhodecode/config/hook_templates *

View file

@ -20,7 +20,7 @@ ci-docs: docs;
clean: test-clean
find . -type f \( -iname '*.c' -o -iname '*.pyc' -o -iname '*.so' \) -exec rm '{}' ';'
test: test-clean test-lint test-only
test: test-clean test-only
test-clean:
rm -rf coverage.xml htmlcov junit.xml pylint.log result

View file

@ -1,47 +0,0 @@
README - Quickstart
===================
This folder contains the functional tests and automation of specification
examples. Details about testing can be found in
`/docs-internal/testing/index.rst`.
Setting up your Rhodecode Enterprise instance
---------------------------------------------
The tests will create users and repositories as needed, so you can start with a
new and empty instance.
Use the following example call for the database setup of Enterprise::
paster setup-rhodecode \
--user=admin \
--email=admin@example.com \
--password=secret \
--api-key=9999999999999999999999999999999999999999 \
your-enterprise-config.ini
This way the username, password, and auth token of the admin user will match the
defaults from the test run.
Usage
-----
1. Make sure your Rhodecode Enterprise instance is running at
http://localhost:5000.
2. Enter `nix-shell` from the acceptance_tests folder::
cd acceptance_tests
nix-shell
Make sure that `rcpkgs` and `rcnixpkgs` are available on the nix path.
3. Run the tests::
py.test -c example.ini -vs
The parameter ``-vs`` allows you to see debugging output during the test
run. Check ``py.test --help`` and the documentation at http://pytest.org to
learn all details about the test runner.

View file

@ -1,24 +1,37 @@
################################################################################
################################################################################
# RhodeCode Enterprise - configuration file #
# Built-in functions and variables #
## RHODECODE ENTERPRISE CONFIGURATION ##
# The %(here)s variable will be replaced with the parent directory of this file#
# #
################################################################################
[DEFAULT]
debug = true
################################################################################
## EMAIL CONFIGURATION ##
## Uncomment and replace with the email address which should receive ##
## any error reports after an application crash ##
## Additionally these settings will be used by the RhodeCode mailing system ##
################################################################################
#email_to = admin@localhost
#error_email_from = paste_error@localhost
#app_email_from = rhodecode-noreply@localhost
#error_message =
## prefix all emails subjects with given prefix, helps filtering out emails
#email_prefix = [RhodeCode]
## email FROM address all mails will be sent
#app_email_from = rhodecode-noreply@localhost
## Uncomment and replace with the address which should receive any error report
## note: using appenlight for error handling doesn't need this to be uncommented
#email_to = admin@localhost
## in case of Application errors, sent an error email form
#error_email_from = rhodecode_error@localhost
## additional error message to be send in case of server crash
#error_message =
#smtp_server = mail.server.com
#smtp_username =
#smtp_password =
@ -37,6 +50,7 @@ port = 5000
## WAITRESS WSGI SERVER ##
## Recommended for Development ##
##################################
use = egg:waitress#main
## number of worker threads
threads = 5
@ -51,6 +65,7 @@ asyncore_use_poll = true
## GUNICORN WSGI SERVER ##
##########################
## run with gunicorn --log-config <inifile.ini> --paste <inifile.ini>
#use = egg:gunicorn#main
## Sets the number of process workers. You must set `instance_id = *`
## when this option is set to more than one worker, recommended
@ -77,15 +92,18 @@ asyncore_use_poll = true
## prefix middleware for RhodeCode, disables force_https flag.
## recommended when using proxy setup.
## allows to set RhodeCode under a prefix in server.
## eg https://server.com/<prefix>. Enable `filter-with =` option below as well.
#[filter:proxy-prefix]
#use = egg:PasteDeploy#prefix
#prefix = /<your-prefix>
## optionally set prefix like: `prefix = /<your-prefix>`
[filter:proxy-prefix]
use = egg:PasteDeploy#prefix
prefix = /
[app:main]
use = egg:rhodecode-enterprise-ce
## enable proxy prefix middleware, defined below
## enable proxy prefix middleware, defined above
#filter-with = proxy-prefix
# During development the we want to have the debug toolbar enabled
@ -123,12 +141,10 @@ rhodecode.api.url = /_admin/api
## `SignatureVerificationError` in case of wrong key, or damaged encryption data.
#rhodecode.encrypted_values.strict = false
full_stack = true
## return gzipped responses from Rhodecode (static files/application)
gzip_responses = false
## Serve static files via RhodeCode, disable to serve them via HTTP server
static_files = true
# autogenerate javascript routes file on startup
## autogenerate javascript routes file on startup
generate_js_files = false
## Optional Languages
@ -317,8 +333,8 @@ beaker.cache.sql_cache_short.type = memory
beaker.cache.sql_cache_short.expire = 10
beaker.cache.sql_cache_short.key_length = 256
# default is memory cache, configure only if required
# using multi-node or multi-worker setup
## default is memory cache, configure only if required
## using multi-node or multi-worker setup
#beaker.cache.auth_plugins.type = ext:database
#beaker.cache.auth_plugins.lock_dir = %(here)s/data/cache/auth_plugin_lock
#beaker.cache.auth_plugins.url = postgresql://postgres:secret@localhost/rhodecode
@ -331,8 +347,8 @@ beaker.cache.repo_cache_long.type = memorylru_base
beaker.cache.repo_cache_long.max_items = 4096
beaker.cache.repo_cache_long.expire = 2592000
# default is memorylru_base cache, configure only if required
# using multi-node or multi-worker setup
## default is memorylru_base cache, configure only if required
## using multi-node or multi-worker setup
#beaker.cache.repo_cache_long.type = ext:memcached
#beaker.cache.repo_cache_long.url = localhost:11211
#beaker.cache.repo_cache_long.expire = 1209600
@ -347,7 +363,7 @@ beaker.cache.repo_cache_long.expire = 2592000
beaker.session.type = file
beaker.session.data_dir = %(here)s/data/sessions/data
## db based session, fast, and allows easy management over logged in users ##
## db based session, fast, and allows easy management over logged in users
#beaker.session.type = ext:database
#beaker.session.table_name = db_session
#beaker.session.sa.url = postgresql://postgres:secret@localhost/rhodecode
@ -368,6 +384,7 @@ beaker.session.lock_dir = %(here)s/data/sessions/lock
## accessed for given amount of time in seconds
beaker.session.timeout = 2592000
beaker.session.httponly = true
## Path to use for the cookie.
#beaker.session.cookie_path = /<your-prefix>
## uncomment for https secure cookie
@ -391,6 +408,23 @@ beaker.session.auto = false
search.module = rhodecode.lib.index.whoosh
search.location = %(here)s/data/index
########################################
### CHANNELSTREAM CONFIG ####
########################################
## channelstream enables persistent connections and live notification
## in the system. It's also used by the chat system
channelstream.enabled = true
## location of channelstream server on the backend
channelstream.server = 127.0.0.1:9800
## location of the channelstream server from outside world
## most likely this would be an http server special backend URL, that handles
## websocket connections see nginx example for config
channelstream.ws_url = ws://rhodecode.yourserver.com/_channelstream
channelstream.secret = secret
channelstream.history.location = %(here)s/channelstream_history
###################################
## APPENLIGHT CONFIG ##
###################################
@ -466,9 +500,10 @@ debug_style = true
#########################################################
### DB CONFIGS - EACH DB WILL HAVE IT'S OWN CONFIG ###
#########################################################
sqlalchemy.db1.url = sqlite:///%(here)s/rhodecode.db?timeout=30
#sqlalchemy.db1.url = sqlite:///%(here)s/rhodecode.db?timeout=30
#sqlalchemy.db1.url = postgresql://postgres:qweqwe@localhost/rhodecode
#sqlalchemy.db1.url = mysql://root:qweqwe@localhost/rhodecode
sqlalchemy.db1.url = sqlite:///%(here)s/rhodecode.db?timeout=30
# see sqlalchemy docs for other advanced settings
@ -498,28 +533,53 @@ vcs.server = localhost:9900
## Available protocols are:
## `pyro4` - using pyro4 server
## `http` - using http-rpc backend
#vcs.server.protocol = http
vcs.server.protocol = http
## Push/Pull operations protocol, available options are:
## `pyro4` - using pyro4 server
## `rhodecode.lib.middleware.utils.scm_app_http` - Http based, recommended
## `vcsserver.scm_app` - internal app (EE only)
#vcs.scm_app_implementation = rhodecode.lib.middleware.utils.scm_app_http
vcs.scm_app_implementation = rhodecode.lib.middleware.utils.scm_app_http
## Push/Pull operations hooks protocol, available options are:
## `pyro4` - using pyro4 server
## `http` - using http-rpc backend
#vcs.hooks.protocol = http
vcs.hooks.protocol = http
vcs.server.log_level = debug
## Start VCSServer with this instance as a subprocess, usefull for development
vcs.start_server = true
## List of enabled VCS backends, available options are:
## `hg` - mercurial
## `git` - git
## `svn` - subversion
vcs.backends = hg, git, svn
vcs.connection_timeout = 3600
## Compatibility version when creating SVN repositories. Defaults to newest version when commented out.
## Available options are: pre-1.4-compatible, pre-1.5-compatible, pre-1.6-compatible, pre-1.8-compatible
#vcs.svn.compatible_version = pre-1.8-compatible
############################################################
### Subversion proxy support (mod_dav_svn) ###
### Maps RhodeCode repo groups into SVN paths for Apache ###
############################################################
## Enable or disable the config file generation.
svn.proxy.generate_config = false
## Generate config file with `SVNListParentPath` set to `On`.
svn.proxy.list_parent_path = true
## Set location and file name of generated config file.
svn.proxy.config_file_path = %(here)s/mod_dav_svn.conf
## File system path to the directory containing the repositories served by
## RhodeCode.
svn.proxy.parent_path_root = /path/to/repo_store
## Used as a prefix to the <Location> block in the generated config file. In
## most cases it should be set to `/`.
svn.proxy.location_root = /
################################
### LOGGING CONFIGURATION ####
################################

View file

@ -1,24 +1,37 @@
################################################################################
################################################################################
# RhodeCode Enterprise - configuration file #
# Built-in functions and variables #
## RHODECODE ENTERPRISE CONFIGURATION ##
# The %(here)s variable will be replaced with the parent directory of this file#
# #
################################################################################
[DEFAULT]
debug = true
################################################################################
## EMAIL CONFIGURATION ##
## Uncomment and replace with the email address which should receive ##
## any error reports after an application crash ##
## Additionally these settings will be used by the RhodeCode mailing system ##
################################################################################
#email_to = admin@localhost
#error_email_from = paste_error@localhost
#app_email_from = rhodecode-noreply@localhost
#error_message =
## prefix all emails subjects with given prefix, helps filtering out emails
#email_prefix = [RhodeCode]
## email FROM address all mails will be sent
#app_email_from = rhodecode-noreply@localhost
## Uncomment and replace with the address which should receive any error report
## note: using appenlight for error handling doesn't need this to be uncommented
#email_to = admin@localhost
## in case of Application errors, sent an error email form
#error_email_from = rhodecode_error@localhost
## additional error message to be send in case of server crash
#error_message =
#smtp_server = mail.server.com
#smtp_username =
#smtp_password =
@ -37,6 +50,7 @@ port = 5000
## WAITRESS WSGI SERVER ##
## Recommended for Development ##
##################################
#use = egg:waitress#main
## number of worker threads
#threads = 5
@ -51,6 +65,7 @@ port = 5000
## GUNICORN WSGI SERVER ##
##########################
## run with gunicorn --log-config <inifile.ini> --paste <inifile.ini>
use = egg:gunicorn#main
## Sets the number of process workers. You must set `instance_id = *`
## when this option is set to more than one worker, recommended
@ -77,15 +92,18 @@ timeout = 21600
## prefix middleware for RhodeCode, disables force_https flag.
## recommended when using proxy setup.
## allows to set RhodeCode under a prefix in server.
## eg https://server.com/<prefix>. Enable `filter-with =` option below as well.
#[filter:proxy-prefix]
#use = egg:PasteDeploy#prefix
#prefix = /<your-prefix>
## optionally set prefix like: `prefix = /<your-prefix>`
[filter:proxy-prefix]
use = egg:PasteDeploy#prefix
prefix = /
[app:main]
use = egg:rhodecode-enterprise-ce
## enable proxy prefix middleware, defined below
## enable proxy prefix middleware, defined above
#filter-with = proxy-prefix
## encryption key used to encrypt social plugin tokens,
@ -97,12 +115,10 @@ use = egg:rhodecode-enterprise-ce
## `SignatureVerificationError` in case of wrong key, or damaged encryption data.
#rhodecode.encrypted_values.strict = false
full_stack = true
## return gzipped responses from Rhodecode (static files/application)
gzip_responses = false
## Serve static files via RhodeCode, disable to serve them via HTTP server
static_files = true
# autogenerate javascript routes file on startup
## autogenerate javascript routes file on startup
generate_js_files = false
## Optional Languages
@ -291,8 +307,8 @@ beaker.cache.sql_cache_short.type = memory
beaker.cache.sql_cache_short.expire = 10
beaker.cache.sql_cache_short.key_length = 256
# default is memory cache, configure only if required
# using multi-node or multi-worker setup
## default is memory cache, configure only if required
## using multi-node or multi-worker setup
#beaker.cache.auth_plugins.type = ext:database
#beaker.cache.auth_plugins.lock_dir = %(here)s/data/cache/auth_plugin_lock
#beaker.cache.auth_plugins.url = postgresql://postgres:secret@localhost/rhodecode
@ -305,8 +321,8 @@ beaker.cache.repo_cache_long.type = memorylru_base
beaker.cache.repo_cache_long.max_items = 4096
beaker.cache.repo_cache_long.expire = 2592000
# default is memorylru_base cache, configure only if required
# using multi-node or multi-worker setup
## default is memorylru_base cache, configure only if required
## using multi-node or multi-worker setup
#beaker.cache.repo_cache_long.type = ext:memcached
#beaker.cache.repo_cache_long.url = localhost:11211
#beaker.cache.repo_cache_long.expire = 1209600
@ -321,7 +337,7 @@ beaker.cache.repo_cache_long.expire = 2592000
beaker.session.type = file
beaker.session.data_dir = %(here)s/data/sessions/data
## db based session, fast, and allows easy management over logged in users ##
## db based session, fast, and allows easy management over logged in users
#beaker.session.type = ext:database
#beaker.session.table_name = db_session
#beaker.session.sa.url = postgresql://postgres:secret@localhost/rhodecode
@ -342,6 +358,7 @@ beaker.session.lock_dir = %(here)s/data/sessions/lock
## accessed for given amount of time in seconds
beaker.session.timeout = 2592000
beaker.session.httponly = true
## Path to use for the cookie.
#beaker.session.cookie_path = /<your-prefix>
## uncomment for https secure cookie
@ -365,6 +382,23 @@ beaker.session.auto = false
search.module = rhodecode.lib.index.whoosh
search.location = %(here)s/data/index
########################################
### CHANNELSTREAM CONFIG ####
########################################
## channelstream enables persistent connections and live notification
## in the system. It's also used by the chat system
channelstream.enabled = true
## location of channelstream server on the backend
channelstream.server = 127.0.0.1:9800
## location of the channelstream server from outside world
## most likely this would be an http server special backend URL, that handles
## websocket connections see nginx example for config
channelstream.ws_url = ws://rhodecode.yourserver.com/_channelstream
channelstream.secret = secret
channelstream.history.location = %(here)s/channelstream_history
###################################
## APPENLIGHT CONFIG ##
###################################
@ -436,8 +470,9 @@ set debug = false
### DB CONFIGS - EACH DB WILL HAVE IT'S OWN CONFIG ###
#########################################################
#sqlalchemy.db1.url = sqlite:///%(here)s/rhodecode.db?timeout=30
sqlalchemy.db1.url = postgresql://postgres:qweqwe@localhost/rhodecode
#sqlalchemy.db1.url = postgresql://postgres:qweqwe@localhost/rhodecode
#sqlalchemy.db1.url = mysql://root:qweqwe@localhost/rhodecode
sqlalchemy.db1.url = postgresql://postgres:qweqwe@localhost/rhodecode
# see sqlalchemy docs for other advanced settings
@ -483,12 +518,37 @@ vcs.server = localhost:9900
vcs.server.log_level = info
## Start VCSServer with this instance as a subprocess, usefull for development
vcs.start_server = false
## List of enabled VCS backends, available options are:
## `hg` - mercurial
## `git` - git
## `svn` - subversion
vcs.backends = hg, git, svn
vcs.connection_timeout = 3600
## Compatibility version when creating SVN repositories. Defaults to newest version when commented out.
## Available options are: pre-1.4-compatible, pre-1.5-compatible, pre-1.6-compatible, pre-1.8-compatible
#vcs.svn.compatible_version = pre-1.8-compatible
############################################################
### Subversion proxy support (mod_dav_svn) ###
### Maps RhodeCode repo groups into SVN paths for Apache ###
############################################################
## Enable or disable the config file generation.
svn.proxy.generate_config = false
## Generate config file with `SVNListParentPath` set to `On`.
svn.proxy.list_parent_path = true
## Set location and file name of generated config file.
svn.proxy.config_file_path = %(here)s/mod_dav_svn.conf
## File system path to the directory containing the repositories served by
## RhodeCode.
svn.proxy.parent_path_root = /path/to/repo_store
## Used as a prefix to the <Location> block in the generated config file. In
## most cases it should be set to `/`.
svn.proxy.location_root = /
################################
### LOGGING CONFIGURATION ####
################################

View file

@ -123,8 +123,9 @@ let
# pkgs/default.nix?
passthru = {
inherit
pythonLocalOverrides
myPythonPackagesUnfix;
linkNodeModules
myPythonPackagesUnfix
pythonLocalOverrides;
pythonPackages = self;
};
@ -165,6 +166,7 @@ let
ln -s ${self.supervisor}/bin/supervisor* $out/bin/
ln -s ${self.gunicorn}/bin/gunicorn $out/bin/
ln -s ${self.PasteScript}/bin/paster $out/bin/
ln -s ${self.channelstream}/bin/channelstream $out/bin/
ln -s ${self.pyramid}/bin/* $out/bin/ #*/
# rhodecode-tools

6
docs/_templates/footer.html vendored Normal file
View file

@ -0,0 +1,6 @@
{% extends "!footer.html" %}
{% block extrafooter %}
<br/>
Documentation defects and suggestions can be submitted <a href="https://issues.rhodecode.com/projects/documentation">here</a>
{% endblock %}

View file

@ -9,9 +9,9 @@ Here is a sample configuration file for using Apache as a reverse proxy.
ServerName hg.myserver.com
ServerAlias hg.myserver.com
## uncomment root directive if you want to serve static files by
## Apache requires static_files = false in .ini file
#DocumentRoot /path/to/rhodecode/installation/public
## uncomment to serve static files by Apache
## ProxyPass /_static/rhodecode !
## Alias /_static/rhodecode /path/to/.rccontrol/enterprise-1/static
<Proxy *>
Order allow,deny

View file

@ -16,17 +16,18 @@ Use the following example to configure Apache to use a URL prefix.
In addition to the regular Apache setup you will need to add the following
lines into the ``rhodecode.ini`` file.
* In the the ``[app:main]`` section of your ``rhodecode.ini`` file add the
following line.
.. code-block:: ini
filter-with = proxy-prefix
* At the end of the ``rhodecode.ini`` file add the following section.
* Above ``[app:main]`` section of the ``rhodecode.ini`` file add the
following section if it doesn't exist yet.
.. code-block:: ini
[filter:proxy-prefix]
use = egg:PasteDeploy#prefix
prefix = /<someprefix> # Change <someprefix> into your chosen prefix
* In the the ``[app:main]`` section of your ``rhodecode.ini`` file add the
following line.
.. code-block:: ini
filter-with = proxy-prefix

View file

@ -121,7 +121,7 @@ then work on restoring any specific setup changes you had made.
:ref:`indexing-ref` section for details.
* To reconfigure any extensions, copy the backed up extensions into the
:file:`/home/{user}/.rccontrol/{instance-id}/rcextensions` and also specify
any custom hooks if necessary. See the :ref:`integrations-ref` section for
any custom hooks if necessary. See the :ref:`extensions-hooks-ref` section for
details.
.. _Schrödinger's Backup: http://novabackup.novastor.com/blog/schrodingers-backup-good-bad-backup/

View file

@ -5,6 +5,11 @@ Use the following example to configure Nginx as a your web server.
.. code-block:: nginx
log_format log_custom '$remote_addr - $remote_user [$time_local] '
'"$request" $status $body_bytes_sent '
'"$http_referer" "$http_user_agent" '
'$request_time $upstream_response_time $pipe';
upstream rc {
server 127.0.0.1:10002;
@ -14,12 +19,12 @@ Use the following example to configure Nginx as a your web server.
# server 127.0.0.1:10004;
}
## gist alias
## gist alias server, for serving nicer GIST urls
server {
listen 443;
server_name gist.myserver.com;
access_log /var/log/nginx/gist.access.log;
access_log /var/log/nginx/gist.access.log log_custom;
error_log /var/log/nginx/gist.error.log;
ssl on;
@ -28,23 +33,36 @@ Use the following example to configure Nginx as a your web server.
ssl_session_timeout 5m;
ssl_protocols SSLv3 TLSv1;
ssl_ciphers DHE-RSA-AES256-SHA:DHE-RSA-AES128-SHA:EDH-RSA-DES-CBC3-SHA:AES256-SHA:DES-CBC3-SHA:AES128-SHA:RC4-SHA:RC4-MD5;
ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
ssl_prefer_server_ciphers on;
ssl_ciphers 'ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:DHE-DSS-AES128-GCM-SHA256:kEDH+AESGCM:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA:ECDHE-ECDSA-AES256-SHA:DHE-RSA-AES128-SHA256:DHE-RSA-AES128-SHA:DHE-DSS-AES128-SHA256:DHE-RSA-AES256-SHA256:DHE-DSS-AES256-SHA:DHE-RSA-AES256-SHA:AES128-GCM-SHA256:AES256-GCM-SHA384:AES128-SHA256:AES256-SHA256:AES128-SHA:AES256-SHA:AES:CAMELLIA:DES-CBC3-SHA:!aNULL:!eNULL:!EXPORT:!DES:!RC4:!MD5:!PSK:!aECDH:!EDH-DSS-DES-CBC3-SHA:!EDH-RSA-DES-CBC3-SHA:!KRB5-DES-CBC3-SHA';
add_header Strict-Transport-Security "max-age=31536000; includeSubdomains;";
# Diffie-Hellman parameter for DHE ciphersuites, recommended 2048 bits
ssl_dhparam /etc/nginx/ssl/dhparam.pem;
#ssl_dhparam /etc/nginx/ssl/dhparam.pem;
rewrite ^/(.+)$ https://rhodecode.myserver.com/_admin/gists/$1;
rewrite (.*) https://rhodecode.myserver.com/_admin/gists;
}
## HTTP to HTTPS rewrite
server {
listen 443;
listen 80;
server_name rhodecode.myserver.com;
access_log /var/log/nginx/rhodecode.access.log;
error_log /var/log/nginx/rhodecode.error.log;
if ($http_host = rhodecode.myserver.com) {
rewrite (.*) https://rhodecode.myserver.com$1 permanent;
}
}
## MAIN SSL enabled server
server {
listen 443 ssl;
server_name rhodecode.myserver.com;
access_log /var/log/nginx/rhodecode.access.log log_custom;
error_log /var/log/nginx/rhodecode.error.log;
ssl on;
ssl_certificate rhodecode.myserver.com.crt;
@ -52,21 +70,51 @@ Use the following example to configure Nginx as a your web server.
ssl_session_timeout 5m;
ssl_protocols SSLv3 TLSv1;
ssl_ciphers DHE-RSA-AES256-SHA:DHE-RSA-AES128-SHA:EDH-RSA-DES-CBC3-SHA:AES256-SHA:DES-CBC3-SHA:AES128-SHA:RC4-SHA:RC4-MD5;
ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
ssl_prefer_server_ciphers on;
ssl_ciphers 'ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:DHE-DSS-AES128-GCM-SHA256:kEDH+AESGCM:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA:ECDHE-ECDSA-AES256-SHA:DHE-RSA-AES128-SHA256:DHE-RSA-AES128-SHA:DHE-DSS-AES128-SHA256:DHE-RSA-AES256-SHA256:DHE-DSS-AES256-SHA:DHE-RSA-AES256-SHA:AES128-GCM-SHA256:AES256-GCM-SHA384:AES128-SHA256:AES256-SHA256:AES128-SHA:AES256-SHA:AES:CAMELLIA:DES-CBC3-SHA:!aNULL:!eNULL:!EXPORT:!DES:!RC4:!MD5:!PSK:!aECDH:!EDH-DSS-DES-CBC3-SHA:!EDH-RSA-DES-CBC3-SHA:!KRB5-DES-CBC3-SHA';
## uncomment root directive if you want to serve static files by nginx
## requires static_files = false in .ini file
# root /path/to/rhodecode/installation/public;
# Diffie-Hellman parameter for DHE ciphersuites, recommended 2048 bits
#ssl_dhparam /etc/nginx/ssl/dhparam.pem;
include /etc/nginx/proxy.conf;
include /etc/nginx/proxy.conf;
## serve static files by nginx, recommended
# location /_static/rhodecode {
# alias /path/to/.rccontrol/enterprise-1/static;
# }
## channel stream live components
location /_channelstream {
rewrite /_channelstream/(.*) /$1 break;
proxy_pass http://127.0.0.1:9800;
proxy_connect_timeout 10;
proxy_send_timeout 10m;
proxy_read_timeout 10m;
tcp_nodelay off;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Url-Scheme $scheme;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
gzip off;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
}
location / {
try_files $uri @rhode;
}
location @rhode {
proxy_pass http://rc;
}
}
location @rhode {
proxy_pass http://rc;
}
## custom 502 error page
error_page 502 /502.html;
location = /502.html {
root /path/to/.rccontrol/enterprise-1/static;
}
}

View file

@ -15,7 +15,16 @@ Use the following example to configure Nginx to use a URL prefix.
}
In addition to the Nginx configuration you will need to add the following
lines into the ``rhodecode.ini`` file.
lines (if they not exist) into the ``rhodecode.ini`` file.
* Above ``[app:main]`` section of the ``rhodecode.ini`` file add the
following section if it doesn't exist yet.
.. code-block:: ini
[filter:proxy-prefix]
use = egg:PasteDeploy#prefix
prefix = /<someprefix> # Change <someprefix> into your chosen prefix
* In the the ``[app:main]`` section of your ``rhodecode.ini`` file add the
following line.
@ -24,10 +33,4 @@ lines into the ``rhodecode.ini`` file.
filter-with = proxy-prefix
* At the end of the ``rhodecode.ini`` file add the following section.
.. code-block:: ini
[filter:proxy-prefix]
use = egg:PasteDeploy#prefix
prefix = /<someprefix> # Change <someprefix> into your chosen prefix

View file

@ -32,7 +32,7 @@ Example Usage
-------------
To use the extra fields in an extension, see the example below. For more
information and examples, see the :ref:`integrations-ref` section.
information and examples, see the :ref:`extensions-hooks-ref` section.
.. code-block:: python

View file

@ -30,7 +30,7 @@ account permissions.
# Use this example to change user permissions
In [1]: adminuser = User.get_by_username('username')
In [2]: adminuser.admin = True
In [3]: Session.add(adminuser);Session().commit()
In [3]: Session().add(adminuser);Session().commit()
In [4]: exit()
Set to read global ``.hgrc`` file

View file

@ -76,7 +76,7 @@ following examples. For more |svn| information, see the `Subversion Red Book`_
.. code-block:: bash
# To clone a repository
svn clone http://my-svn-server.example.com/my-svn-repo
svn checkout http://my-svn-server.example.com/my-svn-repo
# svn commit
svn commit

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,77 @@
.. _deprecated-methods-ref:
deprecated methods
=================
changeset_comment
-----------------
.. py:function:: changeset_comment(apiuser, repoid, revision, message, userid=<Optional:<OptionalAttr:apiuser>>, status=<Optional:None>)
.. deprecated:: 3.4.0
Please use method `comment_commit` instead.
Set a changeset comment, and optionally change the status of the
changeset.
This command can only be run using an |authtoken| with admin
permissions on the |repo|.
:param apiuser: This is filled automatically from the |authtoken|.
:type apiuser: AuthUser
:param repoid: Set the repository name or repository ID.
:type repoid: str or int
:param revision: Specify the revision for which to set a comment.
:type revision: str
:param message: The comment text.
:type message: str
:param userid: Set the user name of the comment creator.
:type userid: Optional(str or int)
:param status: Set the comment status. The following are valid options:
* not_reviewed
* approved
* rejected
* under_review
:type status: str
Example error output:
.. code-block:: json
{
"id" : <id_given_in_input>,
"result" : {
"msg": "Commented on commit `<revision>` for repository `<repoid>`",
"status_change": null or <status>,
"success": true
},
"error" : null
}
get_locks
---------
.. py:function:: get_locks(apiuser, userid=<Optional:<OptionalAttr:apiuser>>)
.. deprecated:: 4.0.0
Please use method `get_user_locks` instead.
None
show_ip
-------
.. py:function:: show_ip(apiuser, userid=<Optional:<OptionalAttr:apiuser>>)
.. deprecated:: 4.0.0
Please use method `get_ip` instead.
None

View file

@ -0,0 +1,121 @@
.. _gist-methods-ref:
gist methods
=================
create_gist
-----------
.. py:function:: create_gist(apiuser, files, gistid=<Optional:None>, owner=<Optional:<OptionalAttr:apiuser>>, gist_type=<Optional:u'public'>, lifetime=<Optional:-1>, acl_level=<Optional:u'acl_public'>, description=<Optional:''>)
Creates a new Gist.
:param apiuser: This is filled automatically from the |authtoken|.
:type apiuser: AuthUser
:param files: files to be added to the gist. The data structure has
to match the following example::
{'filename1': {'content':'...'}, 'filename2': {'content':'...'}}
:type files: dict
:param gistid: Set a custom id for the gist
:type gistid: Optional(str)
:param owner: Set the gist owner, defaults to api method caller
:type owner: Optional(str or int)
:param gist_type: type of gist ``public`` or ``private``
:type gist_type: Optional(str)
:param lifetime: time in minutes of gist lifetime
:type lifetime: Optional(int)
:param acl_level: acl level for this gist, can be
``acl_public`` or ``acl_private`` If the value is set to
``acl_private`` only logged in users are able to access this gist.
If not set it defaults to ``acl_public``.
:type acl_level: Optional(str)
:param description: gist description
:type description: Optional(str)
Example output:
.. code-block:: bash
id : <id_given_in_input>
result : {
"msg": "created new gist",
"gist": {}
}
error : null
Example error output:
.. code-block:: bash
id : <id_given_in_input>
result : null
error : {
"failed to create gist"
}
delete_gist
-----------
.. py:function:: delete_gist(apiuser, gistid)
Deletes existing gist
:param apiuser: filled automatically from apikey
:type apiuser: AuthUser
:param gistid: id of gist to delete
:type gistid: str
Example output:
.. code-block:: bash
id : <id_given_in_input>
result : {
"deleted gist ID: <gist_id>",
"gist": null
}
error : null
Example error output:
.. code-block:: bash
id : <id_given_in_input>
result : null
error : {
"failed to delete gist ID:<gist_id>"
}
get_gist
--------
.. py:function:: get_gist(apiuser, gistid, content=<Optional:False>)
Get the specified gist, based on the gist ID.
:param apiuser: This is filled automatically from the |authtoken|.
:type apiuser: AuthUser
:param gistid: Set the id of the private or public gist
:type gistid: str
:param content: Return the gist content. Default is false.
:type content: Optional(bool)
get_gists
---------
.. py:function:: get_gists(apiuser, userid=<Optional:<OptionalAttr:apiuser>>)
Get all gists for given user. If userid is empty returned gists
are for user who called the api
:param apiuser: This is filled automatically from the |authtoken|.
:type apiuser: AuthUser
:param userid: user to get gists for
:type userid: Optional(str or int)

View file

@ -0,0 +1,71 @@
.. _license-methods-ref:
license methods
=================
get_license_info (EE only)
----------------
.. py:function:: get_license_info(apiuser)
Returns the |RCE| license information.
:param apiuser: This is filled automatically from the |authtoken|.
:type apiuser: AuthUser
Example output:
.. code-block:: bash
id : <id_given_in_input>
result : {
'rhodecode_version': <rhodecode version>,
'token': <license token>,
'issued_to': <license owner>,
'issued_on': <license issue date>,
'expires_on': <license expiration date>,
'type': <license type>,
'users_limit': <license users limit>,
'key': <license key>
}
error : null
set_license_key (EE only)
---------------
.. py:function:: set_license_key(apiuser, key)
Sets the |RCE| license key.
:param apiuser: This is filled automatically from the |authtoken|.
:type apiuser: AuthUser
:param key: This is the license key to be set.
:type key: str
Example output:
.. code-block:: bash
id : <id_given_in_input>
result: {
"msg" : "updated license information",
"key": <key>
}
error: null
Example error output:
.. code-block:: bash
id : <id_given_in_input>
result : null
error : {
"license key is not valid"
or
"trial licenses cannot be uploaded"
or
"error occurred while updating license"
}

View file

@ -0,0 +1,344 @@
.. _pull-request-methods-ref:
pull_request methods
=================
close_pull_request
------------------
.. py:function:: close_pull_request(apiuser, repoid, pullrequestid, userid=<Optional:<OptionalAttr:apiuser>>)
Close the pull request specified by `pullrequestid`.
:param apiuser: This is filled automatically from the |authtoken|.
:type apiuser: AuthUser
:param repoid: Repository name or repository ID to which the pull
request belongs.
:type repoid: str or int
:param pullrequestid: ID of the pull request to be closed.
:type pullrequestid: int
:param userid: Close the pull request as this user.
:type userid: Optional(str or int)
Example output:
.. code-block:: bash
"id": <id_given_in_input>,
"result":
{
"pull_request_id": "<int>",
"closed": "<bool>"
},
"error": null
comment_pull_request
--------------------
.. py:function:: comment_pull_request(apiuser, repoid, pullrequestid, message=<Optional:None>, status=<Optional:None>, userid=<Optional:<OptionalAttr:apiuser>>)
Comment on the pull request specified with the `pullrequestid`,
in the |repo| specified by the `repoid`, and optionally change the
review status.
:param apiuser: This is filled automatically from the |authtoken|.
:type apiuser: AuthUser
:param repoid: The repository name or repository ID.
:type repoid: str or int
:param pullrequestid: The pull request ID.
:type pullrequestid: int
:param message: The text content of the comment.
:type message: str
:param status: (**Optional**) Set the approval status of the pull
request. Valid options are:
* not_reviewed
* approved
* rejected
* under_review
:type status: str
:param userid: Comment on the pull request as this user
:type userid: Optional(str or int)
Example output:
.. code-block:: bash
id : <id_given_in_input>
result :
{
"pull_request_id": "<Integer>",
"comment_id": "<Integer>"
}
error : null
create_pull_request
-------------------
.. py:function:: create_pull_request(apiuser, source_repo, target_repo, source_ref, target_ref, title, description=<Optional:''>, reviewers=<Optional:None>)
Creates a new pull request.
Accepts refs in the following formats:
* branch:<branch_name>:<sha>
* branch:<branch_name>
* bookmark:<bookmark_name>:<sha> (Mercurial only)
* bookmark:<bookmark_name> (Mercurial only)
:param apiuser: This is filled automatically from the |authtoken|.
:type apiuser: AuthUser
:param source_repo: Set the source repository name.
:type source_repo: str
:param target_repo: Set the target repository name.
:type target_repo: str
:param source_ref: Set the source ref name.
:type source_ref: str
:param target_ref: Set the target ref name.
:type target_ref: str
:param title: Set the pull request title.
:type title: str
:param description: Set the pull request description.
:type description: Optional(str)
:param reviewers: Set the new pull request reviewers list.
:type reviewers: Optional(list)
get_pull_request
----------------
.. py:function:: get_pull_request(apiuser, repoid, pullrequestid)
Get a pull request based on the given ID.
:param apiuser: This is filled automatically from the |authtoken|.
:type apiuser: AuthUser
:param repoid: Repository name or repository ID from where the pull
request was opened.
:type repoid: str or int
:param pullrequestid: ID of the requested pull request.
:type pullrequestid: int
Example output:
.. code-block:: bash
"id": <id_given_in_input>,
"result":
{
"pull_request_id": "<pull_request_id>",
"url": "<url>",
"title": "<title>",
"description": "<description>",
"status" : "<status>",
"created_on": "<date_time_created>",
"updated_on": "<date_time_updated>",
"commit_ids": [
...
"<commit_id>",
"<commit_id>",
...
],
"review_status": "<review_status>",
"mergeable": {
"status": "<bool>",
"message": "<message>",
},
"source": {
"clone_url": "<clone_url>",
"repository": "<repository_name>",
"reference":
{
"name": "<name>",
"type": "<type>",
"commit_id": "<commit_id>",
}
},
"target": {
"clone_url": "<clone_url>",
"repository": "<repository_name>",
"reference":
{
"name": "<name>",
"type": "<type>",
"commit_id": "<commit_id>",
}
},
"author": <user_obj>,
"reviewers": [
...
{
"user": "<user_obj>",
"review_status": "<review_status>",
}
...
]
},
"error": null
get_pull_requests
-----------------
.. py:function:: get_pull_requests(apiuser, repoid, status=<Optional:'new'>)
Get all pull requests from the repository specified in `repoid`.
:param apiuser: This is filled automatically from the |authtoken|.
:type apiuser: AuthUser
:param repoid: Repository name or repository ID.
:type repoid: str or int
:param status: Only return pull requests with the specified status.
Valid options are.
* ``new`` (default)
* ``open``
* ``closed``
:type status: str
Example output:
.. code-block:: bash
"id": <id_given_in_input>,
"result":
[
...
{
"pull_request_id": "<pull_request_id>",
"url": "<url>",
"title" : "<title>",
"description": "<description>",
"status": "<status>",
"created_on": "<date_time_created>",
"updated_on": "<date_time_updated>",
"commit_ids": [
...
"<commit_id>",
"<commit_id>",
...
],
"review_status": "<review_status>",
"mergeable": {
"status": "<bool>",
"message: "<message>",
},
"source": {
"clone_url": "<clone_url>",
"reference":
{
"name": "<name>",
"type": "<type>",
"commit_id": "<commit_id>",
}
},
"target": {
"clone_url": "<clone_url>",
"reference":
{
"name": "<name>",
"type": "<type>",
"commit_id": "<commit_id>",
}
},
"author": <user_obj>,
"reviewers": [
...
{
"user": "<user_obj>",
"review_status": "<review_status>",
}
...
]
}
...
],
"error": null
merge_pull_request
------------------
.. py:function:: merge_pull_request(apiuser, repoid, pullrequestid, userid=<Optional:<OptionalAttr:apiuser>>)
Merge the pull request specified by `pullrequestid` into its target
repository.
:param apiuser: This is filled automatically from the |authtoken|.
:type apiuser: AuthUser
:param repoid: The Repository name or repository ID of the
target repository to which the |pr| is to be merged.
:type repoid: str or int
:param pullrequestid: ID of the pull request which shall be merged.
:type pullrequestid: int
:param userid: Merge the pull request as this user.
:type userid: Optional(str or int)
Example output:
.. code-block:: bash
"id": <id_given_in_input>,
"result":
{
"executed": "<bool>",
"failure_reason": "<int>",
"merge_commit_id": "<merge_commit_id>",
"possible": "<bool>"
},
"error": null
update_pull_request
-------------------
.. py:function:: update_pull_request(apiuser, repoid, pullrequestid, title=<Optional:''>, description=<Optional:''>, reviewers=<Optional:None>, update_commits=<Optional:None>, close_pull_request=<Optional:None>)
Updates a pull request.
:param apiuser: This is filled automatically from the |authtoken|.
:type apiuser: AuthUser
:param repoid: The repository name or repository ID.
:type repoid: str or int
:param pullrequestid: The pull request ID.
:type pullrequestid: int
:param title: Set the pull request title.
:type title: str
:param description: Update pull request description.
:type description: Optional(str)
:param reviewers: Update pull request reviewers list with new value.
:type reviewers: Optional(list)
:param update_commits: Trigger update of commits for this pull request
:type: update_commits: Optional(bool)
:param close_pull_request: Close this pull request with rejected state
:type: close_pull_request: Optional(bool)
Example output:
.. code-block:: bash
id : <id_given_in_input>
result :
{
"msg": "Updated pull request `63`",
"pull_request": <pull_request_object>,
"updated_reviewers": {
"added": [
"username"
],
"removed": []
},
"updated_commits": {
"added": [
"<sha1_hash>"
],
"common": [
"<sha1_hash>",
"<sha1_hash>",
],
"removed": []
}
}
error : null

View file

@ -0,0 +1,350 @@
.. _repo-group-methods-ref:
repo_group methods
=================
create_repo_group
-----------------
.. py:function:: create_repo_group(apiuser, group_name, description=<Optional:''>, owner=<Optional:<OptionalAttr:apiuser>>, copy_permissions=<Optional:False>)
Creates a repository group.
* If the repository group name contains "/", all the required repository
groups will be created.
For example "foo/bar/baz" will create |repo| groups "foo" and "bar"
(with "foo" as parent). It will also create the "baz" repository
with "bar" as |repo| group.
This command can only be run using an |authtoken| with admin
permissions.
:param apiuser: This is filled automatically from the |authtoken|.
:type apiuser: AuthUser
:param group_name: Set the repository group name.
:type group_name: str
:param description: Set the |repo| group description.
:type description: str
:param owner: Set the |repo| group owner.
:type owner: str
:param copy_permissions:
:type copy_permissions:
Example output:
.. code-block:: bash
id : <id_given_in_input>
result : {
"msg": "Created new repo group `<repo_group_name>`"
"repo_group": <repogroup_object>
}
error : null
Example error output:
.. code-block:: bash
id : <id_given_in_input>
result : null
error : {
failed to create repo group `<repogroupid>`
}
delete_repo_group
-----------------
.. py:function:: delete_repo_group(apiuser, repogroupid)
Deletes a |repo| group.
:param apiuser: This is filled automatically from the |authtoken|.
:type apiuser: AuthUser
:param repogroupid: Set the name or ID of repository group to be
deleted.
:type repogroupid: str or int
Example output:
.. code-block:: bash
id : <id_given_in_input>
result : {
'msg': 'deleted repo group ID:<repogroupid> <repogroupname>
'repo_group': null
}
error : null
Example error output:
.. code-block:: bash
id : <id_given_in_input>
result : null
error : {
"failed to delete repo group ID:<repogroupid> <repogroupname>"
}
get_repo_group
--------------
.. py:function:: get_repo_group(apiuser, repogroupid)
Return the specified |repo| group, along with permissions,
and repositories inside the group
:param apiuser: This is filled automatically from the |authtoken|.
:type apiuser: AuthUser
:param repogroupid: Specify the name of ID of the repository group.
:type repogroupid: str or int
Example output:
.. code-block:: bash
{
"error": null,
"id": repo-group-id,
"result": {
"group_description": "repo group description",
"group_id": 14,
"group_name": "group name",
"members": [
{
"name": "super-admin-username",
"origin": "super-admin",
"permission": "group.admin",
"type": "user"
},
{
"name": "owner-name",
"origin": "owner",
"permission": "group.admin",
"type": "user"
},
{
"name": "user-group-name",
"origin": "permission",
"permission": "group.write",
"type": "user_group"
}
],
"owner": "owner-name",
"parent_group": null,
"repositories": [ repo-list ]
}
}
get_repo_groups
---------------
.. py:function:: get_repo_groups(apiuser)
Returns all repository groups.
:param apiuser: This is filled automatically from the |authtoken|.
:type apiuser: AuthUser
grant_user_group_permission_to_repo_group
-----------------------------------------
.. py:function:: grant_user_group_permission_to_repo_group(apiuser, repogroupid, usergroupid, perm, apply_to_children=<Optional:'none'>)
Grant permission for a user group on given repository group, or update
existing permissions if found.
This command can only be run using an |authtoken| with admin
permissions on the |repo| group.
:param apiuser: This is filled automatically from the |authtoken|.
:type apiuser: AuthUser
:param repogroupid: Set the name or id of repository group
:type repogroupid: str or int
:param usergroupid: id of usergroup
:type usergroupid: str or int
:param perm: (group.(none|read|write|admin))
:type perm: str
:param apply_to_children: 'none', 'repos', 'groups', 'all'
:type apply_to_children: str
Example output:
.. code-block:: bash
id : <id_given_in_input>
result : {
"msg" : "Granted perm: `<perm>` (recursive:<apply_to_children>) for user group: `<usersgroupname>` in repo group: `<repo_group_name>`",
"success": true
}
error : null
Example error output:
.. code-block:: bash
id : <id_given_in_input>
result : null
error : {
"failed to edit permission for user group: `<usergroup>` in repo group: `<repo_group_name>`"
}
grant_user_permission_to_repo_group
-----------------------------------
.. py:function:: grant_user_permission_to_repo_group(apiuser, repogroupid, userid, perm, apply_to_children=<Optional:'none'>)
Grant permission for a user on the given repository group, or update
existing permissions if found.
This command can only be run using an |authtoken| with admin
permissions.
:param apiuser: This is filled automatically from the |authtoken|.
:type apiuser: AuthUser
:param repogroupid: Set the name or ID of repository group.
:type repogroupid: str or int
:param userid: Set the user name.
:type userid: str
:param perm: (group.(none|read|write|admin))
:type perm: str
:param apply_to_children: 'none', 'repos', 'groups', 'all'
:type apply_to_children: str
Example output:
.. code-block:: bash
id : <id_given_in_input>
result: {
"msg" : "Granted perm: `<perm>` (recursive:<apply_to_children>) for user: `<username>` in repo group: `<repo_group_name>`",
"success": true
}
error: null
Example error output:
.. code-block:: bash
id : <id_given_in_input>
result : null
error : {
"failed to edit permission for user: `<userid>` in repo group: `<repo_group_name>`"
}
revoke_user_group_permission_from_repo_group
--------------------------------------------
.. py:function:: revoke_user_group_permission_from_repo_group(apiuser, repogroupid, usergroupid, apply_to_children=<Optional:'none'>)
Revoke permission for user group on given repository.
This command can only be run using an |authtoken| with admin
permissions on the |repo| group.
:param apiuser: This is filled automatically from the |authtoken|.
:type apiuser: AuthUser
:param repogroupid: name or id of repository group
:type repogroupid: str or int
:param usergroupid:
:param apply_to_children: 'none', 'repos', 'groups', 'all'
:type apply_to_children: str
Example output:
.. code-block:: bash
id : <id_given_in_input>
result: {
"msg" : "Revoked perm (recursive:<apply_to_children>) for user group: `<usersgroupname>` in repo group: `<repo_group_name>`",
"success": true
}
error: null
Example error output:
.. code-block:: bash
id : <id_given_in_input>
result : null
error : {
"failed to edit permission for user group: `<usergroup>` in repo group: `<repo_group_name>`"
}
revoke_user_permission_from_repo_group
--------------------------------------
.. py:function:: revoke_user_permission_from_repo_group(apiuser, repogroupid, userid, apply_to_children=<Optional:'none'>)
Revoke permission for a user in a given repository group.
This command can only be run using an |authtoken| with admin
permissions on the |repo| group.
:param apiuser: This is filled automatically from the |authtoken|.
:type apiuser: AuthUser
:param repogroupid: Set the name or ID of the repository group.
:type repogroupid: str or int
:param userid: Set the user name to revoke.
:type userid: str
:param apply_to_children: 'none', 'repos', 'groups', 'all'
:type apply_to_children: str
Example output:
.. code-block:: bash
id : <id_given_in_input>
result: {
"msg" : "Revoked perm (recursive:<apply_to_children>) for user: `<username>` in repo group: `<repo_group_name>`",
"success": true
}
error: null
Example error output:
.. code-block:: bash
id : <id_given_in_input>
result : null
error : {
"failed to edit permission for user: `<userid>` in repo group: `<repo_group_name>`"
}
update_repo_group
-----------------
.. py:function:: update_repo_group(apiuser, repogroupid, group_name=<Optional:''>, description=<Optional:''>, owner=<Optional:<OptionalAttr:apiuser>>, parent=<Optional:None>, enable_locking=<Optional:False>)
Updates repository group with the details given.
This command can only be run using an |authtoken| with admin
permissions.
:param apiuser: This is filled automatically from the |authtoken|.
:type apiuser: AuthUser
:param repogroupid: Set the ID of repository group.
:type repogroupid: str or int
:param group_name: Set the name of the |repo| group.
:type group_name: str
:param description: Set a description for the group.
:type description: str
:param owner: Set the |repo| group owner.
:type owner: str
:param parent: Set the |repo| group parent.
:type parent: str or int
:param enable_locking: Enable |repo| locking. The default is false.
:type enable_locking: bool

View file

@ -0,0 +1,967 @@
.. _repo-methods-ref:
repo methods
=================
add_field_to_repo
-----------------
.. py:function:: add_field_to_repo(apiuser, repoid, key, label=<Optional:''>, description=<Optional:''>)
Adds an extra field to a repository.
This command can only be run using an |authtoken| with at least
write permissions to the |repo|.
:param apiuser: This is filled automatically from the |authtoken|.
:type apiuser: AuthUser
:param repoid: Set the repository name or repository id.
:type repoid: str or int
:param key: Create a unique field key for this repository.
:type key: str
:param label:
:type label: Optional(str)
:param description:
:type description: Optional(str)
comment_commit
--------------
.. py:function:: comment_commit(apiuser, repoid, commit_id, message, userid=<Optional:<OptionalAttr:apiuser>>, status=<Optional:None>)
Set a commit comment, and optionally change the status of the commit.
:param apiuser: This is filled automatically from the |authtoken|.
:type apiuser: AuthUser
:param repoid: Set the repository name or repository ID.
:type repoid: str or int
:param commit_id: Specify the commit_id for which to set a comment.
:type commit_id: str
:param message: The comment text.
:type message: str
:param userid: Set the user name of the comment creator.
:type userid: Optional(str or int)
:param status: status, one of 'not_reviewed', 'approved', 'rejected',
'under_review'
:type status: str
Example error output:
.. code-block:: json
{
"id" : <id_given_in_input>,
"result" : {
"msg": "Commented on commit `<commit_id>` for repository `<repoid>`",
"status_change": null or <status>,
"success": true
},
"error" : null
}
create_repo
-----------
.. py:function:: create_repo(apiuser, repo_name, repo_type, owner=<Optional:<OptionalAttr:apiuser>>, description=<Optional:''>, private=<Optional:False>, clone_uri=<Optional:None>, landing_rev=<Optional:'rev:tip'>, enable_statistics=<Optional:False>, enable_locking=<Optional:False>, enable_downloads=<Optional:False>, copy_permissions=<Optional:False>)
Creates a repository.
* If the repository name contains "/", all the required repository
groups will be created.
For example "foo/bar/baz" will create |repo| groups "foo" and "bar"
(with "foo" as parent). It will also create the "baz" repository
with "bar" as |repo| group.
This command can only be run using an |authtoken| with at least
write permissions to the |repo|.
:param apiuser: This is filled automatically from the |authtoken|.
:type apiuser: AuthUser
:param repo_name: Set the repository name.
:type repo_name: str
:param repo_type: Set the repository type; 'hg','git', or 'svn'.
:type repo_type: str
:param owner: user_id or username
:type owner: Optional(str)
:param description: Set the repository description.
:type description: Optional(str)
:param private:
:type private: bool
:param clone_uri:
:type clone_uri: str
:param landing_rev: <rev_type>:<rev>
:type landing_rev: str
:param enable_locking:
:type enable_locking: bool
:param enable_downloads:
:type enable_downloads: bool
:param enable_statistics:
:type enable_statistics: bool
:param copy_permissions: Copy permission from group in which the
repository is being created.
:type copy_permissions: bool
Example output:
.. code-block:: bash
id : <id_given_in_input>
result: {
"msg": "Created new repository `<reponame>`",
"success": true,
"task": "<celery task id or None if done sync>"
}
error: null
Example error output:
.. code-block:: bash
id : <id_given_in_input>
result : null
error : {
'failed to create repository `<repo_name>`
}
delete_repo
-----------
.. py:function:: delete_repo(apiuser, repoid, forks=<Optional:''>)
Deletes a repository.
* When the `forks` parameter is set it's possible to detach or delete
forks of deleted repository.
This command can only be run using an |authtoken| with admin
permissions on the |repo|.
:param apiuser: This is filled automatically from the |authtoken|.
:type apiuser: AuthUser
:param repoid: Set the repository name or repository ID.
:type repoid: str or int
:param forks: Set to `detach` or `delete` forks from the |repo|.
:type forks: Optional(str)
Example error output:
.. code-block:: bash
id : <id_given_in_input>
result: {
"msg": "Deleted repository `<reponame>`",
"success": true
}
error: null
fork_repo
---------
.. py:function:: fork_repo(apiuser, repoid, fork_name, owner=<Optional:<OptionalAttr:apiuser>>, description=<Optional:''>, copy_permissions=<Optional:False>, private=<Optional:False>, landing_rev=<Optional:'rev:tip'>)
Creates a fork of the specified |repo|.
* If using |RCE| with Celery this will immediately return a success
message, even though the fork will be created asynchronously.
This command can only be run using an |authtoken| with fork
permissions on the |repo|.
:param apiuser: This is filled automatically from the |authtoken|.
:type apiuser: AuthUser
:param repoid: Set repository name or repository ID.
:type repoid: str or int
:param fork_name: Set the fork name.
:type fork_name: str
:param owner: Set the fork owner.
:type owner: str
:param description: Set the fork descripton.
:type description: str
:param copy_permissions: Copy permissions from parent |repo|. The
default is False.
:type copy_permissions: bool
:param private: Make the fork private. The default is False.
:type private: bool
:param landing_rev: Set the landing revision. The default is tip.
Example output:
.. code-block:: bash
id : <id_for_response>
api_key : "<api_key>"
args: {
"repoid" : "<reponame or repo_id>",
"fork_name": "<forkname>",
"owner": "<username or user_id = Optional(=apiuser)>",
"description": "<description>",
"copy_permissions": "<bool>",
"private": "<bool>",
"landing_rev": "<landing_rev>"
}
Example error output:
.. code-block:: bash
id : <id_given_in_input>
result: {
"msg": "Created fork of `<reponame>` as `<forkname>`",
"success": true,
"task": "<celery task id or None if done sync>"
}
error: null
get_repo
--------
.. py:function:: get_repo(apiuser, repoid, cache=<Optional:True>)
Gets an existing repository by its name or repository_id.
The members section so the output returns users groups or users
associated with that repository.
This command can only be run using an |authtoken| with admin rights,
or users with at least read rights to the |repo|.
:param apiuser: This is filled automatically from the |authtoken|.
:type apiuser: AuthUser
:param repoid: The repository name or repository id.
:type repoid: str or int
:param cache: use the cached value for last changeset
:type: cache: Optional(bool)
Example output:
.. code-block:: bash
{
"error": null,
"id": <repo_id>,
"result": {
"clone_uri": null,
"created_on": "timestamp",
"description": "repo description",
"enable_downloads": false,
"enable_locking": false,
"enable_statistics": false,
"followers": [
{
"active": true,
"admin": false,
"api_key": "****************************************",
"api_keys": [
"****************************************"
],
"email": "user@example.com",
"emails": [
"user@example.com"
],
"extern_name": "rhodecode",
"extern_type": "rhodecode",
"firstname": "username",
"ip_addresses": [],
"language": null,
"last_login": "2015-09-16T17:16:35.854",
"lastname": "surname",
"user_id": <user_id>,
"username": "name"
}
],
"fork_of": "parent-repo",
"landing_rev": [
"rev",
"tip"
],
"last_changeset": {
"author": "User <user@example.com>",
"branch": "default",
"date": "timestamp",
"message": "last commit message",
"parents": [
{
"raw_id": "commit-id"
}
],
"raw_id": "commit-id",
"revision": <revision number>,
"short_id": "short id"
},
"lock_reason": null,
"locked_by": null,
"locked_date": null,
"members": [
{
"name": "super-admin-name",
"origin": "super-admin",
"permission": "repository.admin",
"type": "user"
},
{
"name": "owner-name",
"origin": "owner",
"permission": "repository.admin",
"type": "user"
},
{
"name": "user-group-name",
"origin": "permission",
"permission": "repository.write",
"type": "user_group"
}
],
"owner": "owner-name",
"permissions": [
{
"name": "super-admin-name",
"origin": "super-admin",
"permission": "repository.admin",
"type": "user"
},
{
"name": "owner-name",
"origin": "owner",
"permission": "repository.admin",
"type": "user"
},
{
"name": "user-group-name",
"origin": "permission",
"permission": "repository.write",
"type": "user_group"
}
],
"private": true,
"repo_id": 676,
"repo_name": "user-group/repo-name",
"repo_type": "hg"
}
}
get_repo_changeset
------------------
.. py:function:: get_repo_changeset(apiuser, repoid, revision, details=<Optional:'basic'>)
Returns information about a changeset.
Additionally parameters define the amount of details returned by
this function.
This command can only be run using an |authtoken| with admin rights,
or users with at least read rights to the |repo|.
:param apiuser: This is filled automatically from the |authtoken|.
:type apiuser: AuthUser
:param repoid: The repository name or repository id
:type repoid: str or int
:param revision: revision for which listing should be done
:type revision: str
:param details: details can be 'basic|extended|full' full gives diff
info details like the diff itself, and number of changed files etc.
:type details: Optional(str)
get_repo_changesets
-------------------
.. py:function:: get_repo_changesets(apiuser, repoid, start_rev, limit, details=<Optional:'basic'>)
Returns a set of commits limited by the number starting
from the `start_rev` option.
Additional parameters define the amount of details returned by this
function.
This command can only be run using an |authtoken| with admin rights,
or users with at least read rights to |repos|.
:param apiuser: This is filled automatically from the |authtoken|.
:type apiuser: AuthUser
:param repoid: The repository name or repository ID.
:type repoid: str or int
:param start_rev: The starting revision from where to get changesets.
:type start_rev: str
:param limit: Limit the number of commits to this amount
:type limit: str or int
:param details: Set the level of detail returned. Valid option are:
``basic``, ``extended`` and ``full``.
:type details: Optional(str)
.. note::
Setting the parameter `details` to the value ``full`` is extensive
and returns details like the diff itself, and the number
of changed files.
get_repo_nodes
--------------
.. py:function:: get_repo_nodes(apiuser, repoid, revision, root_path, ret_type=<Optional:'all'>, details=<Optional:'basic'>, max_file_bytes=<Optional:None>)
Returns a list of nodes and children in a flat list for a given
path at given revision.
It's possible to specify ret_type to show only `files` or `dirs`.
This command can only be run using an |authtoken| with admin rights,
or users with at least read rights to |repos|.
:param apiuser: This is filled automatically from the |authtoken|.
:type apiuser: AuthUser
:param repoid: The repository name or repository ID.
:type repoid: str or int
:param revision: The revision for which listing should be done.
:type revision: str
:param root_path: The path from which to start displaying.
:type root_path: str
:param ret_type: Set the return type. Valid options are
``all`` (default), ``files`` and ``dirs``.
:type ret_type: Optional(str)
:param details: Returns extended information about nodes, such as
md5, binary, and or content. The valid options are ``basic`` and
``full``.
:type details: Optional(str)
:param max_file_bytes: Only return file content under this file size bytes
:type details: Optional(int)
Example output:
.. code-block:: bash
id : <id_given_in_input>
result: [
{
"name" : "<name>"
"type" : "<type>",
"binary": "<true|false>" (only in extended mode)
"md5" : "<md5 of file content>" (only in extended mode)
},
...
]
error: null
get_repo_refs
-------------
.. py:function:: get_repo_refs(apiuser, repoid)
Returns a dictionary of current references. It returns
bookmarks, branches, closed_branches, and tags for given repository
It's possible to specify ret_type to show only `files` or `dirs`.
This command can only be run using an |authtoken| with admin rights,
or users with at least read rights to |repos|.
:param apiuser: This is filled automatically from the |authtoken|.
:type apiuser: AuthUser
:param repoid: The repository name or repository ID.
:type repoid: str or int
Example output:
.. code-block:: bash
id : <id_given_in_input>
result: [
TODO...
]
error: null
get_repo_settings
-----------------
.. py:function:: get_repo_settings(apiuser, repoid, key=<Optional:None>)
Returns all settings for a repository. If key is given it only returns the
setting identified by the key or null.
:param apiuser: This is filled automatically from the |authtoken|.
:type apiuser: AuthUser
:param repoid: The repository name or repository id.
:type repoid: str or int
:param key: Key of the setting to return.
:type: key: Optional(str)
Example output:
.. code-block:: bash
{
"error": null,
"id": 237,
"result": {
"extensions_largefiles": true,
"hooks_changegroup_push_logger": true,
"hooks_changegroup_repo_size": false,
"hooks_outgoing_pull_logger": true,
"phases_publish": "True",
"rhodecode_hg_use_rebase_for_merging": true,
"rhodecode_pr_merge_enabled": true,
"rhodecode_use_outdated_comments": true
}
}
get_repos
---------
.. py:function:: get_repos(apiuser)
Lists all existing repositories.
This command can only be run using an |authtoken| with admin rights,
or users with at least read rights to |repos|.
:param apiuser: This is filled automatically from the |authtoken|.
:type apiuser: AuthUser
Example output:
.. code-block:: bash
id : <id_given_in_input>
result: [
{
"repo_id" : "<repo_id>",
"repo_name" : "<reponame>"
"repo_type" : "<repo_type>",
"clone_uri" : "<clone_uri>",
"private": : "<bool>",
"created_on" : "<datetimecreated>",
"description" : "<description>",
"landing_rev": "<landing_rev>",
"owner": "<repo_owner>",
"fork_of": "<name_of_fork_parent>",
"enable_downloads": "<bool>",
"enable_locking": "<bool>",
"enable_statistics": "<bool>",
},
...
]
error: null
grant_user_group_permission
---------------------------
.. py:function:: grant_user_group_permission(apiuser, repoid, usergroupid, perm)
Grant permission for a user group on the specified repository,
or update existing permissions.
This command can only be run using an |authtoken| with admin
permissions on the |repo|.
:param apiuser: This is filled automatically from the |authtoken|.
:type apiuser: AuthUser
:param repoid: Set the repository name or repository ID.
:type repoid: str or int
:param usergroupid: Specify the ID of the user group.
:type usergroupid: str or int
:param perm: Set the user group permissions using the following
format: (repository.(none|read|write|admin))
:type perm: str
Example output:
.. code-block:: bash
id : <id_given_in_input>
result : {
"msg" : "Granted perm: `<perm>` for group: `<usersgroupname>` in repo: `<reponame>`",
"success": true
}
error : null
Example error output:
.. code-block:: bash
id : <id_given_in_input>
result : null
error : {
"failed to edit permission for user group: `<usergroup>` in repo `<repo>`'
}
grant_user_permission
---------------------
.. py:function:: grant_user_permission(apiuser, repoid, userid, perm)
Grant permissions for the specified user on the given repository,
or update existing permissions if found.
This command can only be run using an |authtoken| with admin
permissions on the |repo|.
:param apiuser: This is filled automatically from the |authtoken|.
:type apiuser: AuthUser
:param repoid: Set the repository name or repository ID.
:type repoid: str or int
:param userid: Set the user name.
:type userid: str
:param perm: Set the user permissions, using the following format
``(repository.(none|read|write|admin))``
:type perm: str
Example output:
.. code-block:: bash
id : <id_given_in_input>
result: {
"msg" : "Granted perm: `<perm>` for user: `<username>` in repo: `<reponame>`",
"success": true
}
error: null
invalidate_cache
----------------
.. py:function:: invalidate_cache(apiuser, repoid, delete_keys=<Optional:False>)
Invalidates the cache for the specified repository.
This command can only be run using an |authtoken| with admin rights to
the specified repository.
This command takes the following options:
:param apiuser: This is filled automatically from |authtoken|.
:type apiuser: AuthUser
:param repoid: Sets the repository name or repository ID.
:type repoid: str or int
:param delete_keys: This deletes the invalidated keys instead of
just flagging them.
:type delete_keys: Optional(``True`` | ``False``)
Example output:
.. code-block:: bash
id : <id_given_in_input>
result : {
'msg': Cache for repository `<repository name>` was invalidated,
'repository': <repository name>
}
error : null
Example error output:
.. code-block:: bash
id : <id_given_in_input>
result : null
error : {
'Error occurred during cache invalidation action'
}
lock
----
.. py:function:: lock(apiuser, repoid, locked=<Optional:None>, userid=<Optional:<OptionalAttr:apiuser>>)
Sets the lock state of the specified |repo| by the given user.
From more information, see :ref:`repo-locking`.
* If the ``userid`` option is not set, the repository is locked to the
user who called the method.
* If the ``locked`` parameter is not set, the current lock state of the
repository is displayed.
This command can only be run using an |authtoken| with admin rights to
the specified repository.
This command takes the following options:
:param apiuser: This is filled automatically from the |authtoken|.
:type apiuser: AuthUser
:param repoid: Sets the repository name or repository ID.
:type repoid: str or int
:param locked: Sets the lock state.
:type locked: Optional(``True`` | ``False``)
:param userid: Set the repository lock to this user.
:type userid: Optional(str or int)
Example error output:
.. code-block:: bash
id : <id_given_in_input>
result : {
'repo': '<reponame>',
'locked': <bool: lock state>,
'locked_since': <int: lock timestamp>,
'locked_by': <username of person who made the lock>,
'lock_reason': <str: reason for locking>,
'lock_state_changed': <bool: True if lock state has been changed in this request>,
'msg': 'Repo `<reponame>` locked by `<username>` on <timestamp>.'
or
'msg': 'Repo `<repository name>` not locked.'
or
'msg': 'User `<user name>` set lock state for repo `<repository name>` to `<new lock state>`'
}
error : null
Example error output:
.. code-block:: bash
id : <id_given_in_input>
result : null
error : {
'Error occurred locking repository `<reponame>`
}
pull
----
.. py:function:: pull(apiuser, repoid)
Triggers a pull on the given repository from a remote location. You
can use this to keep remote repositories up-to-date.
This command can only be run using an |authtoken| with admin
rights to the specified repository. For more information,
see :ref:`config-token-ref`.
This command takes the following options:
:param apiuser: This is filled automatically from the |authtoken|.
:type apiuser: AuthUser
:param repoid: The repository name or repository ID.
:type repoid: str or int
Example output:
.. code-block:: bash
id : <id_given_in_input>
result : {
"msg": "Pulled from `<repository name>`"
"repository": "<repository name>"
}
error : null
Example error output:
.. code-block:: bash
id : <id_given_in_input>
result : null
error : {
"Unable to pull changes from `<reponame>`"
}
remove_field_from_repo
----------------------
.. py:function:: remove_field_from_repo(apiuser, repoid, key)
Removes an extra field from a repository.
This command can only be run using an |authtoken| with at least
write permissions to the |repo|.
:param apiuser: This is filled automatically from the |authtoken|.
:type apiuser: AuthUser
:param repoid: Set the repository name or repository ID.
:type repoid: str or int
:param key: Set the unique field key for this repository.
:type key: str
revoke_user_group_permission
----------------------------
.. py:function:: revoke_user_group_permission(apiuser, repoid, usergroupid)
Revoke the permissions of a user group on a given repository.
This command can only be run using an |authtoken| with admin
permissions on the |repo|.
:param apiuser: This is filled automatically from the |authtoken|.
:type apiuser: AuthUser
:param repoid: Set the repository name or repository ID.
:type repoid: str or int
:param usergroupid: Specify the user group ID.
:type usergroupid: str or int
Example output:
.. code-block:: bash
id : <id_given_in_input>
result: {
"msg" : "Revoked perm for group: `<usersgroupname>` in repo: `<reponame>`",
"success": true
}
error: null
revoke_user_permission
----------------------
.. py:function:: revoke_user_permission(apiuser, repoid, userid)
Revoke permission for a user on the specified repository.
This command can only be run using an |authtoken| with admin
permissions on the |repo|.
:param apiuser: This is filled automatically from the |authtoken|.
:type apiuser: AuthUser
:param repoid: Set the repository name or repository ID.
:type repoid: str or int
:param userid: Set the user name of revoked user.
:type userid: str or int
Example error output:
.. code-block:: bash
id : <id_given_in_input>
result: {
"msg" : "Revoked perm for user: `<username>` in repo: `<reponame>`",
"success": true
}
error: null
set_repo_settings
-----------------
.. py:function:: set_repo_settings(apiuser, repoid, settings)
Update repository settings. Returns true on success.
:param apiuser: This is filled automatically from the |authtoken|.
:type apiuser: AuthUser
:param repoid: The repository name or repository id.
:type repoid: str or int
:param settings: The new settings for the repository.
:type: settings: dict
Example output:
.. code-block:: bash
{
"error": null,
"id": 237,
"result": true
}
strip
-----
.. py:function:: strip(apiuser, repoid, revision, branch)
Strips the given revision from the specified repository.
* This will remove the revision and all of its decendants.
This command can only be run using an |authtoken| with admin rights to
the specified repository.
This command takes the following options:
:param apiuser: This is filled automatically from the |authtoken|.
:type apiuser: AuthUser
:param repoid: The repository name or repository ID.
:type repoid: str or int
:param revision: The revision you wish to strip.
:type revision: str
:param branch: The branch from which to strip the revision.
:type branch: str
Example output:
.. code-block:: bash
id : <id_given_in_input>
result : {
"msg": "'Stripped commit <commit_hash> from repo `<repository name>`'"
"repository": "<repository name>"
}
error : null
Example error output:
.. code-block:: bash
id : <id_given_in_input>
result : null
error : {
"Unable to strip commit <commit_hash> from repo `<repository name>`"
}
update_repo
-----------
.. py:function:: update_repo(apiuser, repoid, name=<Optional:None>, owner=<Optional:<OptionalAttr:apiuser>>, group=<Optional:None>, fork_of=<Optional:None>, description=<Optional:''>, private=<Optional:False>, clone_uri=<Optional:None>, landing_rev=<Optional:'rev:tip'>, enable_statistics=<Optional:False>, enable_locking=<Optional:False>, enable_downloads=<Optional:False>, fields=<Optional:''>)
Updates a repository with the given information.
This command can only be run using an |authtoken| with at least
write permissions to the |repo|.
:param apiuser: This is filled automatically from the |authtoken|.
:type apiuser: AuthUser
:param repoid: repository name or repository ID.
:type repoid: str or int
:param name: Update the |repo| name.
:type name: str
:param owner: Set the |repo| owner.
:type owner: str
:param group: Set the |repo| group the |repo| belongs to.
:type group: str
:param fork_of: Set the master |repo| name.
:type fork_of: str
:param description: Update the |repo| description.
:type description: str
:param private: Set the |repo| as private. (True | False)
:type private: bool
:param clone_uri: Update the |repo| clone URI.
:type clone_uri: str
:param landing_rev: Set the |repo| landing revision. Default is
``tip``.
:type landing_rev: str
:param enable_statistics: Enable statistics on the |repo|,
(True | False).
:type enable_statistics: bool
:param enable_locking: Enable |repo| locking.
:type enable_locking: bool
:param enable_downloads: Enable downloads from the |repo|,
(True | False).
:type enable_downloads: bool
:param fields: Add extra fields to the |repo|. Use the following
example format: ``field_key=field_val,field_key2=fieldval2``.
Escape ', ' with \,
:type fields: str

View file

@ -0,0 +1,115 @@
.. _server-methods-ref:
server methods
=================
get_ip
------
.. py:function:: get_ip(apiuser, userid=<Optional:<OptionalAttr:apiuser>>)
Displays the IP Address as seen from the |RCE| server.
* This command displays the IP Address, as well as all the defined IP
addresses for the specified user. If the ``userid`` is not set, the
data returned is for the user calling the method.
This command can only be run using an |authtoken| with admin rights to
the specified repository.
This command takes the following options:
:param apiuser: This is filled automatically from |authtoken|.
:type apiuser: AuthUser
:param userid: Sets the userid for which associated IP Address data
is returned.
:type userid: Optional(str or int)
Example output:
.. code-block:: bash
id : <id_given_in_input>
result : {
"server_ip_addr": "<ip_from_clien>",
"user_ips": [
{
"ip_addr": "<ip_with_mask>",
"ip_range": ["<start_ip>", "<end_ip>"],
},
...
]
}
get_server_info
---------------
.. py:function:: get_server_info(apiuser)
Returns the |RCE| server information.
This includes the running version of |RCE| and all installed
packages. This command takes the following options:
:param apiuser: This is filled automatically from the |authtoken|.
:type apiuser: AuthUser
Example output:
.. code-block:: bash
id : <id_given_in_input>
result : {
'modules': [<module name>,...]
'py_version': <python version>,
'platform': <platform type>,
'rhodecode_version': <rhodecode version>
}
error : null
rescan_repos
------------
.. py:function:: rescan_repos(apiuser, remove_obsolete=<Optional:False>)
Triggers a rescan of the specified repositories.
* If the ``remove_obsolete`` option is set, it also deletes repositories
that are found in the database but not on the file system, so called
"clean zombies".
This command can only be run using an |authtoken| with admin rights to
the specified repository.
This command takes the following options:
:param apiuser: This is filled automatically from the |authtoken|.
:type apiuser: AuthUser
:param remove_obsolete: Deletes repositories from the database that
are not found on the filesystem.
:type remove_obsolete: Optional(``True`` | ``False``)
Example output:
.. code-block:: bash
id : <id_given_in_input>
result : {
'added': [<added repository name>,...]
'removed': [<removed repository name>,...]
}
error : null
Example error output:
.. code-block:: bash
id : <id_given_in_input>
result : null
error : {
'Error occurred during rescan repositories action'
}

View file

@ -0,0 +1,406 @@
.. _user-group-methods-ref:
user_group methods
=================
add_user_to_user_group
----------------------
.. py:function:: add_user_to_user_group(apiuser, usergroupid, userid)
Adds a user to a `user group`. If the user already exists in the group
this command will return false.
This command can only be run using an |authtoken| with admin rights to
the specified user group.
This command takes the following options:
:param apiuser: This is filled automatically from the |authtoken|.
:type apiuser: AuthUser
:param usergroupid: Set the name of the `user group` to which a
user will be added.
:type usergroupid: int
:param userid: Set the `user_id` of the user to add to the group.
:type userid: int
Example output:
.. code-block:: bash
id : <id_given_in_input>
result : {
"success": True|False # depends on if member is in group
"msg": "added member `<username>` to user group `<groupname>` |
User is already in that group"
}
error : null
Example error output:
.. code-block:: bash
id : <id_given_in_input>
result : null
error : {
"failed to add member to user group `<user_group_name>`"
}
create_user_group
-----------------
.. py:function:: create_user_group(apiuser, group_name, description=<Optional:''>, owner=<Optional:<OptionalAttr:apiuser>>, active=<Optional:True>)
Creates a new user group.
This command can only be run using an |authtoken| with admin rights to
the specified repository.
This command takes the following options:
:param apiuser: This is filled automatically from the |authtoken|.
:type apiuser: AuthUser
:param group_name: Set the name of the new user group.
:type group_name: str
:param description: Give a description of the new user group.
:type description: str
:param owner: Set the owner of the new user group.
If not set, the owner is the |authtoken| user.
:type owner: Optional(str or int)
:param active: Set this group as active.
:type active: Optional(``True`` | ``False``)
Example output:
.. code-block:: bash
id : <id_given_in_input>
result: {
"msg": "created new user group `<groupname>`",
"user_group": <user_group_object>
}
error: null
Example error output:
.. code-block:: bash
id : <id_given_in_input>
result : null
error : {
"user group `<group name>` already exist"
or
"failed to create group `<group name>`"
}
delete_user_group
-----------------
.. py:function:: delete_user_group(apiuser, usergroupid)
Deletes the specified `user group`.
This command can only be run using an |authtoken| with admin rights to
the specified repository.
This command takes the following options:
:param apiuser: filled automatically from apikey
:type apiuser: AuthUser
:param usergroupid:
:type usergroupid: int
Example output:
.. code-block:: bash
id : <id_given_in_input>
result : {
"msg": "deleted user group ID:<user_group_id> <user_group_name>"
}
error : null
Example error output:
.. code-block:: bash
id : <id_given_in_input>
result : null
error : {
"failed to delete user group ID:<user_group_id> <user_group_name>"
or
"RepoGroup assigned to <repo_groups_list>"
}
get_user_group
--------------
.. py:function:: get_user_group(apiuser, usergroupid)
Returns the data of an existing user group.
This command can only be run using an |authtoken| with admin rights to
the specified repository.
:param apiuser: This is filled automatically from the |authtoken|.
:type apiuser: AuthUser
:param usergroupid: Set the user group from which to return data.
:type usergroupid: str or int
Example error output:
.. code-block:: bash
{
"error": null,
"id": <id>,
"result": {
"active": true,
"group_description": "group description",
"group_name": "group name",
"members": [
{
"name": "owner-name",
"origin": "owner",
"permission": "usergroup.admin",
"type": "user"
},
{
{
"name": "user name",
"origin": "permission",
"permission": "usergroup.admin",
"type": "user"
},
{
"name": "user group name",
"origin": "permission",
"permission": "usergroup.write",
"type": "user_group"
}
],
"owner": "owner name",
"users": [],
"users_group_id": 2
}
}
get_user_groups
---------------
.. py:function:: get_user_groups(apiuser)
Lists all the existing user groups within RhodeCode.
This command can only be run using an |authtoken| with admin rights to
the specified repository.
This command takes the following options:
:param apiuser: This is filled automatically from the |authtoken|.
:type apiuser: AuthUser
Example error output:
.. code-block:: bash
id : <id_given_in_input>
result : [<user_group_obj>,...]
error : null
grant_user_group_permission_to_user_group
-----------------------------------------
.. py:function:: grant_user_group_permission_to_user_group(apiuser, usergroupid, sourceusergroupid, perm)
Give one user group permissions to another user group.
:param apiuser: This is filled automatically from the |authtoken|.
:type apiuser: AuthUser
:param usergroupid: Set the user group on which to edit permissions.
:type usergroupid: str or int
:param sourceusergroupid: Set the source user group to which
access/permissions will be granted.
:type sourceusergroupid: str or int
:param perm: (usergroup.(none|read|write|admin))
:type perm: str
Example output:
.. code-block:: bash
id : <id_given_in_input>
result : {
"msg": "Granted perm: `<perm_name>` for user group: `<source_user_group_name>` in user group: `<user_group_name>`",
"success": true
}
error : null
grant_user_permission_to_user_group
-----------------------------------
.. py:function:: grant_user_permission_to_user_group(apiuser, usergroupid, userid, perm)
Set permissions for a user in a user group.
:param apiuser: This is filled automatically from the |authtoken|.
:type apiuser: AuthUser
:param usergroupid: Set the user group to edit permissions on.
:type usergroupid: str or int
:param userid: Set the user from whom you wish to set permissions.
:type userid: str
:param perm: (usergroup.(none|read|write|admin))
:type perm: str
Example output:
.. code-block:: bash
id : <id_given_in_input>
result : {
"msg": "Granted perm: `<perm_name>` for user: `<username>` in user group: `<user_group_name>`",
"success": true
}
error : null
remove_user_from_user_group
---------------------------
.. py:function:: remove_user_from_user_group(apiuser, usergroupid, userid)
Removes a user from a user group.
* If the specified user is not in the group, this command will return
`false`.
This command can only be run using an |authtoken| with admin rights to
the specified user group.
:param apiuser: This is filled automatically from the |authtoken|.
:type apiuser: AuthUser
:param usergroupid: Sets the user group name.
:type usergroupid: str or int
:param userid: The user you wish to remove from |RCE|.
:type userid: str or int
Example output:
.. code-block:: bash
id : <id_given_in_input>
result: {
"success": True|False, # depends on if member is in group
"msg": "removed member <username> from user group <groupname> |
User wasn't in group"
}
error: null
revoke_user_group_permission_from_user_group
--------------------------------------------
.. py:function:: revoke_user_group_permission_from_user_group(apiuser, usergroupid, sourceusergroupid)
Revoke the permissions that one user group has to another.
:param apiuser: This is filled automatically from the |authtoken|.
:type apiuser: AuthUser
:param usergroupid: Set the user group on which to edit permissions.
:type usergroupid: str or int
:param sourceusergroupid: Set the user group from which permissions
are revoked.
:type sourceusergroupid: str or int
Example output:
.. code-block:: bash
id : <id_given_in_input>
result : {
"msg": "Revoked perm for user group: `<user_group_name>` in user group: `<target_user_group_name>`",
"success": true
}
error : null
revoke_user_permission_from_user_group
--------------------------------------
.. py:function:: revoke_user_permission_from_user_group(apiuser, usergroupid, userid)
Revoke a users permissions in a user group.
:param apiuser: This is filled automatically from the |authtoken|.
:type apiuser: AuthUser
:param usergroupid: Set the user group from which to revoke the user
permissions.
:type: usergroupid: str or int
:param userid: Set the userid of the user whose permissions will be
revoked.
:type userid: str
Example output:
.. code-block:: bash
id : <id_given_in_input>
result : {
"msg": "Revoked perm for user: `<username>` in user group: `<user_group_name>`",
"success": true
}
error : null
update_user_group
-----------------
.. py:function:: update_user_group(apiuser, usergroupid, group_name=<Optional:''>, description=<Optional:''>, owner=<Optional:None>, active=<Optional:True>)
Updates the specified `user group` with the details provided.
This command can only be run using an |authtoken| with admin rights to
the specified repository.
:param apiuser: This is filled automatically from the |authtoken|.
:type apiuser: AuthUser
:param usergroupid: Set the id of the `user group` to update.
:type usergroupid: str or int
:param group_name: Set the new name the `user group`
:type group_name: str
:param description: Give a description for the `user group`
:type description: str
:param owner: Set the owner of the `user group`.
:type owner: Optional(str or int)
:param active: Set the group as active.
:type active: Optional(``True`` | ``False``)
Example output:
.. code-block:: bash
id : <id_given_in_input>
result : {
"msg": 'updated user group ID:<user group id> <user group name>',
"user_group": <user_group_object>
}
error : null
Example error output:
.. code-block:: bash
id : <id_given_in_input>
result : null
error : {
"failed to update user group `<user group name>`"
}

View file

@ -0,0 +1,295 @@
.. _user-methods-ref:
user methods
=================
create_user
-----------
.. py:function:: create_user(apiuser, username, email, password=<Optional:''>, firstname=<Optional:''>, lastname=<Optional:''>, active=<Optional:True>, admin=<Optional:False>, extern_name=<Optional:'rhodecode'>, extern_type=<Optional:'rhodecode'>, force_password_change=<Optional:False>)
Creates a new user and returns the new user object.
This command can only be run using an |authtoken| with admin rights to
the specified repository.
This command takes the following options:
:param apiuser: This is filled automatically from the |authtoken|.
:type apiuser: AuthUser
:param username: Set the new username.
:type username: str or int
:param email: Set the user email address.
:type email: str
:param password: Set the new user password.
:type password: Optional(str)
:param firstname: Set the new user firstname.
:type firstname: Optional(str)
:param lastname: Set the new user surname.
:type lastname: Optional(str)
:param active: Set the user as active.
:type active: Optional(``True`` | ``False``)
:param admin: Give the new user admin rights.
:type admin: Optional(``True`` | ``False``)
:param extern_name: Set the authentication plugin name.
Using LDAP this is filled with LDAP UID.
:type extern_name: Optional(str)
:param extern_type: Set the new user authentication plugin.
:type extern_type: Optional(str)
:param force_password_change: Force the new user to change password
on next login.
:type force_password_change: Optional(``True`` | ``False``)
Example output:
.. code-block:: bash
id : <id_given_in_input>
result: {
"msg" : "created new user `<username>`",
"user": <user_obj>
}
error: null
Example error output:
.. code-block:: bash
id : <id_given_in_input>
result : null
error : {
"user `<username>` already exist"
or
"email `<email>` already exist"
or
"failed to create user `<username>`"
}
delete_user
-----------
.. py:function:: delete_user(apiuser, userid)
Deletes the specified user from the |RCE| user database.
This command can only be run using an |authtoken| with admin rights to
the specified repository.
.. important::
Ensure all open pull requests and open code review
requests to this user are close.
Also ensure all repositories, or repository groups owned by this
user are reassigned before deletion.
This command takes the following options:
:param apiuser: This is filled automatically from the |authtoken|.
:type apiuser: AuthUser
:param userid: Set the user to delete.
:type userid: str or int
Example output:
.. code-block:: bash
id : <id_given_in_input>
result: {
"msg" : "deleted user ID:<userid> <username>",
"user": null
}
error: null
Example error output:
.. code-block:: bash
id : <id_given_in_input>
result : null
error : {
"failed to delete user ID:<userid> <username>"
}
get_user
--------
.. py:function:: get_user(apiuser, userid=<Optional:<OptionalAttr:apiuser>>)
Returns the information associated with a username or userid.
* If the ``userid`` is not set, this command returns the information
for the ``userid`` calling the method.
.. note::
Normal users may only run this command against their ``userid``. For
full privileges you must run this command using an |authtoken| with
admin rights.
:param apiuser: This is filled automatically from the |authtoken|.
:type apiuser: AuthUser
:param userid: Sets the userid for which data will be returned.
:type userid: Optional(str or int)
Example output:
.. code-block:: bash
{
"error": null,
"id": <id>,
"result": {
"active": true,
"admin": false,
"api_key": "api-key",
"api_keys": [ list of keys ],
"email": "user@example.com",
"emails": [
"user@example.com"
],
"extern_name": "rhodecode",
"extern_type": "rhodecode",
"firstname": "username",
"ip_addresses": [],
"language": null,
"last_login": "Timestamp",
"lastname": "surnae",
"permissions": {
"global": [
"hg.inherit_default_perms.true",
"usergroup.read",
"hg.repogroup.create.false",
"hg.create.none",
"hg.extern_activate.manual",
"hg.create.write_on_repogroup.false",
"hg.usergroup.create.false",
"group.none",
"repository.none",
"hg.register.none",
"hg.fork.repository"
],
"repositories": { "username/example": "repository.write"},
"repositories_groups": { "user-group/repo": "group.none" },
"user_groups": { "user_group_name": "usergroup.read" }
},
"user_id": 32,
"username": "username"
}
}
get_user_locks
--------------
.. py:function:: get_user_locks(apiuser, userid=<Optional:<OptionalAttr:apiuser>>)
Displays all repositories locked by the specified user.
* If this command is run by a non-admin user, it returns
a list of |repos| locked by that user.
This command takes the following options:
:param apiuser: This is filled automatically from the |authtoken|.
:type apiuser: AuthUser
:param userid: Sets the userid whose list of locked |repos| will be
displayed.
:type userid: Optional(str or int)
Example output:
.. code-block:: bash
id : <id_given_in_input>
result : {
[repo_object, repo_object,...]
}
error : null
get_users
---------
.. py:function:: get_users(apiuser)
Lists all users in the |RCE| user database.
This command can only be run using an |authtoken| with admin rights to
the specified repository.
This command takes the following options:
:param apiuser: This is filled automatically from the |authtoken|.
:type apiuser: AuthUser
Example output:
.. code-block:: bash
id : <id_given_in_input>
result: [<user_object>, ...]
error: null
update_user
-----------
.. py:function:: update_user(apiuser, userid, username=<Optional:None>, email=<Optional:None>, password=<Optional:None>, firstname=<Optional:None>, lastname=<Optional:None>, active=<Optional:None>, admin=<Optional:None>, extern_type=<Optional:None>, extern_name=<Optional:None>)
Updates the details for the specified user, if that user exists.
This command can only be run using an |authtoken| with admin rights to
the specified repository.
This command takes the following options:
:param apiuser: This is filled automatically from |authtoken|.
:type apiuser: AuthUser
:param userid: Set the ``userid`` to update.
:type userid: str or int
:param username: Set the new username.
:type username: str or int
:param email: Set the new email.
:type email: str
:param password: Set the new password.
:type password: Optional(str)
:param firstname: Set the new first name.
:type firstname: Optional(str)
:param lastname: Set the new surname.
:type lastname: Optional(str)
:param active: Set the new user as active.
:type active: Optional(``True`` | ``False``)
:param admin: Give the user admin rights.
:type admin: Optional(``True`` | ``False``)
:param extern_name: Set the authentication plugin user name.
Using LDAP this is filled with LDAP UID.
:type extern_name: Optional(str)
:param extern_type: Set the authentication plugin type.
:type extern_type: Optional(str)
Example output:
.. code-block:: bash
id : <id_given_in_input>
result: {
"msg" : "updated user ID:<userid> <username>",
"user": <user_object>,
}
error: null
Example error output:
.. code-block:: bash
id : <id_given_in_input>
result : null
error : {
"failed to update user `<username>`"
}

View file

@ -14,7 +14,7 @@ code review matters, see these posts on the topic:
You can also use the |RCE| API set up continuous integration servers to leave
comments from a test suite. See the :ref:`api` and
:ref:`integrations-ref` sections for examples on how to set this up.
:ref:`extensions-hooks-ref` sections for examples on how to set this up.
.. toctree::

View file

@ -6,6 +6,8 @@ rst_epilog = '''
.. |AE| replace:: Appenlight
.. |authtoken| replace:: Authentication Token
.. |authtokens| replace:: **Auth Tokens**
.. |RCCEshort| replace:: Community
.. |RCEEshort| replace:: Enterprise
.. |git| replace:: Git
.. |hg| replace:: Mercurial
.. |svn| replace:: Subversion

View file

@ -78,7 +78,7 @@ following command from inside the cloned repository::
On the first run, this will take a while to download and optionally compile
a few things. The following runs will be faster. The development shell works
fine on MacOS and Linux platforms.
fine on both MacOS and Linux platforms.
@ -91,9 +91,9 @@ use the following steps:
1. Create a copy of `~/rhodecode-enterprise-ce/configs/development.ini`
2. Adjust the configuration settings to your needs
.. note::
.. note::
It is recommended to use the name `dev.ini`.
It is recommended to use the name `dev.ini`.
Setup the Development Database
@ -108,32 +108,37 @@ time operation::
--repos=~/my_dev_repos
Compile CSS and JavaScript
^^^^^^^^^^^^^^^^^^^^^^^^^^
To use the application's frontend, you will need to compile the CSS and
JavaScript with Grunt. This is easily done from within the nix-shell using the
following command::
make web-build
You will need to recompile following any changes made to the CSS or JavaScript
files.
Start the Development Server
^^^^^^^^^^^^^^^^^^^^^^^^^^^^
When starting the development server, you should start the vcsserver as a
separate process. To do this, use one of the following examples:
From the rhodecode-vcsserver directory, start the development server in another
nix-shell, using the following command::
1. Set the `start.vcs_server` flag in the ``dev.ini`` file to true. For example:
pserve configs/development.ini http_port=9900
.. code-block:: python
In the adjacent nix-shell which you created for your development server, you may
now start CE with the following command::
### VCS CONFIG ###
##################
vcs.start_server = true
vcs.server = localhost:9900
vcs.server.log_level = debug
Then start the server using the following command: ``rcserver dev.ini``
rcserver dev.ini
2. Start the development server using the following example::
.. note::
rcserver --with-vcsserver dev.ini
3. Start the development server in a different terminal using the following
example::
vcsserver
To automatically refresh - and recompile the frontend assets - when changes
are made in the source code, you can use the option `--reload`.
Run the Environment Tests
@ -141,4 +146,12 @@ Run the Environment Tests
Please make sure that the tests are passing to verify that your environment is
set up correctly. RhodeCode uses py.test to run tests.
Please simply run ``make test`` to run the basic test suite.
While your instance is running, start a new nix-shell and simply run
``make test`` to run the basic test suite.
Need Help?
^^^^^^^^^^
Join us on Slack via https://rhodecode.com/join or post questions in our
Community Portal at https://community.rhodecode.com

View file

@ -86,14 +86,11 @@ Sign the Contributor License Agreement
======================================
If your contribution is approved, you will need to virtually sign the license
agreement in order for it to be merged into the project's codebase. You can read
it on our website here: https://rhodecode.com/static/pdf/RhodeCode-CLA.pdf
agreement in order for it to be merged into the project's codebase.
To sign, go to code.rhodecode.com
and clone the CLA repository. Add your name and make a pull request to add it to
the contributor agreement; this serves as your virtual signature. Once your
signature is merged, add a link to the relevant commit to your contribution
pull request.
You can read it on our website at https://rhodecode.com/rhodecode-cla
To sign electronically, go to https://rhodecode.com/sign-cla

View file

@ -28,10 +28,11 @@ let
};
Pygments = buildPythonPackage rec {
name = "Pygments-2.0.2";
name = "Pygments-2.1.3";
doCheck = false;
src = fetchurl {
url = "https://pypi.python.org/packages/source/P/Pygments/${name}.tar.gz";
md5 = "238587a1370d62405edabd0794b3ec4a";
url = "https://pypi.python.org/packages/b8/67/ab177979be1c81bc99c8d0592ef22d547e70bb4c6815c383286ed5dec504/Pygments-2.1.3.tar.gz";
md5 = "ed3fba2467c8afcda4d317e4ef2c6150";
};
};
@ -78,11 +79,19 @@ let
];
};
Sphinx = buildPythonPackage (rec {
name = "Sphinx-1.3.1";
imagesize = buildPythonPackage rec {
name = "imagesize-0.7.1";
src = fetchurl {
url = "http://pypi.python.org/packages/source/S/Sphinx/${name}.tar.gz";
md5 = "8786a194acf9673464c5455b11fd4332";
url = "https://pypi.python.org/packages/53/72/6c6f1e787d9cab2cc733cf042f125abec07209a58308831c9f292504e826/${name}.tar.gz";
md5 = "976148283286a6ba5f69b0f81aef8052";
};
};
Sphinx = buildPythonPackage (rec {
name = "Sphinx-1.4.4";
src = fetchurl {
url = "https://pypi.python.org/packages/20/a2/72f44c84f6c4115e3fef58d36d657ec311d80196eab9fd5ec7bcde76143b/${name}.tar.gz";
md5 = "64ce2ec08d37ed56313a98232cbe2aee";
};
propagatedBuildInputs = [
docutils
@ -93,6 +102,7 @@ let
snowballstemmer
pytz
babel
imagesize
# TODO: johbo: Had to include it here so that can be imported
sphinx_rtd_theme

View file

@ -0,0 +1,25 @@
.. _extensions-hooks-ref:
Extensions & Hooks
==================
The extensions & hooks section references three concepts regularly,
so to clarify what is meant each time, read the following definitions:
* **Plugin**: A Plugin is software that adds a specific feature to
an existing software application.
* **Extension**: An extension extends the capabilities of,
or the data available to, an existing software application.
* **Hook**: A hook intercepts function calls, messages, or events passed
between software components and can be used to trigger plugins, or their
extensions.
.. toctree::
rcx
install-ext
config-ext
extensions
hooks
full-blown-example
int-slack

View file

@ -58,6 +58,7 @@ and commit files and |repos| while managing their security permissions.
collaboration/review-notifications
collaboration/pull-requests
code-review/code-review
integrations/integrations
.. toctree::
:maxdepth: 1
@ -65,7 +66,7 @@ and commit files and |repos| while managing their security permissions.
api/api
tools/rhodecode-tools
integrations/integrations
extensions/extensions-hooks
contributing/contributing
.. toctree::

View file

@ -1,7 +1,7 @@
.. _quick-start:
Quick Start Guide
=================
Quick Start Installation Guide
==============================
.. important::

View file

@ -0,0 +1,23 @@
.. _integrations-email:
Email integration
=================
The email integration allows you to send the summary of repo pushes to a
list of email recipients in the format:
An example::
User: johndoe
Branches: default
Repository: http://rhodecode.company.com/repo
Commit: 8eab60a44a612e331edfcd59b8d96b2f6a935cd9
URL: http://rhodecode.company.com/repo/changeset/8eab60a44a612e331edfcd59b8d96b2f6a935cd9
Author: John Doe
Date: 2016-03-01 11:20:44
Commit Message:
fixed bug with thing
To create one, create a ``email`` integration in `creating-integrations`.

View file

@ -0,0 +1,14 @@
.. _integrations-hipchat:
Hipchat integration
===================
In order to set a Hipchat integration up, it is necessary to obtain the Hipchat
service url by:
1. Log into Hipchat (https://your-hipchat.hipchat.com/)
2. Go to *Integrations* -> *Build your own*
3. Select a room to post notifications to and save it
Hipchat will create a URL for you to use in your integration as outlined in
:ref:`creating-integrations`.

View file

@ -1,25 +1,52 @@
.. _integrations-ref:
.. _integrations:
Integrations and Extensions
===========================
Integrations
------------
The integrations section references three concepts regularly,
so to clarify what is meant each time, read the following definitions:
Rhodecode supports integrations with external services for various events,
such as commit pushes and pull requests. Multiple integrations of the same type
can be added at the same time; this is useful for posting different events to
different Slack channels, for example.
* **Plugin**: A Plugin is software that adds a specific feature to
an existing software application.
* **Extension**: An extension extends the capabilities of,
or the data available to, an existing software application.
* **Hook**: A hook intercepts function calls, messages, or events passed
between software components and can be used to trigger plugins, or their
extensions.
Supported integrations
^^^^^^^^^^^^^^^^^^^^^^
============================ ============ =====================================
Type/Name |RC| Edition Description
============================ ============ =====================================
:ref:`integrations-slack` |RCCEshort| https://slack.com/
:ref:`integrations-hipchat` |RCCEshort| https://www.hipchat.com/
:ref:`integrations-webhook` |RCCEshort| POST events as `json` to a custom url
:ref:`integrations-email` |RCEEshort| Send repo push commits by email
:ref:`integrations-redmine` |RCEEshort| Close/Resolve/Reference redmine issues
:ref:`integrations-jira` |RCEEshort| Close/Resolve/Reference JIRA issues
============================ ============ =====================================
.. _creating-integrations:
Creating an Integration
^^^^^^^^^^^^^^^^^^^^^^^
Integrations can be added globally via the admin UI:
:menuselection:`Admin --> Integrations`
or per repository in each repository's settings:
:menuselection:`Admin --> Repositories --> Edit --> Integrations`
To create an integration, select the type from the list in the *Create New
Integration* section.
The *Current Integrations* section shows existing integrations that have been
created along with their type (eg. Slack) and enabled status.
See pages specific to each type of integration for more instructions:
.. toctree::
rcx
install-ext
config-ext
extensions
hooks
full-blown-example
int-slack
slack
hipchat
redmine
jira
webhook

View file

@ -0,0 +1,27 @@
.. _integrations-jira:
JIRA integration
================
.. important::
JIRA integration is only available in |RCEE|.
.. important::
In order to make issue numbers clickable in commit messages, see the
:ref:`rhodecode-issue-trackers-ref` section. The JIRA integration
only deals with altering JIRA issues.
The JIRA integration allows you to reference and change issue statuses in
JIRA directly from commit messages using commit message patterns such as
``fixes #JIRA-235`` in order to change the status of issue JIRA-235 to
eg. "Resolved".
In order to apply a status to a JIRA issue, it is necessary to find the
transition status id in the *Workflow* section of JIRA.
Once you have the transition status id, you can create a JIRA integration
as outlined in :ref:`creating-integrations`.

View file

@ -0,0 +1,28 @@
.. _integrations-redmine:
Redmine integration
===================
.. important::
Redmine integration is only available in |RCEE|.
.. important::
In order to make issue numbers clickable in commit messages, see the section
:ref:`rhodecode-issue-trackers-ref`. Redmine integration is specifically for
altering Redmine issues.
Redmine integration allows you to reference and change issue statuses in
Redmine directly from commit messages, using commit message patterns such as
``fixes #235`` in order to change the status of issue 235 to eg. "Resolved".
To set a Redmine integration up, it is first necessary to obtain a Redmine API
key. This can be found under *My Account* in the Redmine application.
You may have to enable API Access in Redmine settings if it is not already
available.
Once you have the API key, create a Redmine integration as outlined in
:ref:`creating-integrations`.

View file

@ -0,0 +1,21 @@
.. _integrations-slack:
Slack integration
=================
To set a Slack integration up, it is first necessary to set up a Slack webhook
API endpoint for your Slack channel. This can be done at:
https://my.slack.com/services/new/incoming-webhook/
Select the channel you would like to use, and Slack will provide you with the
webhook URL for configuration.
You can now create a Slack integration as outlined in
:ref:`creating-integrations`.
.. note::
Some settings in the RhodeCode admin are identical to the options within the
Slack integration. For example, if notifications are to be sent in a private
chat, leave the "Channel" field blank. Likewise, the Emoji option within
RhodeCode can override the one set in the Slack admin.

View file

@ -0,0 +1,12 @@
.. _integrations-webhook:
Webhook integration
===================
The Webhook integration allows you to POST events such as repository pushes
or pull requests to a custom http endpoint as a json dict with details of the
event.
To create a webhook integration, select "webhook" in the integration settings
and use the url and key from your custom webhook. See
:ref:`creating-integrations` for additional instructions.

View file

@ -5,12 +5,12 @@ Issue Tracker Integration
You can set an issue tracker connection in two ways with |RCE|.
* At instance level you can set a default issue tracker.
* At |repo| level you can configure an integration with a different issue
* At the instance level, you can set a default issue tracker.
* At the |repo| level, you can configure an integration with a different issue
tracker.
To integrate |RCM| with an issue tracker you need to define a regular
expression that will fetch the issue ID stored in commit messages and replace
To integrate |RCM| with an issue tracker, you need to define a regular
expression that will fetch the issue ID stored in commit messages, and replace
it with a URL. This enables |RCE| to generate a link matching each issue to the
target |repo|.
@ -33,9 +33,8 @@ To integrate your issue tracker, use the following steps:
Repository Issue Tracker Configuration
--------------------------------------
You can configure specific |repos| to use a different issue tracker if
you need to connect to a non-default one. See the instructions in
:ref:`repo-it`
You can configure specific |repos| to use a different issue tracker than the
default one. See the instructions in :ref:`repo-it`
.. _issue-tr-eg-ref:

View file

@ -9,6 +9,6 @@ Release Date
Fixes
^^^^^
- ui: fixed empty labels caused by missing translation of JS components
- login: fixed bad routing URL in comments when user is not logged in.
- celery: make sure to run tasks in sync mode if connection to celery is lost.
- UI: fixed empty labels caused by missing translation of JS components.
- Login: fixed bad routing URL in comments when user is not logged in.
- Celery: make sure to run tasks in sync mode if connection to celery is lost.

View file

@ -0,0 +1,121 @@
|RCE| 4.3.0 |RNS|
-----------------
Release Date
^^^^^^^^^^^^
- 2016-08-12
General
^^^^^^^
- Subversion: detect requests also based on magic path.
This adds subversion 1.9 support for SVN backend.
- Summary/changelog: unified how data is displayed for those pages.
* use consistent order of columns
* fix the link to commit status
* fix order of displaying comments
- Live-chat: refactor live chat system for code review based on
latest channelstream changes.
- SVN: Add template to generate the apache mod_dav_svn config for all
repository groups. Repository groups can now be automatically mapped to be
supported by SVN backend. Set `svn.proxy.generate_config = true` and similar
options found inside .ini config.
- Readme/markup: improved order of generating readme files. Fixes #4050
* we now use order based on default system renderer
* having multiple readme files will pick correct one as set renderer
- Api: add a max_file_bytes parameter to get_nodes so that large files
can be skipped.
- Auth-ldap: added flag to set debug mode for LDAP connections.
- Labs: moved rebase-merge option from labs settings into VCS settings.
- System: send platform type and version to upgrade endpoint when checking
for new versions.
- Packaging: update rhodecode-tools from 0.8.3 to 0.10.0
- Packaging: update codemirror from 5.4.0 to 5.11.0
- Packaging: updated pygments to 2.1.3
- Packaging: bumped supervisor to 3.3.0
- Packaging: bumped psycopg2 to 2.6.1
- Packaging: bumped mercurial to 3.8.4
New Features
^^^^^^^^^^^^
- Integrations: created new event based integration framework.
Allows to configure global, or per repo: Slack, Hipchat, Webhooks, Email
integrations. This also deprecated usage of rcextensions for those.
- Integrations (EE only): added smart commits for Jira and Redmine with
ability to map keywords into issue tracker actions.
`Fixes #123 -> resolves issues`, `Closes #123 -> closes issue` etc.
- Markdown: added improved support for Github flavored markdown.
- Labs: enable labs setting by default. Labs are new experimental features in
RhodeCode that can be used to test new upcomming features.
- Api: Add api methods to get/set repository settings, implements #4021.
- Gravatars: commit emails are now displayed based on the actual email
used inside commit rather then the main one of associated account
inside RhodeCode, #4037.
- Emails: All emails got new styling. They look now consistent
to UI of application. We also added bunch of usefull information into
email body, #4087.
- Pull requests: add show/hide comment functionality inside diffs, #4106.
- Notifications: added real-time notifications with via channelstream
about new comments when reviewing the code. Never miss someone replies
onto comments you submitted while doing a code-review.
Security
^^^^^^^^
- Api: make `comment_commits` api call have consistent permissions
with web interface.
- Files: fixes display of "Add File" button missing or present despite
permissions, because of cached version of the page was rendered, fixes #4083.
- Login/Registration: fixed flash message problem on login/registration
pages, fixes #4043.
- Auth-token: allow other authentication types to use auth-token.
Accounts associated with other types like LDAP, or PAM can
now use auth-tokens to authenticate via RhodeCode.
Performance
^^^^^^^^^^^
- Core: made all RhodeCode components gevent compatible. RhodeCode can now make
use of async workers. You can handle dozens of concurrent operations using a
single worker. This works only with new HTTP backend.
- Core: added new very efficient HTTP backend can be used to replace pyro4.
- Core: Set 'gzip_responses' to false by default. We no longer require any
gzip computations on backed, thus speeding up large file transfers.
- UI: optimized events system for JavaScript to boost performance on
large html pages.
- VCS: moved VCSMiddleware up to pyramid layer as wrapper around pylons app.
Skips few calls, and allows slightly faster clones/pulls and pushes.
Fixes
^^^^^
- VCS: add vcsserver cache invalidation to mercurial backend.
Fixes multi-process problems after Mercurial 3.8.X release with server
side merges.
- VCS: clear caches on remap-and-rescan option.
- VCS: improved logic of updating commit caches in cases of rebases.
- Caches: Add an argument to make the cache context thread scoped. Brings
support to gevent compatible handling.
- Diff2way: fixed unicode problem on non-ascii files.
- Full text search: whoosh schema uses now bigger ints, fixes #4035
- File-browser: optimized cached tree calculation, reduced load times by
50% on complex file trees.
- Styling: #4086 fixing bug where long commit messages did not wrap in file view.
- SVN: Ignore the content length header from response, fixes #4112.
Fixes the "svn: E120106: ra_serf: The server sent a truncated HTTP response body."
- Auth: Fix password_changed function, fixes #4043.
- UI/tables: better message when tables are empty #685 #1832.
- UX: put gravatar and username together in user list #3203.
- Gists: use colander schema to validate input data.
* brings consistent validation acros API and web
* use nicer and stricter schemas to validate data
* fixes #4118
- Appenlight: error reporting can now also report VCSMiddleware errors.
- Users: hash email key for User.get_by_email() fixes #4132

View file

@ -9,6 +9,7 @@ Release Notes
.. toctree::
:maxdepth: 1
release-notes-4.3.0.rst
release-notes-4.2.1.rst
release-notes-4.2.0.rst
release-notes-4.1.2.rst

View file

@ -301,7 +301,7 @@ used to send signals to build-bots such as jenkins. Options:
\ - -plugins
Add plugins to your |RCE| installation. See the
:ref:`integrations-ref` section for more details.
:ref:`extensions-hooks-ref` section for more details.
\ - -version
Display your |RCT| version.

View file

@ -0,0 +1,13 @@
# Copyright 2009 Facebook
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.

View file

@ -1,12 +1,12 @@
diff --git a/requirements.txt b/requirements.txt
--- a/requirements.txt
+++ b/requirements.txt
@@ -3,7 +3,7 @@future==0.14.3
@@ -3,7 +3,7 @@ future==0.14.3
six==1.9.0
mako==1.0.1
markupsafe==0.23
-requests==2.5.1
+requests
#responses
whoosh==2.7.0
elasticsearch==2.3.0
elasticsearch==2.3.0
elasticsearch-dsl==2.0.0

View file

@ -95,6 +95,14 @@ self: super: {
};
});
py-gfm = super.py-gfm.override {
src = pkgs.fetchgit {
url = "https://code.rhodecode.com/upstream/py-gfm";
rev = "0d66a19bc16e3d49de273c0f797d4e4781e8c0f2";
sha256 = "0ryp74jyihd3ckszq31bml5jr3bciimhfp7va7kw6ld92930ksv3";
};
};
pycurl = super.pycurl.override (attrs: {
propagatedBuildInputs = attrs.propagatedBuildInputs ++ [
pkgs.curl

View file

@ -38,6 +38,19 @@
license = [ pkgs.lib.licenses.mit ];
};
};
Chameleon = super.buildPythonPackage {
name = "Chameleon-2.24";
buildInputs = with self; [];
doCheck = false;
propagatedBuildInputs = with self; [];
src = fetchurl {
url = "https://pypi.python.org/packages/5a/9e/637379ffa13c5172b5c0e704833ffea6bf51cec7567f93fd6e903d53ed74/Chameleon-2.24.tar.gz";
md5 = "1b01f1f6533a8a11d0d2f2366dec5342";
};
meta = {
license = [ { fullName = "BSD-like (http://repoze.org/license.html)"; } ];
};
};
Fabric = super.buildPythonPackage {
name = "Fabric-1.10.0";
buildInputs = with self; [];
@ -169,13 +182,13 @@
};
};
Pygments = super.buildPythonPackage {
name = "Pygments-2.0.2";
name = "Pygments-2.1.3";
buildInputs = with self; [];
doCheck = false;
propagatedBuildInputs = with self; [];
src = fetchurl {
url = "https://pypi.python.org/packages/f4/c6/bdbc5a8a112256b2b6136af304dbae93d8b1ef8738ff2d12a51018800e46/Pygments-2.0.2.tar.gz";
md5 = "238587a1370d62405edabd0794b3ec4a";
url = "https://pypi.python.org/packages/b8/67/ab177979be1c81bc99c8d0592ef22d547e70bb4c6815c383286ed5dec504/Pygments-2.1.3.tar.gz";
md5 = "ed3fba2467c8afcda4d317e4ef2c6150";
};
meta = {
license = [ pkgs.lib.licenses.bsdOriginal ];
@ -467,6 +480,19 @@
license = [ pkgs.lib.licenses.bsdOriginal ];
};
};
channelstream = super.buildPythonPackage {
name = "channelstream-0.5.2";
buildInputs = with self; [];
doCheck = false;
propagatedBuildInputs = with self; [gevent ws4py pyramid pyramid-jinja2 itsdangerous requests six];
src = fetchurl {
url = "https://pypi.python.org/packages/2b/31/29a8e085cf5bf97fa88e7b947adabfc581a18a3463adf77fb6dada34a65f/channelstream-0.5.2.tar.gz";
md5 = "1c5eb2a8a405be6f1073da94da6d81d3";
};
meta = {
license = [ pkgs.lib.licenses.bsdOriginal ];
};
};
click = super.buildPythonPackage {
name = "click-5.1";
buildInputs = with self; [];
@ -558,6 +584,19 @@
license = [ pkgs.lib.licenses.bsdOriginal ];
};
};
deform = super.buildPythonPackage {
name = "deform-2.0a2";
buildInputs = with self; [];
doCheck = false;
propagatedBuildInputs = with self; [Chameleon colander peppercorn translationstring zope.deprecation];
src = fetchurl {
url = "https://pypi.python.org/packages/8d/b3/aab57e81da974a806dc9c5fa024a6404720f890a6dcf2e80885e3cb4609a/deform-2.0a2.tar.gz";
md5 = "7a90d41f7fbc18002ce74f39bd90a5e4";
};
meta = {
license = [ { fullName = "BSD-derived (http://www.repoze.org/LICENSE.txt)"; } ];
};
};
docutils = super.buildPythonPackage {
name = "docutils-0.12";
buildInputs = with self; [];
@ -572,13 +611,13 @@
};
};
dogpile.cache = super.buildPythonPackage {
name = "dogpile.cache-0.5.7";
name = "dogpile.cache-0.6.1";
buildInputs = with self; [];
doCheck = false;
propagatedBuildInputs = with self; [dogpile.core];
propagatedBuildInputs = with self; [];
src = fetchurl {
url = "https://pypi.python.org/packages/07/74/2a83bedf758156d9c95d112691bbad870d3b77ccbcfb781b4ef836ea7d96/dogpile.cache-0.5.7.tar.gz";
md5 = "3e58ce41af574aab41d78e9c4190f194";
url = "https://pypi.python.org/packages/f6/a0/6f2142c58c6588d17c734265b103ae1cd0741e1681dd9483a63f22033375/dogpile.cache-0.6.1.tar.gz";
md5 = "35d7fb30f22bbd0685763d894dd079a9";
};
meta = {
license = [ pkgs.lib.licenses.bsdOriginal ];
@ -688,6 +727,19 @@
license = [ pkgs.lib.licenses.bsdOriginal ];
};
};
gevent = super.buildPythonPackage {
name = "gevent-1.1.1";
buildInputs = with self; [];
doCheck = false;
propagatedBuildInputs = with self; [greenlet];
src = fetchurl {
url = "https://pypi.python.org/packages/12/dc/0b2e57823225de86f6e111a65d212c9e3b64847dddaa19691a6cb94b0b2e/gevent-1.1.1.tar.gz";
md5 = "1532f5396ab4d07a231f1935483be7c3";
};
meta = {
license = [ pkgs.lib.licenses.mit ];
};
};
gnureadline = super.buildPythonPackage {
name = "gnureadline-6.3.3";
buildInputs = with self; [];
@ -702,7 +754,7 @@
};
};
gprof2dot = super.buildPythonPackage {
name = "gprof2dot-2015.12.1";
name = "gprof2dot-2015.12.01";
buildInputs = with self; [];
doCheck = false;
propagatedBuildInputs = with self; [];
@ -714,6 +766,19 @@
license = [ { fullName = "LGPL"; } ];
};
};
greenlet = super.buildPythonPackage {
name = "greenlet-0.4.9";
buildInputs = with self; [];
doCheck = false;
propagatedBuildInputs = with self; [];
src = fetchurl {
url = "https://pypi.python.org/packages/4e/3d/9d421539b74e33608b245092870156b2e171fb49f2b51390aa4641eecb4a/greenlet-0.4.9.zip";
md5 = "c6659cdb2a5e591723e629d2eef22e82";
};
meta = {
license = [ pkgs.lib.licenses.mit ];
};
};
gunicorn = super.buildPythonPackage {
name = "gunicorn-19.6.0";
buildInputs = with self; [];
@ -948,6 +1013,19 @@
license = [ { fullName = "Expat license"; } pkgs.lib.licenses.mit ];
};
};
peppercorn = super.buildPythonPackage {
name = "peppercorn-0.5";
buildInputs = with self; [];
doCheck = false;
propagatedBuildInputs = with self; [];
src = fetchurl {
url = "https://pypi.python.org/packages/45/ec/a62ec317d1324a01567c5221b420742f094f05ee48097e5157d32be3755c/peppercorn-0.5.tar.gz";
md5 = "f08efbca5790019ab45d76b7244abd40";
};
meta = {
license = [ { fullName = "BSD-derived (http://www.repoze.org/LICENSE.txt)"; } ];
};
};
psutil = super.buildPythonPackage {
name = "psutil-2.2.1";
buildInputs = with self; [];
@ -962,13 +1040,13 @@
};
};
psycopg2 = super.buildPythonPackage {
name = "psycopg2-2.6";
name = "psycopg2-2.6.1";
buildInputs = with self; [];
doCheck = false;
propagatedBuildInputs = with self; [];
src = fetchurl {
url = "https://pypi.python.org/packages/dd/c7/9016ff8ff69da269b1848276eebfb264af5badf6b38caad805426771f04d/psycopg2-2.6.tar.gz";
md5 = "fbbb039a8765d561a1c04969bbae7c74";
url = "https://pypi.python.org/packages/86/fd/cc8315be63a41fe000cce20482a917e874cdc1151e62cb0141f5e55f711e/psycopg2-2.6.1.tar.gz";
md5 = "842b44f8c95517ed5b792081a2370da1";
};
meta = {
license = [ pkgs.lib.licenses.zpt21 { fullName = "GNU Library or Lesser General Public License (LGPL)"; } { fullName = "LGPL with exceptions or ZPL"; } ];
@ -1000,6 +1078,19 @@
license = [ pkgs.lib.licenses.bsdOriginal ];
};
};
py-gfm = super.buildPythonPackage {
name = "py-gfm-0.1.3";
buildInputs = with self; [];
doCheck = false;
propagatedBuildInputs = with self; [setuptools Markdown];
src = fetchurl {
url = "https://pypi.python.org/packages/12/e4/6b3d8678da04f97d7490d8264d8de51c2dc9fb91209ccee9c515c95e14c5/py-gfm-0.1.3.tar.gz";
md5 = "e588d9e69640a241b97e2c59c22527a6";
};
meta = {
license = [ pkgs.lib.licenses.bsdOriginal ];
};
};
pycrypto = super.buildPythonPackage {
name = "pycrypto-2.6.1";
buildInputs = with self; [];
@ -1339,23 +1430,23 @@
};
};
rhodecode-enterprise-ce = super.buildPythonPackage {
name = "rhodecode-enterprise-ce-4.2.1";
name = "rhodecode-enterprise-ce-4.3.0";
buildInputs = with self; [WebTest configobj cssselect flake8 lxml mock pytest pytest-cov pytest-runner];
doCheck = true;
propagatedBuildInputs = with self; [Babel Beaker FormEncode Mako Markdown MarkupSafe MySQL-python Paste PasteDeploy PasteScript Pygments Pylons Pyro4 Routes SQLAlchemy Tempita URLObject WebError WebHelpers WebHelpers2 WebOb WebTest Whoosh alembic amqplib anyjson appenlight-client authomatic backport-ipaddress celery colander decorator docutils gunicorn infrae.cache ipython iso8601 kombu msgpack-python packaging psycopg2 pycrypto pycurl pyparsing pyramid pyramid-debugtoolbar pyramid-mako pyramid-beaker pysqlite python-dateutil python-ldap python-memcached python-pam recaptcha-client repoze.lru requests simplejson waitress zope.cachedescriptors psutil py-bcrypt];
propagatedBuildInputs = with self; [Babel Beaker FormEncode Mako Markdown MarkupSafe MySQL-python Paste PasteDeploy PasteScript Pygments Pylons Pyro4 Routes SQLAlchemy Tempita URLObject WebError WebHelpers WebHelpers2 WebOb WebTest Whoosh alembic amqplib anyjson appenlight-client authomatic backport-ipaddress celery channelstream colander decorator deform docutils gevent gunicorn infrae.cache ipython iso8601 kombu msgpack-python packaging psycopg2 py-gfm pycrypto pycurl pyparsing pyramid pyramid-debugtoolbar pyramid-mako pyramid-beaker pysqlite python-dateutil python-ldap python-memcached python-pam recaptcha-client repoze.lru requests simplejson waitress zope.cachedescriptors dogpile.cache dogpile.core psutil py-bcrypt];
src = ./.;
meta = {
license = [ { fullName = "AGPLv3, and Commercial License"; } ];
};
};
rhodecode-tools = super.buildPythonPackage {
name = "rhodecode-tools-0.8.3";
name = "rhodecode-tools-0.10.0";
buildInputs = with self; [];
doCheck = false;
propagatedBuildInputs = with self; [click future six Mako MarkupSafe requests Whoosh elasticsearch elasticsearch-dsl];
src = fetchurl {
url = "https://code.rhodecode.com/rhodecode-tools-ce/archive/v0.8.3.zip";
md5 = "9acdfd71b8ddf4056057065f37ab9ccb";
url = "https://code.rhodecode.com/rhodecode-tools-ce/archive/v0.10.0.zip";
md5 = "4762391473ded761bead3aa58c748044";
};
meta = {
license = [ { fullName = "AGPLv3 and Proprietary"; } ];
@ -1453,13 +1544,13 @@
};
};
supervisor = super.buildPythonPackage {
name = "supervisor-3.1.3";
name = "supervisor-3.3.0";
buildInputs = with self; [];
doCheck = false;
propagatedBuildInputs = with self; [meld3];
src = fetchurl {
url = "https://pypi.python.org/packages/a6/41/65ad5bd66230b173eb4d0b8810230f3a9c59ef52ae066e540b6b99895db7/supervisor-3.1.3.tar.gz";
md5 = "aad263c4fbc070de63dd354864d5e552";
url = "https://pypi.python.org/packages/44/80/d28047d120bfcc8158b4e41127706731ee6a3419c661e0a858fb0e7c4b2d/supervisor-3.3.0.tar.gz";
md5 = "46bac00378d1eddb616752b990c67416";
};
meta = {
license = [ { fullName = "BSD-derived (http://www.repoze.org/LICENSE.txt)"; } ];
@ -1556,6 +1647,19 @@
license = [ pkgs.lib.licenses.zpt21 ];
};
};
ws4py = super.buildPythonPackage {
name = "ws4py-0.3.5";
buildInputs = with self; [];
doCheck = false;
propagatedBuildInputs = with self; [];
src = fetchurl {
url = "https://pypi.python.org/packages/b6/4f/34af703be86939629479e74d6e650e39f3bd73b3b09212c34e5125764cbc/ws4py-0.3.5.zip";
md5 = "a261b75c20b980e55ce7451a3576a867";
};
meta = {
license = [ pkgs.lib.licenses.bsdOriginal ];
};
};
wsgiref = super.buildPythonPackage {
name = "wsgiref-0.1.2";
buildInputs = with self; [];

View file

@ -11,7 +11,7 @@ MySQL-python==1.2.5
Paste==2.0.2
PasteDeploy==1.5.2
PasteScript==1.7.5
Pygments==2.0.2
Pygments==2.1.3
# TODO: This version is not available on PyPI
# Pylons==1.0.2.dev20160108
@ -24,10 +24,6 @@ Pyro4==4.41
# TODO: This should probably not be in here
# -e hg+https://johbo@code.rhodecode.com/johbo/rhodecode-fork@3a454bd1f17c0b2b2a951cf2b111e0320d7942a9#egg=RhodeCodeEnterprise-dev
# TODO: This is not really a dependency, we should add it only
# into the development environment, since there it is useful.
# RhodeCodeVCSServer==3.9.0
Routes==1.13
SQLAlchemy==0.9.9
Sphinx==1.2.2
@ -53,6 +49,7 @@ backport-ipaddress==0.1
bottle==0.12.8
bumpversion==0.5.3
celery==2.2.10
channelstream==0.5.2
click==5.1
colander==1.2
configobj==5.0.6
@ -60,15 +57,18 @@ cov-core==1.15.0
coverage==3.7.1
cssselect==0.9.1
decorator==3.4.2
deform==2.0a2
docutils==0.12
dogpile.cache==0.5.7
dogpile.cache==0.6.1
dogpile.core==0.4.1
dulwich==0.12.0
ecdsa==0.11
flake8==2.4.1
future==0.14.3
futures==3.0.2
gevent==1.1.1
gprof2dot==2015.12.1
greenlet==0.4.9
gunicorn==19.6.0
# TODO: Needs subvertpy and blows up without Subversion headers,
@ -94,9 +94,10 @@ packaging==15.2
paramiko==1.15.1
pep8==1.5.7
psutil==2.2.1
psycopg2==2.6
psycopg2==2.6.1
py==1.4.29
py-bcrypt==0.4
py-gfm==0.1.3
pycrypto==2.6.1
pycurl==7.19.5
pyflakes==0.8.1
@ -123,7 +124,7 @@ pyzmq==14.6.0
# TODO: This is not available in public
# rc-testdata==0.2.0
https://code.rhodecode.com/rhodecode-tools-ce/archive/v0.8.3.zip#md5=9acdfd71b8ddf4056057065f37ab9ccb
https://code.rhodecode.com/rhodecode-tools-ce/archive/v0.10.0.zip#md5=4762391473ded761bead3aa58c748044
recaptcha-client==1.0.6
@ -136,7 +137,7 @@ setuptools-scm==1.11.0
simplejson==3.7.2
six==1.9.0
subprocess32==3.2.6
supervisor==3.1.3
supervisor==3.3.0
transifex-client==0.10
translationstring==1.3
trollius==1.0.4

View file

@ -1 +1 @@
4.2.1
4.3.0

View file

@ -43,11 +43,15 @@ CELERY_EAGER = False
# link to config for pylons
CONFIG = {}
# Populated with the settings dictionary from application init in
# rhodecode.conf.environment.load_pyramid_environment
PYRAMID_SETTINGS = {}
# Linked module for extensions
EXTENSIONS = {}
__version__ = ('.'.join((str(each) for each in VERSION[:3])))
__dbversion__ = 54 # defines current db version for migrations
__dbversion__ = 55 # defines current db version for migrations
__platform__ = platform.system()
__license__ = 'AGPLv3, and Commercial License'
__author__ = 'RhodeCode GmbH'

View file

@ -80,6 +80,8 @@ class NavigationRegistry(object):
NavEntry('email', _('Email'), 'admin_settings_email'),
NavEntry('hooks', _('Hooks'), 'admin_settings_hooks'),
NavEntry('search', _('Full Text Search'), 'admin_settings_search'),
NavEntry('integrations', _('Integrations'),
'global_integrations_home', pyramid=True),
NavEntry('system', _('System Info'), 'admin_settings_system'),
NavEntry('open_source', _('Open Source Licenses'),
'admin_settings_open_source', pyramid=True),

View file

@ -25,12 +25,15 @@ import types
import decorator
import venusian
from collections import OrderedDict
from pyramid.exceptions import ConfigurationError
from pyramid.renderers import render
from pyramid.response import Response
from pyramid.httpexceptions import HTTPNotFound
from rhodecode.api.exc import JSONRPCBaseError, JSONRPCError, JSONRPCForbidden
from rhodecode.api.exc import (
JSONRPCBaseError, JSONRPCError, JSONRPCForbidden, JSONRPCValidationError)
from rhodecode.lib.auth import AuthUser
from rhodecode.lib.base import get_ip_addr
from rhodecode.lib.ext_json import json
@ -127,6 +130,11 @@ def exception_view(exc, request):
if isinstance(exc, JSONRPCError):
fault_message = exc.message
log.debug('json-rpc error rpc_id:%s "%s"', rpc_id, fault_message)
elif isinstance(exc, JSONRPCValidationError):
colander_exc = exc.colander_exception
#TODO: think maybe of nicer way to serialize errors ?
fault_message = colander_exc.asdict()
log.debug('json-rpc error rpc_id:%s "%s"', rpc_id, fault_message)
elif isinstance(exc, JSONRPCForbidden):
fault_message = 'Access was denied to this resource.'
log.warning('json-rpc forbidden call rpc_id:%s "%s"', rpc_id, fault_message)
@ -474,7 +482,7 @@ def includeme(config):
plugin_module, config.registry.settings)
if not hasattr(config.registry, 'jsonrpc_methods'):
config.registry.jsonrpc_methods = {}
config.registry.jsonrpc_methods = OrderedDict()
# match filter by given method only
config.add_view_predicate(

View file

@ -27,5 +27,13 @@ class JSONRPCError(JSONRPCBaseError):
pass
class JSONRPCValidationError(JSONRPCBaseError):
def __init__(self, *args, **kwargs):
self.colander_exception = kwargs.pop('colander_exc')
super(JSONRPCValidationError, self).__init__(*args, **kwargs)
class JSONRPCForbidden(JSONRPCBaseError):
pass

View file

@ -43,7 +43,7 @@ class TestApiCreateGist(object):
description='foobar-gist',
gist_type=gist_type,
acl_level=gist_acl_level,
files={'foobar': {'content': 'foo'}})
files={'foobar_ąć': {'content': 'foo'}})
response = api_call(self.app, params)
response_json = response.json
gist = response_json['result']['gist']
@ -68,6 +68,32 @@ class TestApiCreateGist(object):
finally:
Fixture().destroy_gists()
@pytest.mark.parametrize("expected, lifetime, gist_type, gist_acl_level, files", [
({'gist_type': '"ups" is not one of private, public'},
10, 'ups', Gist.ACL_LEVEL_PUBLIC, {'f': {'content': 'f'}}),
({'lifetime': '-120 is less than minimum value -1'},
-120, Gist.GIST_PUBLIC, Gist.ACL_LEVEL_PUBLIC, {'f': {'content': 'f'}}),
({'0.content': 'Required'},
10, Gist.GIST_PUBLIC, Gist.ACL_LEVEL_PUBLIC, {'f': {'x': 'f'}}),
])
def test_api_try_create_gist(
self, expected, lifetime, gist_type, gist_acl_level, files):
id_, params = build_data(
self.apikey_regular, 'create_gist',
lifetime=lifetime,
description='foobar-gist',
gist_type=gist_type,
acl_level=gist_acl_level,
files=files)
response = api_call(self.app, params)
try:
assert_error(id_, expected, given=response.body)
finally:
Fixture().destroy_gists()
@mock.patch.object(GistModel, 'create', crash)
def test_api_create_gist_exception_occurred(self):
id_, params = build_data(self.apikey_regular, 'create_gist', files={})

View file

@ -21,7 +21,7 @@
import pytest
from rhodecode.api.views import depracated_api
from rhodecode.api.views import deprecated_api
from rhodecode.lib.ext_json import json
from rhodecode.api.tests.utils import (
build_data, api_call)
@ -30,7 +30,7 @@ from rhodecode.api.tests.utils import (
@pytest.mark.usefixtures("testuser_api", "app")
class TestCommitComment(object):
def test_deprecated_message_in_docstring(self):
docstring = depracated_api.changeset_comment.__doc__
docstring = deprecated_api.changeset_comment.__doc__
assert '.. deprecated:: 3.4.0' in docstring
assert 'Please use method `comment_commit` instead.' in docstring

View file

@ -73,6 +73,29 @@ class TestGetRepoNodes(object):
expected = 'failed to get repo: `%s` nodes' % (backend.repo_name,)
assert_error(id_, expected, given=response.body)
def test_api_get_repo_nodes_max_file_bytes(self, backend):
commit_id = 'tip'
path = '/'
max_file_bytes = 500
id_, params = build_data(
self.apikey, 'get_repo_nodes',
repoid=backend.repo_name, revision=commit_id, details='full',
root_path=path)
response = api_call(self.app, params)
assert any(file['content'] and len(file['content']) > max_file_bytes
for file in response.json['result'])
id_, params = build_data(
self.apikey, 'get_repo_nodes',
repoid=backend.repo_name, revision=commit_id,
root_path=path, details='full',
max_file_bytes=max_file_bytes)
response = api_call(self.app, params)
assert all(
file['content'] is None if file['size'] > max_file_bytes else True
for file in response.json['result'])
def test_api_get_repo_nodes_bad_ret_type(self, backend):
commit_id = 'tip'
path = '/'

View file

@ -47,9 +47,14 @@ class TestApiUpdateRepo(object):
({'enable_statistics': True}, SAME_AS_UPDATES),
({'enable_locking': True}, SAME_AS_UPDATES),
({'enable_downloads': True}, SAME_AS_UPDATES),
({'name': 'new_repo_name'}, {'repo_name': 'new_repo_name'}),
({'group': 'test_group_for_update'},
{'repo_name': 'test_group_for_update/%s' % UPDATE_REPO_NAME}),
({'name': 'new_repo_name'}, {
'repo_name': 'new_repo_name',
'url': 'http://test.example.com:80/new_repo_name',
}),
({'group': 'test_group_for_update'}, {
'repo_name': 'test_group_for_update/%s' % UPDATE_REPO_NAME,
'url': 'http://test.example.com:80/test_group_for_update/%s' % UPDATE_REPO_NAME
}),
])
def test_api_update_repo(self, updates, expected, backend):
repo_name = UPDATE_REPO_NAME

View file

@ -34,8 +34,6 @@ from rhodecode.lib.vcs.exceptions import RepositoryError
log = logging.getLogger(__name__)
class OAttr(object):
"""
Special Option that defines other attribute, and can default to them

View file

@ -23,6 +23,7 @@ import logging
import time
from rhodecode.api import jsonrpc_method, JSONRPCError
from rhodecode.api.exc import JSONRPCValidationError
from rhodecode.api.utils import (
Optional, OAttr, get_gist_or_error, get_user_or_error,
has_superadmin_permission)
@ -96,7 +97,8 @@ def get_gists(request, apiuser, userid=Optional(OAttr('apiuser'))):
@jsonrpc_method()
def create_gist(
request, apiuser, files, owner=Optional(OAttr('apiuser')),
request, apiuser, files, gistid=Optional(None),
owner=Optional(OAttr('apiuser')),
gist_type=Optional(Gist.GIST_PUBLIC), lifetime=Optional(-1),
acl_level=Optional(Gist.ACL_LEVEL_PUBLIC),
description=Optional('')):
@ -108,10 +110,11 @@ def create_gist(
:param files: files to be added to the gist. The data structure has
to match the following example::
{'filename': {'content':'...', 'lexer': null},
'filename2': {'content':'...', 'lexer': null}}
{'filename1': {'content':'...'}, 'filename2': {'content':'...'}}
:type files: dict
:param gistid: Set a custom id for the gist
:type gistid: Optional(str)
:param owner: Set the gist owner, defaults to api method caller
:type owner: Optional(str or int)
:param gist_type: type of gist ``public`` or ``private``
@ -148,23 +151,49 @@ def create_gist(
}
"""
from rhodecode.model import validation_schema
from rhodecode.model.validation_schema.schemas import gist_schema
if isinstance(owner, Optional):
owner = apiuser.user_id
owner = get_user_or_error(owner)
lifetime = Optional.extract(lifetime)
schema = gist_schema.GistSchema().bind(
# bind the given values if it's allowed, however the deferred
# validator will still validate it according to other rules
lifetime_options=[lifetime])
try:
if isinstance(owner, Optional):
owner = apiuser.user_id
nodes = gist_schema.nodes_to_sequence(
files, colander_node=schema.get('nodes'))
owner = get_user_or_error(owner)
description = Optional.extract(description)
gist_type = Optional.extract(gist_type)
lifetime = Optional.extract(lifetime)
acl_level = Optional.extract(acl_level)
schema_data = schema.deserialize(dict(
gistid=Optional.extract(gistid),
description=Optional.extract(description),
gist_type=Optional.extract(gist_type),
lifetime=lifetime,
gist_acl_level=Optional.extract(acl_level),
nodes=nodes
))
gist = GistModel().create(description=description,
owner=owner,
gist_mapping=files,
gist_type=gist_type,
lifetime=lifetime,
gist_acl_level=acl_level)
# convert to safer format with just KEYs so we sure no duplicates
schema_data['nodes'] = gist_schema.sequence_to_nodes(
schema_data['nodes'], colander_node=schema.get('nodes'))
except validation_schema.Invalid as err:
raise JSONRPCValidationError(colander_exc=err)
try:
gist = GistModel().create(
owner=owner,
gist_id=schema_data['gistid'],
description=schema_data['description'],
gist_mapping=schema_data['nodes'],
gist_type=schema_data['gist_type'],
lifetime=schema_data['lifetime'],
gist_acl_level=schema_data['gist_acl_level'])
Session().commit()
return {
'msg': 'created new gist',

View file

@ -265,7 +265,7 @@ def merge_pull_request(request, apiuser, repoid, pullrequestid,
PullRequestModel().close_pull_request(
pull_request.pull_request_id, apiuser)
Session.commit()
Session().commit()
return data
@ -319,7 +319,7 @@ def close_pull_request(request, apiuser, repoid, pullrequestid,
PullRequestModel().close_pull_request(
pull_request.pull_request_id, apiuser)
Session.commit()
Session().commit()
data = {
'pull_request_id': pull_request.pull_request_id,
'closed': True,
@ -408,6 +408,8 @@ def comment_pull_request(request, apiuser, repoid, pullrequestid,
line_no=None,
status_change=(ChangesetStatus.get_status_lbl(status)
if status and allowed_to_change_status else None),
status_change_type=(status
if status and allowed_to_change_status else None),
closing_pr=False,
renderer=renderer
)

View file

@ -43,8 +43,8 @@ from rhodecode.model.db import (
from rhodecode.model.repo import RepoModel
from rhodecode.model.repo_group import RepoGroupModel
from rhodecode.model.scm import ScmModel, RepoList
from rhodecode.model.settings import SettingsModel
from rhodecode.model.validation_schema import RepoSchema
from rhodecode.model.settings import SettingsModel, VcsSettingsModel
from rhodecode.model.validation_schema.schemas import repo_schema
log = logging.getLogger(__name__)
@ -400,7 +400,8 @@ def get_repo_changesets(request, apiuser, repoid, start_rev, limit,
@jsonrpc_method()
def get_repo_nodes(request, apiuser, repoid, revision, root_path,
ret_type=Optional('all'), details=Optional('basic')):
ret_type=Optional('all'), details=Optional('basic'),
max_file_bytes=Optional(None)):
"""
Returns a list of nodes and children in a flat list for a given
path at given revision.
@ -425,6 +426,8 @@ def get_repo_nodes(request, apiuser, repoid, revision, root_path,
md5, binary, and or content. The valid options are ``basic`` and
``full``.
:type details: Optional(str)
:param max_file_bytes: Only return file content under this file size bytes
:type details: Optional(int)
Example output:
@ -472,7 +475,8 @@ def get_repo_nodes(request, apiuser, repoid, revision, root_path,
_d, _f = ScmModel().get_nodes(
repo, revision, root_path, flat=False,
extended_info=extended_info, content=content)
extended_info=extended_info, content=content,
max_file_bytes=max_file_bytes)
_map = {
'all': _d + _f,
'files': _f,
@ -606,7 +610,7 @@ def create_repo(request, apiuser, repo_name, repo_type,
}
"""
schema = RepoSchema()
schema = repo_schema.RepoSchema()
try:
data = schema.deserialize({
'repo_name': repo_name
@ -1310,8 +1314,6 @@ def comment_commit(
userid=Optional(OAttr('apiuser')), status=Optional(None)):
"""
Set a commit comment, and optionally change the status of the commit.
This command can be executed only using api_key belonging to user
with admin rights, or repository administrator.
:param apiuser: This is filled automatically from the |authtoken|.
:type apiuser: AuthUser
@ -1344,7 +1346,7 @@ def comment_commit(
"""
repo = get_repo_or_error(repoid)
if not has_superadmin_permission(apiuser):
_perms = ('repository.admin',)
_perms = ('repository.read', 'repository.write', 'repository.admin')
has_repo_permissions(apiuser, repoid, repo, _perms)
if isinstance(userid, Optional):
@ -1361,9 +1363,11 @@ def comment_commit(
try:
rc_config = SettingsModel().get_all_settings()
renderer = rc_config.get('rhodecode_markup_renderer', 'rst')
status_change_label = ChangesetStatus.get_status_lbl(status)
comm = ChangesetCommentsModel().create(
message, repo, user, revision=commit_id, status_change=status,
message, repo, user, revision=commit_id,
status_change=status_change_label,
status_change_type=status,
renderer=renderer)
if status:
# also do a status change
@ -1775,3 +1779,110 @@ def strip(request, apiuser, repoid, revision, branch):
'Unable to strip commit %s from repo `%s`' % (
revision, repo.repo_name)
)
@jsonrpc_method()
def get_repo_settings(request, apiuser, repoid, key=Optional(None)):
"""
Returns all settings for a repository. If key is given it only returns the
setting identified by the key or null.
:param apiuser: This is filled automatically from the |authtoken|.
:type apiuser: AuthUser
:param repoid: The repository name or repository id.
:type repoid: str or int
:param key: Key of the setting to return.
:type: key: Optional(str)
Example output:
.. code-block:: bash
{
"error": null,
"id": 237,
"result": {
"extensions_largefiles": true,
"hooks_changegroup_push_logger": true,
"hooks_changegroup_repo_size": false,
"hooks_outgoing_pull_logger": true,
"phases_publish": "True",
"rhodecode_hg_use_rebase_for_merging": true,
"rhodecode_pr_merge_enabled": true,
"rhodecode_use_outdated_comments": true
}
}
"""
# Restrict access to this api method to admins only.
if not has_superadmin_permission(apiuser):
raise JSONRPCForbidden()
try:
repo = get_repo_or_error(repoid)
settings_model = VcsSettingsModel(repo=repo)
settings = settings_model.get_global_settings()
settings.update(settings_model.get_repo_settings())
# If only a single setting is requested fetch it from all settings.
key = Optional.extract(key)
if key is not None:
settings = settings.get(key, None)
except Exception:
msg = 'Failed to fetch settings for repository `{}`'.format(repoid)
log.exception(msg)
raise JSONRPCError(msg)
return settings
@jsonrpc_method()
def set_repo_settings(request, apiuser, repoid, settings):
"""
Update repository settings. Returns true on success.
:param apiuser: This is filled automatically from the |authtoken|.
:type apiuser: AuthUser
:param repoid: The repository name or repository id.
:type repoid: str or int
:param settings: The new settings for the repository.
:type: settings: dict
Example output:
.. code-block:: bash
{
"error": null,
"id": 237,
"result": true
}
"""
# Restrict access to this api method to admins only.
if not has_superadmin_permission(apiuser):
raise JSONRPCForbidden()
if type(settings) is not dict:
raise JSONRPCError('Settings have to be a JSON Object.')
try:
settings_model = VcsSettingsModel(repo=repoid)
# Merge global, repo and incoming settings.
new_settings = settings_model.get_global_settings()
new_settings.update(settings_model.get_repo_settings())
new_settings.update(settings)
# Update the settings.
inherit_global_settings = new_settings.get(
'inherit_global_settings', False)
settings_model.create_or_update_repo_settings(
new_settings, inherit_global_settings=inherit_global_settings)
Session().commit()
except Exception:
msg = 'Failed to update settings for repository `{}`'.format(repoid)
log.exception(msg)
raise JSONRPCError(msg)
# Indicate success.
return True

View file

@ -34,7 +34,7 @@ from rhodecode.lib.auth import (
from rhodecode.model.db import Session, RepoGroup
from rhodecode.model.repo_group import RepoGroupModel
from rhodecode.model.scm import RepoGroupList
from rhodecode.model.validation_schema import RepoGroupSchema
from rhodecode.model.validation_schema.schemas import repo_group_schema
log = logging.getLogger(__name__)
@ -193,7 +193,7 @@ def create_repo_group(request, apiuser, group_name, description=Optional(''),
"""
schema = RepoGroupSchema()
schema = repo_group_schema.RepoGroupSchema()
try:
data = schema.deserialize({
'group_name': group_name

View file

@ -490,20 +490,26 @@ def loadplugin(plugin_id):
or None on failure.
"""
# TODO: Disusing pyramids thread locals to retrieve the registry.
authn_registry = get_current_registry().getUtility(IAuthnPluginRegistry)
authn_registry = get_authn_registry()
plugin = authn_registry.get_plugin(plugin_id)
if plugin is None:
log.error('Authentication plugin not found: "%s"', plugin_id)
return plugin
def get_authn_registry(registry=None):
registry = registry or get_current_registry()
authn_registry = registry.getUtility(IAuthnPluginRegistry)
return authn_registry
def get_auth_cache_manager(custom_ttl=None):
return caches.get_cache_manager(
'auth_plugins', 'rhodecode.authentication', custom_ttl)
def authenticate(username, password, environ=None, auth_type=None,
skip_missing=False):
skip_missing=False, registry=None):
"""
Authentication function used for access control,
It tries to authenticate based on enabled authentication modules.
@ -520,7 +526,7 @@ def authenticate(username, password, environ=None, auth_type=None,
% auth_type)
headers_only = environ and not (username and password)
authn_registry = get_current_registry().getUtility(IAuthnPluginRegistry)
authn_registry = get_authn_registry(registry)
for plugin in authn_registry.get_plugins_for_authentication():
plugin.set_auth_type(auth_type)
user = plugin.get_user(username)
@ -559,16 +565,16 @@ def authenticate(username, password, environ=None, auth_type=None,
if isinstance(plugin.AUTH_CACHE_TTL, (int, long)):
# plugin cache set inside is more important than the settings value
_cache_ttl = plugin.AUTH_CACHE_TTL
elif plugin_settings.get('auth_cache_ttl'):
_cache_ttl = safe_int(plugin_settings.get('auth_cache_ttl'), 0)
elif plugin_settings.get('cache_ttl'):
_cache_ttl = safe_int(plugin_settings.get('cache_ttl'), 0)
plugin_cache_active = bool(_cache_ttl and _cache_ttl > 0)
# get instance of cache manager configured for a namespace
cache_manager = get_auth_cache_manager(custom_ttl=_cache_ttl)
log.debug('Cache for plugin `%s` active: %s', plugin.get_id(),
plugin_cache_active)
log.debug('AUTH_CACHE_TTL for plugin `%s` active: %s (TTL: %s)',
plugin.get_id(), plugin_cache_active, _cache_ttl)
# for environ based password can be empty, but then the validation is
# on the server that fills in the env data needed for authentication
@ -581,8 +587,7 @@ def authenticate(username, password, environ=None, auth_type=None,
# to RhodeCode database. If this function returns data
# then auth is correct.
start = time.time()
log.debug('Running plugin `%s` _authenticate method',
plugin.get_id())
log.debug('Running plugin `%s` _authenticate method', plugin.get_id())
def auth_func():
"""

View file

@ -141,9 +141,9 @@ class LdapSettingsSchema(AuthnPluginSettingsSchemaBase):
colander.String(),
default='',
description=_('LDAP Attribute to map to user name'),
missing_msg=_('The LDAP Login attribute of the CN must be specified'),
preparer=strip_whitespace,
title=_('Login Attribute'),
missing_msg=_('The LDAP Login attribute of the CN must be specified'),
widget='string')
attr_firstname = colander.SchemaNode(
colander.String(),
@ -186,6 +186,7 @@ class AuthLdap(object):
if ldap == Missing:
raise LdapImportError("Missing or incompatible ldap library")
self.debug = False
self.ldap_version = ldap_version
self.ldap_server_type = 'ldap'
@ -213,6 +214,8 @@ class AuthLdap(object):
self.LDAP_FILTER = safe_str(ldap_filter)
def _get_ldap_server(self):
if self.debug:
ldap.set_option(ldap.OPT_DEBUG_LEVEL, 255)
if hasattr(ldap, 'OPT_X_TLS_CACERTDIR'):
ldap.set_option(ldap.OPT_X_TLS_CACERTDIR,
'/etc/openldap/cacerts')

View file

@ -137,5 +137,7 @@ class RhodeCodeAuthPlugin(RhodeCodeAuthPluginBase):
"authenticating on this plugin", userobj)
return None
else:
log.warning('user %s tried auth but is disabled', userobj)
log.warning(
'user `%s` failed to authenticate via %s, reason: account not '
'active.', username, self.name)
return None

View file

@ -83,13 +83,17 @@ class RhodeCodeAuthPlugin(RhodeCodeAuthPluginBase):
allowed_auth_plugins=None, allowed_auth_sources=None):
"""
Custom method for this auth that doesn't accept empty users. And also
allows rhodecode and authtoken extern_type to auth with this. But only
via vcs mode
allows users from all other active plugins to use it and also
authenticate against it. But only via vcs mode
"""
# only this and rhodecode plugins can use this type
from rhodecode.authentication.plugins import auth_rhodecode
allowed_auth_plugins = [
self.name, auth_rhodecode.RhodeCodeAuthPlugin.name]
from rhodecode.authentication.base import get_authn_registry
authn_registry = get_authn_registry()
active_plugins = set(
[x.name for x in authn_registry.get_plugins_for_authentication()])
active_plugins.discard(self.name)
allowed_auth_plugins = [self.name] + list(active_plugins)
# only for vcs operations
allowed_auth_sources = [VCS_TYPE]

View file

@ -26,8 +26,8 @@ from pyramid.httpexceptions import HTTPFound
from pyramid.renderers import render
from pyramid.response import Response
from rhodecode.authentication.base import get_auth_cache_manager
from rhodecode.authentication.interface import IAuthnPluginRegistry
from rhodecode.authentication.base import (
get_auth_cache_manager, get_authn_registry)
from rhodecode.lib import auth
from rhodecode.lib.auth import LoginRequired, HasPermissionAllDecorator
from rhodecode.model.forms import AuthSettingsForm
@ -96,7 +96,7 @@ class AuthnPluginViewBase(object):
# Store validated data.
for name, value in valid_data.items():
self.plugin.create_or_update_setting(name, value)
Session.commit()
Session().commit()
# Display success message and redirect.
self.request.session.flash(
@ -125,7 +125,7 @@ class AuthSettingsView(object):
@HasPermissionAllDecorator('hg.admin')
def index(self, defaults=None, errors=None, prefix_error=False):
defaults = defaults or {}
authn_registry = self.request.registry.getUtility(IAuthnPluginRegistry)
authn_registry = get_authn_registry(self.request.registry)
enabled_plugins = SettingsModel().get_auth_plugins()
# Create template context and render it.

View file

@ -0,0 +1,79 @@
# -*- coding: utf-8 -*-
# Copyright (C) 2010-2016 RhodeCode GmbH
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License, version 3
# (only), as published by the Free Software Foundation.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
# This program is dual-licensed. If you wish to learn more about the
# RhodeCode Enterprise Edition, including its added features, Support services,
# and proprietary license terms, please see https://rhodecode.com/licenses/
import os
from pyramid.settings import asbool
from rhodecode.config.routing import ADMIN_PREFIX
from rhodecode.lib.ext_json import json
def url_gen(request):
urls = {
'connect': request.route_url('channelstream_connect'),
'subscribe': request.route_url('channelstream_subscribe')
}
return json.dumps(urls)
PLUGIN_DEFINITION = {
'name': 'channelstream',
'config': {
'javascript': [],
'css': [],
'template_hooks': {
'plugin_init_template': 'rhodecode:templates/channelstream/plugin_init.html'
},
'url_gen': url_gen,
'static': None,
'enabled': False,
'server': '',
'secret': ''
}
}
def includeme(config):
settings = config.registry.settings
PLUGIN_DEFINITION['config']['enabled'] = asbool(
settings.get('channelstream.enabled'))
PLUGIN_DEFINITION['config']['server'] = settings.get(
'channelstream.server', '')
PLUGIN_DEFINITION['config']['secret'] = settings.get(
'channelstream.secret', '')
PLUGIN_DEFINITION['config']['history.location'] = settings.get(
'channelstream.history.location', '')
config.register_rhodecode_plugin(
PLUGIN_DEFINITION['name'],
PLUGIN_DEFINITION['config']
)
# create plugin history location
history_dir = PLUGIN_DEFINITION['config']['history.location']
if history_dir and not os.path.exists(history_dir):
os.makedirs(history_dir, 0750)
config.add_route(
name='channelstream_connect',
pattern=ADMIN_PREFIX + '/channelstream/connect')
config.add_route(
name='channelstream_subscribe',
pattern=ADMIN_PREFIX + '/channelstream/subscribe')
config.scan('rhodecode.channelstream')

View file

@ -0,0 +1,177 @@
# -*- coding: utf-8 -*-
# Copyright (C) 2010-2016 RhodeCode GmbH
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License, version 3
# (only), as published by the Free Software Foundation.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
# This program is dual-licensed. If you wish to learn more about the
# RhodeCode Enterprise Edition, including its added features, Support services,
# and proprietary license terms, please see https://rhodecode.com/licenses/
"""
Channel Stream controller for rhodecode
:created_on: Oct 10, 2015
:author: marcinl
:copyright: (c) 2013-2015 RhodeCode GmbH.
:license: Commercial License, see LICENSE for more details.
"""
import logging
import uuid
from pylons import tmpl_context as c
from pyramid.settings import asbool
from pyramid.view import view_config
from webob.exc import HTTPBadRequest, HTTPForbidden, HTTPBadGateway
from rhodecode.lib.channelstream import (
channelstream_request,
ChannelstreamConnectionException,
ChannelstreamPermissionException,
check_channel_permissions,
get_connection_validators,
get_user_data,
parse_channels_info,
update_history_from_logs,
STATE_PUBLIC_KEYS)
from rhodecode.lib.auth import NotAnonymous
from rhodecode.lib.utils2 import str2bool
log = logging.getLogger(__name__)
class ChannelstreamView(object):
def __init__(self, context, request):
self.context = context
self.request = request
# Some of the decorators rely on this attribute to be present
# on the class of the decorated method.
self._rhodecode_user = request.user
registry = request.registry
self.channelstream_config = registry.rhodecode_plugins['channelstream']
if not self.channelstream_config.get('enabled'):
log.exception('Channelstream plugin is disabled')
raise HTTPBadRequest()
@NotAnonymous()
@view_config(route_name='channelstream_connect', renderer='json')
def connect(self):
""" handle authorization of users trying to connect """
try:
json_body = self.request.json_body
except Exception:
log.exception('Failed to decode json from request')
raise HTTPBadRequest()
try:
channels = check_channel_permissions(
json_body.get('channels'),
get_connection_validators(self.request.registry))
except ChannelstreamPermissionException:
log.error('Incorrect permissions for requested channels')
raise HTTPForbidden()
user = c.rhodecode_user
if user.user_id:
user_data = get_user_data(user.user_id)
else:
user_data = {
'id': None,
'username': None,
'first_name': None,
'last_name': None,
'icon_link': None,
'display_name': None,
'display_link': None,
}
payload = {
'username': user.username,
'user_state': user_data,
'conn_id': str(uuid.uuid4()),
'channels': channels,
'channel_configs': {},
'state_public_keys': STATE_PUBLIC_KEYS,
'info': {
'exclude_channels': ['broadcast']
}
}
filtered_channels = [channel for channel in channels
if channel != 'broadcast']
for channel in filtered_channels:
payload['channel_configs'][channel] = {
'notify_presence': True,
'history_size': 100,
'store_history': True,
'broadcast_presence_with_user_lists': True
}
# connect user to server
try:
connect_result = channelstream_request(self.channelstream_config,
payload, '/connect')
except ChannelstreamConnectionException:
log.exception('Channelstream service is down')
return HTTPBadGateway()
connect_result['channels'] = channels
connect_result['channels_info'] = parse_channels_info(
connect_result['channels_info'],
include_channel_info=filtered_channels)
update_history_from_logs(self.channelstream_config,
filtered_channels, connect_result)
return connect_result
@NotAnonymous()
@view_config(route_name='channelstream_subscribe', renderer='json')
def subscribe(self):
""" can be used to subscribe specific connection to other channels """
try:
json_body = self.request.json_body
except Exception:
log.exception('Failed to decode json from request')
raise HTTPBadRequest()
try:
channels = check_channel_permissions(
json_body.get('channels'),
get_connection_validators(self.request.registry))
except ChannelstreamPermissionException:
log.error('Incorrect permissions for requested channels')
raise HTTPForbidden()
payload = {'conn_id': json_body.get('conn_id', ''),
'channels': channels,
'channel_configs': {},
'info': {
'exclude_channels': ['broadcast']}
}
filtered_channels = [chan for chan in channels if chan != 'broadcast']
for channel in filtered_channels:
payload['channel_configs'][channel] = {
'notify_presence': True,
'history_size': 100,
'store_history': True,
'broadcast_presence_with_user_lists': True
}
try:
connect_result = channelstream_request(
self.channelstream_config, payload, '/subscribe')
except ChannelstreamConnectionException:
log.exception('Channelstream service is down')
return HTTPBadGateway()
# include_channel_info will limit history only to new channel
# to not overwrite histories on other channels in client
connect_result['channels_info'] = parse_channels_info(
connect_result['channels_info'],
include_channel_info=filtered_channels)
update_history_from_logs(self.channelstream_config,
filtered_channels, connect_result)
return connect_result

View file

@ -30,36 +30,6 @@ from rhodecode.lib.utils2 import __get_lem
# extensions will index it's content
LANGUAGES_EXTENSIONS_MAP = __get_lem()
# list of readme files to search in file tree and display in summary
# attached weights defines the search order lower is first
ALL_READMES = [
('readme', 0), ('README', 0), ('Readme', 0),
('doc/readme', 1), ('doc/README', 1), ('doc/Readme', 1),
('Docs/readme', 2), ('Docs/README', 2), ('Docs/Readme', 2),
('DOCS/readme', 2), ('DOCS/README', 2), ('DOCS/Readme', 2),
('docs/readme', 2), ('docs/README', 2), ('docs/Readme', 2),
]
# extension together with weights to search lower is first
RST_EXTS = [
('', 0), ('.rst', 1), ('.rest', 1),
('.RST', 2), ('.REST', 2)
]
MARKDOWN_EXTS = [
('.md', 1), ('.MD', 1),
('.mkdn', 2), ('.MKDN', 2),
('.mdown', 3), ('.MDOWN', 3),
('.markdown', 4), ('.MARKDOWN', 4)
]
PLAIN_EXTS = [
('.text', 2), ('.TEXT', 2),
('.txt', 3), ('.TXT', 3)
]
ALL_EXTS = MARKDOWN_EXTS + RST_EXTS + PLAIN_EXTS
DATETIME_FORMAT = "%Y-%m-%d %H:%M:%S"
DATE_FORMAT = "%Y-%m-%d"

View file

@ -34,11 +34,16 @@ from pylons.configuration import PylonsConfig
from pylons.error import handle_mako_error
from pyramid.settings import asbool
# don't remove this import it does magic for celery
from rhodecode.lib import celerypylons # noqa
# ------------------------------------------------------------------------------
# CELERY magic until refactor - issue #4163 - import order matters here:
from rhodecode.lib import celerypylons # this must be first, celerypylons
# sets config settings upon import
import rhodecode.lib.app_globals as app_globals
import rhodecode.integrations # any modules using celery task
# decorators should be added afterwards:
# ------------------------------------------------------------------------------
from rhodecode.lib import app_globals
from rhodecode.config import utils
from rhodecode.config.routing import make_map
from rhodecode.config.jsroutes import generate_jsroutes_content
@ -112,25 +117,12 @@ def load_environment(global_conf, app_conf, initial=False,
# sets the c attribute access when don't existing attribute are accessed
config['pylons.strict_tmpl_context'] = True
# Limit backends to "vcs.backends" from configuration
backends = config['vcs.backends'] = aslist(
config.get('vcs.backends', 'hg,git'), sep=',')
for alias in rhodecode.BACKENDS.keys():
if alias not in backends:
del rhodecode.BACKENDS[alias]
log.info("Enabled backends: %s", backends)
# initialize vcs client and optionally run the server if enabled
vcs_server_uri = config.get('vcs.server', '')
vcs_server_enabled = str2bool(config.get('vcs.server.enable', 'true'))
start_server = (
str2bool(config.get('vcs.start_server', 'false')) and
not int(os.environ.get('RC_VCSSERVER_TEST_DISABLE', '0')))
if vcs_server_enabled and start_server:
log.info("Starting vcsserver")
start_vcs_server(server_and_port=vcs_server_uri,
protocol=utils.get_vcs_server_protocol(config),
log_level=config['vcs.server.log_level'])
# configure channelstream
config['channelstream_config'] = {
'enabled': asbool(config.get('channelstream.enabled', False)),
'server': config.get('channelstream.server'),
'secret': config.get('channelstream.secret')
}
set_available_permissions(config)
db_cfg = make_db_config(clear_session=True)
@ -138,9 +130,6 @@ def load_environment(global_conf, app_conf, initial=False,
repos_path = list(db_cfg.items('paths'))[0][1]
config['base_path'] = repos_path
config['vcs.hooks.direct_calls'] = _use_direct_hook_calls(config)
config['vcs.hooks.protocol'] = _get_vcs_hooks_protocol(config)
# store db config also in main global CONFIG
set_rhodecode_config(config)
@ -153,34 +142,17 @@ def load_environment(global_conf, app_conf, initial=False,
# store config reference into our module to skip import magic of pylons
rhodecode.CONFIG.update(config)
utils.configure_pyro4(config)
utils.configure_vcs(config)
if vcs_server_enabled:
connect_vcs(vcs_server_uri, utils.get_vcs_server_protocol(config))
import_on_startup = str2bool(config.get('startup.import_repos', False))
if vcs_server_enabled and import_on_startup:
repo2db_mapper(ScmModel().repo_scan(repos_path), remove_obsolete=False)
return config
def _use_direct_hook_calls(config):
default_direct_hook_calls = 'false'
direct_hook_calls = str2bool(
config.get('vcs.hooks.direct_calls', default_direct_hook_calls))
return direct_hook_calls
def _get_vcs_hooks_protocol(config):
protocol = config.get('vcs.hooks.protocol', 'pyro4').lower()
return protocol
def load_pyramid_environment(global_config, settings):
# Some parts of the code expect a merge of global and app settings.
settings_merged = global_config.copy()
settings_merged.update(settings)
# Store the settings to make them available to other modules.
rhodecode.PYRAMID_SETTINGS = settings_merged
# If this is a test run we prepare the test environment like
# creating a test database, test search index and test repositories.
# This has to be done before the database connection is initialized.
@ -190,3 +162,27 @@ def load_pyramid_environment(global_config, settings):
# Initialize the database connection.
utils.initialize_database(settings_merged)
# Limit backends to `vcs.backends` from configuration
for alias in rhodecode.BACKENDS.keys():
if alias not in settings['vcs.backends']:
del rhodecode.BACKENDS[alias]
log.info('Enabled VCS backends: %s', rhodecode.BACKENDS.keys())
# initialize vcs client and optionally run the server if enabled
vcs_server_uri = settings['vcs.server']
vcs_server_enabled = settings['vcs.server.enable']
start_server = (
settings['vcs.start_server'] and
not int(os.environ.get('RC_VCSSERVER_TEST_DISABLE', '0')))
if vcs_server_enabled and start_server:
log.info("Starting vcsserver")
start_vcs_server(server_and_port=vcs_server_uri,
protocol=utils.get_vcs_server_protocol(settings),
log_level=settings['vcs.server.log_level'])
utils.configure_pyro4(settings)
utils.configure_vcs(settings)
if vcs_server_enabled:
connect_vcs(vcs_server_uri, utils.get_vcs_server_protocol(settings))

View file

@ -22,23 +22,25 @@
Pylons middleware initialization
"""
import logging
from collections import OrderedDict
from paste.registry import RegistryManager
from paste.gzipper import make_gzip_middleware
from pylons.wsgiapp import PylonsApp
from pyramid.authorization import ACLAuthorizationPolicy
from pyramid.config import Configurator
from pyramid.static import static_view
from pyramid.settings import asbool, aslist
from pyramid.wsgi import wsgiapp
from pyramid.httpexceptions import HTTPError, HTTPInternalServerError
from pyramid.httpexceptions import HTTPError, HTTPInternalServerError, HTTPFound
from pyramid.events import ApplicationCreated
import pyramid.httpexceptions as httpexceptions
from pyramid.renderers import render_to_response, render
from pyramid.renderers import render_to_response
from routes.middleware import RoutesMiddleware
import routes.util
import rhodecode
from rhodecode.config import patches
from rhodecode.config.routing import STATIC_FILE_PREFIX
from rhodecode.config.environment import (
load_environment, load_pyramid_environment)
from rhodecode.lib.middleware import csrf
@ -47,24 +49,45 @@ from rhodecode.lib.middleware.disable_vcs import DisableVCSPagesWrapper
from rhodecode.lib.middleware.https_fixup import HttpsFixup
from rhodecode.lib.middleware.vcs import VCSMiddleware
from rhodecode.lib.plugins.utils import register_rhodecode_plugin
from rhodecode.lib.utils2 import aslist as rhodecode_aslist
from rhodecode.subscribers import scan_repositories_if_enabled
log = logging.getLogger(__name__)
def make_app(global_conf, full_stack=True, static_files=True, **app_conf):
# this is used to avoid avoid the route lookup overhead in routesmiddleware
# for certain routes which won't go to pylons to - eg. static files, debugger
# it is only needed for the pylons migration and can be removed once complete
class SkippableRoutesMiddleware(RoutesMiddleware):
""" Routes middleware that allows you to skip prefixes """
def __init__(self, *args, **kw):
self.skip_prefixes = kw.pop('skip_prefixes', [])
super(SkippableRoutesMiddleware, self).__init__(*args, **kw)
def __call__(self, environ, start_response):
for prefix in self.skip_prefixes:
if environ['PATH_INFO'].startswith(prefix):
# added to avoid the case when a missing /_static route falls
# through to pylons and causes an exception as pylons is
# expecting wsgiorg.routingargs to be set in the environ
# by RoutesMiddleware.
if 'wsgiorg.routing_args' not in environ:
environ['wsgiorg.routing_args'] = (None, {})
return self.app(environ, start_response)
return super(SkippableRoutesMiddleware, self).__call__(
environ, start_response)
def make_app(global_conf, static_files=True, **app_conf):
"""Create a Pylons WSGI application and return it
``global_conf``
The inherited configuration for this application. Normally from
the [DEFAULT] section of the Paste ini file.
``full_stack``
Whether or not this application provides a full WSGI stack (by
default, meaning it handles its own exceptions and errors).
Disable full_stack when this application is "managed" by
another WSGI middleware.
``app_conf``
The application's local configuration. Normally specified in
the [app:<name>] section of the Paste ini file (where <name>
@ -89,16 +112,6 @@ def make_app(global_conf, full_stack=True, static_files=True, **app_conf):
app = csrf.OriginChecker(app, expected_origin,
skip_urls=[routes.util.url_for('api')])
if asbool(full_stack):
# Appenlight monitoring and error handler
app, appenlight_client = wrap_in_appenlight_if_enabled(app, config)
# we want our low level middleware to get to the request ASAP. We don't
# need any pylons stack middleware in them
app = VCSMiddleware(app, config, appenlight_client)
# Establish the Registry for this application
app = RegistryManager(app)
@ -140,13 +153,78 @@ def make_pyramid_app(global_config, **settings):
load_pyramid_environment(global_config, settings)
includeme_first(config)
includeme(config)
includeme_last(config)
pyramid_app = config.make_wsgi_app()
pyramid_app = wrap_app_in_wsgi_middlewares(pyramid_app, config)
pyramid_app.config = config
return pyramid_app
def make_not_found_view(config):
"""
This creates the view which should be registered as not-found-view to
pyramid. Basically it contains of the old pylons app, converted to a view.
Additionally it is wrapped by some other middlewares.
"""
settings = config.registry.settings
vcs_server_enabled = settings['vcs.server.enable']
# Make pylons app from unprepared settings.
pylons_app = make_app(
config.registry._pylons_compat_global_config,
**config.registry._pylons_compat_settings)
config.registry._pylons_compat_config = pylons_app.config
# Appenlight monitoring.
pylons_app, appenlight_client = wrap_in_appenlight_if_enabled(
pylons_app, settings)
# The VCSMiddleware shall operate like a fallback if pyramid doesn't find
# a view to handle the request. Therefore we wrap it around the pylons app.
if vcs_server_enabled:
pylons_app = VCSMiddleware(
pylons_app, settings, appenlight_client, registry=config.registry)
pylons_app_as_view = wsgiapp(pylons_app)
# Protect from VCS Server error related pages when server is not available
if not vcs_server_enabled:
pylons_app_as_view = DisableVCSPagesWrapper(pylons_app_as_view)
def pylons_app_with_error_handler(context, request):
"""
Handle exceptions from rc pylons app:
- old webob type exceptions get converted to pyramid exceptions
- pyramid exceptions are passed to the error handler view
"""
def is_vcs_response(response):
return 'X-RhodeCode-Backend' in response.headers
def is_http_error(response):
# webob type error responses
return (400 <= response.status_int <= 599)
def is_error_handling_needed(response):
return is_http_error(response) and not is_vcs_response(response)
try:
response = pylons_app_as_view(context, request)
if is_error_handling_needed(response):
response = webob_to_pyramid_http_response(response)
return error_handler(response, request)
except HTTPError as e: # pyramid type exceptions
return error_handler(e, request)
except Exception:
if settings.get('debugtoolbar.enabled', False):
raise
return error_handler(HTTPInternalServerError(), request)
return response
return pylons_app_with_error_handler
def add_pylons_compat_data(registry, global_config, settings):
"""
Attach data to the registry to support the Pylons integration.
@ -205,20 +283,32 @@ def error_handler(exception, request):
def includeme(config):
settings = config.registry.settings
# plugin information
config.registry.rhodecode_plugins = OrderedDict()
config.add_directive(
'register_rhodecode_plugin', register_rhodecode_plugin)
if asbool(settings.get('appenlight', 'false')):
config.include('appenlight_client.ext.pyramid_tween')
# Includes which are required. The application would fail without them.
config.include('pyramid_mako')
config.include('pyramid_beaker')
config.include('rhodecode.channelstream')
config.include('rhodecode.admin')
config.include('rhodecode.authentication')
config.include('rhodecode.integrations')
config.include('rhodecode.login')
config.include('rhodecode.tweens')
config.include('rhodecode.api')
config.include('rhodecode.svn_support')
config.add_route(
'rhodecode_support', 'https://rhodecode.com/help/', static=True)
# Add subscribers.
config.add_subscriber(scan_repositories_if_enabled, ApplicationCreated)
# Set the authorization policy.
authz_policy = ACLAuthorizationPolicy()
config.set_authorization_policy(authz_policy)
@ -226,86 +316,37 @@ def includeme(config):
# Set the default renderer for HTML templates to mako.
config.add_mako_renderer('.html')
# plugin information
config.registry.rhodecode_plugins = {}
config.add_directive(
'register_rhodecode_plugin', register_rhodecode_plugin)
# include RhodeCode plugins
includes = aslist(settings.get('rhodecode.includes', []))
for inc in includes:
config.include(inc)
pylons_app = make_app(
config.registry._pylons_compat_global_config,
**config.registry._pylons_compat_settings)
config.registry._pylons_compat_config = pylons_app.config
pylons_app_as_view = wsgiapp(pylons_app)
# Protect from VCS Server error related pages when server is not available
vcs_server_enabled = asbool(settings.get('vcs.server.enable', 'true'))
if not vcs_server_enabled:
pylons_app_as_view = DisableVCSPagesWrapper(pylons_app_as_view)
def pylons_app_with_error_handler(context, request):
"""
Handle exceptions from rc pylons app:
- old webob type exceptions get converted to pyramid exceptions
- pyramid exceptions are passed to the error handler view
"""
try:
response = pylons_app_as_view(context, request)
if 400 <= response.status_int <= 599: # webob type error responses
return error_handler(
webob_to_pyramid_http_response(response), request)
except HTTPError as e: # pyramid type exceptions
return error_handler(e, request)
except Exception:
if settings.get('debugtoolbar.enabled', False):
raise
return error_handler(HTTPInternalServerError(), request)
return response
# This is the glue which allows us to migrate in chunks. By registering the
# pylons based application as the "Not Found" view in Pyramid, we will
# fallback to the old application each time the new one does not yet know
# how to handle a request.
config.add_notfound_view(pylons_app_with_error_handler)
config.add_notfound_view(make_not_found_view(config))
if settings.get('debugtoolbar.enabled', False):
# if toolbar, then only http type exceptions get caught and rendered
ExcClass = HTTPError
else:
if not settings.get('debugtoolbar.enabled', False):
# if no toolbar, then any exception gets caught and rendered
ExcClass = Exception
config.add_view(error_handler, context=ExcClass)
config.add_view(error_handler, context=Exception)
config.add_view(error_handler, context=HTTPError)
def includeme_last(config):
"""
The static file catchall needs to be last in the view configuration.
"""
settings = config.registry.settings
def includeme_first(config):
# redirect automatic browser favicon.ico requests to correct place
def favicon_redirect(context, request):
return HTTPFound(
request.static_path('rhodecode:public/images/favicon.ico'))
# Note: johbo: I would prefer to register a prefix for static files at some
# point, e.g. move them under '_static/'. This would fully avoid that we
# can have name clashes with a repository name. Imaging someone calling his
# repo "css" ;-) Also having an external web server to serve out the static
# files seems to be easier to set up if they have a common prefix.
#
# Example: config.add_static_view('_static', path='rhodecode:public')
#
# It might be an option to register both paths for a while and then migrate
# over to the new location.
config.add_view(favicon_redirect, route_name='favicon')
config.add_route('favicon', '/favicon.ico')
# Serving static files with a catchall.
if settings['static_files']:
config.add_route('catchall_static', '/*subpath')
config.add_view(
static_view('rhodecode:public'), route_name='catchall_static')
config.add_static_view(
'_static/deform', 'deform:static')
config.add_static_view(
'_static/rhodecode', path='rhodecode:public', cache_max_age=3600 * 24)
def wrap_app_in_wsgi_middlewares(pyramid_app, config):
@ -322,19 +363,14 @@ def wrap_app_in_wsgi_middlewares(pyramid_app, config):
pyramid_app = HttpsFixup(pyramid_app, settings)
# Add RoutesMiddleware to support the pylons compatibility tween during
# migration to pyramid.
pyramid_app = RoutesMiddleware(
pyramid_app, config.registry._pylons_compat_config['routes.map'])
pyramid_app = SkippableRoutesMiddleware(
pyramid_app, config.registry._pylons_compat_config['routes.map'],
skip_prefixes=(STATIC_FILE_PREFIX, '/_debug_toolbar'))
if asbool(settings.get('appenlight', 'false')):
pyramid_app, _ = wrap_in_appenlight_if_enabled(
pyramid_app, config.registry._pylons_compat_config)
pyramid_app, _ = wrap_in_appenlight_if_enabled(pyramid_app, settings)
# TODO: johbo: Don't really see why we enable the gzip middleware when
# serving static files, might be something that should have its own setting
# as well?
if settings['static_files']:
if settings['gzip_responses']:
pyramid_app = make_gzip_middleware(
pyramid_app, settings, compress_level=1)
@ -376,12 +412,63 @@ def sanitize_settings_and_apply_defaults(settings):
# should allow to pass in a prefix.
settings.setdefault('rhodecode.api.url', '/_admin/api')
_bool_setting(settings, 'vcs.server.enable', 'true')
_bool_setting(settings, 'static_files', 'true')
# Sanitize generic settings.
_list_setting(settings, 'default_encoding', 'UTF-8')
_bool_setting(settings, 'is_test', 'false')
_bool_setting(settings, 'gzip_responses', 'false')
# Call split out functions that sanitize settings for each topic.
_sanitize_appenlight_settings(settings)
_sanitize_vcs_settings(settings)
return settings
def _sanitize_appenlight_settings(settings):
_bool_setting(settings, 'appenlight', 'false')
def _sanitize_vcs_settings(settings):
"""
Applies settings defaults and does type conversion for all VCS related
settings.
"""
_string_setting(settings, 'vcs.svn.compatible_version', '')
_string_setting(settings, 'git_rev_filter', '--all')
_string_setting(settings, 'vcs.hooks.protocol', 'pyro4')
_string_setting(settings, 'vcs.server', '')
_string_setting(settings, 'vcs.server.log_level', 'debug')
_string_setting(settings, 'vcs.server.protocol', 'pyro4')
_bool_setting(settings, 'startup.import_repos', 'false')
_bool_setting(settings, 'vcs.hooks.direct_calls', 'false')
_bool_setting(settings, 'vcs.server.enable', 'true')
_bool_setting(settings, 'vcs.start_server', 'false')
_list_setting(settings, 'vcs.backends', 'hg, git, svn')
_int_setting(settings, 'vcs.connection_timeout', 3600)
def _int_setting(settings, name, default):
settings[name] = int(settings.get(name, default))
def _bool_setting(settings, name, default):
settings[name] = asbool(settings.get(name, default))
input = settings.get(name, default)
if isinstance(input, unicode):
input = input.encode('utf8')
settings[name] = asbool(input)
def _list_setting(settings, name, default):
raw_value = settings.get(name, default)
old_separator = ','
if old_separator in raw_value:
# If we get a comma separated list, pass it to our own function.
settings[name] = rhodecode_aslist(raw_value, sep=old_separator)
else:
# Otherwise we assume it uses pyramids space/newline separation.
settings[name] = aslist(raw_value)
def _string_setting(settings, name, default):
settings[name] = settings.get(name, default).lower()

View file

@ -36,6 +36,7 @@ from rhodecode.config import routing_links
# prefix for non repository related links needs to be prefixed with `/`
ADMIN_PREFIX = '/_admin'
STATIC_FILE_PREFIX = '/_static'
# Default requirements for URL parts
URL_NAME_REQUIREMENTS = {
@ -51,6 +52,19 @@ URL_NAME_REQUIREMENTS = {
}
def add_route_requirements(route_path, requirements):
"""
Adds regex requirements to pyramid routes using a mapping dict
>>> add_route_requirements('/{action}/{id}', {'id': r'\d+'})
'/{action}/{id:\d+}'
"""
for key, regex in requirements.items():
route_path = route_path.replace('{%s}' % key, '{%s:%s}' % (key, regex))
return route_path
class JSRoutesMapper(Mapper):
"""
Wrapper for routes.Mapper to make pyroutes compatible url definitions
@ -546,6 +560,13 @@ def make_map(config):
action='my_account_auth_tokens_add', conditions={'method': ['POST']})
m.connect('my_account_auth_tokens', '/my_account/auth_tokens',
action='my_account_auth_tokens_delete', conditions={'method': ['DELETE']})
m.connect('my_account_notifications', '/my_account/notifications',
action='my_notifications',
conditions={'method': ['GET']})
m.connect('my_account_notifications_toggle_visibility',
'/my_account/toggle_visibility',
action='my_notifications_toggle_visibility',
conditions={'method': ['POST']})
# NOTIFICATION REST ROUTES
with rmap.submapper(path_prefix=ADMIN_PREFIX,
@ -554,7 +575,6 @@ def make_map(config):
action='index', conditions={'method': ['GET']})
m.connect('notifications_mark_all_read', '/notifications/mark_all_read',
action='mark_all_read', conditions={'method': ['POST']})
m.connect('/notifications/{notification_id}',
action='update', conditions={'method': ['PUT']})
m.connect('/notifications/{notification_id}',
@ -850,7 +870,7 @@ def make_map(config):
conditions={'function': check_repo, 'method': ['DELETE']},
requirements=URL_NAME_REQUIREMENTS, jsroute=True)
rmap.connect('changeset_info', '/changeset_info/{repo_name}/{revision}',
rmap.connect('changeset_info', '/{repo_name}/changeset_info/{revision}',
controller='changeset', action='changeset_info',
requirements=URL_NAME_REQUIREMENTS, jsroute=True)
@ -1090,9 +1110,9 @@ def make_map(config):
conditions={'function': check_repo},
requirements=URL_NAME_REQUIREMENTS, jsroute=True)
rmap.connect('files_metadata_list_home',
'/{repo_name}/metadata_list/{revision}/{f_path}',
controller='files', action='metadata_list',
rmap.connect('files_nodetree_full',
'/{repo_name}/nodetree_full/{commit_id}/{f_path}',
controller='files', action='nodetree_full',
conditions={'function': check_repo},
requirements=URL_NAME_REQUIREMENTS, jsroute=True)

View file

@ -49,22 +49,18 @@ def configure_vcs(config):
Patch VCS config with some RhodeCode specific stuff
"""
from rhodecode.lib.vcs import conf
from rhodecode.lib.utils2 import aslist
conf.settings.BACKENDS = {
'hg': 'rhodecode.lib.vcs.backends.hg.MercurialRepository',
'git': 'rhodecode.lib.vcs.backends.git.GitRepository',
'svn': 'rhodecode.lib.vcs.backends.svn.SubversionRepository',
}
conf.settings.HG_USE_REBASE_FOR_MERGING = config.get(
'rhodecode_hg_use_rebase_for_merging', False)
conf.settings.GIT_REV_FILTER = shlex.split(
config.get('git_rev_filter', '--all').strip())
conf.settings.DEFAULT_ENCODINGS = aslist(config.get('default_encoding',
'UTF-8'), sep=',')
conf.settings.ALIASES[:] = config.get('vcs.backends')
conf.settings.SVN_COMPATIBLE_VERSION = config.get(
'vcs.svn.compatible_version')
conf.settings.HOOKS_PROTOCOL = config['vcs.hooks.protocol']
conf.settings.HOOKS_DIRECT_CALLS = config['vcs.hooks.direct_calls']
conf.settings.GIT_REV_FILTER = shlex.split(config['git_rev_filter'])
conf.settings.DEFAULT_ENCODINGS = config['default_encoding']
conf.settings.ALIASES[:] = config['vcs.backends']
conf.settings.SVN_COMPATIBLE_VERSION = config['vcs.svn.compatible_version']
def initialize_database(config):
@ -90,8 +86,7 @@ def initialize_test_environment(settings, test_env=None):
def get_vcs_server_protocol(config):
protocol = config.get('vcs.server.protocol', 'pyro4')
return protocol
return config['vcs.server.protocol']
def set_instance_id(config):

View file

@ -25,15 +25,18 @@ gist controller for RhodeCode
import time
import logging
import traceback
import formencode
import peppercorn
from formencode import htmlfill
from pylons import request, response, tmpl_context as c, url
from pylons.controllers.util import abort, redirect
from pylons.i18n.translation import _
from webob.exc import HTTPNotFound, HTTPForbidden
from sqlalchemy.sql.expression import or_
from rhodecode.model.forms import GistForm
from rhodecode.model.gist import GistModel
from rhodecode.model.meta import Session
from rhodecode.model.db import Gist, User
@ -44,9 +47,10 @@ from rhodecode.lib.auth import LoginRequired, NotAnonymous
from rhodecode.lib.utils import jsonify
from rhodecode.lib.utils2 import safe_str, safe_int, time_to_datetime
from rhodecode.lib.ext_json import json
from webob.exc import HTTPNotFound, HTTPForbidden
from sqlalchemy.sql.expression import or_
from rhodecode.lib.vcs.exceptions import VCSError, NodeNotChangedError
from rhodecode.model import validation_schema
from rhodecode.model.validation_schema.schemas import gist_schema
log = logging.getLogger(__name__)
@ -56,11 +60,11 @@ class GistsController(BaseController):
def __load_defaults(self, extra_values=None):
c.lifetime_values = [
(str(-1), _('forever')),
(str(5), _('5 minutes')),
(str(60), _('1 hour')),
(str(60 * 24), _('1 day')),
(str(60 * 24 * 30), _('1 month')),
(-1, _('forever')),
(5, _('5 minutes')),
(60, _('1 hour')),
(60 * 24, _('1 day')),
(60 * 24 * 30, _('1 month')),
]
if extra_values:
c.lifetime_values.append(extra_values)
@ -136,40 +140,56 @@ class GistsController(BaseController):
"""POST /admin/gists: Create a new item"""
# url('gists')
self.__load_defaults()
gist_form = GistForm([x[0] for x in c.lifetime_values],
[x[0] for x in c.acl_options])()
data = dict(request.POST)
data['filename'] = data.get('filename') or Gist.DEFAULT_FILENAME
data['nodes'] = [{
'filename': data['filename'],
'content': data.get('content'),
'mimetype': data.get('mimetype') # None is autodetect
}]
data['gist_type'] = (
Gist.GIST_PUBLIC if data.get('public') else Gist.GIST_PRIVATE)
data['gist_acl_level'] = (
data.get('gist_acl_level') or Gist.ACL_LEVEL_PRIVATE)
schema = gist_schema.GistSchema().bind(
lifetime_options=[x[0] for x in c.lifetime_values])
try:
form_result = gist_form.to_python(dict(request.POST))
# TODO: multiple files support, from the form
filename = form_result['filename'] or Gist.DEFAULT_FILENAME
nodes = {
filename: {
'content': form_result['content'],
'lexer': form_result['mimetype'] # None is autodetect
}
}
_public = form_result['public']
gist_type = Gist.GIST_PUBLIC if _public else Gist.GIST_PRIVATE
gist_acl_level = form_result.get(
'acl_level', Gist.ACL_LEVEL_PRIVATE)
schema_data = schema.deserialize(data)
# convert to safer format with just KEYs so we sure no duplicates
schema_data['nodes'] = gist_schema.sequence_to_nodes(
schema_data['nodes'])
gist = GistModel().create(
description=form_result['description'],
gist_id=schema_data['gistid'], # custom access id not real ID
description=schema_data['description'],
owner=c.rhodecode_user.user_id,
gist_mapping=nodes,
gist_type=gist_type,
lifetime=form_result['lifetime'],
gist_id=form_result['gistid'],
gist_acl_level=gist_acl_level
gist_mapping=schema_data['nodes'],
gist_type=schema_data['gist_type'],
lifetime=schema_data['lifetime'],
gist_acl_level=schema_data['gist_acl_level']
)
Session().commit()
new_gist_id = gist.gist_access_id
except formencode.Invalid as errors:
defaults = errors.value
except validation_schema.Invalid as errors:
defaults = data
errors = errors.asdict()
if 'nodes.0.content' in errors:
errors['content'] = errors['nodes.0.content']
del errors['nodes.0.content']
if 'nodes.0.filename' in errors:
errors['filename'] = errors['nodes.0.filename']
del errors['nodes.0.filename']
return formencode.htmlfill.render(
render('admin/gists/new.html'),
defaults=defaults,
errors=errors.error_dict or {},
errors=errors,
prefix_error=False,
encoding="UTF-8",
force_defaults=False
@ -243,7 +263,8 @@ class GistsController(BaseController):
log.exception("Exception in gist show")
raise HTTPNotFound()
if format == 'raw':
content = '\n\n'.join([f.content for f in c.files if (f_path is None or f.path == f_path)])
content = '\n\n'.join([f.content for f in c.files
if (f_path is None or f.path == f_path)])
response.content_type = 'text/plain'
return content
return render('admin/gists/show.html')
@ -252,32 +273,35 @@ class GistsController(BaseController):
@NotAnonymous()
@auth.CSRFRequired()
def edit(self, gist_id):
self.__load_defaults()
self._add_gist_to_context(gist_id)
owner = c.gist.gist_owner == c.rhodecode_user.user_id
if not (h.HasPermissionAny('hg.admin')() or owner):
raise HTTPForbidden()
rpost = request.POST
nodes = {}
_file_data = zip(rpost.getall('org_files'), rpost.getall('files'),
rpost.getall('mimetypes'), rpost.getall('contents'))
for org_filename, filename, mimetype, content in _file_data:
nodes[org_filename] = {
'org_filename': org_filename,
'filename': filename,
'content': content,
'lexer': mimetype,
}
data = peppercorn.parse(request.POST.items())
schema = gist_schema.GistSchema()
schema = schema.bind(
# '0' is special value to leave lifetime untouched
lifetime_options=[x[0] for x in c.lifetime_values] + [0],
)
try:
schema_data = schema.deserialize(data)
# convert to safer format with just KEYs so we sure no duplicates
schema_data['nodes'] = gist_schema.sequence_to_nodes(
schema_data['nodes'])
GistModel().update(
gist=c.gist,
description=rpost['description'],
description=schema_data['description'],
owner=c.gist.owner,
gist_mapping=nodes,
gist_type=c.gist.gist_type,
lifetime=rpost['lifetime'],
gist_acl_level=rpost['acl_level']
gist_mapping=schema_data['nodes'],
gist_type=schema_data['gist_type'],
lifetime=schema_data['lifetime'],
gist_acl_level=schema_data['gist_acl_level']
)
Session().commit()
@ -287,6 +311,10 @@ class GistsController(BaseController):
# store only DB stuff for gist
Session().commit()
h.flash(_('Successfully updated gist data'), category='success')
except validation_schema.Invalid as errors:
errors = errors.asdict()
h.flash(_('Error occurred during update of gist {}: {}').format(
gist_id, errors), category='error')
except Exception:
log.exception("Exception in gist edit")
h.flash(_('Error occurred during update of gist %s') % gist_id,
@ -317,7 +345,7 @@ class GistsController(BaseController):
# this cannot use timeago, since it's used in select2 as a value
expiry = h.age(h.time_to_datetime(c.gist.gist_expires))
self.__load_defaults(
extra_values=('0', _('%(expiry)s - current value') % {'expiry': expiry}))
extra_values=(0, _('%(expiry)s - current value') % {'expiry': expiry}))
return render('admin/gists/edit.html')
@LoginRequired()

View file

@ -346,3 +346,17 @@ class MyAccountController(BaseController):
h.flash(_("Auth token successfully deleted"), category='success')
return redirect(url('my_account_auth_tokens'))
def my_notifications(self):
c.active = 'notifications'
return render('admin/my_account/my_account.html')
@auth.CSRFRequired()
def my_notifications_toggle_visibility(self):
user = c.rhodecode_user.get_instance()
user_data = user.user_data
status = user_data.get('notification_status', False)
user_data['notification_status'] = not status
user.user_data = user_data
Session().commit()
return redirect(url('my_account_notifications'))

View file

@ -86,6 +86,7 @@ class NotificationsController(BaseController):
return render('admin/notifications/notifications.html')
@auth.CSRFRequired()
def mark_all_read(self):
if request.is_xhr:

View file

@ -33,6 +33,7 @@ from pylons.controllers.util import redirect
from pylons.i18n.translation import _
from webob.exc import HTTPForbidden, HTTPNotFound, HTTPBadRequest
import rhodecode
from rhodecode.lib import auth, helpers as h
from rhodecode.lib.auth import (
LoginRequired, HasPermissionAllDecorator,
@ -42,7 +43,7 @@ from rhodecode.lib.base import BaseRepoController, render
from rhodecode.lib.ext_json import json
from rhodecode.lib.exceptions import AttachedForksError
from rhodecode.lib.utils import action_logger, repo_name_slug, jsonify
from rhodecode.lib.utils2 import safe_int
from rhodecode.lib.utils2 import safe_int, str2bool
from rhodecode.lib.vcs import RepositoryError
from rhodecode.model.db import (
User, Repository, UserFollowing, RepoGroup, RepositoryField)
@ -779,6 +780,8 @@ class ReposController(BaseRepoController):
c.repo_info = self._load_repo(repo_name)
defaults = self._vcs_form_defaults(repo_name)
c.inherit_global_settings = defaults['inherit_global_settings']
c.labs_active = str2bool(
rhodecode.CONFIG.get('labs_settings_active', 'true'))
return htmlfill.render(
render('admin/repos/repo_edit.html'),

View file

@ -79,7 +79,7 @@ class SettingsController(BaseController):
def __before__(self):
super(SettingsController, self).__before__()
c.labs_active = str2bool(
rhodecode.CONFIG.get('labs_settings_active', 'false'))
rhodecode.CONFIG.get('labs_settings_active', 'true'))
c.navlist = navigation_list(request)
def _get_hg_ui_settings(self):
@ -789,13 +789,6 @@ LabSetting = collections.namedtuple(
# This list has to be kept in sync with the form
# rhodecode.model.forms.LabsSettingsForm.
_LAB_SETTINGS = [
LabSetting(
key='rhodecode_hg_use_rebase_for_merging',
type='bool',
group=lazy_ugettext('Mercurial server-side merge'),
label=lazy_ugettext('Use rebase instead of creating a merge commit when merging via web interface'),
help='' # Do not translate the empty string!
),
LabSetting(
key='rhodecode_proxy_subversion_http_requests',
type='bool',

View file

@ -83,9 +83,6 @@ class UsersController(BaseController):
from rhodecode.lib.utils import PartialRenderer
_render = PartialRenderer('data_table/_dt_elements.html')
def grav_tmpl(user_email, size):
return _render("user_gravatar", user_email, size)
def username(user_id, username):
return _render("user_name", user_id, username)
@ -100,9 +97,7 @@ class UsersController(BaseController):
users_data = []
for user in c.users_list:
users_data.append({
"gravatar": grav_tmpl(user.email, 20),
"username": h.link_to(
user.username, h.url('user_profile', username=user.username)),
"username": h.gravatar_with_user(user.username),
"username_raw": user.username,
"email": user.email,
"first_name": h.escape(user.name),

View file

@ -351,7 +351,8 @@ class ChangesetController(BaseRepoController):
f_path=request.POST.get('f_path'),
line_no=request.POST.get('line'),
status_change=(ChangesetStatus.get_status_lbl(status)
if status else None)
if status else None),
status_change_type=status
)
# get status if set !
if status:

View file

@ -136,11 +136,13 @@ class FilesController(BaseRepoController):
_namespace = caches.get_repo_namespace_key(namespace_type, repo_name)
return caches.get_cache_manager('repo_cache_long', _namespace)
def _get_tree_at_commit(self, repo_name, commit_id, f_path):
def _get_tree_at_commit(self, repo_name, commit_id, f_path,
full_load=False, force=False):
def _cached_tree():
log.debug('Generating cached file tree for %s, %s, %s',
repo_name, commit_id, f_path)
return render('files/files_browser.html')
c.full_load = full_load
return render('files/files_browser_tree.html')
cache_manager = self.__get_tree_cache_manager(
repo_name, caches.FILE_TREE)
@ -148,6 +150,10 @@ class FilesController(BaseRepoController):
cache_key = caches.compute_key_from_params(
repo_name, commit_id, f_path)
if force:
# we want to force recompute of caches
cache_manager.remove_value(cache_key)
return cache_manager.get(cache_key, createfunc=_cached_tree)
def _get_nodelist_at_commit(self, repo_name, commit_id, f_path):
@ -165,22 +171,6 @@ class FilesController(BaseRepoController):
repo_name, commit_id, f_path)
return cache_manager.get(cache_key, createfunc=_cached_nodes)
def _get_metadata_at_commit(self, repo_name, commit, dir_node):
def _cached_metadata():
log.debug('Generating cached metadata for %s, %s, %s',
repo_name, commit.raw_id, safe_str(dir_node.path))
data = ScmModel().get_dirnode_metadata(commit, dir_node)
return data
cache_manager = self.__get_tree_cache_manager(
repo_name, caches.FILE_TREE_META)
cache_key = caches.compute_key_from_params(
repo_name, commit.raw_id, safe_str(dir_node.path))
return cache_manager.get(cache_key, createfunc=_cached_metadata)
@LoginRequired()
@HasRepoPermissionAnyDecorator(
'repository.read', 'repository.write', 'repository.admin')
@ -246,6 +236,7 @@ class FilesController(BaseRepoController):
c.authors = []
c.file_tree = self._get_tree_at_commit(
repo_name, c.commit.raw_id, f_path)
except RepositoryError as e:
h.flash(safe_str(e), category='error')
raise HTTPNotFound()
@ -1092,23 +1083,32 @@ class FilesController(BaseRepoController):
@XHRRequired()
@HasRepoPermissionAnyDecorator(
'repository.read', 'repository.write', 'repository.admin')
@jsonify
def metadata_list(self, repo_name, revision, f_path):
def nodetree_full(self, repo_name, commit_id, f_path):
"""
Returns a json dict that contains commit date, author, revision
and id for the specified repo, revision and file path
Returns rendered html of file tree that contains commit date,
author, revision for the specified combination of
repo, commit_id and file path
:param repo_name: name of the repository
:param revision: revision of files
:param commit_id: commit_id of file tree
:param f_path: file path of the requested directory
"""
commit = self.__get_commit_or_redirect(revision, repo_name)
commit = self.__get_commit_or_redirect(commit_id, repo_name)
try:
file_node = commit.get_node(f_path)
dir_node = commit.get_node(f_path)
except RepositoryError as e:
return {'error': safe_str(e)}
return 'error {}'.format(safe_str(e))
metadata = self._get_metadata_at_commit(
repo_name, commit, file_node)
return {'metadata': metadata}
if dir_node.is_file():
return ''
c.file = dir_node
c.commit = commit
# using force=True here, make a little trick. We flush the cache and
# compute it using the same key as without full_load, so the fully
# loaded cached tree is now returned instead of partial
return self._get_tree_at_commit(
repo_name, commit.raw_id, dir_node.path, full_load=True,
force=True)

View file

@ -244,7 +244,7 @@ class JournalController(BaseController):
try:
self.scm_model.toggle_following_user(
user_id, c.rhodecode_user.user_id)
Session.commit()
Session().commit()
return 'ok'
except Exception:
raise HTTPBadRequest()
@ -254,7 +254,7 @@ class JournalController(BaseController):
try:
self.scm_model.toggle_following_repo(
repo_id, c.rhodecode_user.user_id)
Session.commit()
Session().commit()
return 'ok'
except Exception:
raise HTTPBadRequest()

View file

@ -32,6 +32,7 @@ from pylons.i18n.translation import _
from sqlalchemy.sql import func
from sqlalchemy.sql.expression import or_
from rhodecode import events
from rhodecode.lib import auth, diffs, helpers as h
from rhodecode.lib.ext_json import json
from rhodecode.lib.base import (
@ -640,6 +641,9 @@ class PullrequestsController(BaseRepoController):
pull_request_id = safe_int(pull_request_id)
c.pull_request = PullRequest.get_or_404(pull_request_id)
c.template_context['pull_request_data']['pull_request_id'] = \
pull_request_id
# pull_requests repo_name we opened it against
# ie. target_repo must match
if repo_name != c.pull_request.target_repo.repo_name:
@ -758,9 +762,13 @@ class PullrequestsController(BaseRepoController):
line_no=request.POST.get('line'),
status_change=(ChangesetStatus.get_status_lbl(status)
if status and allowed_to_change_status else None),
status_change_type=(status
if status and allowed_to_change_status else None),
closing_pr=close_pr
)
if allowed_to_change_status:
old_calculated_status = pull_request.calculated_review_status()
# get status if set !
@ -774,6 +782,7 @@ class PullrequestsController(BaseRepoController):
)
Session().flush()
events.trigger(events.PullRequestCommentEvent(pull_request, comm))
# we now calculate the status of pull request, and based on that
# calculation we set the commits status
calculated_status = pull_request.calculated_review_status()

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