##// END OF EJS Templates
docs: fixed small wanrings/errors during build.
marcink -
r1120:d4155363 default
parent child Browse files
Show More
@@ -0,0 +1,17 b''
1 .. _checklist-pull-request:
2
3 =======================
4 Pull Request Checklists
5 =======================
6
7
8
9 Checklists for Pull Request
10 ===========================
11
12
13 - Informative description
14 - Linear commit history
15 - Rebased on top of latest changes
16 - Add ticket references. eg fixes #123, references #123 etc.
17
1 NO CONTENT: new file 100644, binary diff hidden
NO CONTENT: new file 100644, binary diff hidden
@@ -1,151 +1,151 b''
1 .. _backup-ref:
1 .. _backup-ref:
2
2
3 Backup and Restore
3 Backup and Restore
4 ==================
4 ==================
5
5
6 *β€œThe condition of any backup is unknown until a restore is attempted.”*
6 *β€œThe condition of any backup is unknown until a restore is attempted.”*
7 `SchrΓΆdinger's Backup`_
7 `SchrΓΆdinger's Backup`_
8
8
9 To snapshot an instance of |RCE|, and save its settings, you need to backup the
9 To snapshot an instance of |RCE|, and save its settings, you need to backup the
10 following parts of the system at the same time.
10 following parts of the system at the same time.
11
11
12 * The |repos| managed by the instance together with the stored Gists.
12 * The |repos| managed by the instance together with the stored Gists.
13 * The |RCE| database.
13 * The |RCE| database.
14 * Any configuration files or extensions that you've configured. In most
14 * Any configuration files or extensions that you've configured. In most
15 cases it's only the :file:`rhodecode.ini` file.
15 cases it's only the :file:`rhodecode.ini` file.
16 * Installer files such as those in `/opt/rhodecode` can be backed-up, however
16 * Installer files such as those in `/opt/rhodecode` can be backed-up, however
17 it's not required since in case of a recovery installer simply
17 it's not required since in case of a recovery installer simply
18 re-creates those.
18 re-creates those.
19
19
20
20
21 .. important::
21 .. important::
22
22
23 Ideally you should script all of these functions so that it creates a
23 Ideally you should script all of these functions so that it creates a
24 backup snapshot of your system at a particular timestamp and then run that
24 backup snapshot of your system at a particular timestamp and then run that
25 script regularly.
25 script regularly.
26
26
27 Backup Details
27 Backup Details
28 --------------
28 --------------
29
29
30 To backup the relevant parts of |RCE| required to restore your system, use
30 To backup the relevant parts of |RCE| required to restore your system, use
31 the information in this section to identify what is important to you.
31 the information in this section to identify what is important to you.
32
32
33 Repository Backup
33 Repository Backup
34 ^^^^^^^^^^^^^^^^^
34 ^^^^^^^^^^^^^^^^^
35
35
36 To back up your |repos|, use the API to get a list of all |repos| managed,
36 To back up your |repos|, use the API to get a list of all |repos| managed,
37 and then clone them to your backup location. This is the most safe backup option.
37 and then clone them to your backup location. This is the most safe backup option.
38 Backing up the storage directory could potentially result in a backup of
38 Backing up the storage directory could potentially result in a backup of
39 partially committed files or commits. (Backup taking place during a big push)
39 partially committed files or commits. (Backup taking place during a big push)
40 As an alternative you could use a rsync or simple `cp` commands if you can
40 As an alternative you could use a rsync or simple `cp` commands if you can
41 ensure your instance is only in read-only mode or stopped at the moment.
41 ensure your instance is only in read-only mode or stopped at the moment.
42
42
43
43
44 Use the ``get_repos`` method to list all your managed |repos|,
44 Use the ``get_repos`` method to list all your managed |repos|,
45 and use the ``clone_uri`` information that is returned. See the :ref:`api`
45 and use the ``clone_uri`` information that is returned. See the :ref:`api`
46 for more information. Be sure to keep the structure or repositories with their
46 for more information. Be sure to keep the structure or repositories with their
47 repository groups.
47 repository groups.
48
48
49 .. important::
49 .. important::
50
50
51 This will not work for |svn| |repos|. Currently the only way to back up
51 This will not work for |svn| |repos|. Currently the only way to back up
52 your |svn| |repos| is to make a copy of them.
52 your |svn| |repos| is to make a copy of them.
53
53
54 It is also important to note, that you can only restore the |svn| |repos|
54 It is also important to note, that you can only restore the |svn| |repos|
55 using the same version as they were saved with.
55 using the same version as they were saved with.
56
56
57 Database Backup
57 Database Backup
58 ^^^^^^^^^^^^^^^
58 ^^^^^^^^^^^^^^^
59
59
60 The instance database contains all the |RCE| permissions settings,
60 The instance database contains all the |RCE| permissions settings,
61 and user management information. To backup your database,
61 and user management information. To backup your database,
62 export it using the following appropriate example, and then move it to your
62 export it using the following appropriate example, and then move it to your
63 backup location:
63 backup location:
64
64
65 .. code-block:: bash
65 .. code-block:: bash
66
66
67 # For MySQL DBs
67 # For MySQL DBs
68 $ mysqldump -u <uname> -p <pass> rhodecode_db_name > mysql-db-backup
68 $ mysqldump -u <uname> -p <pass> rhodecode_db_name > mysql-db-backup
69 # MySQL restore command
69 # MySQL restore command
70 $ mysql -u <uname> -p <pass> rhodecode_db_name < mysql-db-backup
70 $ mysql -u <uname> -p <pass> rhodecode_db_name < mysql-db-backup
71
71
72 # For PostgreSQL DBs
72 # For PostgreSQL DBs
73 $ PGPASSWORD=<pass> pg_dump rhodecode_db_name > postgresql-db-backup
73 $ PGPASSWORD=<pass> pg_dump rhodecode_db_name > postgresql-db-backup
74 # PosgreSQL restore
74 # PosgreSQL restore
75 $ PGPASSWORD=<pass> psql -U <uname> -h localhost -d rhodecode_db_name -1 -f postgresql-db-backup
75 $ PGPASSWORD=<pass> psql -U <uname> -h localhost -d rhodecode_db_name -1 -f postgresql-db-backup
76
76
77 # For SQLite
77 # For SQLite
78 $ sqlite3 rhodecode.db β€˜.dump’ > sqlite-db-backup
78 $ sqlite3 rhodecode.db β€˜.dump’ > sqlite-db-backup
79 # SQLite restore
79 # SQLite restore
80 $ copy sqlite-db-backup rhodecode.db
80 $ copy sqlite-db-backup rhodecode.db
81
81
82
82
83 The default |RCE| SQLite database location is
83 The default |RCE| SQLite database location is
84 :file:`/home/{user}/.rccontrol/{instance-id}/rhodecode.db`
84 :file:`/home/{user}/.rccontrol/{instance-id}/rhodecode.db`
85
85
86 If running MySQL or PostgreSQL databases, you will have configured these
86 If running MySQL or PostgreSQL databases, you will have configured these
87 separately, for more information see :ref:`rhodecode-database-ref`
87 separately, for more information see :ref:`rhodecode-database-ref`
88
88
89 Configuration File Backup
89 Configuration File Backup
90 ^^^^^^^^^^^^^^^^^^^^^^^^^
90 ^^^^^^^^^^^^^^^^^^^^^^^^^
91
91
92 Depending on your setup, you could have a number of configuration files that
92 Depending on your setup, you could have a number of configuration files that
93 should be backed up. You may have some, or all of the configuration files
93 should be backed up. You may have some, or all of the configuration files
94 listed in the :ref:`config-rce-files` section. Ideally you should back these
94 listed in the :ref:`config-rce-files` section. Ideally you should back these
95 up at the same time as the database and |repos|. It really depends on if you need
95 up at the same time as the database and |repos|. It really depends on if you need
96 the configuration file like logs, custom modules. We always recommend backing
96 the configuration file like logs, custom modules. We always recommend backing
97 those up.
97 those up.
98
98
99 Gist Backup
99 Gist Backup
100 ^^^^^^^^^^^
100 ^^^^^^^^^^^
101
101
102 To backup the gists on your |RCE| instance you usually have to backup the
102 To backup the gists on your |RCE| instance you usually have to backup the
103 gist storage path. If this haven't been changed it's located inside
103 gist storage path. If this haven't been changed it's located inside
104 :file:`.rc_gist_store` and the metadata in :file:`.rc_gist_metadata`.
104 :file:`.rc_gist_store` and the metadata in :file:`.rc_gist_metadata`.
105 You can use the ``get_users`` and ``get_gists`` API methods to fetch the
105 You can use the ``get_users`` and ``get_gists`` API methods to fetch the
106 gists for each user on the instance.
106 gists for each user on the instance.
107
107
108 Extension Backups
108 Extension Backups
109 ^^^^^^^^^^^^^^^^^
109 ^^^^^^^^^^^^^^^^^
110
110
111 You should also backup any extensions added in the
111 You should also backup any extensions added in the
112 :file:`home/{user}/.rccontrol/{instance-id}/rcextensions` directory.
112 :file:`home/{user}/.rccontrol/{instance-id}/rcextensions` directory.
113
113
114 Full-text Search Backup
114 Full-text Search Backup
115 ^^^^^^^^^^^^^^^^^^^^^^^
115 ^^^^^^^^^^^^^^^^^^^^^^^
116
116
117 You may also have full text search set up, but the index can be rebuild from
117 You may also have full text search set up, but the index can be rebuild from
118 re-imported |repos| if necessary. You will most likely want to backup your
118 re-imported |repos| if necessary. You will most likely want to backup your
119 :file:`mapping.ini` file if you've configured that. For more information, see
119 :file:`mapping.ini` file if you've configured that. For more information, see
120 the :ref:`indexing-ref` section.
120 the :ref:`indexing-ref` section.
121
121
122 Restoration Steps
122 Restoration Steps
123 -----------------
123 -----------------
124
124
125 To restore an instance of |RCE| from its backed up components, to a fresh
125 To restore an instance of |RCE| from its backed up components, to a fresh
126 system use the following steps.
126 system use the following steps.
127
127
128 1. Install a new instance of |RCE| using sqlite option as database.
128 1. Install a new instance of |RCE| using sqlite option as database.
129 2. Restore your database.
129 2. Restore your database.
130 2. Once installed, replace you backed up the :file:`rhodecode.ini` with your
130 3. Once installed, replace you backed up the :file:`rhodecode.ini` with your
131 backup version. Ensure this file points to the restored
131 backup version. Ensure this file points to the restored
132 database, see the :ref:`config-database` section.
132 database, see the :ref:`config-database` section.
133 3. Restart |RCE| and remap and rescan your |repos| to verify filesystem access,
133 4. Restart |RCE| and remap and rescan your |repos| to verify filesystem access,
134 see the :ref:`remap-rescan` section.
134 see the :ref:`remap-rescan` section.
135
135
136
136
137 Post Restoration Steps
137 Post Restoration Steps
138 ^^^^^^^^^^^^^^^^^^^^^^
138 ^^^^^^^^^^^^^^^^^^^^^^
139
139
140 Once you have restored your |RCE| instance to basic functionality, you can
140 Once you have restored your |RCE| instance to basic functionality, you can
141 then work on restoring any specific setup changes you had made.
141 then work on restoring any specific setup changes you had made.
142
142
143 * To recreate the |RCE| index, use the backed up :file:`mapping.ini` file if
143 * To recreate the |RCE| index, use the backed up :file:`mapping.ini` file if
144 you had made changes and rerun the indexer. See the
144 you had made changes and rerun the indexer. See the
145 :ref:`indexing-ref` section for details.
145 :ref:`indexing-ref` section for details.
146 * To reconfigure any extensions, copy the backed up extensions into the
146 * To reconfigure any extensions, copy the backed up extensions into the
147 :file:`/home/{user}/.rccontrol/{instance-id}/rcextensions` and also specify
147 :file:`/home/{user}/.rccontrol/{instance-id}/rcextensions` and also specify
148 any custom hooks if necessary. See the :ref:`extensions-hooks-ref` section for
148 any custom hooks if necessary. See the :ref:`extensions-hooks-ref` section for
149 details.
149 details.
150
150
151 .. _SchrΓΆdinger's Backup: http://novabackup.novastor.com/blog/schrodingers-backup-good-bad-backup/
151 .. _SchrΓΆdinger's Backup: http://novabackup.novastor.com/blog/schrodingers-backup-good-bad-backup/
@@ -1,179 +1,179 b''
1 .. _sec-your-server:
1 .. _sec-your-server:
2
2
3 Securing Your Server
3 Securing Your Server
4 --------------------
4 --------------------
5
5
6 |RCE| runs on your hardware, and while it is developed with security in mind
6 |RCE| runs on your hardware, and while it is developed with security in mind
7 it is also important that you ensure your servers are well secured. In this
7 it is also important that you ensure your servers are well secured. In this
8 section we will cover some basic security practices that are best to
8 section we will cover some basic security practices that are best to
9 configure when setting up your |RCE| instances.
9 configure when setting up your |RCE| instances.
10
10
11 SSH Keys
11 SSH Keys
12 ^^^^^^^^
12 ^^^^^^^^
13
13
14 Using SSH keys to access your server provides more security than using the
14 Using SSH keys to access your server provides more security than using the
15 standard username and password combination. To set up your SSH Keys, use the
15 standard username and password combination. To set up your SSH Keys, use the
16 following steps:
16 following steps:
17
17
18 1. On your local machine create the public/private key combination. The
18 1. On your local machine create the public/private key combination. The
19 private key you will keep, and the matching public key is copied to the
19 private key you will keep, and the matching public key is copied to the
20 server. Setting a passphrase here is optional, if you set one you will
20 server. Setting a passphrase here is optional, if you set one you will
21 always be prompted for it when logging in.
21 always be prompted for it when logging in.
22
22
23 .. code-block:: bash
23 .. code-block:: bash
24
24
25 # Generate SSH Keys
25 # Generate SSH Keys
26 user@ubuntu:~$ ssh-keygen -t rsa
26 user@ubuntu:~$ ssh-keygen -t rsa
27
27
28 .. code-block:: bash
28 .. code-block:: bash
29
29
30 Generating public/private rsa key pair.
30 Generating public/private rsa key pair.
31 Enter file in which to save the key (/home/user/.ssh/id_rsa):
31 Enter file in which to save the key (/home/user/.ssh/id_rsa):
32 Created directory '/home/user/.ssh'.
32 Created directory '/home/user/.ssh'.
33 Enter passphrase (empty for no passphrase):
33 Enter passphrase (empty for no passphrase):
34 Enter same passphrase again:
34 Enter same passphrase again:
35 Your identification has been saved in /home/user/.ssh/id_rsa.
35 Your identification has been saved in /home/user/.ssh/id_rsa.
36 Your public key has been saved in /home/user/.ssh/id_rsa.pub.
36 Your public key has been saved in /home/user/.ssh/id_rsa.pub.
37 The key fingerprint is:
37 The key fingerprint is:
38 02:82:38:95:e5:30:d2:ad:17:60:15:7f:94:17:9f:30 user@ubuntu
38 02:82:38:95:e5:30:d2:ad:17:60:15:7f:94:17:9f:30 user@ubuntu
39 The key's randomart image is:
39 The key\'s randomart image is:
40 +--[ RSA 2048]----+
40 +--[ RSA 2048]----+
41
41
42 2. SFTP to your server, and copy the public key to the ``~/.ssh`` folder.
42 2. SFTP to your server, and copy the public key to the ``~/.ssh`` folder.
43
43
44 .. code-block:: bash
44 .. code-block:: bash
45
45
46 # SFTP to your server
46 # SFTP to your server
47 $ sftp user@hostname
47 $ sftp user@hostname
48
48
49 # copy your public key
49 # copy your public key
50 sftp> mput /home/user/.ssh/id_rsa.pub /home/user/.ssh
50 sftp> mput /home/user/.ssh/id_rsa.pub /home/user/.ssh
51 Uploading /home/user/.ssh/id_rsa.pub to /home/user/.ssh/id_rsa.pub
51 Uploading /home/user/.ssh/id_rsa.pub to /home/user/.ssh/id_rsa.pub
52 /home/user/.ssh/id_rsa.pub 100% 394 0.4KB/s 00:00
52 /home/user/.ssh/id_rsa.pub 100% 394 0.4KB/s 00:00
53
53
54 3. On your server, add the public key to the :file:`~/.ssh/authorized_keys`
54 3. On your server, add the public key to the :file:`~/.ssh/authorized_keys`
55 file.
55 file.
56
56
57 .. code-block:: bash
57 .. code-block:: bash
58
58
59 $ cat /home/user/.ssh/id_rsa.pub > /home/user/.ssh/authorized_keys
59 $ cat /home/user/.ssh/id_rsa.pub > /home/user/.ssh/authorized_keys
60
60
61 You should now be able to log into your server using your SSH
61 You should now be able to log into your server using your SSH
62 Keys. If you've added a passphrase you'll be asked for it. For more
62 Keys. If you've added a passphrase you'll be asked for it. For more
63 information about using SSH keys with |RCE| |repos|, see the
63 information about using SSH keys with |RCE| |repos|, see the
64 :ref:`ssh-connection` section.
64 :ref:`ssh-connection` section.
65
65
66 VPN Whitelist
66 VPN Whitelist
67 ^^^^^^^^^^^^^
67 ^^^^^^^^^^^^^
68
68
69 Most company networks will have a VPN. If you need to set one up, there are
69 Most company networks will have a VPN. If you need to set one up, there are
70 many tutorials online for how to do that. Getting it right requires good
70 many tutorials online for how to do that. Getting it right requires good
71 knowledge and attention to detail. Once set up, you can configure your
71 knowledge and attention to detail. Once set up, you can configure your
72 |RCE| instances to only allow user access from the VPN, to do this see the
72 |RCE| instances to only allow user access from the VPN, to do this see the
73 :ref:`settip-ip-white` section.
73 :ref:`settip-ip-white` section.
74
74
75 Public Key Infrastructure and SSL/TLS Encryption
75 Public Key Infrastructure and SSL/TLS Encryption
76 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
76 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
77
77
78 Public key infrastructure (PKI) is a system that creates, manages, and
78 Public key infrastructure (PKI) is a system that creates, manages, and
79 validates certificates for identifying nodes on a network and encrypting
79 validates certificates for identifying nodes on a network and encrypting
80 communication between them. SSL or TLS certificates can be used to
80 communication between them. SSL or TLS certificates can be used to
81 authenticate different entities with one another. To read more about PKIs,
81 authenticate different entities with one another. To read more about PKIs,
82 see the `OpenSSL PKI tutorial`_ site, or this `Cloudflare PKI post`_.
82 see the `OpenSSL PKI tutorial`_ site, or this `Cloudflare PKI post`_.
83
83
84 If the network you are running is SSL/TLS encrypted, you can configure |RCE|
84 If the network you are running is SSL/TLS encrypted, you can configure |RCE|
85 to always use secure connections using the ``force_https`` and ``use_htsts``
85 to always use secure connections using the ``force_https`` and ``use_htsts``
86 options in the :file:`/home/user/.rccontrol/instance-id/rhodecode.ini` file.
86 options in the :file:`/home/user/.rccontrol/instance-id/rhodecode.ini` file.
87 For more details, see the :ref:`x-frame` section.
87 For more details, see the :ref:`x-frame` section.
88
88
89 FireWalls and Ports
89 FireWalls and Ports
90 ^^^^^^^^^^^^^^^^^^^
90 ^^^^^^^^^^^^^^^^^^^
91
91
92 Setting up a network firewall for your internal traffic is a good way
92 Setting up a network firewall for your internal traffic is a good way
93 of keeping it secure by blocking off any ports that should not be used.
93 of keeping it secure by blocking off any ports that should not be used.
94 Additionally, you can set non-default ports for certain functions which adds
94 Additionally, you can set non-default ports for certain functions which adds
95 an extra layer of security to your setup.
95 an extra layer of security to your setup.
96
96
97 A well configured firewall will restrict access to everything except the
97 A well configured firewall will restrict access to everything except the
98 services you need to remain open. By exposing fewer services you reduce the
98 services you need to remain open. By exposing fewer services you reduce the
99 number of potential vulnerabilities.
99 number of potential vulnerabilities.
100
100
101 There are a number of different firewall solutions, but for most Linux systems
101 There are a number of different firewall solutions, but for most Linux systems
102 using the built in `IpTables`_ firewall should suffice. On BSD systems you
102 using the built in `IpTables`_ firewall should suffice. On BSD systems you
103 can use `IPFILTER`_ or `IPFW`_. Use the following examples, and the IpTables
103 can use `IPFILTER`_ or `IPFW`_. Use the following examples, and the IpTables
104 documentation to configure your IP Tables on Ubuntu.
104 documentation to configure your IP Tables on Ubuntu.
105
105
106 Changing the default SSH port.
106 Changing the default SSH port.
107
107
108 .. code-block:: bash
108 .. code-block:: bash
109
109
110 # Open SSH config file and change to port 10022
110 # Open SSH config file and change to port 10022
111 vi /etc/ssh/sshd_config
111 vi /etc/ssh/sshd_config
112
112
113 # What ports, IPs and protocols we listen for
113 # What ports, IPs and protocols we listen for
114 Port 10022
114 Port 10022
115
115
116 Setting IP Table rules for SSH traffic. It is important to note that the
116 Setting IP Table rules for SSH traffic. It is important to note that the
117 default policy of your IpTables can differ and it is worth checking how each
117 default policy of your IpTables can differ and it is worth checking how each
118 is configured. The options are *ACCEPT*, *REJECT*, *DROP*, or *LOG*. The
118 is configured. The options are *ACCEPT*, *REJECT*, *DROP*, or *LOG*. The
119 usual practice is to block access on all ports and then enable access only on
119 usual practice is to block access on all ports and then enable access only on
120 the ports you with to expose.
120 the ports you with to expose.
121
121
122 .. code-block:: bash
122 .. code-block:: bash
123
123
124 # Check iptables policy
124 # Check iptables policy
125 $ sudo iptables -L
125 $ sudo iptables -L
126
126
127 Chain INPUT (policy ACCEPT)
127 Chain INPUT (policy ACCEPT)
128 target prot opt source destination
128 target prot opt source destination
129
129
130 Chain FORWARD (policy ACCEPT)
130 Chain FORWARD (policy ACCEPT)
131 target prot opt source destination
131 target prot opt source destination
132
132
133 Chain OUTPUT (policy ACCEPT)
133 Chain OUTPUT (policy ACCEPT)
134 target prot opt source destination
134 target prot opt source destination
135
135
136 # Close all ports by default
136 # Close all ports by default
137 $ sudo iptables -P INPUT DROP
137 $ sudo iptables -P INPUT DROP
138
138
139 $ sudo iptables -L
139 $ sudo iptables -L
140 Chain INPUT (policy DROP)
140 Chain INPUT (policy DROP)
141 target prot opt source destination
141 target prot opt source destination
142 DROP all -- anywhere anywhere
142 DROP all -- anywhere anywhere
143
143
144 Chain FORWARD (policy ACCEPT)
144 Chain FORWARD (policy ACCEPT)
145 target prot opt source destination
145 target prot opt source destination
146
146
147 Chain OUTPUT (policy ACCEPT)
147 Chain OUTPUT (policy ACCEPT)
148 target prot opt source destination
148 target prot opt source destination
149
149
150 .. code-block:: bash
150 .. code-block:: bash
151
151
152 # Deny outbound SSH traffic
152 # Deny outbound SSH traffic
153 sudo iptables -A OUTPUT -p tcp --dport 10022 -j DROP
153 sudo iptables -A OUTPUT -p tcp --dport 10022 -j DROP
154
154
155 # Allow incoming SSH traffic on port 10022
155 # Allow incoming SSH traffic on port 10022
156 sudo iptables -A INPUT -p tcp --dport 10022 -j ACCEPT
156 sudo iptables -A INPUT -p tcp --dport 10022 -j ACCEPT
157
157
158 # Allow incoming HTML traffic on port 80 and 443
158 # Allow incoming HTML traffic on port 80 and 443
159 iptables -A INPUT -p tcp -m tcp --dport 80 -j ACCEPT
159 iptables -A INPUT -p tcp -m tcp --dport 80 -j ACCEPT
160 iptables -A INPUT -p tcp -m tcp --dport 443 -j ACCEPT
160 iptables -A INPUT -p tcp -m tcp --dport 443 -j ACCEPT
161
161
162 Saving your IP Table rules, and restoring them from file.
162 Saving your IP Table rules, and restoring them from file.
163
163
164 .. code-block:: bash
164 .. code-block:: bash
165
165
166 # Save you IP Table Rules
166 # Save you IP Table Rules
167 iptables-save
167 iptables-save
168
168
169 # Save your IP Table Rules to a file
169 # Save your IP Table Rules to a file
170 sudo sh -c "iptables-save > /etc/iptables.rules"
170 sudo sh -c "iptables-save > /etc/iptables.rules"
171
171
172 # Restore your IP Table rules from file
172 # Restore your IP Table rules from file
173 iptables-restore < /etc/iptables.rules
173 iptables-restore < /etc/iptables.rules
174
174
175 .. _OpenSSL PKI tutorial: https://pki-tutorial.readthedocs.org/en/latest/#
175 .. _OpenSSL PKI tutorial: https://pki-tutorial.readthedocs.org/en/latest/#
176 .. _Cloudflare PKI post: https://blog.cloudflare.com/how-to-build-your-own-public-key-infrastructure/
176 .. _Cloudflare PKI post: https://blog.cloudflare.com/how-to-build-your-own-public-key-infrastructure/
177 .. _IpTables: https://help.ubuntu.com/community/IptablesHowTo
177 .. _IpTables: https://help.ubuntu.com/community/IptablesHowTo
178 .. _IPFW: https://www.freebsd.org/doc/handbook/firewalls-ipfw.html
178 .. _IPFW: https://www.freebsd.org/doc/handbook/firewalls-ipfw.html
179 .. _IPFILTER: https://www.freebsd.org/doc/handbook/firewalls-ipf.html
179 .. _IPFILTER: https://www.freebsd.org/doc/handbook/firewalls-ipf.html
@@ -1,32 +1,32 b''
1 .. _hg-lrg-loc:
1 .. _hg-lrg-loc:
2
2
3 Change the |hg| Large Files Location
3 Change the |hg| Large Files Location
4 ------------------------------------
4 ------------------------------------
5
5
6 |RCE| manages |hg| larges files from the following default location
6 |RCE| manages |hg| larges files from the following default location
7 :file:`/home/{user}/repos/.cache/largefiles`. If you wish to change this, use
7 :file:`/home/{user}/repos/.cache/largefiles`. If you wish to change this, use
8 the following steps:
8 the following steps:
9
9
10 1. Open ishell from the terminal and use it to log into the |RCE| database by
10 1. Open ishell from the terminal and use it to log into the |RCE| database by
11 specifying the instance :file:`rhodecode.ini` file.
11 specifying the instance :file:`rhodecode.ini` file.
12
12
13 .. code-block:: bash
13 .. code-block:: bash
14
14
15 # Open iShell from the terminal and set ini file
15 # Open iShell from the terminal and set ini file
16 $ .rccontrol/enterprise-1/profile/bin/paster ishell .rccontrol/enterprise-1/rhodecode.ini
16 $ .rccontrol/enterprise-1/profile/bin/paster ishell .rccontrol/enterprise-1/rhodecode.ini
17
17
18 2. Run the following commands, and ensure that |RCE| has write access to the
18 2. Run the following commands, and ensure that |RCE| has write access to the
19 new directory:
19 new directory:
20
20
21 .. code-block:: mysql
21 .. code-block:: bash
22
22
23 # Once logged into the database, use SQL to redirect
23 # Once logged into the database, use SQL to redirect
24 # the large files location
24 # the large files location
25 In [1]: from rhodecode.model.settings import SettingsModel
25 In [1]: from rhodecode.model.settings import SettingsModel
26 In [2]: SettingsModel().get_ui_by_key('usercache')
26 In [2]: SettingsModel().get_ui_by_key('usercache')
27 Out[2]: <RhodeCodeUi[largefiles]usercache=>/mnt/hgfs/shared/workspace/xxxx/.cache/largefiles]>
27 Out[2]: <RhodeCodeUi[largefiles]usercache=>/mnt/hgfs/shared/workspace/xxxx/.cache/largefiles]>
28
28
29 In [3]: largefiles_cache = SettingsModel().get_ui_by_key('usercache')
29 In [3]: largefiles_cache = SettingsModel().get_ui_by_key('usercache')
30 In [4]: largefiles_cache.ui_value = '/new/path’
30 In [4]: largefiles_cache.ui_value = '/new/path’
31 In [5]: Session().add(largefiles_cache);Session().commit()
31 In [5]: Session().add(largefiles_cache);Session().commit()
32
32
@@ -1,77 +1,77 b''
1 .. _deprecated-methods-ref:
1 .. _deprecated-methods-ref:
2
2
3 deprecated methods
3 deprecated methods
4 ==================
4 ==================
5
5
6 changeset_comment
6 changeset_comment
7 -----------------
7 -----------------
8
8
9 .. py:function:: changeset_comment(apiuser, repoid, revision, message, userid=<Optional:<OptionalAttr:apiuser>>, status=<Optional:None>)
9 .. py:function:: changeset_comment(apiuser, repoid, revision, message, userid=<Optional:<OptionalAttr:apiuser>>, status=<Optional:None>)
10
10
11 .. deprecated:: 3.4.0
11 .. deprecated:: 3.4.0
12
12
13 Please use method `comment_commit` instead.
13 Please use method `comment_commit` instead.
14
14
15
15
16 Set a changeset comment, and optionally change the status of the
16 Set a changeset comment, and optionally change the status of the
17 changeset.
17 changeset.
18
18
19 This command can only be run using an |authtoken| with admin
19 This command can only be run using an |authtoken| with admin
20 permissions on the |repo|.
20 permissions on the |repo|.
21
21
22 :param apiuser: This is filled automatically from the |authtoken|.
22 :param apiuser: This is filled automatically from the |authtoken|.
23 :type apiuser: AuthUser
23 :type apiuser: AuthUser
24 :param repoid: Set the repository name or repository ID.
24 :param repoid: Set the repository name or repository ID.
25 :type repoid: str or int
25 :type repoid: str or int
26 :param revision: Specify the revision for which to set a comment.
26 :param revision: Specify the revision for which to set a comment.
27 :type revision: str
27 :type revision: str
28 :param message: The comment text.
28 :param message: The comment text.
29 :type message: str
29 :type message: str
30 :param userid: Set the user name of the comment creator.
30 :param userid: Set the user name of the comment creator.
31 :type userid: Optional(str or int)
31 :type userid: Optional(str or int)
32 :param status: Set the comment status. The following are valid options:
32 :param status: Set the comment status. The following are valid options:
33 * not_reviewed
33 * not_reviewed
34 * approved
34 * approved
35 * rejected
35 * rejected
36 * under_review
36 * under_review
37 :type status: str
37 :type status: str
38
38
39 Example error output:
39 Example error output:
40
40
41 .. code-block:: json
41 .. code-block:: bash
42
42
43 {
43 {
44 "id" : <id_given_in_input>,
44 "id" : <id_given_in_input>,
45 "result" : {
45 "result" : {
46 "msg": "Commented on commit `<revision>` for repository `<repoid>`",
46 "msg": "Commented on commit `<revision>` for repository `<repoid>`",
47 "status_change": null or <status>,
47 "status_change": null or <status>,
48 "success": true
48 "success": true
49 },
49 },
50 "error" : null
50 "error" : null
51 }
51 }
52
52
53
53
54 get_locks
54 get_locks
55 ---------
55 ---------
56
56
57 .. py:function:: get_locks(apiuser, userid=<Optional:<OptionalAttr:apiuser>>)
57 .. py:function:: get_locks(apiuser, userid=<Optional:<OptionalAttr:apiuser>>)
58
58
59 .. deprecated:: 4.0.0
59 .. deprecated:: 4.0.0
60
60
61 Please use method `get_user_locks` instead.
61 Please use method `get_user_locks` instead.
62
62
63 None
63 None
64
64
65
65
66 show_ip
66 show_ip
67 -------
67 -------
68
68
69 .. py:function:: show_ip(apiuser, userid=<Optional:<OptionalAttr:apiuser>>)
69 .. py:function:: show_ip(apiuser, userid=<Optional:<OptionalAttr:apiuser>>)
70
70
71 .. deprecated:: 4.0.0
71 .. deprecated:: 4.0.0
72
72
73 Please use method `get_ip` instead.
73 Please use method `get_ip` instead.
74
74
75 None
75 None
76
76
77
77
@@ -1,71 +1,71 b''
1 .. _license-methods-ref:
1 .. _license-methods-ref:
2
2
3 license methods
3 license methods
4 ===============
4 ===============
5
5
6 get_license_info (EE only)
6 get_license_info (EE only)
7 ----------------
7 --------------------------
8
8
9 .. py:function:: get_license_info(apiuser)
9 .. py:function:: get_license_info(apiuser)
10
10
11 Returns the |RCE| license information.
11 Returns the |RCE| license information.
12
12
13 :param apiuser: This is filled automatically from the |authtoken|.
13 :param apiuser: This is filled automatically from the |authtoken|.
14 :type apiuser: AuthUser
14 :type apiuser: AuthUser
15
15
16 Example output:
16 Example output:
17
17
18 .. code-block:: bash
18 .. code-block:: bash
19
19
20 id : <id_given_in_input>
20 id : <id_given_in_input>
21 result : {
21 result : {
22 'rhodecode_version': <rhodecode version>,
22 'rhodecode_version': <rhodecode version>,
23 'token': <license token>,
23 'token': <license token>,
24 'issued_to': <license owner>,
24 'issued_to': <license owner>,
25 'issued_on': <license issue date>,
25 'issued_on': <license issue date>,
26 'expires_on': <license expiration date>,
26 'expires_on': <license expiration date>,
27 'type': <license type>,
27 'type': <license type>,
28 'users_limit': <license users limit>,
28 'users_limit': <license users limit>,
29 'key': <license key>
29 'key': <license key>
30 }
30 }
31 error : null
31 error : null
32
32
33
33
34 set_license_key (EE only)
34 set_license_key (EE only)
35 ---------------
35 -------------------------
36
36
37 .. py:function:: set_license_key(apiuser, key)
37 .. py:function:: set_license_key(apiuser, key)
38
38
39 Sets the |RCE| license key.
39 Sets the |RCE| license key.
40
40
41 :param apiuser: This is filled automatically from the |authtoken|.
41 :param apiuser: This is filled automatically from the |authtoken|.
42 :type apiuser: AuthUser
42 :type apiuser: AuthUser
43 :param key: This is the license key to be set.
43 :param key: This is the license key to be set.
44 :type key: str
44 :type key: str
45
45
46 Example output:
46 Example output:
47
47
48 .. code-block:: bash
48 .. code-block:: bash
49
49
50 id : <id_given_in_input>
50 id : <id_given_in_input>
51 result: {
51 result: {
52 "msg" : "updated license information",
52 "msg" : "updated license information",
53 "key": <key>
53 "key": <key>
54 }
54 }
55 error: null
55 error: null
56
56
57 Example error output:
57 Example error output:
58
58
59 .. code-block:: bash
59 .. code-block:: bash
60
60
61 id : <id_given_in_input>
61 id : <id_given_in_input>
62 result : null
62 result : null
63 error : {
63 error : {
64 "license key is not valid"
64 "license key is not valid"
65 or
65 or
66 "trial licenses cannot be uploaded"
66 "trial licenses cannot be uploaded"
67 or
67 or
68 "error occurred while updating license"
68 "error occurred while updating license"
69 }
69 }
70
70
71
71
@@ -1,350 +1,350 b''
1 .. _repo-group-methods-ref:
1 .. _repo-group-methods-ref:
2
2
3 repo_group methods
3 repo_group methods
4 ==================
4 ==================
5
5
6 create_repo_group
6 create_repo_group
7 -----------------
7 -----------------
8
8
9 .. py:function:: create_repo_group(apiuser, group_name, description=<Optional:''>, owner=<Optional:<OptionalAttr:apiuser>>, copy_permissions=<Optional:False>)
9 .. py:function:: create_repo_group(apiuser, group_name, description=<Optional:''>, owner=<Optional:<OptionalAttr:apiuser>>, copy_permissions=<Optional:False>)
10
10
11 Creates a repository group.
11 Creates a repository group.
12
12
13 * If the repository group name contains "/", all the required repository
13 * If the repository group name contains "/", all the required repository
14 groups will be created.
14 groups will be created.
15
15
16 For example "foo/bar/baz" will create |repo| groups "foo" and "bar"
16 For example "foo/bar/baz" will create |repo| groups "foo" and "bar"
17 (with "foo" as parent). It will also create the "baz" repository
17 (with "foo" as parent). It will also create the "baz" repository
18 with "bar" as |repo| group.
18 with "bar" as |repo| group.
19
19
20 This command can only be run using an |authtoken| with admin
20 This command can only be run using an |authtoken| with admin
21 permissions.
21 permissions.
22
22
23 :param apiuser: This is filled automatically from the |authtoken|.
23 :param apiuser: This is filled automatically from the |authtoken|.
24 :type apiuser: AuthUser
24 :type apiuser: AuthUser
25 :param group_name: Set the repository group name.
25 :param group_name: Set the repository group name.
26 :type group_name: str
26 :type group_name: str
27 :param description: Set the |repo| group description.
27 :param description: Set the |repo| group description.
28 :type description: str
28 :type description: str
29 :param owner: Set the |repo| group owner.
29 :param owner: Set the |repo| group owner.
30 :type owner: str
30 :type owner: str
31 :param copy_permissions:
31 :param copy_permissions:
32 :type copy_permissions:
32 :type copy_permissions:
33
33
34 Example output:
34 Example output:
35
35
36 .. code-block:: bash
36 .. code-block:: bash
37
37
38 id : <id_given_in_input>
38 id : <id_given_in_input>
39 result : {
39 result : {
40 "msg": "Created new repo group `<repo_group_name>`"
40 "msg": "Created new repo group `<repo_group_name>`"
41 "repo_group": <repogroup_object>
41 "repo_group": <repogroup_object>
42 }
42 }
43 error : null
43 error : null
44
44
45
45
46 Example error output:
46 Example error output:
47
47
48 .. code-block:: bash
48 .. code-block:: bash
49
49
50 id : <id_given_in_input>
50 id : <id_given_in_input>
51 result : null
51 result : null
52 error : {
52 error : {
53 failed to create repo group `<repogroupid>`
53 failed to create repo group `<repogroupid>`
54 }
54 }
55
55
56
56
57 delete_repo_group
57 delete_repo_group
58 -----------------
58 -----------------
59
59
60 .. py:function:: delete_repo_group(apiuser, repogroupid)
60 .. py:function:: delete_repo_group(apiuser, repogroupid)
61
61
62 Deletes a |repo| group.
62 Deletes a |repo| group.
63
63
64 :param apiuser: This is filled automatically from the |authtoken|.
64 :param apiuser: This is filled automatically from the |authtoken|.
65 :type apiuser: AuthUser
65 :type apiuser: AuthUser
66 :param repogroupid: Set the name or ID of repository group to be
66 :param repogroupid: Set the name or ID of repository group to be
67 deleted.
67 deleted.
68 :type repogroupid: str or int
68 :type repogroupid: str or int
69
69
70 Example output:
70 Example output:
71
71
72 .. code-block:: bash
72 .. code-block:: bash
73
73
74 id : <id_given_in_input>
74 id : <id_given_in_input>
75 result : {
75 result : {
76 'msg': 'deleted repo group ID:<repogroupid> <repogroupname>
76 'msg': 'deleted repo group ID:<repogroupid> <repogroupname>'
77 'repo_group': null
77 'repo_group': null
78 }
78 }
79 error : null
79 error : null
80
80
81 Example error output:
81 Example error output:
82
82
83 .. code-block:: bash
83 .. code-block:: bash
84
84
85 id : <id_given_in_input>
85 id : <id_given_in_input>
86 result : null
86 result : null
87 error : {
87 error : {
88 "failed to delete repo group ID:<repogroupid> <repogroupname>"
88 "failed to delete repo group ID:<repogroupid> <repogroupname>"
89 }
89 }
90
90
91
91
92 get_repo_group
92 get_repo_group
93 --------------
93 --------------
94
94
95 .. py:function:: get_repo_group(apiuser, repogroupid)
95 .. py:function:: get_repo_group(apiuser, repogroupid)
96
96
97 Return the specified |repo| group, along with permissions,
97 Return the specified |repo| group, along with permissions,
98 and repositories inside the group
98 and repositories inside the group
99
99
100 :param apiuser: This is filled automatically from the |authtoken|.
100 :param apiuser: This is filled automatically from the |authtoken|.
101 :type apiuser: AuthUser
101 :type apiuser: AuthUser
102 :param repogroupid: Specify the name of ID of the repository group.
102 :param repogroupid: Specify the name of ID of the repository group.
103 :type repogroupid: str or int
103 :type repogroupid: str or int
104
104
105
105
106 Example output:
106 Example output:
107
107
108 .. code-block:: bash
108 .. code-block:: bash
109
109
110 {
110 {
111 "error": null,
111 "error": null,
112 "id": repo-group-id,
112 "id": repo-group-id,
113 "result": {
113 "result": {
114 "group_description": "repo group description",
114 "group_description": "repo group description",
115 "group_id": 14,
115 "group_id": 14,
116 "group_name": "group name",
116 "group_name": "group name",
117 "members": [
117 "members": [
118 {
118 {
119 "name": "super-admin-username",
119 "name": "super-admin-username",
120 "origin": "super-admin",
120 "origin": "super-admin",
121 "permission": "group.admin",
121 "permission": "group.admin",
122 "type": "user"
122 "type": "user"
123 },
123 },
124 {
124 {
125 "name": "owner-name",
125 "name": "owner-name",
126 "origin": "owner",
126 "origin": "owner",
127 "permission": "group.admin",
127 "permission": "group.admin",
128 "type": "user"
128 "type": "user"
129 },
129 },
130 {
130 {
131 "name": "user-group-name",
131 "name": "user-group-name",
132 "origin": "permission",
132 "origin": "permission",
133 "permission": "group.write",
133 "permission": "group.write",
134 "type": "user_group"
134 "type": "user_group"
135 }
135 }
136 ],
136 ],
137 "owner": "owner-name",
137 "owner": "owner-name",
138 "parent_group": null,
138 "parent_group": null,
139 "repositories": [ repo-list ]
139 "repositories": [ repo-list ]
140 }
140 }
141 }
141 }
142
142
143
143
144 get_repo_groups
144 get_repo_groups
145 ---------------
145 ---------------
146
146
147 .. py:function:: get_repo_groups(apiuser)
147 .. py:function:: get_repo_groups(apiuser)
148
148
149 Returns all repository groups.
149 Returns all repository groups.
150
150
151 :param apiuser: This is filled automatically from the |authtoken|.
151 :param apiuser: This is filled automatically from the |authtoken|.
152 :type apiuser: AuthUser
152 :type apiuser: AuthUser
153
153
154
154
155 grant_user_group_permission_to_repo_group
155 grant_user_group_permission_to_repo_group
156 -----------------------------------------
156 -----------------------------------------
157
157
158 .. py:function:: grant_user_group_permission_to_repo_group(apiuser, repogroupid, usergroupid, perm, apply_to_children=<Optional:'none'>)
158 .. py:function:: grant_user_group_permission_to_repo_group(apiuser, repogroupid, usergroupid, perm, apply_to_children=<Optional:'none'>)
159
159
160 Grant permission for a user group on given repository group, or update
160 Grant permission for a user group on given repository group, or update
161 existing permissions if found.
161 existing permissions if found.
162
162
163 This command can only be run using an |authtoken| with admin
163 This command can only be run using an |authtoken| with admin
164 permissions on the |repo| group.
164 permissions on the |repo| group.
165
165
166 :param apiuser: This is filled automatically from the |authtoken|.
166 :param apiuser: This is filled automatically from the |authtoken|.
167 :type apiuser: AuthUser
167 :type apiuser: AuthUser
168 :param repogroupid: Set the name or id of repository group
168 :param repogroupid: Set the name or id of repository group
169 :type repogroupid: str or int
169 :type repogroupid: str or int
170 :param usergroupid: id of usergroup
170 :param usergroupid: id of usergroup
171 :type usergroupid: str or int
171 :type usergroupid: str or int
172 :param perm: (group.(none|read|write|admin))
172 :param perm: (group.(none|read|write|admin))
173 :type perm: str
173 :type perm: str
174 :param apply_to_children: 'none', 'repos', 'groups', 'all'
174 :param apply_to_children: 'none', 'repos', 'groups', 'all'
175 :type apply_to_children: str
175 :type apply_to_children: str
176
176
177 Example output:
177 Example output:
178
178
179 .. code-block:: bash
179 .. code-block:: bash
180
180
181 id : <id_given_in_input>
181 id : <id_given_in_input>
182 result : {
182 result : {
183 "msg" : "Granted perm: `<perm>` (recursive:<apply_to_children>) for user group: `<usersgroupname>` in repo group: `<repo_group_name>`",
183 "msg" : "Granted perm: `<perm>` (recursive:<apply_to_children>) for user group: `<usersgroupname>` in repo group: `<repo_group_name>`",
184 "success": true
184 "success": true
185
185
186 }
186 }
187 error : null
187 error : null
188
188
189 Example error output:
189 Example error output:
190
190
191 .. code-block:: bash
191 .. code-block:: bash
192
192
193 id : <id_given_in_input>
193 id : <id_given_in_input>
194 result : null
194 result : null
195 error : {
195 error : {
196 "failed to edit permission for user group: `<usergroup>` in repo group: `<repo_group_name>`"
196 "failed to edit permission for user group: `<usergroup>` in repo group: `<repo_group_name>`"
197 }
197 }
198
198
199
199
200 grant_user_permission_to_repo_group
200 grant_user_permission_to_repo_group
201 -----------------------------------
201 -----------------------------------
202
202
203 .. py:function:: grant_user_permission_to_repo_group(apiuser, repogroupid, userid, perm, apply_to_children=<Optional:'none'>)
203 .. py:function:: grant_user_permission_to_repo_group(apiuser, repogroupid, userid, perm, apply_to_children=<Optional:'none'>)
204
204
205 Grant permission for a user on the given repository group, or update
205 Grant permission for a user on the given repository group, or update
206 existing permissions if found.
206 existing permissions if found.
207
207
208 This command can only be run using an |authtoken| with admin
208 This command can only be run using an |authtoken| with admin
209 permissions.
209 permissions.
210
210
211 :param apiuser: This is filled automatically from the |authtoken|.
211 :param apiuser: This is filled automatically from the |authtoken|.
212 :type apiuser: AuthUser
212 :type apiuser: AuthUser
213 :param repogroupid: Set the name or ID of repository group.
213 :param repogroupid: Set the name or ID of repository group.
214 :type repogroupid: str or int
214 :type repogroupid: str or int
215 :param userid: Set the user name.
215 :param userid: Set the user name.
216 :type userid: str
216 :type userid: str
217 :param perm: (group.(none|read|write|admin))
217 :param perm: (group.(none|read|write|admin))
218 :type perm: str
218 :type perm: str
219 :param apply_to_children: 'none', 'repos', 'groups', 'all'
219 :param apply_to_children: 'none', 'repos', 'groups', 'all'
220 :type apply_to_children: str
220 :type apply_to_children: str
221
221
222 Example output:
222 Example output:
223
223
224 .. code-block:: bash
224 .. code-block:: bash
225
225
226 id : <id_given_in_input>
226 id : <id_given_in_input>
227 result: {
227 result: {
228 "msg" : "Granted perm: `<perm>` (recursive:<apply_to_children>) for user: `<username>` in repo group: `<repo_group_name>`",
228 "msg" : "Granted perm: `<perm>` (recursive:<apply_to_children>) for user: `<username>` in repo group: `<repo_group_name>`",
229 "success": true
229 "success": true
230 }
230 }
231 error: null
231 error: null
232
232
233 Example error output:
233 Example error output:
234
234
235 .. code-block:: bash
235 .. code-block:: bash
236
236
237 id : <id_given_in_input>
237 id : <id_given_in_input>
238 result : null
238 result : null
239 error : {
239 error : {
240 "failed to edit permission for user: `<userid>` in repo group: `<repo_group_name>`"
240 "failed to edit permission for user: `<userid>` in repo group: `<repo_group_name>`"
241 }
241 }
242
242
243
243
244 revoke_user_group_permission_from_repo_group
244 revoke_user_group_permission_from_repo_group
245 --------------------------------------------
245 --------------------------------------------
246
246
247 .. py:function:: revoke_user_group_permission_from_repo_group(apiuser, repogroupid, usergroupid, apply_to_children=<Optional:'none'>)
247 .. py:function:: revoke_user_group_permission_from_repo_group(apiuser, repogroupid, usergroupid, apply_to_children=<Optional:'none'>)
248
248
249 Revoke permission for user group on given repository.
249 Revoke permission for user group on given repository.
250
250
251 This command can only be run using an |authtoken| with admin
251 This command can only be run using an |authtoken| with admin
252 permissions on the |repo| group.
252 permissions on the |repo| group.
253
253
254 :param apiuser: This is filled automatically from the |authtoken|.
254 :param apiuser: This is filled automatically from the |authtoken|.
255 :type apiuser: AuthUser
255 :type apiuser: AuthUser
256 :param repogroupid: name or id of repository group
256 :param repogroupid: name or id of repository group
257 :type repogroupid: str or int
257 :type repogroupid: str or int
258 :param usergroupid:
258 :param usergroupid:
259 :param apply_to_children: 'none', 'repos', 'groups', 'all'
259 :param apply_to_children: 'none', 'repos', 'groups', 'all'
260 :type apply_to_children: str
260 :type apply_to_children: str
261
261
262 Example output:
262 Example output:
263
263
264 .. code-block:: bash
264 .. code-block:: bash
265
265
266 id : <id_given_in_input>
266 id : <id_given_in_input>
267 result: {
267 result: {
268 "msg" : "Revoked perm (recursive:<apply_to_children>) for user group: `<usersgroupname>` in repo group: `<repo_group_name>`",
268 "msg" : "Revoked perm (recursive:<apply_to_children>) for user group: `<usersgroupname>` in repo group: `<repo_group_name>`",
269 "success": true
269 "success": true
270 }
270 }
271 error: null
271 error: null
272
272
273 Example error output:
273 Example error output:
274
274
275 .. code-block:: bash
275 .. code-block:: bash
276
276
277 id : <id_given_in_input>
277 id : <id_given_in_input>
278 result : null
278 result : null
279 error : {
279 error : {
280 "failed to edit permission for user group: `<usergroup>` in repo group: `<repo_group_name>`"
280 "failed to edit permission for user group: `<usergroup>` in repo group: `<repo_group_name>`"
281 }
281 }
282
282
283
283
284 revoke_user_permission_from_repo_group
284 revoke_user_permission_from_repo_group
285 --------------------------------------
285 --------------------------------------
286
286
287 .. py:function:: revoke_user_permission_from_repo_group(apiuser, repogroupid, userid, apply_to_children=<Optional:'none'>)
287 .. py:function:: revoke_user_permission_from_repo_group(apiuser, repogroupid, userid, apply_to_children=<Optional:'none'>)
288
288
289 Revoke permission for a user in a given repository group.
289 Revoke permission for a user in a given repository group.
290
290
291 This command can only be run using an |authtoken| with admin
291 This command can only be run using an |authtoken| with admin
292 permissions on the |repo| group.
292 permissions on the |repo| group.
293
293
294 :param apiuser: This is filled automatically from the |authtoken|.
294 :param apiuser: This is filled automatically from the |authtoken|.
295 :type apiuser: AuthUser
295 :type apiuser: AuthUser
296 :param repogroupid: Set the name or ID of the repository group.
296 :param repogroupid: Set the name or ID of the repository group.
297 :type repogroupid: str or int
297 :type repogroupid: str or int
298 :param userid: Set the user name to revoke.
298 :param userid: Set the user name to revoke.
299 :type userid: str
299 :type userid: str
300 :param apply_to_children: 'none', 'repos', 'groups', 'all'
300 :param apply_to_children: 'none', 'repos', 'groups', 'all'
301 :type apply_to_children: str
301 :type apply_to_children: str
302
302
303 Example output:
303 Example output:
304
304
305 .. code-block:: bash
305 .. code-block:: bash
306
306
307 id : <id_given_in_input>
307 id : <id_given_in_input>
308 result: {
308 result: {
309 "msg" : "Revoked perm (recursive:<apply_to_children>) for user: `<username>` in repo group: `<repo_group_name>`",
309 "msg" : "Revoked perm (recursive:<apply_to_children>) for user: `<username>` in repo group: `<repo_group_name>`",
310 "success": true
310 "success": true
311 }
311 }
312 error: null
312 error: null
313
313
314 Example error output:
314 Example error output:
315
315
316 .. code-block:: bash
316 .. code-block:: bash
317
317
318 id : <id_given_in_input>
318 id : <id_given_in_input>
319 result : null
319 result : null
320 error : {
320 error : {
321 "failed to edit permission for user: `<userid>` in repo group: `<repo_group_name>`"
321 "failed to edit permission for user: `<userid>` in repo group: `<repo_group_name>`"
322 }
322 }
323
323
324
324
325 update_repo_group
325 update_repo_group
326 -----------------
326 -----------------
327
327
328 .. py:function:: update_repo_group(apiuser, repogroupid, group_name=<Optional:''>, description=<Optional:''>, owner=<Optional:<OptionalAttr:apiuser>>, parent=<Optional:None>, enable_locking=<Optional:False>)
328 .. py:function:: update_repo_group(apiuser, repogroupid, group_name=<Optional:''>, description=<Optional:''>, owner=<Optional:<OptionalAttr:apiuser>>, parent=<Optional:None>, enable_locking=<Optional:False>)
329
329
330 Updates repository group with the details given.
330 Updates repository group with the details given.
331
331
332 This command can only be run using an |authtoken| with admin
332 This command can only be run using an |authtoken| with admin
333 permissions.
333 permissions.
334
334
335 :param apiuser: This is filled automatically from the |authtoken|.
335 :param apiuser: This is filled automatically from the |authtoken|.
336 :type apiuser: AuthUser
336 :type apiuser: AuthUser
337 :param repogroupid: Set the ID of repository group.
337 :param repogroupid: Set the ID of repository group.
338 :type repogroupid: str or int
338 :type repogroupid: str or int
339 :param group_name: Set the name of the |repo| group.
339 :param group_name: Set the name of the |repo| group.
340 :type group_name: str
340 :type group_name: str
341 :param description: Set a description for the group.
341 :param description: Set a description for the group.
342 :type description: str
342 :type description: str
343 :param owner: Set the |repo| group owner.
343 :param owner: Set the |repo| group owner.
344 :type owner: str
344 :type owner: str
345 :param parent: Set the |repo| group parent.
345 :param parent: Set the |repo| group parent.
346 :type parent: str or int
346 :type parent: str or int
347 :param enable_locking: Enable |repo| locking. The default is false.
347 :param enable_locking: Enable |repo| locking. The default is false.
348 :type enable_locking: bool
348 :type enable_locking: bool
349
349
350
350
@@ -1,967 +1,967 b''
1 .. _repo-methods-ref:
1 .. _repo-methods-ref:
2
2
3 repo methods
3 repo methods
4 ============
4 ============
5
5
6 add_field_to_repo
6 add_field_to_repo
7 -----------------
7 -----------------
8
8
9 .. py:function:: add_field_to_repo(apiuser, repoid, key, label=<Optional:''>, description=<Optional:''>)
9 .. py:function:: add_field_to_repo(apiuser, repoid, key, label=<Optional:''>, description=<Optional:''>)
10
10
11 Adds an extra field to a repository.
11 Adds an extra field to a repository.
12
12
13 This command can only be run using an |authtoken| with at least
13 This command can only be run using an |authtoken| with at least
14 write permissions to the |repo|.
14 write permissions to the |repo|.
15
15
16 :param apiuser: This is filled automatically from the |authtoken|.
16 :param apiuser: This is filled automatically from the |authtoken|.
17 :type apiuser: AuthUser
17 :type apiuser: AuthUser
18 :param repoid: Set the repository name or repository id.
18 :param repoid: Set the repository name or repository id.
19 :type repoid: str or int
19 :type repoid: str or int
20 :param key: Create a unique field key for this repository.
20 :param key: Create a unique field key for this repository.
21 :type key: str
21 :type key: str
22 :param label:
22 :param label:
23 :type label: Optional(str)
23 :type label: Optional(str)
24 :param description:
24 :param description:
25 :type description: Optional(str)
25 :type description: Optional(str)
26
26
27
27
28 comment_commit
28 comment_commit
29 --------------
29 --------------
30
30
31 .. py:function:: comment_commit(apiuser, repoid, commit_id, message, userid=<Optional:<OptionalAttr:apiuser>>, status=<Optional:None>)
31 .. py:function:: comment_commit(apiuser, repoid, commit_id, message, userid=<Optional:<OptionalAttr:apiuser>>, status=<Optional:None>)
32
32
33 Set a commit comment, and optionally change the status of the commit.
33 Set a commit comment, and optionally change the status of the commit.
34
34
35 :param apiuser: This is filled automatically from the |authtoken|.
35 :param apiuser: This is filled automatically from the |authtoken|.
36 :type apiuser: AuthUser
36 :type apiuser: AuthUser
37 :param repoid: Set the repository name or repository ID.
37 :param repoid: Set the repository name or repository ID.
38 :type repoid: str or int
38 :type repoid: str or int
39 :param commit_id: Specify the commit_id for which to set a comment.
39 :param commit_id: Specify the commit_id for which to set a comment.
40 :type commit_id: str
40 :type commit_id: str
41 :param message: The comment text.
41 :param message: The comment text.
42 :type message: str
42 :type message: str
43 :param userid: Set the user name of the comment creator.
43 :param userid: Set the user name of the comment creator.
44 :type userid: Optional(str or int)
44 :type userid: Optional(str or int)
45 :param status: status, one of 'not_reviewed', 'approved', 'rejected',
45 :param status: status, one of 'not_reviewed', 'approved', 'rejected',
46 'under_review'
46 'under_review'
47 :type status: str
47 :type status: str
48
48
49 Example error output:
49 Example error output:
50
50
51 .. code-block:: json
51 .. code-block:: bash
52
52
53 {
53 {
54 "id" : <id_given_in_input>,
54 "id" : <id_given_in_input>,
55 "result" : {
55 "result" : {
56 "msg": "Commented on commit `<commit_id>` for repository `<repoid>`",
56 "msg": "Commented on commit `<commit_id>` for repository `<repoid>`",
57 "status_change": null or <status>,
57 "status_change": null or <status>,
58 "success": true
58 "success": true
59 },
59 },
60 "error" : null
60 "error" : null
61 }
61 }
62
62
63
63
64 create_repo
64 create_repo
65 -----------
65 -----------
66
66
67 .. 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>)
67 .. 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>)
68
68
69 Creates a repository.
69 Creates a repository.
70
70
71 * If the repository name contains "/", all the required repository
71 * If the repository name contains "/", all the required repository
72 groups will be created.
72 groups will be created.
73
73
74 For example "foo/bar/baz" will create |repo| groups "foo" and "bar"
74 For example "foo/bar/baz" will create |repo| groups "foo" and "bar"
75 (with "foo" as parent). It will also create the "baz" repository
75 (with "foo" as parent). It will also create the "baz" repository
76 with "bar" as |repo| group.
76 with "bar" as |repo| group.
77
77
78 This command can only be run using an |authtoken| with at least
78 This command can only be run using an |authtoken| with at least
79 write permissions to the |repo|.
79 write permissions to the |repo|.
80
80
81 :param apiuser: This is filled automatically from the |authtoken|.
81 :param apiuser: This is filled automatically from the |authtoken|.
82 :type apiuser: AuthUser
82 :type apiuser: AuthUser
83 :param repo_name: Set the repository name.
83 :param repo_name: Set the repository name.
84 :type repo_name: str
84 :type repo_name: str
85 :param repo_type: Set the repository type; 'hg','git', or 'svn'.
85 :param repo_type: Set the repository type; 'hg','git', or 'svn'.
86 :type repo_type: str
86 :type repo_type: str
87 :param owner: user_id or username
87 :param owner: user_id or username
88 :type owner: Optional(str)
88 :type owner: Optional(str)
89 :param description: Set the repository description.
89 :param description: Set the repository description.
90 :type description: Optional(str)
90 :type description: Optional(str)
91 :param private:
91 :param private:
92 :type private: bool
92 :type private: bool
93 :param clone_uri:
93 :param clone_uri:
94 :type clone_uri: str
94 :type clone_uri: str
95 :param landing_rev: <rev_type>:<rev>
95 :param landing_rev: <rev_type>:<rev>
96 :type landing_rev: str
96 :type landing_rev: str
97 :param enable_locking:
97 :param enable_locking:
98 :type enable_locking: bool
98 :type enable_locking: bool
99 :param enable_downloads:
99 :param enable_downloads:
100 :type enable_downloads: bool
100 :type enable_downloads: bool
101 :param enable_statistics:
101 :param enable_statistics:
102 :type enable_statistics: bool
102 :type enable_statistics: bool
103 :param copy_permissions: Copy permission from group in which the
103 :param copy_permissions: Copy permission from group in which the
104 repository is being created.
104 repository is being created.
105 :type copy_permissions: bool
105 :type copy_permissions: bool
106
106
107
107
108 Example output:
108 Example output:
109
109
110 .. code-block:: bash
110 .. code-block:: bash
111
111
112 id : <id_given_in_input>
112 id : <id_given_in_input>
113 result: {
113 result: {
114 "msg": "Created new repository `<reponame>`",
114 "msg": "Created new repository `<reponame>`",
115 "success": true,
115 "success": true,
116 "task": "<celery task id or None if done sync>"
116 "task": "<celery task id or None if done sync>"
117 }
117 }
118 error: null
118 error: null
119
119
120
120
121 Example error output:
121 Example error output:
122
122
123 .. code-block:: bash
123 .. code-block:: bash
124
124
125 id : <id_given_in_input>
125 id : <id_given_in_input>
126 result : null
126 result : null
127 error : {
127 error : {
128 'failed to create repository `<repo_name>`
128 'failed to create repository `<repo_name>`'
129 }
129 }
130
130
131
131
132 delete_repo
132 delete_repo
133 -----------
133 -----------
134
134
135 .. py:function:: delete_repo(apiuser, repoid, forks=<Optional:''>)
135 .. py:function:: delete_repo(apiuser, repoid, forks=<Optional:''>)
136
136
137 Deletes a repository.
137 Deletes a repository.
138
138
139 * When the `forks` parameter is set it's possible to detach or delete
139 * When the `forks` parameter is set it's possible to detach or delete
140 forks of deleted repository.
140 forks of deleted repository.
141
141
142 This command can only be run using an |authtoken| with admin
142 This command can only be run using an |authtoken| with admin
143 permissions on the |repo|.
143 permissions on the |repo|.
144
144
145 :param apiuser: This is filled automatically from the |authtoken|.
145 :param apiuser: This is filled automatically from the |authtoken|.
146 :type apiuser: AuthUser
146 :type apiuser: AuthUser
147 :param repoid: Set the repository name or repository ID.
147 :param repoid: Set the repository name or repository ID.
148 :type repoid: str or int
148 :type repoid: str or int
149 :param forks: Set to `detach` or `delete` forks from the |repo|.
149 :param forks: Set to `detach` or `delete` forks from the |repo|.
150 :type forks: Optional(str)
150 :type forks: Optional(str)
151
151
152 Example error output:
152 Example error output:
153
153
154 .. code-block:: bash
154 .. code-block:: bash
155
155
156 id : <id_given_in_input>
156 id : <id_given_in_input>
157 result: {
157 result: {
158 "msg": "Deleted repository `<reponame>`",
158 "msg": "Deleted repository `<reponame>`",
159 "success": true
159 "success": true
160 }
160 }
161 error: null
161 error: null
162
162
163
163
164 fork_repo
164 fork_repo
165 ---------
165 ---------
166
166
167 .. 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'>)
167 .. 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'>)
168
168
169 Creates a fork of the specified |repo|.
169 Creates a fork of the specified |repo|.
170
170
171 * If using |RCE| with Celery this will immediately return a success
171 * If using |RCE| with Celery this will immediately return a success
172 message, even though the fork will be created asynchronously.
172 message, even though the fork will be created asynchronously.
173
173
174 This command can only be run using an |authtoken| with fork
174 This command can only be run using an |authtoken| with fork
175 permissions on the |repo|.
175 permissions on the |repo|.
176
176
177 :param apiuser: This is filled automatically from the |authtoken|.
177 :param apiuser: This is filled automatically from the |authtoken|.
178 :type apiuser: AuthUser
178 :type apiuser: AuthUser
179 :param repoid: Set repository name or repository ID.
179 :param repoid: Set repository name or repository ID.
180 :type repoid: str or int
180 :type repoid: str or int
181 :param fork_name: Set the fork name.
181 :param fork_name: Set the fork name.
182 :type fork_name: str
182 :type fork_name: str
183 :param owner: Set the fork owner.
183 :param owner: Set the fork owner.
184 :type owner: str
184 :type owner: str
185 :param description: Set the fork descripton.
185 :param description: Set the fork descripton.
186 :type description: str
186 :type description: str
187 :param copy_permissions: Copy permissions from parent |repo|. The
187 :param copy_permissions: Copy permissions from parent |repo|. The
188 default is False.
188 default is False.
189 :type copy_permissions: bool
189 :type copy_permissions: bool
190 :param private: Make the fork private. The default is False.
190 :param private: Make the fork private. The default is False.
191 :type private: bool
191 :type private: bool
192 :param landing_rev: Set the landing revision. The default is tip.
192 :param landing_rev: Set the landing revision. The default is tip.
193
193
194 Example output:
194 Example output:
195
195
196 .. code-block:: bash
196 .. code-block:: bash
197
197
198 id : <id_for_response>
198 id : <id_for_response>
199 api_key : "<api_key>"
199 api_key : "<api_key>"
200 args: {
200 args: {
201 "repoid" : "<reponame or repo_id>",
201 "repoid" : "<reponame or repo_id>",
202 "fork_name": "<forkname>",
202 "fork_name": "<forkname>",
203 "owner": "<username or user_id = Optional(=apiuser)>",
203 "owner": "<username or user_id = Optional(=apiuser)>",
204 "description": "<description>",
204 "description": "<description>",
205 "copy_permissions": "<bool>",
205 "copy_permissions": "<bool>",
206 "private": "<bool>",
206 "private": "<bool>",
207 "landing_rev": "<landing_rev>"
207 "landing_rev": "<landing_rev>"
208 }
208 }
209
209
210 Example error output:
210 Example error output:
211
211
212 .. code-block:: bash
212 .. code-block:: bash
213
213
214 id : <id_given_in_input>
214 id : <id_given_in_input>
215 result: {
215 result: {
216 "msg": "Created fork of `<reponame>` as `<forkname>`",
216 "msg": "Created fork of `<reponame>` as `<forkname>`",
217 "success": true,
217 "success": true,
218 "task": "<celery task id or None if done sync>"
218 "task": "<celery task id or None if done sync>"
219 }
219 }
220 error: null
220 error: null
221
221
222
222
223 get_repo
223 get_repo
224 --------
224 --------
225
225
226 .. py:function:: get_repo(apiuser, repoid, cache=<Optional:True>)
226 .. py:function:: get_repo(apiuser, repoid, cache=<Optional:True>)
227
227
228 Gets an existing repository by its name or repository_id.
228 Gets an existing repository by its name or repository_id.
229
229
230 The members section so the output returns users groups or users
230 The members section so the output returns users groups or users
231 associated with that repository.
231 associated with that repository.
232
232
233 This command can only be run using an |authtoken| with admin rights,
233 This command can only be run using an |authtoken| with admin rights,
234 or users with at least read rights to the |repo|.
234 or users with at least read rights to the |repo|.
235
235
236 :param apiuser: This is filled automatically from the |authtoken|.
236 :param apiuser: This is filled automatically from the |authtoken|.
237 :type apiuser: AuthUser
237 :type apiuser: AuthUser
238 :param repoid: The repository name or repository id.
238 :param repoid: The repository name or repository id.
239 :type repoid: str or int
239 :type repoid: str or int
240 :param cache: use the cached value for last changeset
240 :param cache: use the cached value for last changeset
241 :type: cache: Optional(bool)
241 :type: cache: Optional(bool)
242
242
243 Example output:
243 Example output:
244
244
245 .. code-block:: bash
245 .. code-block:: bash
246
246
247 {
247 {
248 "error": null,
248 "error": null,
249 "id": <repo_id>,
249 "id": <repo_id>,
250 "result": {
250 "result": {
251 "clone_uri": null,
251 "clone_uri": null,
252 "created_on": "timestamp",
252 "created_on": "timestamp",
253 "description": "repo description",
253 "description": "repo description",
254 "enable_downloads": false,
254 "enable_downloads": false,
255 "enable_locking": false,
255 "enable_locking": false,
256 "enable_statistics": false,
256 "enable_statistics": false,
257 "followers": [
257 "followers": [
258 {
258 {
259 "active": true,
259 "active": true,
260 "admin": false,
260 "admin": false,
261 "api_key": "****************************************",
261 "api_key": "****************************************",
262 "api_keys": [
262 "api_keys": [
263 "****************************************"
263 "****************************************"
264 ],
264 ],
265 "email": "user@example.com",
265 "email": "user@example.com",
266 "emails": [
266 "emails": [
267 "user@example.com"
267 "user@example.com"
268 ],
268 ],
269 "extern_name": "rhodecode",
269 "extern_name": "rhodecode",
270 "extern_type": "rhodecode",
270 "extern_type": "rhodecode",
271 "firstname": "username",
271 "firstname": "username",
272 "ip_addresses": [],
272 "ip_addresses": [],
273 "language": null,
273 "language": null,
274 "last_login": "2015-09-16T17:16:35.854",
274 "last_login": "2015-09-16T17:16:35.854",
275 "lastname": "surname",
275 "lastname": "surname",
276 "user_id": <user_id>,
276 "user_id": <user_id>,
277 "username": "name"
277 "username": "name"
278 }
278 }
279 ],
279 ],
280 "fork_of": "parent-repo",
280 "fork_of": "parent-repo",
281 "landing_rev": [
281 "landing_rev": [
282 "rev",
282 "rev",
283 "tip"
283 "tip"
284 ],
284 ],
285 "last_changeset": {
285 "last_changeset": {
286 "author": "User <user@example.com>",
286 "author": "User <user@example.com>",
287 "branch": "default",
287 "branch": "default",
288 "date": "timestamp",
288 "date": "timestamp",
289 "message": "last commit message",
289 "message": "last commit message",
290 "parents": [
290 "parents": [
291 {
291 {
292 "raw_id": "commit-id"
292 "raw_id": "commit-id"
293 }
293 }
294 ],
294 ],
295 "raw_id": "commit-id",
295 "raw_id": "commit-id",
296 "revision": <revision number>,
296 "revision": <revision number>,
297 "short_id": "short id"
297 "short_id": "short id"
298 },
298 },
299 "lock_reason": null,
299 "lock_reason": null,
300 "locked_by": null,
300 "locked_by": null,
301 "locked_date": null,
301 "locked_date": null,
302 "members": [
302 "members": [
303 {
303 {
304 "name": "super-admin-name",
304 "name": "super-admin-name",
305 "origin": "super-admin",
305 "origin": "super-admin",
306 "permission": "repository.admin",
306 "permission": "repository.admin",
307 "type": "user"
307 "type": "user"
308 },
308 },
309 {
309 {
310 "name": "owner-name",
310 "name": "owner-name",
311 "origin": "owner",
311 "origin": "owner",
312 "permission": "repository.admin",
312 "permission": "repository.admin",
313 "type": "user"
313 "type": "user"
314 },
314 },
315 {
315 {
316 "name": "user-group-name",
316 "name": "user-group-name",
317 "origin": "permission",
317 "origin": "permission",
318 "permission": "repository.write",
318 "permission": "repository.write",
319 "type": "user_group"
319 "type": "user_group"
320 }
320 }
321 ],
321 ],
322 "owner": "owner-name",
322 "owner": "owner-name",
323 "permissions": [
323 "permissions": [
324 {
324 {
325 "name": "super-admin-name",
325 "name": "super-admin-name",
326 "origin": "super-admin",
326 "origin": "super-admin",
327 "permission": "repository.admin",
327 "permission": "repository.admin",
328 "type": "user"
328 "type": "user"
329 },
329 },
330 {
330 {
331 "name": "owner-name",
331 "name": "owner-name",
332 "origin": "owner",
332 "origin": "owner",
333 "permission": "repository.admin",
333 "permission": "repository.admin",
334 "type": "user"
334 "type": "user"
335 },
335 },
336 {
336 {
337 "name": "user-group-name",
337 "name": "user-group-name",
338 "origin": "permission",
338 "origin": "permission",
339 "permission": "repository.write",
339 "permission": "repository.write",
340 "type": "user_group"
340 "type": "user_group"
341 }
341 }
342 ],
342 ],
343 "private": true,
343 "private": true,
344 "repo_id": 676,
344 "repo_id": 676,
345 "repo_name": "user-group/repo-name",
345 "repo_name": "user-group/repo-name",
346 "repo_type": "hg"
346 "repo_type": "hg"
347 }
347 }
348 }
348 }
349
349
350
350
351 get_repo_changeset
351 get_repo_changeset
352 ------------------
352 ------------------
353
353
354 .. py:function:: get_repo_changeset(apiuser, repoid, revision, details=<Optional:'basic'>)
354 .. py:function:: get_repo_changeset(apiuser, repoid, revision, details=<Optional:'basic'>)
355
355
356 Returns information about a changeset.
356 Returns information about a changeset.
357
357
358 Additionally parameters define the amount of details returned by
358 Additionally parameters define the amount of details returned by
359 this function.
359 this function.
360
360
361 This command can only be run using an |authtoken| with admin rights,
361 This command can only be run using an |authtoken| with admin rights,
362 or users with at least read rights to the |repo|.
362 or users with at least read rights to the |repo|.
363
363
364 :param apiuser: This is filled automatically from the |authtoken|.
364 :param apiuser: This is filled automatically from the |authtoken|.
365 :type apiuser: AuthUser
365 :type apiuser: AuthUser
366 :param repoid: The repository name or repository id
366 :param repoid: The repository name or repository id
367 :type repoid: str or int
367 :type repoid: str or int
368 :param revision: revision for which listing should be done
368 :param revision: revision for which listing should be done
369 :type revision: str
369 :type revision: str
370 :param details: details can be 'basic|extended|full' full gives diff
370 :param details: details can be 'basic|extended|full' full gives diff
371 info details like the diff itself, and number of changed files etc.
371 info details like the diff itself, and number of changed files etc.
372 :type details: Optional(str)
372 :type details: Optional(str)
373
373
374
374
375 get_repo_changesets
375 get_repo_changesets
376 -------------------
376 -------------------
377
377
378 .. py:function:: get_repo_changesets(apiuser, repoid, start_rev, limit, details=<Optional:'basic'>)
378 .. py:function:: get_repo_changesets(apiuser, repoid, start_rev, limit, details=<Optional:'basic'>)
379
379
380 Returns a set of commits limited by the number starting
380 Returns a set of commits limited by the number starting
381 from the `start_rev` option.
381 from the `start_rev` option.
382
382
383 Additional parameters define the amount of details returned by this
383 Additional parameters define the amount of details returned by this
384 function.
384 function.
385
385
386 This command can only be run using an |authtoken| with admin rights,
386 This command can only be run using an |authtoken| with admin rights,
387 or users with at least read rights to |repos|.
387 or users with at least read rights to |repos|.
388
388
389 :param apiuser: This is filled automatically from the |authtoken|.
389 :param apiuser: This is filled automatically from the |authtoken|.
390 :type apiuser: AuthUser
390 :type apiuser: AuthUser
391 :param repoid: The repository name or repository ID.
391 :param repoid: The repository name or repository ID.
392 :type repoid: str or int
392 :type repoid: str or int
393 :param start_rev: The starting revision from where to get changesets.
393 :param start_rev: The starting revision from where to get changesets.
394 :type start_rev: str
394 :type start_rev: str
395 :param limit: Limit the number of commits to this amount
395 :param limit: Limit the number of commits to this amount
396 :type limit: str or int
396 :type limit: str or int
397 :param details: Set the level of detail returned. Valid option are:
397 :param details: Set the level of detail returned. Valid option are:
398 ``basic``, ``extended`` and ``full``.
398 ``basic``, ``extended`` and ``full``.
399 :type details: Optional(str)
399 :type details: Optional(str)
400
400
401 .. note::
401 .. note::
402
402
403 Setting the parameter `details` to the value ``full`` is extensive
403 Setting the parameter `details` to the value ``full`` is extensive
404 and returns details like the diff itself, and the number
404 and returns details like the diff itself, and the number
405 of changed files.
405 of changed files.
406
406
407
407
408 get_repo_nodes
408 get_repo_nodes
409 --------------
409 --------------
410
410
411 .. py:function:: get_repo_nodes(apiuser, repoid, revision, root_path, ret_type=<Optional:'all'>, details=<Optional:'basic'>, max_file_bytes=<Optional:None>)
411 .. py:function:: get_repo_nodes(apiuser, repoid, revision, root_path, ret_type=<Optional:'all'>, details=<Optional:'basic'>, max_file_bytes=<Optional:None>)
412
412
413 Returns a list of nodes and children in a flat list for a given
413 Returns a list of nodes and children in a flat list for a given
414 path at given revision.
414 path at given revision.
415
415
416 It's possible to specify ret_type to show only `files` or `dirs`.
416 It's possible to specify ret_type to show only `files` or `dirs`.
417
417
418 This command can only be run using an |authtoken| with admin rights,
418 This command can only be run using an |authtoken| with admin rights,
419 or users with at least read rights to |repos|.
419 or users with at least read rights to |repos|.
420
420
421 :param apiuser: This is filled automatically from the |authtoken|.
421 :param apiuser: This is filled automatically from the |authtoken|.
422 :type apiuser: AuthUser
422 :type apiuser: AuthUser
423 :param repoid: The repository name or repository ID.
423 :param repoid: The repository name or repository ID.
424 :type repoid: str or int
424 :type repoid: str or int
425 :param revision: The revision for which listing should be done.
425 :param revision: The revision for which listing should be done.
426 :type revision: str
426 :type revision: str
427 :param root_path: The path from which to start displaying.
427 :param root_path: The path from which to start displaying.
428 :type root_path: str
428 :type root_path: str
429 :param ret_type: Set the return type. Valid options are
429 :param ret_type: Set the return type. Valid options are
430 ``all`` (default), ``files`` and ``dirs``.
430 ``all`` (default), ``files`` and ``dirs``.
431 :type ret_type: Optional(str)
431 :type ret_type: Optional(str)
432 :param details: Returns extended information about nodes, such as
432 :param details: Returns extended information about nodes, such as
433 md5, binary, and or content. The valid options are ``basic`` and
433 md5, binary, and or content. The valid options are ``basic`` and
434 ``full``.
434 ``full``.
435 :type details: Optional(str)
435 :type details: Optional(str)
436 :param max_file_bytes: Only return file content under this file size bytes
436 :param max_file_bytes: Only return file content under this file size bytes
437 :type details: Optional(int)
437 :type details: Optional(int)
438
438
439 Example output:
439 Example output:
440
440
441 .. code-block:: bash
441 .. code-block:: bash
442
442
443 id : <id_given_in_input>
443 id : <id_given_in_input>
444 result: [
444 result: [
445 {
445 {
446 "name" : "<name>"
446 "name" : "<name>"
447 "type" : "<type>",
447 "type" : "<type>",
448 "binary": "<true|false>" (only in extended mode)
448 "binary": "<true|false>" (only in extended mode)
449 "md5" : "<md5 of file content>" (only in extended mode)
449 "md5" : "<md5 of file content>" (only in extended mode)
450 },
450 },
451 ...
451 ...
452 ]
452 ]
453 error: null
453 error: null
454
454
455
455
456 get_repo_refs
456 get_repo_refs
457 -------------
457 -------------
458
458
459 .. py:function:: get_repo_refs(apiuser, repoid)
459 .. py:function:: get_repo_refs(apiuser, repoid)
460
460
461 Returns a dictionary of current references. It returns
461 Returns a dictionary of current references. It returns
462 bookmarks, branches, closed_branches, and tags for given repository
462 bookmarks, branches, closed_branches, and tags for given repository
463
463
464 It's possible to specify ret_type to show only `files` or `dirs`.
464 It's possible to specify ret_type to show only `files` or `dirs`.
465
465
466 This command can only be run using an |authtoken| with admin rights,
466 This command can only be run using an |authtoken| with admin rights,
467 or users with at least read rights to |repos|.
467 or users with at least read rights to |repos|.
468
468
469 :param apiuser: This is filled automatically from the |authtoken|.
469 :param apiuser: This is filled automatically from the |authtoken|.
470 :type apiuser: AuthUser
470 :type apiuser: AuthUser
471 :param repoid: The repository name or repository ID.
471 :param repoid: The repository name or repository ID.
472 :type repoid: str or int
472 :type repoid: str or int
473
473
474 Example output:
474 Example output:
475
475
476 .. code-block:: bash
476 .. code-block:: bash
477
477
478 id : <id_given_in_input>
478 id : <id_given_in_input>
479 result: [
479 result: [
480 TODO...
480 TODO...
481 ]
481 ]
482 error: null
482 error: null
483
483
484
484
485 get_repo_settings
485 get_repo_settings
486 -----------------
486 -----------------
487
487
488 .. py:function:: get_repo_settings(apiuser, repoid, key=<Optional:None>)
488 .. py:function:: get_repo_settings(apiuser, repoid, key=<Optional:None>)
489
489
490 Returns all settings for a repository. If key is given it only returns the
490 Returns all settings for a repository. If key is given it only returns the
491 setting identified by the key or null.
491 setting identified by the key or null.
492
492
493 :param apiuser: This is filled automatically from the |authtoken|.
493 :param apiuser: This is filled automatically from the |authtoken|.
494 :type apiuser: AuthUser
494 :type apiuser: AuthUser
495 :param repoid: The repository name or repository id.
495 :param repoid: The repository name or repository id.
496 :type repoid: str or int
496 :type repoid: str or int
497 :param key: Key of the setting to return.
497 :param key: Key of the setting to return.
498 :type: key: Optional(str)
498 :type: key: Optional(str)
499
499
500 Example output:
500 Example output:
501
501
502 .. code-block:: bash
502 .. code-block:: bash
503
503
504 {
504 {
505 "error": null,
505 "error": null,
506 "id": 237,
506 "id": 237,
507 "result": {
507 "result": {
508 "extensions_largefiles": true,
508 "extensions_largefiles": true,
509 "hooks_changegroup_push_logger": true,
509 "hooks_changegroup_push_logger": true,
510 "hooks_changegroup_repo_size": false,
510 "hooks_changegroup_repo_size": false,
511 "hooks_outgoing_pull_logger": true,
511 "hooks_outgoing_pull_logger": true,
512 "phases_publish": "True",
512 "phases_publish": "True",
513 "rhodecode_hg_use_rebase_for_merging": true,
513 "rhodecode_hg_use_rebase_for_merging": true,
514 "rhodecode_pr_merge_enabled": true,
514 "rhodecode_pr_merge_enabled": true,
515 "rhodecode_use_outdated_comments": true
515 "rhodecode_use_outdated_comments": true
516 }
516 }
517 }
517 }
518
518
519
519
520 get_repos
520 get_repos
521 ---------
521 ---------
522
522
523 .. py:function:: get_repos(apiuser)
523 .. py:function:: get_repos(apiuser)
524
524
525 Lists all existing repositories.
525 Lists all existing repositories.
526
526
527 This command can only be run using an |authtoken| with admin rights,
527 This command can only be run using an |authtoken| with admin rights,
528 or users with at least read rights to |repos|.
528 or users with at least read rights to |repos|.
529
529
530 :param apiuser: This is filled automatically from the |authtoken|.
530 :param apiuser: This is filled automatically from the |authtoken|.
531 :type apiuser: AuthUser
531 :type apiuser: AuthUser
532
532
533 Example output:
533 Example output:
534
534
535 .. code-block:: bash
535 .. code-block:: bash
536
536
537 id : <id_given_in_input>
537 id : <id_given_in_input>
538 result: [
538 result: [
539 {
539 {
540 "repo_id" : "<repo_id>",
540 "repo_id" : "<repo_id>",
541 "repo_name" : "<reponame>"
541 "repo_name" : "<reponame>"
542 "repo_type" : "<repo_type>",
542 "repo_type" : "<repo_type>",
543 "clone_uri" : "<clone_uri>",
543 "clone_uri" : "<clone_uri>",
544 "private": : "<bool>",
544 "private": : "<bool>",
545 "created_on" : "<datetimecreated>",
545 "created_on" : "<datetimecreated>",
546 "description" : "<description>",
546 "description" : "<description>",
547 "landing_rev": "<landing_rev>",
547 "landing_rev": "<landing_rev>",
548 "owner": "<repo_owner>",
548 "owner": "<repo_owner>",
549 "fork_of": "<name_of_fork_parent>",
549 "fork_of": "<name_of_fork_parent>",
550 "enable_downloads": "<bool>",
550 "enable_downloads": "<bool>",
551 "enable_locking": "<bool>",
551 "enable_locking": "<bool>",
552 "enable_statistics": "<bool>",
552 "enable_statistics": "<bool>",
553 },
553 },
554 ...
554 ...
555 ]
555 ]
556 error: null
556 error: null
557
557
558
558
559 grant_user_group_permission
559 grant_user_group_permission
560 ---------------------------
560 ---------------------------
561
561
562 .. py:function:: grant_user_group_permission(apiuser, repoid, usergroupid, perm)
562 .. py:function:: grant_user_group_permission(apiuser, repoid, usergroupid, perm)
563
563
564 Grant permission for a user group on the specified repository,
564 Grant permission for a user group on the specified repository,
565 or update existing permissions.
565 or update existing permissions.
566
566
567 This command can only be run using an |authtoken| with admin
567 This command can only be run using an |authtoken| with admin
568 permissions on the |repo|.
568 permissions on the |repo|.
569
569
570 :param apiuser: This is filled automatically from the |authtoken|.
570 :param apiuser: This is filled automatically from the |authtoken|.
571 :type apiuser: AuthUser
571 :type apiuser: AuthUser
572 :param repoid: Set the repository name or repository ID.
572 :param repoid: Set the repository name or repository ID.
573 :type repoid: str or int
573 :type repoid: str or int
574 :param usergroupid: Specify the ID of the user group.
574 :param usergroupid: Specify the ID of the user group.
575 :type usergroupid: str or int
575 :type usergroupid: str or int
576 :param perm: Set the user group permissions using the following
576 :param perm: Set the user group permissions using the following
577 format: (repository.(none|read|write|admin))
577 format: (repository.(none|read|write|admin))
578 :type perm: str
578 :type perm: str
579
579
580 Example output:
580 Example output:
581
581
582 .. code-block:: bash
582 .. code-block:: bash
583
583
584 id : <id_given_in_input>
584 id : <id_given_in_input>
585 result : {
585 result : {
586 "msg" : "Granted perm: `<perm>` for group: `<usersgroupname>` in repo: `<reponame>`",
586 "msg" : "Granted perm: `<perm>` for group: `<usersgroupname>` in repo: `<reponame>`",
587 "success": true
587 "success": true
588
588
589 }
589 }
590 error : null
590 error : null
591
591
592 Example error output:
592 Example error output:
593
593
594 .. code-block:: bash
594 .. code-block:: bash
595
595
596 id : <id_given_in_input>
596 id : <id_given_in_input>
597 result : null
597 result : null
598 error : {
598 error : {
599 "failed to edit permission for user group: `<usergroup>` in repo `<repo>`'
599 "failed to edit permission for user group: `<usergroup>` in repo `<repo>`'
600 }
600 }
601
601
602
602
603 grant_user_permission
603 grant_user_permission
604 ---------------------
604 ---------------------
605
605
606 .. py:function:: grant_user_permission(apiuser, repoid, userid, perm)
606 .. py:function:: grant_user_permission(apiuser, repoid, userid, perm)
607
607
608 Grant permissions for the specified user on the given repository,
608 Grant permissions for the specified user on the given repository,
609 or update existing permissions if found.
609 or update existing permissions if found.
610
610
611 This command can only be run using an |authtoken| with admin
611 This command can only be run using an |authtoken| with admin
612 permissions on the |repo|.
612 permissions on the |repo|.
613
613
614 :param apiuser: This is filled automatically from the |authtoken|.
614 :param apiuser: This is filled automatically from the |authtoken|.
615 :type apiuser: AuthUser
615 :type apiuser: AuthUser
616 :param repoid: Set the repository name or repository ID.
616 :param repoid: Set the repository name or repository ID.
617 :type repoid: str or int
617 :type repoid: str or int
618 :param userid: Set the user name.
618 :param userid: Set the user name.
619 :type userid: str
619 :type userid: str
620 :param perm: Set the user permissions, using the following format
620 :param perm: Set the user permissions, using the following format
621 ``(repository.(none|read|write|admin))``
621 ``(repository.(none|read|write|admin))``
622 :type perm: str
622 :type perm: str
623
623
624 Example output:
624 Example output:
625
625
626 .. code-block:: bash
626 .. code-block:: bash
627
627
628 id : <id_given_in_input>
628 id : <id_given_in_input>
629 result: {
629 result: {
630 "msg" : "Granted perm: `<perm>` for user: `<username>` in repo: `<reponame>`",
630 "msg" : "Granted perm: `<perm>` for user: `<username>` in repo: `<reponame>`",
631 "success": true
631 "success": true
632 }
632 }
633 error: null
633 error: null
634
634
635
635
636 invalidate_cache
636 invalidate_cache
637 ----------------
637 ----------------
638
638
639 .. py:function:: invalidate_cache(apiuser, repoid, delete_keys=<Optional:False>)
639 .. py:function:: invalidate_cache(apiuser, repoid, delete_keys=<Optional:False>)
640
640
641 Invalidates the cache for the specified repository.
641 Invalidates the cache for the specified repository.
642
642
643 This command can only be run using an |authtoken| with admin rights to
643 This command can only be run using an |authtoken| with admin rights to
644 the specified repository.
644 the specified repository.
645
645
646 This command takes the following options:
646 This command takes the following options:
647
647
648 :param apiuser: This is filled automatically from |authtoken|.
648 :param apiuser: This is filled automatically from |authtoken|.
649 :type apiuser: AuthUser
649 :type apiuser: AuthUser
650 :param repoid: Sets the repository name or repository ID.
650 :param repoid: Sets the repository name or repository ID.
651 :type repoid: str or int
651 :type repoid: str or int
652 :param delete_keys: This deletes the invalidated keys instead of
652 :param delete_keys: This deletes the invalidated keys instead of
653 just flagging them.
653 just flagging them.
654 :type delete_keys: Optional(``True`` | ``False``)
654 :type delete_keys: Optional(``True`` | ``False``)
655
655
656 Example output:
656 Example output:
657
657
658 .. code-block:: bash
658 .. code-block:: bash
659
659
660 id : <id_given_in_input>
660 id : <id_given_in_input>
661 result : {
661 result : {
662 'msg': Cache for repository `<repository name>` was invalidated,
662 'msg': Cache for repository `<repository name>` was invalidated,
663 'repository': <repository name>
663 'repository': <repository name>
664 }
664 }
665 error : null
665 error : null
666
666
667 Example error output:
667 Example error output:
668
668
669 .. code-block:: bash
669 .. code-block:: bash
670
670
671 id : <id_given_in_input>
671 id : <id_given_in_input>
672 result : null
672 result : null
673 error : {
673 error : {
674 'Error occurred during cache invalidation action'
674 'Error occurred during cache invalidation action'
675 }
675 }
676
676
677
677
678 lock
678 lock
679 ----
679 ----
680
680
681 .. py:function:: lock(apiuser, repoid, locked=<Optional:None>, userid=<Optional:<OptionalAttr:apiuser>>)
681 .. py:function:: lock(apiuser, repoid, locked=<Optional:None>, userid=<Optional:<OptionalAttr:apiuser>>)
682
682
683 Sets the lock state of the specified |repo| by the given user.
683 Sets the lock state of the specified |repo| by the given user.
684 From more information, see :ref:`repo-locking`.
684 From more information, see :ref:`repo-locking`.
685
685
686 * If the ``userid`` option is not set, the repository is locked to the
686 * If the ``userid`` option is not set, the repository is locked to the
687 user who called the method.
687 user who called the method.
688 * If the ``locked`` parameter is not set, the current lock state of the
688 * If the ``locked`` parameter is not set, the current lock state of the
689 repository is displayed.
689 repository is displayed.
690
690
691 This command can only be run using an |authtoken| with admin rights to
691 This command can only be run using an |authtoken| with admin rights to
692 the specified repository.
692 the specified repository.
693
693
694 This command takes the following options:
694 This command takes the following options:
695
695
696 :param apiuser: This is filled automatically from the |authtoken|.
696 :param apiuser: This is filled automatically from the |authtoken|.
697 :type apiuser: AuthUser
697 :type apiuser: AuthUser
698 :param repoid: Sets the repository name or repository ID.
698 :param repoid: Sets the repository name or repository ID.
699 :type repoid: str or int
699 :type repoid: str or int
700 :param locked: Sets the lock state.
700 :param locked: Sets the lock state.
701 :type locked: Optional(``True`` | ``False``)
701 :type locked: Optional(``True`` | ``False``)
702 :param userid: Set the repository lock to this user.
702 :param userid: Set the repository lock to this user.
703 :type userid: Optional(str or int)
703 :type userid: Optional(str or int)
704
704
705 Example error output:
705 Example error output:
706
706
707 .. code-block:: bash
707 .. code-block:: bash
708
708
709 id : <id_given_in_input>
709 id : <id_given_in_input>
710 result : {
710 result : {
711 'repo': '<reponame>',
711 'repo': '<reponame>',
712 'locked': <bool: lock state>,
712 'locked': <bool: lock state>,
713 'locked_since': <int: lock timestamp>,
713 'locked_since': <int: lock timestamp>,
714 'locked_by': <username of person who made the lock>,
714 'locked_by': <username of person who made the lock>,
715 'lock_reason': <str: reason for locking>,
715 'lock_reason': <str: reason for locking>,
716 'lock_state_changed': <bool: True if lock state has been changed in this request>,
716 'lock_state_changed': <bool: True if lock state has been changed in this request>,
717 'msg': 'Repo `<reponame>` locked by `<username>` on <timestamp>.'
717 'msg': 'Repo `<reponame>` locked by `<username>` on <timestamp>.'
718 or
718 or
719 'msg': 'Repo `<repository name>` not locked.'
719 'msg': 'Repo `<repository name>` not locked.'
720 or
720 or
721 'msg': 'User `<user name>` set lock state for repo `<repository name>` to `<new lock state>`'
721 'msg': 'User `<user name>` set lock state for repo `<repository name>` to `<new lock state>`'
722 }
722 }
723 error : null
723 error : null
724
724
725 Example error output:
725 Example error output:
726
726
727 .. code-block:: bash
727 .. code-block:: bash
728
728
729 id : <id_given_in_input>
729 id : <id_given_in_input>
730 result : null
730 result : null
731 error : {
731 error : {
732 'Error occurred locking repository `<reponame>`
732 'Error occurred locking repository `<reponame>`'
733 }
733 }
734
734
735
735
736 pull
736 pull
737 ----
737 ----
738
738
739 .. py:function:: pull(apiuser, repoid)
739 .. py:function:: pull(apiuser, repoid)
740
740
741 Triggers a pull on the given repository from a remote location. You
741 Triggers a pull on the given repository from a remote location. You
742 can use this to keep remote repositories up-to-date.
742 can use this to keep remote repositories up-to-date.
743
743
744 This command can only be run using an |authtoken| with admin
744 This command can only be run using an |authtoken| with admin
745 rights to the specified repository. For more information,
745 rights to the specified repository. For more information,
746 see :ref:`config-token-ref`.
746 see :ref:`config-token-ref`.
747
747
748 This command takes the following options:
748 This command takes the following options:
749
749
750 :param apiuser: This is filled automatically from the |authtoken|.
750 :param apiuser: This is filled automatically from the |authtoken|.
751 :type apiuser: AuthUser
751 :type apiuser: AuthUser
752 :param repoid: The repository name or repository ID.
752 :param repoid: The repository name or repository ID.
753 :type repoid: str or int
753 :type repoid: str or int
754
754
755 Example output:
755 Example output:
756
756
757 .. code-block:: bash
757 .. code-block:: bash
758
758
759 id : <id_given_in_input>
759 id : <id_given_in_input>
760 result : {
760 result : {
761 "msg": "Pulled from `<repository name>`"
761 "msg": "Pulled from `<repository name>`"
762 "repository": "<repository name>"
762 "repository": "<repository name>"
763 }
763 }
764 error : null
764 error : null
765
765
766 Example error output:
766 Example error output:
767
767
768 .. code-block:: bash
768 .. code-block:: bash
769
769
770 id : <id_given_in_input>
770 id : <id_given_in_input>
771 result : null
771 result : null
772 error : {
772 error : {
773 "Unable to pull changes from `<reponame>`"
773 "Unable to pull changes from `<reponame>`"
774 }
774 }
775
775
776
776
777 remove_field_from_repo
777 remove_field_from_repo
778 ----------------------
778 ----------------------
779
779
780 .. py:function:: remove_field_from_repo(apiuser, repoid, key)
780 .. py:function:: remove_field_from_repo(apiuser, repoid, key)
781
781
782 Removes an extra field from a repository.
782 Removes an extra field from a repository.
783
783
784 This command can only be run using an |authtoken| with at least
784 This command can only be run using an |authtoken| with at least
785 write permissions to the |repo|.
785 write permissions to the |repo|.
786
786
787 :param apiuser: This is filled automatically from the |authtoken|.
787 :param apiuser: This is filled automatically from the |authtoken|.
788 :type apiuser: AuthUser
788 :type apiuser: AuthUser
789 :param repoid: Set the repository name or repository ID.
789 :param repoid: Set the repository name or repository ID.
790 :type repoid: str or int
790 :type repoid: str or int
791 :param key: Set the unique field key for this repository.
791 :param key: Set the unique field key for this repository.
792 :type key: str
792 :type key: str
793
793
794
794
795 revoke_user_group_permission
795 revoke_user_group_permission
796 ----------------------------
796 ----------------------------
797
797
798 .. py:function:: revoke_user_group_permission(apiuser, repoid, usergroupid)
798 .. py:function:: revoke_user_group_permission(apiuser, repoid, usergroupid)
799
799
800 Revoke the permissions of a user group on a given repository.
800 Revoke the permissions of a user group on a given repository.
801
801
802 This command can only be run using an |authtoken| with admin
802 This command can only be run using an |authtoken| with admin
803 permissions on the |repo|.
803 permissions on the |repo|.
804
804
805 :param apiuser: This is filled automatically from the |authtoken|.
805 :param apiuser: This is filled automatically from the |authtoken|.
806 :type apiuser: AuthUser
806 :type apiuser: AuthUser
807 :param repoid: Set the repository name or repository ID.
807 :param repoid: Set the repository name or repository ID.
808 :type repoid: str or int
808 :type repoid: str or int
809 :param usergroupid: Specify the user group ID.
809 :param usergroupid: Specify the user group ID.
810 :type usergroupid: str or int
810 :type usergroupid: str or int
811
811
812 Example output:
812 Example output:
813
813
814 .. code-block:: bash
814 .. code-block:: bash
815
815
816 id : <id_given_in_input>
816 id : <id_given_in_input>
817 result: {
817 result: {
818 "msg" : "Revoked perm for group: `<usersgroupname>` in repo: `<reponame>`",
818 "msg" : "Revoked perm for group: `<usersgroupname>` in repo: `<reponame>`",
819 "success": true
819 "success": true
820 }
820 }
821 error: null
821 error: null
822
822
823
823
824 revoke_user_permission
824 revoke_user_permission
825 ----------------------
825 ----------------------
826
826
827 .. py:function:: revoke_user_permission(apiuser, repoid, userid)
827 .. py:function:: revoke_user_permission(apiuser, repoid, userid)
828
828
829 Revoke permission for a user on the specified repository.
829 Revoke permission for a user on the specified repository.
830
830
831 This command can only be run using an |authtoken| with admin
831 This command can only be run using an |authtoken| with admin
832 permissions on the |repo|.
832 permissions on the |repo|.
833
833
834 :param apiuser: This is filled automatically from the |authtoken|.
834 :param apiuser: This is filled automatically from the |authtoken|.
835 :type apiuser: AuthUser
835 :type apiuser: AuthUser
836 :param repoid: Set the repository name or repository ID.
836 :param repoid: Set the repository name or repository ID.
837 :type repoid: str or int
837 :type repoid: str or int
838 :param userid: Set the user name of revoked user.
838 :param userid: Set the user name of revoked user.
839 :type userid: str or int
839 :type userid: str or int
840
840
841 Example error output:
841 Example error output:
842
842
843 .. code-block:: bash
843 .. code-block:: bash
844
844
845 id : <id_given_in_input>
845 id : <id_given_in_input>
846 result: {
846 result: {
847 "msg" : "Revoked perm for user: `<username>` in repo: `<reponame>`",
847 "msg" : "Revoked perm for user: `<username>` in repo: `<reponame>`",
848 "success": true
848 "success": true
849 }
849 }
850 error: null
850 error: null
851
851
852
852
853 set_repo_settings
853 set_repo_settings
854 -----------------
854 -----------------
855
855
856 .. py:function:: set_repo_settings(apiuser, repoid, settings)
856 .. py:function:: set_repo_settings(apiuser, repoid, settings)
857
857
858 Update repository settings. Returns true on success.
858 Update repository settings. Returns true on success.
859
859
860 :param apiuser: This is filled automatically from the |authtoken|.
860 :param apiuser: This is filled automatically from the |authtoken|.
861 :type apiuser: AuthUser
861 :type apiuser: AuthUser
862 :param repoid: The repository name or repository id.
862 :param repoid: The repository name or repository id.
863 :type repoid: str or int
863 :type repoid: str or int
864 :param settings: The new settings for the repository.
864 :param settings: The new settings for the repository.
865 :type: settings: dict
865 :type: settings: dict
866
866
867 Example output:
867 Example output:
868
868
869 .. code-block:: bash
869 .. code-block:: bash
870
870
871 {
871 {
872 "error": null,
872 "error": null,
873 "id": 237,
873 "id": 237,
874 "result": true
874 "result": true
875 }
875 }
876
876
877
877
878 strip
878 strip
879 -----
879 -----
880
880
881 .. py:function:: strip(apiuser, repoid, revision, branch)
881 .. py:function:: strip(apiuser, repoid, revision, branch)
882
882
883 Strips the given revision from the specified repository.
883 Strips the given revision from the specified repository.
884
884
885 * This will remove the revision and all of its decendants.
885 * This will remove the revision and all of its decendants.
886
886
887 This command can only be run using an |authtoken| with admin rights to
887 This command can only be run using an |authtoken| with admin rights to
888 the specified repository.
888 the specified repository.
889
889
890 This command takes the following options:
890 This command takes the following options:
891
891
892 :param apiuser: This is filled automatically from the |authtoken|.
892 :param apiuser: This is filled automatically from the |authtoken|.
893 :type apiuser: AuthUser
893 :type apiuser: AuthUser
894 :param repoid: The repository name or repository ID.
894 :param repoid: The repository name or repository ID.
895 :type repoid: str or int
895 :type repoid: str or int
896 :param revision: The revision you wish to strip.
896 :param revision: The revision you wish to strip.
897 :type revision: str
897 :type revision: str
898 :param branch: The branch from which to strip the revision.
898 :param branch: The branch from which to strip the revision.
899 :type branch: str
899 :type branch: str
900
900
901 Example output:
901 Example output:
902
902
903 .. code-block:: bash
903 .. code-block:: bash
904
904
905 id : <id_given_in_input>
905 id : <id_given_in_input>
906 result : {
906 result : {
907 "msg": "'Stripped commit <commit_hash> from repo `<repository name>`'"
907 "msg": "'Stripped commit <commit_hash> from repo `<repository name>`'"
908 "repository": "<repository name>"
908 "repository": "<repository name>"
909 }
909 }
910 error : null
910 error : null
911
911
912 Example error output:
912 Example error output:
913
913
914 .. code-block:: bash
914 .. code-block:: bash
915
915
916 id : <id_given_in_input>
916 id : <id_given_in_input>
917 result : null
917 result : null
918 error : {
918 error : {
919 "Unable to strip commit <commit_hash> from repo `<repository name>`"
919 "Unable to strip commit <commit_hash> from repo `<repository name>`"
920 }
920 }
921
921
922
922
923 update_repo
923 update_repo
924 -----------
924 -----------
925
925
926 .. 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:''>)
926 .. 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:''>)
927
927
928 Updates a repository with the given information.
928 Updates a repository with the given information.
929
929
930 This command can only be run using an |authtoken| with at least
930 This command can only be run using an |authtoken| with at least
931 write permissions to the |repo|.
931 write permissions to the |repo|.
932
932
933 :param apiuser: This is filled automatically from the |authtoken|.
933 :param apiuser: This is filled automatically from the |authtoken|.
934 :type apiuser: AuthUser
934 :type apiuser: AuthUser
935 :param repoid: repository name or repository ID.
935 :param repoid: repository name or repository ID.
936 :type repoid: str or int
936 :type repoid: str or int
937 :param name: Update the |repo| name.
937 :param name: Update the |repo| name.
938 :type name: str
938 :type name: str
939 :param owner: Set the |repo| owner.
939 :param owner: Set the |repo| owner.
940 :type owner: str
940 :type owner: str
941 :param group: Set the |repo| group the |repo| belongs to.
941 :param group: Set the |repo| group the |repo| belongs to.
942 :type group: str
942 :type group: str
943 :param fork_of: Set the master |repo| name.
943 :param fork_of: Set the master |repo| name.
944 :type fork_of: str
944 :type fork_of: str
945 :param description: Update the |repo| description.
945 :param description: Update the |repo| description.
946 :type description: str
946 :type description: str
947 :param private: Set the |repo| as private. (True | False)
947 :param private: Set the |repo| as private. (True | False)
948 :type private: bool
948 :type private: bool
949 :param clone_uri: Update the |repo| clone URI.
949 :param clone_uri: Update the |repo| clone URI.
950 :type clone_uri: str
950 :type clone_uri: str
951 :param landing_rev: Set the |repo| landing revision. Default is
951 :param landing_rev: Set the |repo| landing revision. Default is
952 ``tip``.
952 ``tip``.
953 :type landing_rev: str
953 :type landing_rev: str
954 :param enable_statistics: Enable statistics on the |repo|,
954 :param enable_statistics: Enable statistics on the |repo|,
955 (True | False).
955 (True | False).
956 :type enable_statistics: bool
956 :type enable_statistics: bool
957 :param enable_locking: Enable |repo| locking.
957 :param enable_locking: Enable |repo| locking.
958 :type enable_locking: bool
958 :type enable_locking: bool
959 :param enable_downloads: Enable downloads from the |repo|,
959 :param enable_downloads: Enable downloads from the |repo|,
960 (True | False).
960 (True | False).
961 :type enable_downloads: bool
961 :type enable_downloads: bool
962 :param fields: Add extra fields to the |repo|. Use the following
962 :param fields: Add extra fields to the |repo|. Use the following
963 example format: ``field_key=field_val,field_key2=fieldval2``.
963 example format: ``field_key=field_val,field_key2=fieldval2``.
964 Escape ', ' with \,
964 Escape ', ' with \,
965 :type fields: str
965 :type fields: str
966
966
967
967
@@ -1,60 +1,60 b''
1
1
2 =====
2 ===================
3 API
3 CONTRIBUTING TO API
4 =====
4 ===================
5
5
6
6
7
7
8 Naming conventions
8 Naming conventions
9 ==================
9 ==================
10
10
11 We keep the calls in the form ``{verb}_{noun}``.
11 We keep the calls in the form ``{verb}_{noun}``.
12
12
13
13
14
14
15 Change and Deprecation
15 Change and Deprecation
16 ======================
16 ======================
17
17
18 API deprecation is documented in the section :ref:`deprecated` together with
18 API deprecation is documented in the section :ref:`deprecated` together with
19 other notes about deprecated parts of the application.
19 other notes about deprecated parts of the application.
20
20
21
21
22 Deprecated API calls
22 Deprecated API calls
23 --------------------
23 --------------------
24
24
25 - Make sure to add them into the section :ref:`deprecated`.
25 - Make sure to add them into the section :ref:`deprecated`.
26
26
27 - Use `deprecated` inside of the call docstring to make our users aware of the
27 - Use `deprecated` inside of the call docstring to make our users aware of the
28 deprecation::
28 deprecation::
29
29
30 .. deprecated:: 1.2.3
30 .. deprecated:: 1.2.3
31
31
32 Use `new_call_name` instead to fetch this information.
32 Use `new_call_name` instead to fetch this information.
33
33
34 - Make sure to log on level `logging.WARNING` a message that the API call or
34 - Make sure to log on level `logging.WARNING` a message that the API call or
35 specific parameters are deprecated.
35 specific parameters are deprecated.
36
36
37 - If possible return deprecation information inside of the result from the API
37 - If possible return deprecation information inside of the result from the API
38 call. Use the attribute `_warning_` to contain a message.
38 call. Use the attribute `_warning_` to contain a message.
39
39
40
40
41 Changed API calls
41 Changed API calls
42 -----------------
42 -----------------
43
43
44 - If the change is significant, consider to use `versionchanged` in the
44 - If the change is significant, consider to use `versionchanged` in the
45 docstring::
45 docstring::
46
46
47 .. versionchanged:: 1.2.3
47 .. versionchanged:: 1.2.3
48
48
49 Optional explanation if reasonable.
49 Optional explanation if reasonable.
50
50
51
51
52 Added API calls
52 Added API calls
53 ---------------
53 ---------------
54
54
55 - Use `versionadded` to document since which version this API call is
55 - Use `versionadded` to document since which version this API call is
56 available::
56 available::
57
57
58 .. versionadded:: 1.2.3
58 .. versionadded:: 1.2.3
59
59
60 Optional explanation if reasonable.
60 Optional explanation if reasonable.
@@ -1,137 +1,137 b''
1 .. _checklist-tickets:
1 .. _checklist-tickets:
2
2
3 =================
3 =================
4 Ticket Checklists
4 Ticket Checklists
5 =================
5 =================
6
6
7
7
8 Ticket Description
8 Ticket Description
9 ==================
9 ==================
10
10
11 In general these things really matter in the description:
11 In general these things really matter in the description:
12
12
13 - Reasoning / Rationale. Explain "WHY" it makes sense and is important.
13 - Reasoning / Rationale. Explain "WHY" it makes sense and is important.
14
14
15 - How to reproduce. Easy to follow steps, that’s important.
15 - How to reproduce. Easy to follow steps, that’s important.
16
16
17 - Observation: The problem (short)
17 - Observation: The problem (short)
18
18
19 - Expectation: How it should be (short)
19 - Expectation: How it should be (short)
20
20
21 - Specs: It is fine to draft them as good as it works.
21 - Specs: It is fine to draft them as good as it works.
22
22
23 If anything is unclear, please ask for a review or help on this via the
23 If anything is unclear, please ask for a review or help on this via the
24 Community Portal or Slack channel.
24 Community Portal or Slack channel.
25
25
26
26
27 Checklists for Tickets
27 Checklists for Tickets
28 ======================
28 ======================
29
29
30 BUG
30 BUG
31 ---
31 ---
32
32
33 Definition: An existing function that does not work as expected for the user.
33 Definition: An existing function that does not work as expected for the user.
34
34
35 - Problem description
35 - Problem description
36 - Steps needed to recreate (gherkin)
36 - Steps needed to recreate (gherkin)
37 - Link to the screen in question and/or description of how to find it via
37 - Link to the screen in question and/or description of how to find it via
38 navigation
38 navigation
39 - Explanation of what the expected outcome is
39 - Explanation of what the expected outcome is
40 - Any hints into the source of the problem
40 - Any hints into the source of the problem
41 - Information about platform/browser/db/etc. where applicable
41 - Information about platform/browser/db/etc. where applicable
42 - Examples of other similar cases which have different behaviour
42 - Examples of other similar cases which have different behaviour
43
43
44 DESIGN
44 DESIGN
45 ------
45 ------
46
46
47 Definition: Styling and user interface issues, including cosmetic improvements
47 Definition: Styling and user interface issues, including cosmetic improvements
48 or appearance and behaviour of frontend functionality.
48 or appearance and behaviour of frontend functionality.
49
49
50 - Screenshot/animation of existing page/behaviour
50 - Screenshot/animation of existing page/behaviour
51 - Sketches or wireframes if available
51 - Sketches or wireframes if available
52 - Link to the screen in question and/or description of how to find it via
52 - Link to the screen in question and/or description of how to find it via
53 navigation
53 navigation
54 - Problem description
54 - Problem description
55 - Explanation of what the expected outcome is
55 - Explanation of what the expected outcome is
56 - Since this may be examined by a designer; it should be written in a way that a
56 - Since this may be examined by a designer; it should be written in a way that a
57 non-developer can understand
57 non-developer can understand
58
58
59 EPIC
59 EPIC
60 ----
60 ----
61
61
62 Definition: A collection of tickets which together complete a larger overall
62 Definition: A collection of tickets which together complete a larger overall
63 project.
63 project.
64
64
65 - Benefit explanation
65 - Benefit explanation
66 - Clear objective - when is this complete?
66 - Clear objective - when is this complete?
67 - Explanations of exceptions/corner cases
67 - Explanations of exceptions/corner cases
68 - Documentation subtask
68 - Documentation subtask
69 - Comprehensive wireframes and/or design subtasks
69 - Comprehensive wireframes and/or design subtasks
70 - Links to subtasks
70 - Links to subtasks
71
71
72 FEATURE
72 FEATURE
73 -------
73 -------
74
74
75 Definition: A new function in the software which previously did not exist.
75 Definition: A new function in the software which previously did not exist.
76
76
77 - Benefit explanation
77 - Benefit explanation
78 - Clear objective
78 - Clear objective
79 - Explanations of exceptions/corner cases
79 - Explanations of exceptions/corner cases
80 - Documentation subtask
80 - Documentation subtask
81 - Comprehensive wireframes and/or design subtasks
81 - Comprehensive wireframes and/or design subtasks
82
82
83 SUPPORT
83 SUPPORT
84 -------
84 -------
85
85
86 Definition: An issue related to a customer report.
86 Definition: An issue related to a customer report.
87
87
88 - Link to support ticket, if available
88 - Link to support ticket, if available
89 - Problem description
89 - Problem description
90 - Steps needed to recreate (gherkin)
90 - Steps needed to recreate (gherkin)
91 - Link to the screen in question and/or description of how to find it via
91 - Link to the screen in question and/or description of how to find it via
92 navigation
92 navigation
93 - Explanation of what the expected outcome is
93 - Explanation of what the expected outcome is
94 - Any hints into the source of the problem
94 - Any hints into the source of the problem
95 - Information about platform/browser/db/etc. where applicable
95 - Information about platform/browser/db/etc. where applicable
96 - Examples of other similar cases which have different behaviour
96 - Examples of other similar cases which have different behaviour
97
97
98 TASK
98 TASK
99 ----
99 ----
100
100
101 Definition: An improvement or step towards implementing a feature or fixing
101 Definition: An improvement or step towards implementing a feature or fixing
102 a bug. Includes refactoring and other tech debt.
102 a bug. Includes refactoring and other tech debt.
103
103
104 - Clear objective
104 - Clear objective
105 - Benefit explanation
105 - Benefit explanation
106 - Links to parent/related tickets
106 - Links to parent/related tickets
107
107
108
108
109 All details below.
109 All details below.
110
110
111
111
112 External links:
112 External links:
113
113
114 - Avoid linking to external images; they disappear over time. Please attach any
114 - Avoid linking to external images; they disappear over time. Please attach any
115 relevant images to the ticket itself.
115 relevant images to the ticket itself.
116
116
117 - External links in general: They also disappear over time, consider copying the
117 - External links in general: They also disappear over time, consider copying the
118 relevant bit of information into a comment or write a paragraph to sum up the
118 relevant bit of information into a comment or write a paragraph to sum up the
119 general idea.
119 general idea.
120
120
121
121
122 Hints
122 Hints
123 =====
123 =====
124
124
125 Change Description
125 Change Description
126 ------------------
126 ------------------
127
127
128 It can be tricky to figure out how to change the description of a ticket. There
128 It can be tricky to figure out how to change the description of a ticket. There
129 is a very small pencil which has to be clicked once you see the edit form of a
129 is a very small pencil which has to be clicked once you see the edit form of a
130 ticket.
130 ticket.
131
131
132
132
133 .. figure:: images/redmine-description.png
133 .. figure:: ../images/redmine-description.png
134 :alt: Example of pencil to change the ticket description
134 :alt: Example of pencil to change the ticket description
135
135
136 Shows an example of the pencil which lets you change the description.
136 Shows an example of the pencil which lets you change the description.
137
137
@@ -1,75 +1,72 b''
1
1
2 .. _test-spec-by-example:
2 .. _test-spec-by-example:
3
3
4 ==========================
4 ==========================
5 Specification by Example
5 Specification by Example
6 ==========================
6 ==========================
7
7
8
8
9 .. Avoid duplicating the quickstart instructions by importing the README
9 .. Avoid duplicating the quickstart instructions by importing the README
10 file.
10 file.
11
11
12 .. include:: ../../../acceptance_tests/README.rst
13
14
15
12
16 Choices of technology and tools
13 Choices of technology and tools
17 ===============================
14 ===============================
18
15
19
16
20 `nix` as runtime environment
17 `nix` as runtime environment
21 ----------------------------
18 ----------------------------
22
19
23 We settled to use the `nix` tools to provide us the needed environment for
20 We settled to use the `nix` tools to provide us the needed environment for
24 running the tests.
21 running the tests.
25
22
26
23
27
24
28 `Gherkins` as specification language
25 `Gherkins` as specification language
29 ------------------------------------
26 ------------------------------------
30
27
31 To specify by example, we settled on Gherkins as the semi-formal specification
28 To specify by example, we settled on Gherkins as the semi-formal specification
32 language.
29 language.
33
30
34
31
35 `py.test` as a runner
32 `py.test` as a runner
36 ---------------------
33 ---------------------
37
34
38 After experimenting with `behave` and `py.test` our choice was `pytest-bdd`
35 After experimenting with `behave` and `py.test` our choice was `pytest-bdd`
39 because it allows us to use our existing knowledge about `py.test` and avoids
36 because it allows us to use our existing knowledge about `py.test` and avoids
40 that we have to learn another tool.
37 that we have to learn another tool.
41
38
42
39
43
40
44 Concepts
41 Concepts
45 ========
42 ========
46
43
47 The logic is structured around the design pattern of "page objects". The
44 The logic is structured around the design pattern of "page objects". The
48 documentation of `python-selemium` contains a few more details about this
45 documentation of `python-selemium` contains a few more details about this
49 pattern.
46 pattern.
50
47
51
48
52
49
53 Page Objects
50 Page Objects
54 ------------
51 ------------
55
52
56 We introduce an abstraction class for every page which we have to interact with
53 We introduce an abstraction class for every page which we have to interact with
57 in order to validate the specifications.
54 in order to validate the specifications.
58
55
59 The implementation for the page objects is inside of the module
56 The implementation for the page objects is inside of the module
60 :mod:`page_objects`. The class :class:`page_objects.base.BasePage` should be
57 :mod:`page_objects`. The class :class:`page_objects.base.BasePage` should be
61 used as a base for all page object implementations.
58 used as a base for all page object implementations.
62
59
63
60
64
61
65 Locators
62 Locators
66 --------
63 --------
67
64
68 The specific information how to locate an element inside of the DOM tree of a
65 The specific information how to locate an element inside of the DOM tree of a
69 page is kept in a separate class. This class serves mainly as a data container;
66 page is kept in a separate class. This class serves mainly as a data container;
70 it shall not contain any logic.
67 it shall not contain any logic.
71
68
72 The reason for keeping the locators separate is that we expect a frequent need
69 The reason for keeping the locators separate is that we expect a frequent need
73 for change whenever we work on our templates. In such a case, it is more
70 for change whenever we work on our templates. In such a case, it is more
74 efficient to have all of thelocators together and update them there instead of
71 efficient to have all of thelocators together and update them there instead of
75 having to find every locator inside of the logic of a page object.
72 having to find every locator inside of the logic of a page object.
@@ -1,144 +1,144 b''
1 { system ? builtins.currentSystem
1 { system ? builtins.currentSystem
2 }:
2 }:
3
3
4 let
4 let
5
5
6 pkgs = import <nixpkgs> { inherit system; };
6 pkgs = import <nixpkgs> { inherit system; };
7
7
8 inherit (pkgs) fetchurl fetchgit;
8 inherit (pkgs) fetchurl fetchgit;
9
9
10 buildPythonPackage = pkgs.python27Packages.buildPythonPackage;
10 buildPythonPackage = pkgs.python27Packages.buildPythonPackage;
11 python = pkgs.python27Packages.python;
11 python = pkgs.python27Packages.python;
12
12
13 Jinja2 = buildPythonPackage rec {
13 Jinja2 = buildPythonPackage rec {
14 name = "Jinja2-2.7.3";
14 name = "Jinja2-2.7.3";
15 src = fetchurl {
15 src = fetchurl {
16 url = "http://pypi.python.org/packages/source/J/Jinja2/${name}.tar.gz";
16 url = "http://pypi.python.org/packages/source/J/Jinja2/${name}.tar.gz";
17 md5 = "b9dffd2f3b43d673802fe857c8445b1a";
17 md5 = "b9dffd2f3b43d673802fe857c8445b1a";
18 };
18 };
19 propagatedBuildInputs = [ MarkupSafe ];
19 propagatedBuildInputs = [ MarkupSafe ];
20 };
20 };
21
21
22 MarkupSafe = buildPythonPackage rec {
22 MarkupSafe = buildPythonPackage rec {
23 name = "MarkupSafe-0.23";
23 name = "MarkupSafe-0.23";
24 src = fetchurl {
24 src = fetchurl {
25 url = "https://pypi.python.org/packages/source/M/MarkupSafe/${name}.tar.gz";
25 url = "https://pypi.python.org/packages/source/M/MarkupSafe/${name}.tar.gz";
26 md5 = "f5ab3deee4c37cd6a922fb81e730da6e";
26 md5 = "f5ab3deee4c37cd6a922fb81e730da6e";
27 };
27 };
28 };
28 };
29
29
30 Pygments = buildPythonPackage rec {
30 Pygments = buildPythonPackage rec {
31 name = "Pygments-2.1.3";
31 name = "Pygments-2.1.3";
32 doCheck = false;
32 doCheck = false;
33 src = fetchurl {
33 src = fetchurl {
34 url = "https://pypi.python.org/packages/b8/67/ab177979be1c81bc99c8d0592ef22d547e70bb4c6815c383286ed5dec504/Pygments-2.1.3.tar.gz";
34 url = "https://pypi.python.org/packages/b8/67/ab177979be1c81bc99c8d0592ef22d547e70bb4c6815c383286ed5dec504/Pygments-2.1.3.tar.gz";
35 md5 = "ed3fba2467c8afcda4d317e4ef2c6150";
35 md5 = "ed3fba2467c8afcda4d317e4ef2c6150";
36 };
36 };
37 };
37 };
38
38
39 alabaster = buildPythonPackage rec {
39 alabaster = buildPythonPackage rec {
40 name = "alabaster-0.7.3";
40 name = "alabaster-0.7.3";
41 src = fetchurl {
41 src = fetchurl {
42 url = "https://pypi.python.org/packages/source/a/alabaster/${name}.tar.gz";
42 url = "https://pypi.python.org/packages/source/a/alabaster/${name}.tar.gz";
43 md5 = "67428d1383fd833f1282fed5deba0898";
43 md5 = "67428d1383fd833f1282fed5deba0898";
44 };
44 };
45 };
45 };
46
46
47 six = buildPythonPackage rec {
47 six = buildPythonPackage rec {
48 name = "six-1.9.0";
48 name = "six-1.9.0";
49 src = fetchurl {
49 src = fetchurl {
50 url = "https://pypi.python.org/packages/source/s/six/${name}.tar.gz";
50 url = "https://pypi.python.org/packages/source/s/six/${name}.tar.gz";
51 md5 = "476881ef4012262dfc8adc645ee786c4";
51 md5 = "476881ef4012262dfc8adc645ee786c4";
52 };
52 };
53 };
53 };
54
54
55 snowballstemmer = buildPythonPackage rec {
55 snowballstemmer = buildPythonPackage rec {
56 name = "snowballstemmer-1.2.0";
56 name = "snowballstemmer-1.2.0";
57 src = fetchurl {
57 src = fetchurl {
58 url = "https://pypi.python.org/packages/source/s/snowballstemmer/${name}.tar.gz";
58 url = "https://pypi.python.org/packages/source/s/snowballstemmer/${name}.tar.gz";
59 md5 = "51f2ef829db8129dd0f2354f0b209970";
59 md5 = "51f2ef829db8129dd0f2354f0b209970";
60 };
60 };
61 };
61 };
62
62
63 pytz = buildPythonPackage rec {
63 pytz = buildPythonPackage rec {
64 name = "pytz-2015.2";
64 name = "pytz-2015.2";
65 src = fetchurl {
65 src = fetchurl {
66 url = "https://pypi.python.org/packages/source/p/pytz/${name}.tar.gz";
66 url = "https://pypi.python.org/packages/source/p/pytz/${name}.tar.gz";
67 md5 = "08440d994cfbbf13d3343362cc3173f7";
67 md5 = "08440d994cfbbf13d3343362cc3173f7";
68 };
68 };
69 };
69 };
70
70
71 babel = buildPythonPackage rec {
71 babel = buildPythonPackage rec {
72 name = "Babel-1.3";
72 name = "Babel-1.3";
73 src = fetchurl {
73 src = fetchurl {
74 url = "https://pypi.python.org/packages/source/B/Babel/${name}.tar.gz";
74 url = "https://pypi.python.org/packages/source/B/Babel/${name}.tar.gz";
75 md5 = "5264ceb02717843cbc9ffce8e6e06bdb";
75 md5 = "5264ceb02717843cbc9ffce8e6e06bdb";
76 };
76 };
77 propagatedBuildInputs = [
77 propagatedBuildInputs = [
78 pytz
78 pytz
79 ];
79 ];
80 };
80 };
81
81
82 imagesize = buildPythonPackage rec {
82 imagesize = buildPythonPackage rec {
83 name = "imagesize-0.7.1";
83 name = "imagesize-0.7.1";
84 src = fetchurl {
84 src = fetchurl {
85 url = "https://pypi.python.org/packages/53/72/6c6f1e787d9cab2cc733cf042f125abec07209a58308831c9f292504e826/${name}.tar.gz";
85 url = "https://pypi.python.org/packages/53/72/6c6f1e787d9cab2cc733cf042f125abec07209a58308831c9f292504e826/${name}.tar.gz";
86 md5 = "976148283286a6ba5f69b0f81aef8052";
86 md5 = "976148283286a6ba5f69b0f81aef8052";
87 };
87 };
88 };
88 };
89
89
90 Sphinx = buildPythonPackage (rec {
90 Sphinx = buildPythonPackage (rec {
91 name = "Sphinx-1.4.4";
91 name = "Sphinx-1.4.8";
92 src = fetchurl {
92 src = fetchurl {
93 url = "https://pypi.python.org/packages/20/a2/72f44c84f6c4115e3fef58d36d657ec311d80196eab9fd5ec7bcde76143b/${name}.tar.gz";
93 url = "https://pypi.python.org/packages/1f/f6/e54a7aad73e35232356103771ae76306dadd8546b024c646fbe75135571c/${name}.tar.gz";
94 md5 = "64ce2ec08d37ed56313a98232cbe2aee";
94 md5 = "5ec718a4855917e149498bba91b74e67";
95 };
95 };
96 propagatedBuildInputs = [
96 propagatedBuildInputs = [
97 docutils
97 docutils
98 Jinja2
98 Jinja2
99 Pygments
99 Pygments
100 alabaster
100 alabaster
101 six
101 six
102 snowballstemmer
102 snowballstemmer
103 pytz
103 pytz
104 babel
104 babel
105 imagesize
105 imagesize
106
106
107 # TODO: johbo: Had to include it here so that can be imported
107 # TODO: johbo: Had to include it here so that can be imported
108 sphinx_rtd_theme
108 sphinx_rtd_theme
109 ];
109 ];
110 });
110 });
111
111
112 docutils = buildPythonPackage rec {
112 docutils = buildPythonPackage rec {
113 name = "docutils-0.12";
113 name = "docutils-0.12";
114 src = fetchurl {
114 src = fetchurl {
115 url = "https://pypi.python.org/packages/source/d/docutils/${name}.tar.gz";
115 url = "https://pypi.python.org/packages/source/d/docutils/${name}.tar.gz";
116 md5 = "4622263b62c5c771c03502afa3157768";
116 md5 = "4622263b62c5c771c03502afa3157768";
117 };
117 };
118 };
118 };
119
119
120 sphinx_rtd_theme = buildPythonPackage rec {
120 sphinx_rtd_theme = buildPythonPackage rec {
121 name = "sphinx_rtd_theme-0.1.9";
121 name = "sphinx_rtd_theme-0.1.9";
122 src = fetchurl {
122 src = fetchurl {
123 url = "https://pypi.python.org/packages/source/s/sphinx_rtd_theme/${name}.tar.gz";
123 url = "https://pypi.python.org/packages/source/s/sphinx_rtd_theme/${name}.tar.gz";
124 md5 = "86a25c8d47147c872e42dc84cc66f97b";
124 md5 = "86a25c8d47147c872e42dc84cc66f97b";
125 };
125 };
126
126
127 # Note: johbo: Sphinx needs this package and this package needs sphinx,
127 # Note: johbo: Sphinx needs this package and this package needs sphinx,
128 # ignore the requirements file to solve this cycle.
128 # ignore the requirements file to solve this cycle.
129 postPatch = ''
129 postPatch = ''
130 rm requirements.txt
130 rm requirements.txt
131 touch requirements.txt
131 touch requirements.txt
132 '';
132 '';
133
133
134 # TODO: johbo: Tests would require sphinx and this creates recursion issues
134 # TODO: johbo: Tests would require sphinx and this creates recursion issues
135 doCheck = false;
135 doCheck = false;
136 };
136 };
137
137
138 in python.buildEnv.override {
138 in python.buildEnv.override {
139 inherit python;
139 inherit python;
140 extraLibs = [
140 extraLibs = [
141 Sphinx
141 Sphinx
142 sphinx_rtd_theme
142 sphinx_rtd_theme
143 ];
143 ];
144 }
144 }
@@ -1,52 +1,53 b''
1 .. _integrations:
1 .. _integrations:
2
2
3 Integrations
3 Integrations
4 ------------
4 ------------
5
5
6 Rhodecode supports integrations with external services for various events,
6 Rhodecode supports integrations with external services for various events,
7 such as commit pushes and pull requests. Multiple integrations of the same type
7 such as commit pushes and pull requests. Multiple integrations of the same type
8 can be added at the same time; this is useful for posting different events to
8 can be added at the same time; this is useful for posting different events to
9 different Slack channels, for example.
9 different Slack channels, for example.
10
10
11 Supported integrations
11 Supported integrations
12 ^^^^^^^^^^^^^^^^^^^^^^
12 ^^^^^^^^^^^^^^^^^^^^^^
13
13
14 ============================ ============ =====================================
14 ============================ ============ =====================================
15 Type/Name |RC| Edition Description
15 Type/Name |RC| Edition Description
16 ============================ ============ =====================================
16 ============================ ============ =====================================
17 :ref:`integrations-slack` |RCCEshort| https://slack.com/
17 :ref:`integrations-slack` |RCCEshort| https://slack.com/
18 :ref:`integrations-hipchat` |RCCEshort| https://www.hipchat.com/
18 :ref:`integrations-hipchat` |RCCEshort| https://www.hipchat.com/
19 :ref:`integrations-webhook` |RCCEshort| POST events as `json` to a custom url
19 :ref:`integrations-webhook` |RCCEshort| POST events as `json` to a custom url
20 :ref:`integrations-email` |RCEEshort| Send repo push commits by email
20 :ref:`integrations-email` |RCEEshort| Send repo push commits by email
21 :ref:`integrations-redmine` |RCEEshort| Close/Resolve/Reference redmine issues
21 :ref:`integrations-redmine` |RCEEshort| Close/Resolve/Reference redmine issues
22 :ref:`integrations-jira` |RCEEshort| Close/Resolve/Reference JIRA issues
22 :ref:`integrations-jira` |RCEEshort| Close/Resolve/Reference JIRA issues
23 ============================ ============ =====================================
23 ============================ ============ =====================================
24
24
25 .. _creating-integrations:
25 .. _creating-integrations:
26
26
27 Creating an Integration
27 Creating an Integration
28 ^^^^^^^^^^^^^^^^^^^^^^^
28 ^^^^^^^^^^^^^^^^^^^^^^^
29
29
30 Integrations can be added globally via the admin UI:
30 Integrations can be added globally via the admin UI:
31
31
32 :menuselection:`Admin --> Integrations`
32 :menuselection:`Admin --> Integrations`
33
33
34 or per repository in each repository's settings:
34 or per repository in each repository's settings:
35
35
36 :menuselection:`Admin --> Repositories --> Edit --> Integrations`
36 :menuselection:`Admin --> Repositories --> Edit --> Integrations`
37
37
38 To create an integration, select the type from the list in the *Create New
38 To create an integration, select the type from the list in the *Create New
39 Integration* section.
39 Integration* section.
40
40
41 The *Current Integrations* section shows existing integrations that have been
41 The *Current Integrations* section shows existing integrations that have been
42 created along with their type (eg. Slack) and enabled status.
42 created along with their type (eg. Slack) and enabled status.
43
43
44 See pages specific to each type of integration for more instructions:
44 See pages specific to each type of integration for more instructions:
45
45
46 .. toctree::
46 .. toctree::
47
47
48 slack
48 slack
49 hipchat
49 hipchat
50 redmine
50 redmine
51 jira
51 jira
52 webhook
52 webhook
53 email
@@ -1,1888 +1,1888 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2
2
3 # Copyright (C) 2011-2016 RhodeCode GmbH
3 # Copyright (C) 2011-2016 RhodeCode GmbH
4 #
4 #
5 # This program is free software: you can redistribute it and/or modify
5 # This program is free software: you can redistribute it and/or modify
6 # it under the terms of the GNU Affero General Public License, version 3
6 # it under the terms of the GNU Affero General Public License, version 3
7 # (only), as published by the Free Software Foundation.
7 # (only), as published by the Free Software Foundation.
8 #
8 #
9 # This program is distributed in the hope that it will be useful,
9 # This program is distributed in the hope that it will be useful,
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 # GNU General Public License for more details.
12 # GNU General Public License for more details.
13 #
13 #
14 # You should have received a copy of the GNU Affero General Public License
14 # You should have received a copy of the GNU Affero General Public License
15 # along with this program. If not, see <http://www.gnu.org/licenses/>.
15 # along with this program. If not, see <http://www.gnu.org/licenses/>.
16 #
16 #
17 # This program is dual-licensed. If you wish to learn more about the
17 # This program is dual-licensed. If you wish to learn more about the
18 # RhodeCode Enterprise Edition, including its added features, Support services,
18 # RhodeCode Enterprise Edition, including its added features, Support services,
19 # and proprietary license terms, please see https://rhodecode.com/licenses/
19 # and proprietary license terms, please see https://rhodecode.com/licenses/
20
20
21 import logging
21 import logging
22 import time
22 import time
23
23
24 import colander
24 import colander
25
25
26 from rhodecode import BACKENDS
26 from rhodecode import BACKENDS
27 from rhodecode.api import jsonrpc_method, JSONRPCError, JSONRPCForbidden, json
27 from rhodecode.api import jsonrpc_method, JSONRPCError, JSONRPCForbidden, json
28 from rhodecode.api.utils import (
28 from rhodecode.api.utils import (
29 has_superadmin_permission, Optional, OAttr, get_repo_or_error,
29 has_superadmin_permission, Optional, OAttr, get_repo_or_error,
30 get_user_group_or_error, get_user_or_error, has_repo_permissions,
30 get_user_group_or_error, get_user_or_error, has_repo_permissions,
31 get_perm_or_error, store_update, get_repo_group_or_error, parse_args,
31 get_perm_or_error, store_update, get_repo_group_or_error, parse_args,
32 get_origin, build_commit_data)
32 get_origin, build_commit_data)
33 from rhodecode.lib.auth import (
33 from rhodecode.lib.auth import (
34 HasPermissionAnyApi, HasRepoGroupPermissionAnyApi,
34 HasPermissionAnyApi, HasRepoGroupPermissionAnyApi,
35 HasUserGroupPermissionAnyApi)
35 HasUserGroupPermissionAnyApi)
36 from rhodecode.lib.exceptions import StatusChangeOnClosedPullRequestError
36 from rhodecode.lib.exceptions import StatusChangeOnClosedPullRequestError
37 from rhodecode.lib.utils import map_groups
37 from rhodecode.lib.utils import map_groups
38 from rhodecode.lib.utils2 import str2bool, time_to_datetime
38 from rhodecode.lib.utils2 import str2bool, time_to_datetime
39 from rhodecode.model.changeset_status import ChangesetStatusModel
39 from rhodecode.model.changeset_status import ChangesetStatusModel
40 from rhodecode.model.comment import ChangesetCommentsModel
40 from rhodecode.model.comment import ChangesetCommentsModel
41 from rhodecode.model.db import (
41 from rhodecode.model.db import (
42 Session, ChangesetStatus, RepositoryField, Repository)
42 Session, ChangesetStatus, RepositoryField, Repository)
43 from rhodecode.model.repo import RepoModel
43 from rhodecode.model.repo import RepoModel
44 from rhodecode.model.repo_group import RepoGroupModel
44 from rhodecode.model.repo_group import RepoGroupModel
45 from rhodecode.model.scm import ScmModel, RepoList
45 from rhodecode.model.scm import ScmModel, RepoList
46 from rhodecode.model.settings import SettingsModel, VcsSettingsModel
46 from rhodecode.model.settings import SettingsModel, VcsSettingsModel
47 from rhodecode.model.validation_schema.schemas import repo_schema
47 from rhodecode.model.validation_schema.schemas import repo_schema
48
48
49 log = logging.getLogger(__name__)
49 log = logging.getLogger(__name__)
50
50
51
51
52 @jsonrpc_method()
52 @jsonrpc_method()
53 def get_repo(request, apiuser, repoid, cache=Optional(True)):
53 def get_repo(request, apiuser, repoid, cache=Optional(True)):
54 """
54 """
55 Gets an existing repository by its name or repository_id.
55 Gets an existing repository by its name or repository_id.
56
56
57 The members section so the output returns users groups or users
57 The members section so the output returns users groups or users
58 associated with that repository.
58 associated with that repository.
59
59
60 This command can only be run using an |authtoken| with admin rights,
60 This command can only be run using an |authtoken| with admin rights,
61 or users with at least read rights to the |repo|.
61 or users with at least read rights to the |repo|.
62
62
63 :param apiuser: This is filled automatically from the |authtoken|.
63 :param apiuser: This is filled automatically from the |authtoken|.
64 :type apiuser: AuthUser
64 :type apiuser: AuthUser
65 :param repoid: The repository name or repository id.
65 :param repoid: The repository name or repository id.
66 :type repoid: str or int
66 :type repoid: str or int
67 :param cache: use the cached value for last changeset
67 :param cache: use the cached value for last changeset
68 :type: cache: Optional(bool)
68 :type: cache: Optional(bool)
69
69
70 Example output:
70 Example output:
71
71
72 .. code-block:: bash
72 .. code-block:: bash
73
73
74 {
74 {
75 "error": null,
75 "error": null,
76 "id": <repo_id>,
76 "id": <repo_id>,
77 "result": {
77 "result": {
78 "clone_uri": null,
78 "clone_uri": null,
79 "created_on": "timestamp",
79 "created_on": "timestamp",
80 "description": "repo description",
80 "description": "repo description",
81 "enable_downloads": false,
81 "enable_downloads": false,
82 "enable_locking": false,
82 "enable_locking": false,
83 "enable_statistics": false,
83 "enable_statistics": false,
84 "followers": [
84 "followers": [
85 {
85 {
86 "active": true,
86 "active": true,
87 "admin": false,
87 "admin": false,
88 "api_key": "****************************************",
88 "api_key": "****************************************",
89 "api_keys": [
89 "api_keys": [
90 "****************************************"
90 "****************************************"
91 ],
91 ],
92 "email": "user@example.com",
92 "email": "user@example.com",
93 "emails": [
93 "emails": [
94 "user@example.com"
94 "user@example.com"
95 ],
95 ],
96 "extern_name": "rhodecode",
96 "extern_name": "rhodecode",
97 "extern_type": "rhodecode",
97 "extern_type": "rhodecode",
98 "firstname": "username",
98 "firstname": "username",
99 "ip_addresses": [],
99 "ip_addresses": [],
100 "language": null,
100 "language": null,
101 "last_login": "2015-09-16T17:16:35.854",
101 "last_login": "2015-09-16T17:16:35.854",
102 "lastname": "surname",
102 "lastname": "surname",
103 "user_id": <user_id>,
103 "user_id": <user_id>,
104 "username": "name"
104 "username": "name"
105 }
105 }
106 ],
106 ],
107 "fork_of": "parent-repo",
107 "fork_of": "parent-repo",
108 "landing_rev": [
108 "landing_rev": [
109 "rev",
109 "rev",
110 "tip"
110 "tip"
111 ],
111 ],
112 "last_changeset": {
112 "last_changeset": {
113 "author": "User <user@example.com>",
113 "author": "User <user@example.com>",
114 "branch": "default",
114 "branch": "default",
115 "date": "timestamp",
115 "date": "timestamp",
116 "message": "last commit message",
116 "message": "last commit message",
117 "parents": [
117 "parents": [
118 {
118 {
119 "raw_id": "commit-id"
119 "raw_id": "commit-id"
120 }
120 }
121 ],
121 ],
122 "raw_id": "commit-id",
122 "raw_id": "commit-id",
123 "revision": <revision number>,
123 "revision": <revision number>,
124 "short_id": "short id"
124 "short_id": "short id"
125 },
125 },
126 "lock_reason": null,
126 "lock_reason": null,
127 "locked_by": null,
127 "locked_by": null,
128 "locked_date": null,
128 "locked_date": null,
129 "members": [
129 "members": [
130 {
130 {
131 "name": "super-admin-name",
131 "name": "super-admin-name",
132 "origin": "super-admin",
132 "origin": "super-admin",
133 "permission": "repository.admin",
133 "permission": "repository.admin",
134 "type": "user"
134 "type": "user"
135 },
135 },
136 {
136 {
137 "name": "owner-name",
137 "name": "owner-name",
138 "origin": "owner",
138 "origin": "owner",
139 "permission": "repository.admin",
139 "permission": "repository.admin",
140 "type": "user"
140 "type": "user"
141 },
141 },
142 {
142 {
143 "name": "user-group-name",
143 "name": "user-group-name",
144 "origin": "permission",
144 "origin": "permission",
145 "permission": "repository.write",
145 "permission": "repository.write",
146 "type": "user_group"
146 "type": "user_group"
147 }
147 }
148 ],
148 ],
149 "owner": "owner-name",
149 "owner": "owner-name",
150 "permissions": [
150 "permissions": [
151 {
151 {
152 "name": "super-admin-name",
152 "name": "super-admin-name",
153 "origin": "super-admin",
153 "origin": "super-admin",
154 "permission": "repository.admin",
154 "permission": "repository.admin",
155 "type": "user"
155 "type": "user"
156 },
156 },
157 {
157 {
158 "name": "owner-name",
158 "name": "owner-name",
159 "origin": "owner",
159 "origin": "owner",
160 "permission": "repository.admin",
160 "permission": "repository.admin",
161 "type": "user"
161 "type": "user"
162 },
162 },
163 {
163 {
164 "name": "user-group-name",
164 "name": "user-group-name",
165 "origin": "permission",
165 "origin": "permission",
166 "permission": "repository.write",
166 "permission": "repository.write",
167 "type": "user_group"
167 "type": "user_group"
168 }
168 }
169 ],
169 ],
170 "private": true,
170 "private": true,
171 "repo_id": 676,
171 "repo_id": 676,
172 "repo_name": "user-group/repo-name",
172 "repo_name": "user-group/repo-name",
173 "repo_type": "hg"
173 "repo_type": "hg"
174 }
174 }
175 }
175 }
176 """
176 """
177
177
178 repo = get_repo_or_error(repoid)
178 repo = get_repo_or_error(repoid)
179 cache = Optional.extract(cache)
179 cache = Optional.extract(cache)
180 include_secrets = False
180 include_secrets = False
181 if has_superadmin_permission(apiuser):
181 if has_superadmin_permission(apiuser):
182 include_secrets = True
182 include_secrets = True
183 else:
183 else:
184 # check if we have at least read permission for this repo !
184 # check if we have at least read permission for this repo !
185 _perms = (
185 _perms = (
186 'repository.admin', 'repository.write', 'repository.read',)
186 'repository.admin', 'repository.write', 'repository.read',)
187 has_repo_permissions(apiuser, repoid, repo, _perms)
187 has_repo_permissions(apiuser, repoid, repo, _perms)
188
188
189 permissions = []
189 permissions = []
190 for _user in repo.permissions():
190 for _user in repo.permissions():
191 user_data = {
191 user_data = {
192 'name': _user.username,
192 'name': _user.username,
193 'permission': _user.permission,
193 'permission': _user.permission,
194 'origin': get_origin(_user),
194 'origin': get_origin(_user),
195 'type': "user",
195 'type': "user",
196 }
196 }
197 permissions.append(user_data)
197 permissions.append(user_data)
198
198
199 for _user_group in repo.permission_user_groups():
199 for _user_group in repo.permission_user_groups():
200 user_group_data = {
200 user_group_data = {
201 'name': _user_group.users_group_name,
201 'name': _user_group.users_group_name,
202 'permission': _user_group.permission,
202 'permission': _user_group.permission,
203 'origin': get_origin(_user_group),
203 'origin': get_origin(_user_group),
204 'type': "user_group",
204 'type': "user_group",
205 }
205 }
206 permissions.append(user_group_data)
206 permissions.append(user_group_data)
207
207
208 following_users = [
208 following_users = [
209 user.user.get_api_data(include_secrets=include_secrets)
209 user.user.get_api_data(include_secrets=include_secrets)
210 for user in repo.followers]
210 for user in repo.followers]
211
211
212 if not cache:
212 if not cache:
213 repo.update_commit_cache()
213 repo.update_commit_cache()
214 data = repo.get_api_data(include_secrets=include_secrets)
214 data = repo.get_api_data(include_secrets=include_secrets)
215 data['members'] = permissions # TODO: this should be deprecated soon
215 data['members'] = permissions # TODO: this should be deprecated soon
216 data['permissions'] = permissions
216 data['permissions'] = permissions
217 data['followers'] = following_users
217 data['followers'] = following_users
218 return data
218 return data
219
219
220
220
221 @jsonrpc_method()
221 @jsonrpc_method()
222 def get_repos(request, apiuser):
222 def get_repos(request, apiuser):
223 """
223 """
224 Lists all existing repositories.
224 Lists all existing repositories.
225
225
226 This command can only be run using an |authtoken| with admin rights,
226 This command can only be run using an |authtoken| with admin rights,
227 or users with at least read rights to |repos|.
227 or users with at least read rights to |repos|.
228
228
229 :param apiuser: This is filled automatically from the |authtoken|.
229 :param apiuser: This is filled automatically from the |authtoken|.
230 :type apiuser: AuthUser
230 :type apiuser: AuthUser
231
231
232 Example output:
232 Example output:
233
233
234 .. code-block:: bash
234 .. code-block:: bash
235
235
236 id : <id_given_in_input>
236 id : <id_given_in_input>
237 result: [
237 result: [
238 {
238 {
239 "repo_id" : "<repo_id>",
239 "repo_id" : "<repo_id>",
240 "repo_name" : "<reponame>"
240 "repo_name" : "<reponame>"
241 "repo_type" : "<repo_type>",
241 "repo_type" : "<repo_type>",
242 "clone_uri" : "<clone_uri>",
242 "clone_uri" : "<clone_uri>",
243 "private": : "<bool>",
243 "private": : "<bool>",
244 "created_on" : "<datetimecreated>",
244 "created_on" : "<datetimecreated>",
245 "description" : "<description>",
245 "description" : "<description>",
246 "landing_rev": "<landing_rev>",
246 "landing_rev": "<landing_rev>",
247 "owner": "<repo_owner>",
247 "owner": "<repo_owner>",
248 "fork_of": "<name_of_fork_parent>",
248 "fork_of": "<name_of_fork_parent>",
249 "enable_downloads": "<bool>",
249 "enable_downloads": "<bool>",
250 "enable_locking": "<bool>",
250 "enable_locking": "<bool>",
251 "enable_statistics": "<bool>",
251 "enable_statistics": "<bool>",
252 },
252 },
253 ...
253 ...
254 ]
254 ]
255 error: null
255 error: null
256 """
256 """
257
257
258 include_secrets = has_superadmin_permission(apiuser)
258 include_secrets = has_superadmin_permission(apiuser)
259 _perms = ('repository.read', 'repository.write', 'repository.admin',)
259 _perms = ('repository.read', 'repository.write', 'repository.admin',)
260 extras = {'user': apiuser}
260 extras = {'user': apiuser}
261
261
262 repo_list = RepoList(
262 repo_list = RepoList(
263 RepoModel().get_all(), perm_set=_perms, extra_kwargs=extras)
263 RepoModel().get_all(), perm_set=_perms, extra_kwargs=extras)
264 return [repo.get_api_data(include_secrets=include_secrets)
264 return [repo.get_api_data(include_secrets=include_secrets)
265 for repo in repo_list]
265 for repo in repo_list]
266
266
267
267
268 @jsonrpc_method()
268 @jsonrpc_method()
269 def get_repo_changeset(request, apiuser, repoid, revision,
269 def get_repo_changeset(request, apiuser, repoid, revision,
270 details=Optional('basic')):
270 details=Optional('basic')):
271 """
271 """
272 Returns information about a changeset.
272 Returns information about a changeset.
273
273
274 Additionally parameters define the amount of details returned by
274 Additionally parameters define the amount of details returned by
275 this function.
275 this function.
276
276
277 This command can only be run using an |authtoken| with admin rights,
277 This command can only be run using an |authtoken| with admin rights,
278 or users with at least read rights to the |repo|.
278 or users with at least read rights to the |repo|.
279
279
280 :param apiuser: This is filled automatically from the |authtoken|.
280 :param apiuser: This is filled automatically from the |authtoken|.
281 :type apiuser: AuthUser
281 :type apiuser: AuthUser
282 :param repoid: The repository name or repository id
282 :param repoid: The repository name or repository id
283 :type repoid: str or int
283 :type repoid: str or int
284 :param revision: revision for which listing should be done
284 :param revision: revision for which listing should be done
285 :type revision: str
285 :type revision: str
286 :param details: details can be 'basic|extended|full' full gives diff
286 :param details: details can be 'basic|extended|full' full gives diff
287 info details like the diff itself, and number of changed files etc.
287 info details like the diff itself, and number of changed files etc.
288 :type details: Optional(str)
288 :type details: Optional(str)
289
289
290 """
290 """
291 repo = get_repo_or_error(repoid)
291 repo = get_repo_or_error(repoid)
292 if not has_superadmin_permission(apiuser):
292 if not has_superadmin_permission(apiuser):
293 _perms = (
293 _perms = (
294 'repository.admin', 'repository.write', 'repository.read',)
294 'repository.admin', 'repository.write', 'repository.read',)
295 has_repo_permissions(apiuser, repoid, repo, _perms)
295 has_repo_permissions(apiuser, repoid, repo, _perms)
296
296
297 changes_details = Optional.extract(details)
297 changes_details = Optional.extract(details)
298 _changes_details_types = ['basic', 'extended', 'full']
298 _changes_details_types = ['basic', 'extended', 'full']
299 if changes_details not in _changes_details_types:
299 if changes_details not in _changes_details_types:
300 raise JSONRPCError(
300 raise JSONRPCError(
301 'ret_type must be one of %s' % (
301 'ret_type must be one of %s' % (
302 ','.join(_changes_details_types)))
302 ','.join(_changes_details_types)))
303
303
304 pre_load = ['author', 'branch', 'date', 'message', 'parents',
304 pre_load = ['author', 'branch', 'date', 'message', 'parents',
305 'status', '_commit', '_file_paths']
305 'status', '_commit', '_file_paths']
306
306
307 try:
307 try:
308 cs = repo.get_commit(commit_id=revision, pre_load=pre_load)
308 cs = repo.get_commit(commit_id=revision, pre_load=pre_load)
309 except TypeError as e:
309 except TypeError as e:
310 raise JSONRPCError(e.message)
310 raise JSONRPCError(e.message)
311 _cs_json = cs.__json__()
311 _cs_json = cs.__json__()
312 _cs_json['diff'] = build_commit_data(cs, changes_details)
312 _cs_json['diff'] = build_commit_data(cs, changes_details)
313 if changes_details == 'full':
313 if changes_details == 'full':
314 _cs_json['refs'] = {
314 _cs_json['refs'] = {
315 'branches': [cs.branch],
315 'branches': [cs.branch],
316 'bookmarks': getattr(cs, 'bookmarks', []),
316 'bookmarks': getattr(cs, 'bookmarks', []),
317 'tags': cs.tags
317 'tags': cs.tags
318 }
318 }
319 return _cs_json
319 return _cs_json
320
320
321
321
322 @jsonrpc_method()
322 @jsonrpc_method()
323 def get_repo_changesets(request, apiuser, repoid, start_rev, limit,
323 def get_repo_changesets(request, apiuser, repoid, start_rev, limit,
324 details=Optional('basic')):
324 details=Optional('basic')):
325 """
325 """
326 Returns a set of commits limited by the number starting
326 Returns a set of commits limited by the number starting
327 from the `start_rev` option.
327 from the `start_rev` option.
328
328
329 Additional parameters define the amount of details returned by this
329 Additional parameters define the amount of details returned by this
330 function.
330 function.
331
331
332 This command can only be run using an |authtoken| with admin rights,
332 This command can only be run using an |authtoken| with admin rights,
333 or users with at least read rights to |repos|.
333 or users with at least read rights to |repos|.
334
334
335 :param apiuser: This is filled automatically from the |authtoken|.
335 :param apiuser: This is filled automatically from the |authtoken|.
336 :type apiuser: AuthUser
336 :type apiuser: AuthUser
337 :param repoid: The repository name or repository ID.
337 :param repoid: The repository name or repository ID.
338 :type repoid: str or int
338 :type repoid: str or int
339 :param start_rev: The starting revision from where to get changesets.
339 :param start_rev: The starting revision from where to get changesets.
340 :type start_rev: str
340 :type start_rev: str
341 :param limit: Limit the number of commits to this amount
341 :param limit: Limit the number of commits to this amount
342 :type limit: str or int
342 :type limit: str or int
343 :param details: Set the level of detail returned. Valid option are:
343 :param details: Set the level of detail returned. Valid option are:
344 ``basic``, ``extended`` and ``full``.
344 ``basic``, ``extended`` and ``full``.
345 :type details: Optional(str)
345 :type details: Optional(str)
346
346
347 .. note::
347 .. note::
348
348
349 Setting the parameter `details` to the value ``full`` is extensive
349 Setting the parameter `details` to the value ``full`` is extensive
350 and returns details like the diff itself, and the number
350 and returns details like the diff itself, and the number
351 of changed files.
351 of changed files.
352
352
353 """
353 """
354 repo = get_repo_or_error(repoid)
354 repo = get_repo_or_error(repoid)
355 if not has_superadmin_permission(apiuser):
355 if not has_superadmin_permission(apiuser):
356 _perms = (
356 _perms = (
357 'repository.admin', 'repository.write', 'repository.read',)
357 'repository.admin', 'repository.write', 'repository.read',)
358 has_repo_permissions(apiuser, repoid, repo, _perms)
358 has_repo_permissions(apiuser, repoid, repo, _perms)
359
359
360 changes_details = Optional.extract(details)
360 changes_details = Optional.extract(details)
361 _changes_details_types = ['basic', 'extended', 'full']
361 _changes_details_types = ['basic', 'extended', 'full']
362 if changes_details not in _changes_details_types:
362 if changes_details not in _changes_details_types:
363 raise JSONRPCError(
363 raise JSONRPCError(
364 'ret_type must be one of %s' % (
364 'ret_type must be one of %s' % (
365 ','.join(_changes_details_types)))
365 ','.join(_changes_details_types)))
366
366
367 limit = int(limit)
367 limit = int(limit)
368 pre_load = ['author', 'branch', 'date', 'message', 'parents',
368 pre_load = ['author', 'branch', 'date', 'message', 'parents',
369 'status', '_commit', '_file_paths']
369 'status', '_commit', '_file_paths']
370
370
371 vcs_repo = repo.scm_instance()
371 vcs_repo = repo.scm_instance()
372 # SVN needs a special case to distinguish its index and commit id
372 # SVN needs a special case to distinguish its index and commit id
373 if vcs_repo and vcs_repo.alias == 'svn' and (start_rev == '0'):
373 if vcs_repo and vcs_repo.alias == 'svn' and (start_rev == '0'):
374 start_rev = vcs_repo.commit_ids[0]
374 start_rev = vcs_repo.commit_ids[0]
375
375
376 try:
376 try:
377 commits = vcs_repo.get_commits(
377 commits = vcs_repo.get_commits(
378 start_id=start_rev, pre_load=pre_load)
378 start_id=start_rev, pre_load=pre_load)
379 except TypeError as e:
379 except TypeError as e:
380 raise JSONRPCError(e.message)
380 raise JSONRPCError(e.message)
381 except Exception:
381 except Exception:
382 log.exception('Fetching of commits failed')
382 log.exception('Fetching of commits failed')
383 raise JSONRPCError('Error occurred during commit fetching')
383 raise JSONRPCError('Error occurred during commit fetching')
384
384
385 ret = []
385 ret = []
386 for cnt, commit in enumerate(commits):
386 for cnt, commit in enumerate(commits):
387 if cnt >= limit != -1:
387 if cnt >= limit != -1:
388 break
388 break
389 _cs_json = commit.__json__()
389 _cs_json = commit.__json__()
390 _cs_json['diff'] = build_commit_data(commit, changes_details)
390 _cs_json['diff'] = build_commit_data(commit, changes_details)
391 if changes_details == 'full':
391 if changes_details == 'full':
392 _cs_json['refs'] = {
392 _cs_json['refs'] = {
393 'branches': [commit.branch],
393 'branches': [commit.branch],
394 'bookmarks': getattr(commit, 'bookmarks', []),
394 'bookmarks': getattr(commit, 'bookmarks', []),
395 'tags': commit.tags
395 'tags': commit.tags
396 }
396 }
397 ret.append(_cs_json)
397 ret.append(_cs_json)
398 return ret
398 return ret
399
399
400
400
401 @jsonrpc_method()
401 @jsonrpc_method()
402 def get_repo_nodes(request, apiuser, repoid, revision, root_path,
402 def get_repo_nodes(request, apiuser, repoid, revision, root_path,
403 ret_type=Optional('all'), details=Optional('basic'),
403 ret_type=Optional('all'), details=Optional('basic'),
404 max_file_bytes=Optional(None)):
404 max_file_bytes=Optional(None)):
405 """
405 """
406 Returns a list of nodes and children in a flat list for a given
406 Returns a list of nodes and children in a flat list for a given
407 path at given revision.
407 path at given revision.
408
408
409 It's possible to specify ret_type to show only `files` or `dirs`.
409 It's possible to specify ret_type to show only `files` or `dirs`.
410
410
411 This command can only be run using an |authtoken| with admin rights,
411 This command can only be run using an |authtoken| with admin rights,
412 or users with at least read rights to |repos|.
412 or users with at least read rights to |repos|.
413
413
414 :param apiuser: This is filled automatically from the |authtoken|.
414 :param apiuser: This is filled automatically from the |authtoken|.
415 :type apiuser: AuthUser
415 :type apiuser: AuthUser
416 :param repoid: The repository name or repository ID.
416 :param repoid: The repository name or repository ID.
417 :type repoid: str or int
417 :type repoid: str or int
418 :param revision: The revision for which listing should be done.
418 :param revision: The revision for which listing should be done.
419 :type revision: str
419 :type revision: str
420 :param root_path: The path from which to start displaying.
420 :param root_path: The path from which to start displaying.
421 :type root_path: str
421 :type root_path: str
422 :param ret_type: Set the return type. Valid options are
422 :param ret_type: Set the return type. Valid options are
423 ``all`` (default), ``files`` and ``dirs``.
423 ``all`` (default), ``files`` and ``dirs``.
424 :type ret_type: Optional(str)
424 :type ret_type: Optional(str)
425 :param details: Returns extended information about nodes, such as
425 :param details: Returns extended information about nodes, such as
426 md5, binary, and or content. The valid options are ``basic`` and
426 md5, binary, and or content. The valid options are ``basic`` and
427 ``full``.
427 ``full``.
428 :type details: Optional(str)
428 :type details: Optional(str)
429 :param max_file_bytes: Only return file content under this file size bytes
429 :param max_file_bytes: Only return file content under this file size bytes
430 :type details: Optional(int)
430 :type details: Optional(int)
431
431
432 Example output:
432 Example output:
433
433
434 .. code-block:: bash
434 .. code-block:: bash
435
435
436 id : <id_given_in_input>
436 id : <id_given_in_input>
437 result: [
437 result: [
438 {
438 {
439 "name" : "<name>"
439 "name" : "<name>"
440 "type" : "<type>",
440 "type" : "<type>",
441 "binary": "<true|false>" (only in extended mode)
441 "binary": "<true|false>" (only in extended mode)
442 "md5" : "<md5 of file content>" (only in extended mode)
442 "md5" : "<md5 of file content>" (only in extended mode)
443 },
443 },
444 ...
444 ...
445 ]
445 ]
446 error: null
446 error: null
447 """
447 """
448
448
449 repo = get_repo_or_error(repoid)
449 repo = get_repo_or_error(repoid)
450 if not has_superadmin_permission(apiuser):
450 if not has_superadmin_permission(apiuser):
451 _perms = (
451 _perms = (
452 'repository.admin', 'repository.write', 'repository.read',)
452 'repository.admin', 'repository.write', 'repository.read',)
453 has_repo_permissions(apiuser, repoid, repo, _perms)
453 has_repo_permissions(apiuser, repoid, repo, _perms)
454
454
455 ret_type = Optional.extract(ret_type)
455 ret_type = Optional.extract(ret_type)
456 details = Optional.extract(details)
456 details = Optional.extract(details)
457 _extended_types = ['basic', 'full']
457 _extended_types = ['basic', 'full']
458 if details not in _extended_types:
458 if details not in _extended_types:
459 raise JSONRPCError(
459 raise JSONRPCError(
460 'ret_type must be one of %s' % (','.join(_extended_types)))
460 'ret_type must be one of %s' % (','.join(_extended_types)))
461 extended_info = False
461 extended_info = False
462 content = False
462 content = False
463 if details == 'basic':
463 if details == 'basic':
464 extended_info = True
464 extended_info = True
465
465
466 if details == 'full':
466 if details == 'full':
467 extended_info = content = True
467 extended_info = content = True
468
468
469 _map = {}
469 _map = {}
470 try:
470 try:
471 # check if repo is not empty by any chance, skip quicker if it is.
471 # check if repo is not empty by any chance, skip quicker if it is.
472 _scm = repo.scm_instance()
472 _scm = repo.scm_instance()
473 if _scm.is_empty():
473 if _scm.is_empty():
474 return []
474 return []
475
475
476 _d, _f = ScmModel().get_nodes(
476 _d, _f = ScmModel().get_nodes(
477 repo, revision, root_path, flat=False,
477 repo, revision, root_path, flat=False,
478 extended_info=extended_info, content=content,
478 extended_info=extended_info, content=content,
479 max_file_bytes=max_file_bytes)
479 max_file_bytes=max_file_bytes)
480 _map = {
480 _map = {
481 'all': _d + _f,
481 'all': _d + _f,
482 'files': _f,
482 'files': _f,
483 'dirs': _d,
483 'dirs': _d,
484 }
484 }
485 return _map[ret_type]
485 return _map[ret_type]
486 except KeyError:
486 except KeyError:
487 raise JSONRPCError(
487 raise JSONRPCError(
488 'ret_type must be one of %s' % (','.join(sorted(_map.keys()))))
488 'ret_type must be one of %s' % (','.join(sorted(_map.keys()))))
489 except Exception:
489 except Exception:
490 log.exception("Exception occurred while trying to get repo nodes")
490 log.exception("Exception occurred while trying to get repo nodes")
491 raise JSONRPCError(
491 raise JSONRPCError(
492 'failed to get repo: `%s` nodes' % repo.repo_name
492 'failed to get repo: `%s` nodes' % repo.repo_name
493 )
493 )
494
494
495
495
496 @jsonrpc_method()
496 @jsonrpc_method()
497 def get_repo_refs(request, apiuser, repoid):
497 def get_repo_refs(request, apiuser, repoid):
498 """
498 """
499 Returns a dictionary of current references. It returns
499 Returns a dictionary of current references. It returns
500 bookmarks, branches, closed_branches, and tags for given repository
500 bookmarks, branches, closed_branches, and tags for given repository
501
501
502 It's possible to specify ret_type to show only `files` or `dirs`.
502 It's possible to specify ret_type to show only `files` or `dirs`.
503
503
504 This command can only be run using an |authtoken| with admin rights,
504 This command can only be run using an |authtoken| with admin rights,
505 or users with at least read rights to |repos|.
505 or users with at least read rights to |repos|.
506
506
507 :param apiuser: This is filled automatically from the |authtoken|.
507 :param apiuser: This is filled automatically from the |authtoken|.
508 :type apiuser: AuthUser
508 :type apiuser: AuthUser
509 :param repoid: The repository name or repository ID.
509 :param repoid: The repository name or repository ID.
510 :type repoid: str or int
510 :type repoid: str or int
511
511
512 Example output:
512 Example output:
513
513
514 .. code-block:: bash
514 .. code-block:: bash
515
515
516 id : <id_given_in_input>
516 id : <id_given_in_input>
517 result: [
517 result: [
518 TODO...
518 TODO...
519 ]
519 ]
520 error: null
520 error: null
521 """
521 """
522
522
523 repo = get_repo_or_error(repoid)
523 repo = get_repo_or_error(repoid)
524 if not has_superadmin_permission(apiuser):
524 if not has_superadmin_permission(apiuser):
525 _perms = ('repository.admin', 'repository.write', 'repository.read',)
525 _perms = ('repository.admin', 'repository.write', 'repository.read',)
526 has_repo_permissions(apiuser, repoid, repo, _perms)
526 has_repo_permissions(apiuser, repoid, repo, _perms)
527
527
528 try:
528 try:
529 # check if repo is not empty by any chance, skip quicker if it is.
529 # check if repo is not empty by any chance, skip quicker if it is.
530 vcs_instance = repo.scm_instance()
530 vcs_instance = repo.scm_instance()
531 refs = vcs_instance.refs()
531 refs = vcs_instance.refs()
532 return refs
532 return refs
533 except Exception:
533 except Exception:
534 log.exception("Exception occurred while trying to get repo refs")
534 log.exception("Exception occurred while trying to get repo refs")
535 raise JSONRPCError(
535 raise JSONRPCError(
536 'failed to get repo: `%s` references' % repo.repo_name
536 'failed to get repo: `%s` references' % repo.repo_name
537 )
537 )
538
538
539
539
540 @jsonrpc_method()
540 @jsonrpc_method()
541 def create_repo(request, apiuser, repo_name, repo_type,
541 def create_repo(request, apiuser, repo_name, repo_type,
542 owner=Optional(OAttr('apiuser')), description=Optional(''),
542 owner=Optional(OAttr('apiuser')), description=Optional(''),
543 private=Optional(False), clone_uri=Optional(None),
543 private=Optional(False), clone_uri=Optional(None),
544 landing_rev=Optional('rev:tip'),
544 landing_rev=Optional('rev:tip'),
545 enable_statistics=Optional(False),
545 enable_statistics=Optional(False),
546 enable_locking=Optional(False),
546 enable_locking=Optional(False),
547 enable_downloads=Optional(False),
547 enable_downloads=Optional(False),
548 copy_permissions=Optional(False)):
548 copy_permissions=Optional(False)):
549 """
549 """
550 Creates a repository.
550 Creates a repository.
551
551
552 * If the repository name contains "/", all the required repository
552 * If the repository name contains "/", all the required repository
553 groups will be created.
553 groups will be created.
554
554
555 For example "foo/bar/baz" will create |repo| groups "foo" and "bar"
555 For example "foo/bar/baz" will create |repo| groups "foo" and "bar"
556 (with "foo" as parent). It will also create the "baz" repository
556 (with "foo" as parent). It will also create the "baz" repository
557 with "bar" as |repo| group.
557 with "bar" as |repo| group.
558
558
559 This command can only be run using an |authtoken| with at least
559 This command can only be run using an |authtoken| with at least
560 write permissions to the |repo|.
560 write permissions to the |repo|.
561
561
562 :param apiuser: This is filled automatically from the |authtoken|.
562 :param apiuser: This is filled automatically from the |authtoken|.
563 :type apiuser: AuthUser
563 :type apiuser: AuthUser
564 :param repo_name: Set the repository name.
564 :param repo_name: Set the repository name.
565 :type repo_name: str
565 :type repo_name: str
566 :param repo_type: Set the repository type; 'hg','git', or 'svn'.
566 :param repo_type: Set the repository type; 'hg','git', or 'svn'.
567 :type repo_type: str
567 :type repo_type: str
568 :param owner: user_id or username
568 :param owner: user_id or username
569 :type owner: Optional(str)
569 :type owner: Optional(str)
570 :param description: Set the repository description.
570 :param description: Set the repository description.
571 :type description: Optional(str)
571 :type description: Optional(str)
572 :param private:
572 :param private:
573 :type private: bool
573 :type private: bool
574 :param clone_uri:
574 :param clone_uri:
575 :type clone_uri: str
575 :type clone_uri: str
576 :param landing_rev: <rev_type>:<rev>
576 :param landing_rev: <rev_type>:<rev>
577 :type landing_rev: str
577 :type landing_rev: str
578 :param enable_locking:
578 :param enable_locking:
579 :type enable_locking: bool
579 :type enable_locking: bool
580 :param enable_downloads:
580 :param enable_downloads:
581 :type enable_downloads: bool
581 :type enable_downloads: bool
582 :param enable_statistics:
582 :param enable_statistics:
583 :type enable_statistics: bool
583 :type enable_statistics: bool
584 :param copy_permissions: Copy permission from group in which the
584 :param copy_permissions: Copy permission from group in which the
585 repository is being created.
585 repository is being created.
586 :type copy_permissions: bool
586 :type copy_permissions: bool
587
587
588
588
589 Example output:
589 Example output:
590
590
591 .. code-block:: bash
591 .. code-block:: bash
592
592
593 id : <id_given_in_input>
593 id : <id_given_in_input>
594 result: {
594 result: {
595 "msg": "Created new repository `<reponame>`",
595 "msg": "Created new repository `<reponame>`",
596 "success": true,
596 "success": true,
597 "task": "<celery task id or None if done sync>"
597 "task": "<celery task id or None if done sync>"
598 }
598 }
599 error: null
599 error: null
600
600
601
601
602 Example error output:
602 Example error output:
603
603
604 .. code-block:: bash
604 .. code-block:: bash
605
605
606 id : <id_given_in_input>
606 id : <id_given_in_input>
607 result : null
607 result : null
608 error : {
608 error : {
609 'failed to create repository `<repo_name>`
609 'failed to create repository `<repo_name>`'
610 }
610 }
611
611
612 """
612 """
613 schema = repo_schema.RepoSchema()
613 schema = repo_schema.RepoSchema()
614 try:
614 try:
615 data = schema.deserialize({
615 data = schema.deserialize({
616 'repo_name': repo_name
616 'repo_name': repo_name
617 })
617 })
618 except colander.Invalid as e:
618 except colander.Invalid as e:
619 raise JSONRPCError("Validation failed: %s" % (e.asdict(),))
619 raise JSONRPCError("Validation failed: %s" % (e.asdict(),))
620 repo_name = data['repo_name']
620 repo_name = data['repo_name']
621
621
622 (repo_name_cleaned,
622 (repo_name_cleaned,
623 parent_group_name) = RepoGroupModel()._get_group_name_and_parent(
623 parent_group_name) = RepoGroupModel()._get_group_name_and_parent(
624 repo_name)
624 repo_name)
625
625
626 if not HasPermissionAnyApi(
626 if not HasPermissionAnyApi(
627 'hg.admin', 'hg.create.repository')(user=apiuser):
627 'hg.admin', 'hg.create.repository')(user=apiuser):
628 # check if we have admin permission for this repo group if given !
628 # check if we have admin permission for this repo group if given !
629
629
630 if parent_group_name:
630 if parent_group_name:
631 repogroupid = parent_group_name
631 repogroupid = parent_group_name
632 repo_group = get_repo_group_or_error(parent_group_name)
632 repo_group = get_repo_group_or_error(parent_group_name)
633
633
634 _perms = ('group.admin',)
634 _perms = ('group.admin',)
635 if not HasRepoGroupPermissionAnyApi(*_perms)(
635 if not HasRepoGroupPermissionAnyApi(*_perms)(
636 user=apiuser, group_name=repo_group.group_name):
636 user=apiuser, group_name=repo_group.group_name):
637 raise JSONRPCError(
637 raise JSONRPCError(
638 'repository group `%s` does not exist' % (
638 'repository group `%s` does not exist' % (
639 repogroupid,))
639 repogroupid,))
640 else:
640 else:
641 raise JSONRPCForbidden()
641 raise JSONRPCForbidden()
642
642
643 if not has_superadmin_permission(apiuser):
643 if not has_superadmin_permission(apiuser):
644 if not isinstance(owner, Optional):
644 if not isinstance(owner, Optional):
645 # forbid setting owner for non-admins
645 # forbid setting owner for non-admins
646 raise JSONRPCError(
646 raise JSONRPCError(
647 'Only RhodeCode admin can specify `owner` param')
647 'Only RhodeCode admin can specify `owner` param')
648
648
649 if isinstance(owner, Optional):
649 if isinstance(owner, Optional):
650 owner = apiuser.user_id
650 owner = apiuser.user_id
651
651
652 owner = get_user_or_error(owner)
652 owner = get_user_or_error(owner)
653
653
654 if RepoModel().get_by_repo_name(repo_name):
654 if RepoModel().get_by_repo_name(repo_name):
655 raise JSONRPCError("repo `%s` already exist" % repo_name)
655 raise JSONRPCError("repo `%s` already exist" % repo_name)
656
656
657 defs = SettingsModel().get_default_repo_settings(strip_prefix=True)
657 defs = SettingsModel().get_default_repo_settings(strip_prefix=True)
658 if isinstance(private, Optional):
658 if isinstance(private, Optional):
659 private = defs.get('repo_private') or Optional.extract(private)
659 private = defs.get('repo_private') or Optional.extract(private)
660 if isinstance(repo_type, Optional):
660 if isinstance(repo_type, Optional):
661 repo_type = defs.get('repo_type')
661 repo_type = defs.get('repo_type')
662 if isinstance(enable_statistics, Optional):
662 if isinstance(enable_statistics, Optional):
663 enable_statistics = defs.get('repo_enable_statistics')
663 enable_statistics = defs.get('repo_enable_statistics')
664 if isinstance(enable_locking, Optional):
664 if isinstance(enable_locking, Optional):
665 enable_locking = defs.get('repo_enable_locking')
665 enable_locking = defs.get('repo_enable_locking')
666 if isinstance(enable_downloads, Optional):
666 if isinstance(enable_downloads, Optional):
667 enable_downloads = defs.get('repo_enable_downloads')
667 enable_downloads = defs.get('repo_enable_downloads')
668
668
669 clone_uri = Optional.extract(clone_uri)
669 clone_uri = Optional.extract(clone_uri)
670 description = Optional.extract(description)
670 description = Optional.extract(description)
671 landing_rev = Optional.extract(landing_rev)
671 landing_rev = Optional.extract(landing_rev)
672 copy_permissions = Optional.extract(copy_permissions)
672 copy_permissions = Optional.extract(copy_permissions)
673
673
674 try:
674 try:
675 # create structure of groups and return the last group
675 # create structure of groups and return the last group
676 repo_group = map_groups(repo_name)
676 repo_group = map_groups(repo_name)
677 data = {
677 data = {
678 'repo_name': repo_name_cleaned,
678 'repo_name': repo_name_cleaned,
679 'repo_name_full': repo_name,
679 'repo_name_full': repo_name,
680 'repo_type': repo_type,
680 'repo_type': repo_type,
681 'repo_description': description,
681 'repo_description': description,
682 'owner': owner,
682 'owner': owner,
683 'repo_private': private,
683 'repo_private': private,
684 'clone_uri': clone_uri,
684 'clone_uri': clone_uri,
685 'repo_group': repo_group.group_id if repo_group else None,
685 'repo_group': repo_group.group_id if repo_group else None,
686 'repo_landing_rev': landing_rev,
686 'repo_landing_rev': landing_rev,
687 'enable_statistics': enable_statistics,
687 'enable_statistics': enable_statistics,
688 'enable_locking': enable_locking,
688 'enable_locking': enable_locking,
689 'enable_downloads': enable_downloads,
689 'enable_downloads': enable_downloads,
690 'repo_copy_permissions': copy_permissions,
690 'repo_copy_permissions': copy_permissions,
691 }
691 }
692
692
693 if repo_type not in BACKENDS.keys():
693 if repo_type not in BACKENDS.keys():
694 raise Exception("Invalid backend type %s" % repo_type)
694 raise Exception("Invalid backend type %s" % repo_type)
695 task = RepoModel().create(form_data=data, cur_user=owner)
695 task = RepoModel().create(form_data=data, cur_user=owner)
696 from celery.result import BaseAsyncResult
696 from celery.result import BaseAsyncResult
697 task_id = None
697 task_id = None
698 if isinstance(task, BaseAsyncResult):
698 if isinstance(task, BaseAsyncResult):
699 task_id = task.task_id
699 task_id = task.task_id
700 # no commit, it's done in RepoModel, or async via celery
700 # no commit, it's done in RepoModel, or async via celery
701 return {
701 return {
702 'msg': "Created new repository `%s`" % (repo_name,),
702 'msg': "Created new repository `%s`" % (repo_name,),
703 'success': True, # cannot return the repo data here since fork
703 'success': True, # cannot return the repo data here since fork
704 # cann be done async
704 # cann be done async
705 'task': task_id
705 'task': task_id
706 }
706 }
707 except Exception:
707 except Exception:
708 log.exception(
708 log.exception(
709 u"Exception while trying to create the repository %s",
709 u"Exception while trying to create the repository %s",
710 repo_name)
710 repo_name)
711 raise JSONRPCError(
711 raise JSONRPCError(
712 'failed to create repository `%s`' % (repo_name,))
712 'failed to create repository `%s`' % (repo_name,))
713
713
714
714
715 @jsonrpc_method()
715 @jsonrpc_method()
716 def add_field_to_repo(request, apiuser, repoid, key, label=Optional(''),
716 def add_field_to_repo(request, apiuser, repoid, key, label=Optional(''),
717 description=Optional('')):
717 description=Optional('')):
718 """
718 """
719 Adds an extra field to a repository.
719 Adds an extra field to a repository.
720
720
721 This command can only be run using an |authtoken| with at least
721 This command can only be run using an |authtoken| with at least
722 write permissions to the |repo|.
722 write permissions to the |repo|.
723
723
724 :param apiuser: This is filled automatically from the |authtoken|.
724 :param apiuser: This is filled automatically from the |authtoken|.
725 :type apiuser: AuthUser
725 :type apiuser: AuthUser
726 :param repoid: Set the repository name or repository id.
726 :param repoid: Set the repository name or repository id.
727 :type repoid: str or int
727 :type repoid: str or int
728 :param key: Create a unique field key for this repository.
728 :param key: Create a unique field key for this repository.
729 :type key: str
729 :type key: str
730 :param label:
730 :param label:
731 :type label: Optional(str)
731 :type label: Optional(str)
732 :param description:
732 :param description:
733 :type description: Optional(str)
733 :type description: Optional(str)
734 """
734 """
735 repo = get_repo_or_error(repoid)
735 repo = get_repo_or_error(repoid)
736 if not has_superadmin_permission(apiuser):
736 if not has_superadmin_permission(apiuser):
737 _perms = ('repository.admin',)
737 _perms = ('repository.admin',)
738 has_repo_permissions(apiuser, repoid, repo, _perms)
738 has_repo_permissions(apiuser, repoid, repo, _perms)
739
739
740 label = Optional.extract(label) or key
740 label = Optional.extract(label) or key
741 description = Optional.extract(description)
741 description = Optional.extract(description)
742
742
743 field = RepositoryField.get_by_key_name(key, repo)
743 field = RepositoryField.get_by_key_name(key, repo)
744 if field:
744 if field:
745 raise JSONRPCError('Field with key '
745 raise JSONRPCError('Field with key '
746 '`%s` exists for repo `%s`' % (key, repoid))
746 '`%s` exists for repo `%s`' % (key, repoid))
747
747
748 try:
748 try:
749 RepoModel().add_repo_field(repo, key, field_label=label,
749 RepoModel().add_repo_field(repo, key, field_label=label,
750 field_desc=description)
750 field_desc=description)
751 Session().commit()
751 Session().commit()
752 return {
752 return {
753 'msg': "Added new repository field `%s`" % (key,),
753 'msg': "Added new repository field `%s`" % (key,),
754 'success': True,
754 'success': True,
755 }
755 }
756 except Exception:
756 except Exception:
757 log.exception("Exception occurred while trying to add field to repo")
757 log.exception("Exception occurred while trying to add field to repo")
758 raise JSONRPCError(
758 raise JSONRPCError(
759 'failed to create new field for repository `%s`' % (repoid,))
759 'failed to create new field for repository `%s`' % (repoid,))
760
760
761
761
762 @jsonrpc_method()
762 @jsonrpc_method()
763 def remove_field_from_repo(request, apiuser, repoid, key):
763 def remove_field_from_repo(request, apiuser, repoid, key):
764 """
764 """
765 Removes an extra field from a repository.
765 Removes an extra field from a repository.
766
766
767 This command can only be run using an |authtoken| with at least
767 This command can only be run using an |authtoken| with at least
768 write permissions to the |repo|.
768 write permissions to the |repo|.
769
769
770 :param apiuser: This is filled automatically from the |authtoken|.
770 :param apiuser: This is filled automatically from the |authtoken|.
771 :type apiuser: AuthUser
771 :type apiuser: AuthUser
772 :param repoid: Set the repository name or repository ID.
772 :param repoid: Set the repository name or repository ID.
773 :type repoid: str or int
773 :type repoid: str or int
774 :param key: Set the unique field key for this repository.
774 :param key: Set the unique field key for this repository.
775 :type key: str
775 :type key: str
776 """
776 """
777
777
778 repo = get_repo_or_error(repoid)
778 repo = get_repo_or_error(repoid)
779 if not has_superadmin_permission(apiuser):
779 if not has_superadmin_permission(apiuser):
780 _perms = ('repository.admin',)
780 _perms = ('repository.admin',)
781 has_repo_permissions(apiuser, repoid, repo, _perms)
781 has_repo_permissions(apiuser, repoid, repo, _perms)
782
782
783 field = RepositoryField.get_by_key_name(key, repo)
783 field = RepositoryField.get_by_key_name(key, repo)
784 if not field:
784 if not field:
785 raise JSONRPCError('Field with key `%s` does not '
785 raise JSONRPCError('Field with key `%s` does not '
786 'exists for repo `%s`' % (key, repoid))
786 'exists for repo `%s`' % (key, repoid))
787
787
788 try:
788 try:
789 RepoModel().delete_repo_field(repo, field_key=key)
789 RepoModel().delete_repo_field(repo, field_key=key)
790 Session().commit()
790 Session().commit()
791 return {
791 return {
792 'msg': "Deleted repository field `%s`" % (key,),
792 'msg': "Deleted repository field `%s`" % (key,),
793 'success': True,
793 'success': True,
794 }
794 }
795 except Exception:
795 except Exception:
796 log.exception(
796 log.exception(
797 "Exception occurred while trying to delete field from repo")
797 "Exception occurred while trying to delete field from repo")
798 raise JSONRPCError(
798 raise JSONRPCError(
799 'failed to delete field for repository `%s`' % (repoid,))
799 'failed to delete field for repository `%s`' % (repoid,))
800
800
801
801
802 @jsonrpc_method()
802 @jsonrpc_method()
803 def update_repo(request, apiuser, repoid, name=Optional(None),
803 def update_repo(request, apiuser, repoid, name=Optional(None),
804 owner=Optional(OAttr('apiuser')),
804 owner=Optional(OAttr('apiuser')),
805 group=Optional(None),
805 group=Optional(None),
806 fork_of=Optional(None),
806 fork_of=Optional(None),
807 description=Optional(''), private=Optional(False),
807 description=Optional(''), private=Optional(False),
808 clone_uri=Optional(None), landing_rev=Optional('rev:tip'),
808 clone_uri=Optional(None), landing_rev=Optional('rev:tip'),
809 enable_statistics=Optional(False),
809 enable_statistics=Optional(False),
810 enable_locking=Optional(False),
810 enable_locking=Optional(False),
811 enable_downloads=Optional(False),
811 enable_downloads=Optional(False),
812 fields=Optional('')):
812 fields=Optional('')):
813 """
813 """
814 Updates a repository with the given information.
814 Updates a repository with the given information.
815
815
816 This command can only be run using an |authtoken| with at least
816 This command can only be run using an |authtoken| with at least
817 write permissions to the |repo|.
817 write permissions to the |repo|.
818
818
819 :param apiuser: This is filled automatically from the |authtoken|.
819 :param apiuser: This is filled automatically from the |authtoken|.
820 :type apiuser: AuthUser
820 :type apiuser: AuthUser
821 :param repoid: repository name or repository ID.
821 :param repoid: repository name or repository ID.
822 :type repoid: str or int
822 :type repoid: str or int
823 :param name: Update the |repo| name.
823 :param name: Update the |repo| name.
824 :type name: str
824 :type name: str
825 :param owner: Set the |repo| owner.
825 :param owner: Set the |repo| owner.
826 :type owner: str
826 :type owner: str
827 :param group: Set the |repo| group the |repo| belongs to.
827 :param group: Set the |repo| group the |repo| belongs to.
828 :type group: str
828 :type group: str
829 :param fork_of: Set the master |repo| name.
829 :param fork_of: Set the master |repo| name.
830 :type fork_of: str
830 :type fork_of: str
831 :param description: Update the |repo| description.
831 :param description: Update the |repo| description.
832 :type description: str
832 :type description: str
833 :param private: Set the |repo| as private. (True | False)
833 :param private: Set the |repo| as private. (True | False)
834 :type private: bool
834 :type private: bool
835 :param clone_uri: Update the |repo| clone URI.
835 :param clone_uri: Update the |repo| clone URI.
836 :type clone_uri: str
836 :type clone_uri: str
837 :param landing_rev: Set the |repo| landing revision. Default is
837 :param landing_rev: Set the |repo| landing revision. Default is
838 ``tip``.
838 ``tip``.
839 :type landing_rev: str
839 :type landing_rev: str
840 :param enable_statistics: Enable statistics on the |repo|,
840 :param enable_statistics: Enable statistics on the |repo|,
841 (True | False).
841 (True | False).
842 :type enable_statistics: bool
842 :type enable_statistics: bool
843 :param enable_locking: Enable |repo| locking.
843 :param enable_locking: Enable |repo| locking.
844 :type enable_locking: bool
844 :type enable_locking: bool
845 :param enable_downloads: Enable downloads from the |repo|,
845 :param enable_downloads: Enable downloads from the |repo|,
846 (True | False).
846 (True | False).
847 :type enable_downloads: bool
847 :type enable_downloads: bool
848 :param fields: Add extra fields to the |repo|. Use the following
848 :param fields: Add extra fields to the |repo|. Use the following
849 example format: ``field_key=field_val,field_key2=fieldval2``.
849 example format: ``field_key=field_val,field_key2=fieldval2``.
850 Escape ', ' with \,
850 Escape ', ' with \,
851 :type fields: str
851 :type fields: str
852 """
852 """
853 repo = get_repo_or_error(repoid)
853 repo = get_repo_or_error(repoid)
854 include_secrets = False
854 include_secrets = False
855 if has_superadmin_permission(apiuser):
855 if has_superadmin_permission(apiuser):
856 include_secrets = True
856 include_secrets = True
857 else:
857 else:
858 _perms = ('repository.admin',)
858 _perms = ('repository.admin',)
859 has_repo_permissions(apiuser, repoid, repo, _perms)
859 has_repo_permissions(apiuser, repoid, repo, _perms)
860
860
861 updates = {
861 updates = {
862 # update function requires this.
862 # update function requires this.
863 'repo_name': repo.just_name
863 'repo_name': repo.just_name
864 }
864 }
865 repo_group = group
865 repo_group = group
866 if not isinstance(repo_group, Optional):
866 if not isinstance(repo_group, Optional):
867 repo_group = get_repo_group_or_error(repo_group)
867 repo_group = get_repo_group_or_error(repo_group)
868 repo_group = repo_group.group_id
868 repo_group = repo_group.group_id
869
869
870 repo_fork_of = fork_of
870 repo_fork_of = fork_of
871 if not isinstance(repo_fork_of, Optional):
871 if not isinstance(repo_fork_of, Optional):
872 repo_fork_of = get_repo_or_error(repo_fork_of)
872 repo_fork_of = get_repo_or_error(repo_fork_of)
873 repo_fork_of = repo_fork_of.repo_id
873 repo_fork_of = repo_fork_of.repo_id
874
874
875 try:
875 try:
876 store_update(updates, name, 'repo_name')
876 store_update(updates, name, 'repo_name')
877 store_update(updates, repo_group, 'repo_group')
877 store_update(updates, repo_group, 'repo_group')
878 store_update(updates, repo_fork_of, 'fork_id')
878 store_update(updates, repo_fork_of, 'fork_id')
879 store_update(updates, owner, 'user')
879 store_update(updates, owner, 'user')
880 store_update(updates, description, 'repo_description')
880 store_update(updates, description, 'repo_description')
881 store_update(updates, private, 'repo_private')
881 store_update(updates, private, 'repo_private')
882 store_update(updates, clone_uri, 'clone_uri')
882 store_update(updates, clone_uri, 'clone_uri')
883 store_update(updates, landing_rev, 'repo_landing_rev')
883 store_update(updates, landing_rev, 'repo_landing_rev')
884 store_update(updates, enable_statistics, 'repo_enable_statistics')
884 store_update(updates, enable_statistics, 'repo_enable_statistics')
885 store_update(updates, enable_locking, 'repo_enable_locking')
885 store_update(updates, enable_locking, 'repo_enable_locking')
886 store_update(updates, enable_downloads, 'repo_enable_downloads')
886 store_update(updates, enable_downloads, 'repo_enable_downloads')
887
887
888 # extra fields
888 # extra fields
889 fields = parse_args(Optional.extract(fields), key_prefix='ex_')
889 fields = parse_args(Optional.extract(fields), key_prefix='ex_')
890 if fields:
890 if fields:
891 updates.update(fields)
891 updates.update(fields)
892
892
893 RepoModel().update(repo, **updates)
893 RepoModel().update(repo, **updates)
894 Session().commit()
894 Session().commit()
895 return {
895 return {
896 'msg': 'updated repo ID:%s %s' % (
896 'msg': 'updated repo ID:%s %s' % (
897 repo.repo_id, repo.repo_name),
897 repo.repo_id, repo.repo_name),
898 'repository': repo.get_api_data(
898 'repository': repo.get_api_data(
899 include_secrets=include_secrets)
899 include_secrets=include_secrets)
900 }
900 }
901 except Exception:
901 except Exception:
902 log.exception(
902 log.exception(
903 u"Exception while trying to update the repository %s",
903 u"Exception while trying to update the repository %s",
904 repoid)
904 repoid)
905 raise JSONRPCError('failed to update repo `%s`' % repoid)
905 raise JSONRPCError('failed to update repo `%s`' % repoid)
906
906
907
907
908 @jsonrpc_method()
908 @jsonrpc_method()
909 def fork_repo(request, apiuser, repoid, fork_name,
909 def fork_repo(request, apiuser, repoid, fork_name,
910 owner=Optional(OAttr('apiuser')),
910 owner=Optional(OAttr('apiuser')),
911 description=Optional(''), copy_permissions=Optional(False),
911 description=Optional(''), copy_permissions=Optional(False),
912 private=Optional(False), landing_rev=Optional('rev:tip')):
912 private=Optional(False), landing_rev=Optional('rev:tip')):
913 """
913 """
914 Creates a fork of the specified |repo|.
914 Creates a fork of the specified |repo|.
915
915
916 * If using |RCE| with Celery this will immediately return a success
916 * If using |RCE| with Celery this will immediately return a success
917 message, even though the fork will be created asynchronously.
917 message, even though the fork will be created asynchronously.
918
918
919 This command can only be run using an |authtoken| with fork
919 This command can only be run using an |authtoken| with fork
920 permissions on the |repo|.
920 permissions on the |repo|.
921
921
922 :param apiuser: This is filled automatically from the |authtoken|.
922 :param apiuser: This is filled automatically from the |authtoken|.
923 :type apiuser: AuthUser
923 :type apiuser: AuthUser
924 :param repoid: Set repository name or repository ID.
924 :param repoid: Set repository name or repository ID.
925 :type repoid: str or int
925 :type repoid: str or int
926 :param fork_name: Set the fork name.
926 :param fork_name: Set the fork name.
927 :type fork_name: str
927 :type fork_name: str
928 :param owner: Set the fork owner.
928 :param owner: Set the fork owner.
929 :type owner: str
929 :type owner: str
930 :param description: Set the fork descripton.
930 :param description: Set the fork descripton.
931 :type description: str
931 :type description: str
932 :param copy_permissions: Copy permissions from parent |repo|. The
932 :param copy_permissions: Copy permissions from parent |repo|. The
933 default is False.
933 default is False.
934 :type copy_permissions: bool
934 :type copy_permissions: bool
935 :param private: Make the fork private. The default is False.
935 :param private: Make the fork private. The default is False.
936 :type private: bool
936 :type private: bool
937 :param landing_rev: Set the landing revision. The default is tip.
937 :param landing_rev: Set the landing revision. The default is tip.
938
938
939 Example output:
939 Example output:
940
940
941 .. code-block:: bash
941 .. code-block:: bash
942
942
943 id : <id_for_response>
943 id : <id_for_response>
944 api_key : "<api_key>"
944 api_key : "<api_key>"
945 args: {
945 args: {
946 "repoid" : "<reponame or repo_id>",
946 "repoid" : "<reponame or repo_id>",
947 "fork_name": "<forkname>",
947 "fork_name": "<forkname>",
948 "owner": "<username or user_id = Optional(=apiuser)>",
948 "owner": "<username or user_id = Optional(=apiuser)>",
949 "description": "<description>",
949 "description": "<description>",
950 "copy_permissions": "<bool>",
950 "copy_permissions": "<bool>",
951 "private": "<bool>",
951 "private": "<bool>",
952 "landing_rev": "<landing_rev>"
952 "landing_rev": "<landing_rev>"
953 }
953 }
954
954
955 Example error output:
955 Example error output:
956
956
957 .. code-block:: bash
957 .. code-block:: bash
958
958
959 id : <id_given_in_input>
959 id : <id_given_in_input>
960 result: {
960 result: {
961 "msg": "Created fork of `<reponame>` as `<forkname>`",
961 "msg": "Created fork of `<reponame>` as `<forkname>`",
962 "success": true,
962 "success": true,
963 "task": "<celery task id or None if done sync>"
963 "task": "<celery task id or None if done sync>"
964 }
964 }
965 error: null
965 error: null
966
966
967 """
967 """
968 if not has_superadmin_permission(apiuser):
968 if not has_superadmin_permission(apiuser):
969 if not HasPermissionAnyApi('hg.fork.repository')(user=apiuser):
969 if not HasPermissionAnyApi('hg.fork.repository')(user=apiuser):
970 raise JSONRPCForbidden()
970 raise JSONRPCForbidden()
971
971
972 repo = get_repo_or_error(repoid)
972 repo = get_repo_or_error(repoid)
973 repo_name = repo.repo_name
973 repo_name = repo.repo_name
974
974
975 (fork_name_cleaned,
975 (fork_name_cleaned,
976 parent_group_name) = RepoGroupModel()._get_group_name_and_parent(
976 parent_group_name) = RepoGroupModel()._get_group_name_and_parent(
977 fork_name)
977 fork_name)
978
978
979 if not has_superadmin_permission(apiuser):
979 if not has_superadmin_permission(apiuser):
980 # check if we have at least read permission for
980 # check if we have at least read permission for
981 # this repo that we fork !
981 # this repo that we fork !
982 _perms = (
982 _perms = (
983 'repository.admin', 'repository.write', 'repository.read')
983 'repository.admin', 'repository.write', 'repository.read')
984 has_repo_permissions(apiuser, repoid, repo, _perms)
984 has_repo_permissions(apiuser, repoid, repo, _perms)
985
985
986 if not isinstance(owner, Optional):
986 if not isinstance(owner, Optional):
987 # forbid setting owner for non super admins
987 # forbid setting owner for non super admins
988 raise JSONRPCError(
988 raise JSONRPCError(
989 'Only RhodeCode admin can specify `owner` param'
989 'Only RhodeCode admin can specify `owner` param'
990 )
990 )
991 # check if we have a create.repo permission if not maybe the parent
991 # check if we have a create.repo permission if not maybe the parent
992 # group permission
992 # group permission
993 if not HasPermissionAnyApi('hg.create.repository')(user=apiuser):
993 if not HasPermissionAnyApi('hg.create.repository')(user=apiuser):
994 if parent_group_name:
994 if parent_group_name:
995 repogroupid = parent_group_name
995 repogroupid = parent_group_name
996 repo_group = get_repo_group_or_error(parent_group_name)
996 repo_group = get_repo_group_or_error(parent_group_name)
997
997
998 _perms = ('group.admin',)
998 _perms = ('group.admin',)
999 if not HasRepoGroupPermissionAnyApi(*_perms)(
999 if not HasRepoGroupPermissionAnyApi(*_perms)(
1000 user=apiuser, group_name=repo_group.group_name):
1000 user=apiuser, group_name=repo_group.group_name):
1001 raise JSONRPCError(
1001 raise JSONRPCError(
1002 'repository group `%s` does not exist' % (
1002 'repository group `%s` does not exist' % (
1003 repogroupid,))
1003 repogroupid,))
1004 else:
1004 else:
1005 raise JSONRPCForbidden()
1005 raise JSONRPCForbidden()
1006
1006
1007 _repo = RepoModel().get_by_repo_name(fork_name)
1007 _repo = RepoModel().get_by_repo_name(fork_name)
1008 if _repo:
1008 if _repo:
1009 type_ = 'fork' if _repo.fork else 'repo'
1009 type_ = 'fork' if _repo.fork else 'repo'
1010 raise JSONRPCError("%s `%s` already exist" % (type_, fork_name))
1010 raise JSONRPCError("%s `%s` already exist" % (type_, fork_name))
1011
1011
1012 if isinstance(owner, Optional):
1012 if isinstance(owner, Optional):
1013 owner = apiuser.user_id
1013 owner = apiuser.user_id
1014
1014
1015 owner = get_user_or_error(owner)
1015 owner = get_user_or_error(owner)
1016
1016
1017 try:
1017 try:
1018 # create structure of groups and return the last group
1018 # create structure of groups and return the last group
1019 repo_group = map_groups(fork_name)
1019 repo_group = map_groups(fork_name)
1020 form_data = {
1020 form_data = {
1021 'repo_name': fork_name_cleaned,
1021 'repo_name': fork_name_cleaned,
1022 'repo_name_full': fork_name,
1022 'repo_name_full': fork_name,
1023 'repo_group': repo_group.group_id if repo_group else None,
1023 'repo_group': repo_group.group_id if repo_group else None,
1024 'repo_type': repo.repo_type,
1024 'repo_type': repo.repo_type,
1025 'description': Optional.extract(description),
1025 'description': Optional.extract(description),
1026 'private': Optional.extract(private),
1026 'private': Optional.extract(private),
1027 'copy_permissions': Optional.extract(copy_permissions),
1027 'copy_permissions': Optional.extract(copy_permissions),
1028 'landing_rev': Optional.extract(landing_rev),
1028 'landing_rev': Optional.extract(landing_rev),
1029 'fork_parent_id': repo.repo_id,
1029 'fork_parent_id': repo.repo_id,
1030 }
1030 }
1031
1031
1032 task = RepoModel().create_fork(form_data, cur_user=owner)
1032 task = RepoModel().create_fork(form_data, cur_user=owner)
1033 # no commit, it's done in RepoModel, or async via celery
1033 # no commit, it's done in RepoModel, or async via celery
1034 from celery.result import BaseAsyncResult
1034 from celery.result import BaseAsyncResult
1035 task_id = None
1035 task_id = None
1036 if isinstance(task, BaseAsyncResult):
1036 if isinstance(task, BaseAsyncResult):
1037 task_id = task.task_id
1037 task_id = task.task_id
1038 return {
1038 return {
1039 'msg': 'Created fork of `%s` as `%s`' % (
1039 'msg': 'Created fork of `%s` as `%s`' % (
1040 repo.repo_name, fork_name),
1040 repo.repo_name, fork_name),
1041 'success': True, # cannot return the repo data here since fork
1041 'success': True, # cannot return the repo data here since fork
1042 # can be done async
1042 # can be done async
1043 'task': task_id
1043 'task': task_id
1044 }
1044 }
1045 except Exception:
1045 except Exception:
1046 log.exception("Exception occurred while trying to fork a repo")
1046 log.exception("Exception occurred while trying to fork a repo")
1047 raise JSONRPCError(
1047 raise JSONRPCError(
1048 'failed to fork repository `%s` as `%s`' % (
1048 'failed to fork repository `%s` as `%s`' % (
1049 repo_name, fork_name))
1049 repo_name, fork_name))
1050
1050
1051
1051
1052 @jsonrpc_method()
1052 @jsonrpc_method()
1053 def delete_repo(request, apiuser, repoid, forks=Optional('')):
1053 def delete_repo(request, apiuser, repoid, forks=Optional('')):
1054 """
1054 """
1055 Deletes a repository.
1055 Deletes a repository.
1056
1056
1057 * When the `forks` parameter is set it's possible to detach or delete
1057 * When the `forks` parameter is set it's possible to detach or delete
1058 forks of deleted repository.
1058 forks of deleted repository.
1059
1059
1060 This command can only be run using an |authtoken| with admin
1060 This command can only be run using an |authtoken| with admin
1061 permissions on the |repo|.
1061 permissions on the |repo|.
1062
1062
1063 :param apiuser: This is filled automatically from the |authtoken|.
1063 :param apiuser: This is filled automatically from the |authtoken|.
1064 :type apiuser: AuthUser
1064 :type apiuser: AuthUser
1065 :param repoid: Set the repository name or repository ID.
1065 :param repoid: Set the repository name or repository ID.
1066 :type repoid: str or int
1066 :type repoid: str or int
1067 :param forks: Set to `detach` or `delete` forks from the |repo|.
1067 :param forks: Set to `detach` or `delete` forks from the |repo|.
1068 :type forks: Optional(str)
1068 :type forks: Optional(str)
1069
1069
1070 Example error output:
1070 Example error output:
1071
1071
1072 .. code-block:: bash
1072 .. code-block:: bash
1073
1073
1074 id : <id_given_in_input>
1074 id : <id_given_in_input>
1075 result: {
1075 result: {
1076 "msg": "Deleted repository `<reponame>`",
1076 "msg": "Deleted repository `<reponame>`",
1077 "success": true
1077 "success": true
1078 }
1078 }
1079 error: null
1079 error: null
1080 """
1080 """
1081
1081
1082 repo = get_repo_or_error(repoid)
1082 repo = get_repo_or_error(repoid)
1083 if not has_superadmin_permission(apiuser):
1083 if not has_superadmin_permission(apiuser):
1084 _perms = ('repository.admin',)
1084 _perms = ('repository.admin',)
1085 has_repo_permissions(apiuser, repoid, repo, _perms)
1085 has_repo_permissions(apiuser, repoid, repo, _perms)
1086
1086
1087 try:
1087 try:
1088 handle_forks = Optional.extract(forks)
1088 handle_forks = Optional.extract(forks)
1089 _forks_msg = ''
1089 _forks_msg = ''
1090 _forks = [f for f in repo.forks]
1090 _forks = [f for f in repo.forks]
1091 if handle_forks == 'detach':
1091 if handle_forks == 'detach':
1092 _forks_msg = ' ' + 'Detached %s forks' % len(_forks)
1092 _forks_msg = ' ' + 'Detached %s forks' % len(_forks)
1093 elif handle_forks == 'delete':
1093 elif handle_forks == 'delete':
1094 _forks_msg = ' ' + 'Deleted %s forks' % len(_forks)
1094 _forks_msg = ' ' + 'Deleted %s forks' % len(_forks)
1095 elif _forks:
1095 elif _forks:
1096 raise JSONRPCError(
1096 raise JSONRPCError(
1097 'Cannot delete `%s` it still contains attached forks' %
1097 'Cannot delete `%s` it still contains attached forks' %
1098 (repo.repo_name,)
1098 (repo.repo_name,)
1099 )
1099 )
1100
1100
1101 RepoModel().delete(repo, forks=forks)
1101 RepoModel().delete(repo, forks=forks)
1102 Session().commit()
1102 Session().commit()
1103 return {
1103 return {
1104 'msg': 'Deleted repository `%s`%s' % (
1104 'msg': 'Deleted repository `%s`%s' % (
1105 repo.repo_name, _forks_msg),
1105 repo.repo_name, _forks_msg),
1106 'success': True
1106 'success': True
1107 }
1107 }
1108 except Exception:
1108 except Exception:
1109 log.exception("Exception occurred while trying to delete repo")
1109 log.exception("Exception occurred while trying to delete repo")
1110 raise JSONRPCError(
1110 raise JSONRPCError(
1111 'failed to delete repository `%s`' % (repo.repo_name,)
1111 'failed to delete repository `%s`' % (repo.repo_name,)
1112 )
1112 )
1113
1113
1114
1114
1115 #TODO: marcink, change name ?
1115 #TODO: marcink, change name ?
1116 @jsonrpc_method()
1116 @jsonrpc_method()
1117 def invalidate_cache(request, apiuser, repoid, delete_keys=Optional(False)):
1117 def invalidate_cache(request, apiuser, repoid, delete_keys=Optional(False)):
1118 """
1118 """
1119 Invalidates the cache for the specified repository.
1119 Invalidates the cache for the specified repository.
1120
1120
1121 This command can only be run using an |authtoken| with admin rights to
1121 This command can only be run using an |authtoken| with admin rights to
1122 the specified repository.
1122 the specified repository.
1123
1123
1124 This command takes the following options:
1124 This command takes the following options:
1125
1125
1126 :param apiuser: This is filled automatically from |authtoken|.
1126 :param apiuser: This is filled automatically from |authtoken|.
1127 :type apiuser: AuthUser
1127 :type apiuser: AuthUser
1128 :param repoid: Sets the repository name or repository ID.
1128 :param repoid: Sets the repository name or repository ID.
1129 :type repoid: str or int
1129 :type repoid: str or int
1130 :param delete_keys: This deletes the invalidated keys instead of
1130 :param delete_keys: This deletes the invalidated keys instead of
1131 just flagging them.
1131 just flagging them.
1132 :type delete_keys: Optional(``True`` | ``False``)
1132 :type delete_keys: Optional(``True`` | ``False``)
1133
1133
1134 Example output:
1134 Example output:
1135
1135
1136 .. code-block:: bash
1136 .. code-block:: bash
1137
1137
1138 id : <id_given_in_input>
1138 id : <id_given_in_input>
1139 result : {
1139 result : {
1140 'msg': Cache for repository `<repository name>` was invalidated,
1140 'msg': Cache for repository `<repository name>` was invalidated,
1141 'repository': <repository name>
1141 'repository': <repository name>
1142 }
1142 }
1143 error : null
1143 error : null
1144
1144
1145 Example error output:
1145 Example error output:
1146
1146
1147 .. code-block:: bash
1147 .. code-block:: bash
1148
1148
1149 id : <id_given_in_input>
1149 id : <id_given_in_input>
1150 result : null
1150 result : null
1151 error : {
1151 error : {
1152 'Error occurred during cache invalidation action'
1152 'Error occurred during cache invalidation action'
1153 }
1153 }
1154
1154
1155 """
1155 """
1156
1156
1157 repo = get_repo_or_error(repoid)
1157 repo = get_repo_or_error(repoid)
1158 if not has_superadmin_permission(apiuser):
1158 if not has_superadmin_permission(apiuser):
1159 _perms = ('repository.admin', 'repository.write',)
1159 _perms = ('repository.admin', 'repository.write',)
1160 has_repo_permissions(apiuser, repoid, repo, _perms)
1160 has_repo_permissions(apiuser, repoid, repo, _perms)
1161
1161
1162 delete = Optional.extract(delete_keys)
1162 delete = Optional.extract(delete_keys)
1163 try:
1163 try:
1164 ScmModel().mark_for_invalidation(repo.repo_name, delete=delete)
1164 ScmModel().mark_for_invalidation(repo.repo_name, delete=delete)
1165 return {
1165 return {
1166 'msg': 'Cache for repository `%s` was invalidated' % (repoid,),
1166 'msg': 'Cache for repository `%s` was invalidated' % (repoid,),
1167 'repository': repo.repo_name
1167 'repository': repo.repo_name
1168 }
1168 }
1169 except Exception:
1169 except Exception:
1170 log.exception(
1170 log.exception(
1171 "Exception occurred while trying to invalidate repo cache")
1171 "Exception occurred while trying to invalidate repo cache")
1172 raise JSONRPCError(
1172 raise JSONRPCError(
1173 'Error occurred during cache invalidation action'
1173 'Error occurred during cache invalidation action'
1174 )
1174 )
1175
1175
1176
1176
1177 #TODO: marcink, change name ?
1177 #TODO: marcink, change name ?
1178 @jsonrpc_method()
1178 @jsonrpc_method()
1179 def lock(request, apiuser, repoid, locked=Optional(None),
1179 def lock(request, apiuser, repoid, locked=Optional(None),
1180 userid=Optional(OAttr('apiuser'))):
1180 userid=Optional(OAttr('apiuser'))):
1181 """
1181 """
1182 Sets the lock state of the specified |repo| by the given user.
1182 Sets the lock state of the specified |repo| by the given user.
1183 From more information, see :ref:`repo-locking`.
1183 From more information, see :ref:`repo-locking`.
1184
1184
1185 * If the ``userid`` option is not set, the repository is locked to the
1185 * If the ``userid`` option is not set, the repository is locked to the
1186 user who called the method.
1186 user who called the method.
1187 * If the ``locked`` parameter is not set, the current lock state of the
1187 * If the ``locked`` parameter is not set, the current lock state of the
1188 repository is displayed.
1188 repository is displayed.
1189
1189
1190 This command can only be run using an |authtoken| with admin rights to
1190 This command can only be run using an |authtoken| with admin rights to
1191 the specified repository.
1191 the specified repository.
1192
1192
1193 This command takes the following options:
1193 This command takes the following options:
1194
1194
1195 :param apiuser: This is filled automatically from the |authtoken|.
1195 :param apiuser: This is filled automatically from the |authtoken|.
1196 :type apiuser: AuthUser
1196 :type apiuser: AuthUser
1197 :param repoid: Sets the repository name or repository ID.
1197 :param repoid: Sets the repository name or repository ID.
1198 :type repoid: str or int
1198 :type repoid: str or int
1199 :param locked: Sets the lock state.
1199 :param locked: Sets the lock state.
1200 :type locked: Optional(``True`` | ``False``)
1200 :type locked: Optional(``True`` | ``False``)
1201 :param userid: Set the repository lock to this user.
1201 :param userid: Set the repository lock to this user.
1202 :type userid: Optional(str or int)
1202 :type userid: Optional(str or int)
1203
1203
1204 Example error output:
1204 Example error output:
1205
1205
1206 .. code-block:: bash
1206 .. code-block:: bash
1207
1207
1208 id : <id_given_in_input>
1208 id : <id_given_in_input>
1209 result : {
1209 result : {
1210 'repo': '<reponame>',
1210 'repo': '<reponame>',
1211 'locked': <bool: lock state>,
1211 'locked': <bool: lock state>,
1212 'locked_since': <int: lock timestamp>,
1212 'locked_since': <int: lock timestamp>,
1213 'locked_by': <username of person who made the lock>,
1213 'locked_by': <username of person who made the lock>,
1214 'lock_reason': <str: reason for locking>,
1214 'lock_reason': <str: reason for locking>,
1215 'lock_state_changed': <bool: True if lock state has been changed in this request>,
1215 'lock_state_changed': <bool: True if lock state has been changed in this request>,
1216 'msg': 'Repo `<reponame>` locked by `<username>` on <timestamp>.'
1216 'msg': 'Repo `<reponame>` locked by `<username>` on <timestamp>.'
1217 or
1217 or
1218 'msg': 'Repo `<repository name>` not locked.'
1218 'msg': 'Repo `<repository name>` not locked.'
1219 or
1219 or
1220 'msg': 'User `<user name>` set lock state for repo `<repository name>` to `<new lock state>`'
1220 'msg': 'User `<user name>` set lock state for repo `<repository name>` to `<new lock state>`'
1221 }
1221 }
1222 error : null
1222 error : null
1223
1223
1224 Example error output:
1224 Example error output:
1225
1225
1226 .. code-block:: bash
1226 .. code-block:: bash
1227
1227
1228 id : <id_given_in_input>
1228 id : <id_given_in_input>
1229 result : null
1229 result : null
1230 error : {
1230 error : {
1231 'Error occurred locking repository `<reponame>`
1231 'Error occurred locking repository `<reponame>`'
1232 }
1232 }
1233 """
1233 """
1234
1234
1235 repo = get_repo_or_error(repoid)
1235 repo = get_repo_or_error(repoid)
1236 if not has_superadmin_permission(apiuser):
1236 if not has_superadmin_permission(apiuser):
1237 # check if we have at least write permission for this repo !
1237 # check if we have at least write permission for this repo !
1238 _perms = ('repository.admin', 'repository.write',)
1238 _perms = ('repository.admin', 'repository.write',)
1239 has_repo_permissions(apiuser, repoid, repo, _perms)
1239 has_repo_permissions(apiuser, repoid, repo, _perms)
1240
1240
1241 # make sure normal user does not pass someone else userid,
1241 # make sure normal user does not pass someone else userid,
1242 # he is not allowed to do that
1242 # he is not allowed to do that
1243 if not isinstance(userid, Optional) and userid != apiuser.user_id:
1243 if not isinstance(userid, Optional) and userid != apiuser.user_id:
1244 raise JSONRPCError('userid is not the same as your user')
1244 raise JSONRPCError('userid is not the same as your user')
1245
1245
1246 if isinstance(userid, Optional):
1246 if isinstance(userid, Optional):
1247 userid = apiuser.user_id
1247 userid = apiuser.user_id
1248
1248
1249 user = get_user_or_error(userid)
1249 user = get_user_or_error(userid)
1250
1250
1251 if isinstance(locked, Optional):
1251 if isinstance(locked, Optional):
1252 lockobj = repo.locked
1252 lockobj = repo.locked
1253
1253
1254 if lockobj[0] is None:
1254 if lockobj[0] is None:
1255 _d = {
1255 _d = {
1256 'repo': repo.repo_name,
1256 'repo': repo.repo_name,
1257 'locked': False,
1257 'locked': False,
1258 'locked_since': None,
1258 'locked_since': None,
1259 'locked_by': None,
1259 'locked_by': None,
1260 'lock_reason': None,
1260 'lock_reason': None,
1261 'lock_state_changed': False,
1261 'lock_state_changed': False,
1262 'msg': 'Repo `%s` not locked.' % repo.repo_name
1262 'msg': 'Repo `%s` not locked.' % repo.repo_name
1263 }
1263 }
1264 return _d
1264 return _d
1265 else:
1265 else:
1266 _user_id, _time, _reason = lockobj
1266 _user_id, _time, _reason = lockobj
1267 lock_user = get_user_or_error(userid)
1267 lock_user = get_user_or_error(userid)
1268 _d = {
1268 _d = {
1269 'repo': repo.repo_name,
1269 'repo': repo.repo_name,
1270 'locked': True,
1270 'locked': True,
1271 'locked_since': _time,
1271 'locked_since': _time,
1272 'locked_by': lock_user.username,
1272 'locked_by': lock_user.username,
1273 'lock_reason': _reason,
1273 'lock_reason': _reason,
1274 'lock_state_changed': False,
1274 'lock_state_changed': False,
1275 'msg': ('Repo `%s` locked by `%s` on `%s`.'
1275 'msg': ('Repo `%s` locked by `%s` on `%s`.'
1276 % (repo.repo_name, lock_user.username,
1276 % (repo.repo_name, lock_user.username,
1277 json.dumps(time_to_datetime(_time))))
1277 json.dumps(time_to_datetime(_time))))
1278 }
1278 }
1279 return _d
1279 return _d
1280
1280
1281 # force locked state through a flag
1281 # force locked state through a flag
1282 else:
1282 else:
1283 locked = str2bool(locked)
1283 locked = str2bool(locked)
1284 lock_reason = Repository.LOCK_API
1284 lock_reason = Repository.LOCK_API
1285 try:
1285 try:
1286 if locked:
1286 if locked:
1287 lock_time = time.time()
1287 lock_time = time.time()
1288 Repository.lock(repo, user.user_id, lock_time, lock_reason)
1288 Repository.lock(repo, user.user_id, lock_time, lock_reason)
1289 else:
1289 else:
1290 lock_time = None
1290 lock_time = None
1291 Repository.unlock(repo)
1291 Repository.unlock(repo)
1292 _d = {
1292 _d = {
1293 'repo': repo.repo_name,
1293 'repo': repo.repo_name,
1294 'locked': locked,
1294 'locked': locked,
1295 'locked_since': lock_time,
1295 'locked_since': lock_time,
1296 'locked_by': user.username,
1296 'locked_by': user.username,
1297 'lock_reason': lock_reason,
1297 'lock_reason': lock_reason,
1298 'lock_state_changed': True,
1298 'lock_state_changed': True,
1299 'msg': ('User `%s` set lock state for repo `%s` to `%s`'
1299 'msg': ('User `%s` set lock state for repo `%s` to `%s`'
1300 % (user.username, repo.repo_name, locked))
1300 % (user.username, repo.repo_name, locked))
1301 }
1301 }
1302 return _d
1302 return _d
1303 except Exception:
1303 except Exception:
1304 log.exception(
1304 log.exception(
1305 "Exception occurred while trying to lock repository")
1305 "Exception occurred while trying to lock repository")
1306 raise JSONRPCError(
1306 raise JSONRPCError(
1307 'Error occurred locking repository `%s`' % repo.repo_name
1307 'Error occurred locking repository `%s`' % repo.repo_name
1308 )
1308 )
1309
1309
1310
1310
1311 @jsonrpc_method()
1311 @jsonrpc_method()
1312 def comment_commit(
1312 def comment_commit(
1313 request, apiuser, repoid, commit_id, message,
1313 request, apiuser, repoid, commit_id, message,
1314 userid=Optional(OAttr('apiuser')), status=Optional(None)):
1314 userid=Optional(OAttr('apiuser')), status=Optional(None)):
1315 """
1315 """
1316 Set a commit comment, and optionally change the status of the commit.
1316 Set a commit comment, and optionally change the status of the commit.
1317
1317
1318 :param apiuser: This is filled automatically from the |authtoken|.
1318 :param apiuser: This is filled automatically from the |authtoken|.
1319 :type apiuser: AuthUser
1319 :type apiuser: AuthUser
1320 :param repoid: Set the repository name or repository ID.
1320 :param repoid: Set the repository name or repository ID.
1321 :type repoid: str or int
1321 :type repoid: str or int
1322 :param commit_id: Specify the commit_id for which to set a comment.
1322 :param commit_id: Specify the commit_id for which to set a comment.
1323 :type commit_id: str
1323 :type commit_id: str
1324 :param message: The comment text.
1324 :param message: The comment text.
1325 :type message: str
1325 :type message: str
1326 :param userid: Set the user name of the comment creator.
1326 :param userid: Set the user name of the comment creator.
1327 :type userid: Optional(str or int)
1327 :type userid: Optional(str or int)
1328 :param status: status, one of 'not_reviewed', 'approved', 'rejected',
1328 :param status: status, one of 'not_reviewed', 'approved', 'rejected',
1329 'under_review'
1329 'under_review'
1330 :type status: str
1330 :type status: str
1331
1331
1332 Example error output:
1332 Example error output:
1333
1333
1334 .. code-block:: json
1334 .. code-block:: json
1335
1335
1336 {
1336 {
1337 "id" : <id_given_in_input>,
1337 "id" : <id_given_in_input>,
1338 "result" : {
1338 "result" : {
1339 "msg": "Commented on commit `<commit_id>` for repository `<repoid>`",
1339 "msg": "Commented on commit `<commit_id>` for repository `<repoid>`",
1340 "status_change": null or <status>,
1340 "status_change": null or <status>,
1341 "success": true
1341 "success": true
1342 },
1342 },
1343 "error" : null
1343 "error" : null
1344 }
1344 }
1345
1345
1346 """
1346 """
1347 repo = get_repo_or_error(repoid)
1347 repo = get_repo_or_error(repoid)
1348 if not has_superadmin_permission(apiuser):
1348 if not has_superadmin_permission(apiuser):
1349 _perms = ('repository.read', 'repository.write', 'repository.admin')
1349 _perms = ('repository.read', 'repository.write', 'repository.admin')
1350 has_repo_permissions(apiuser, repoid, repo, _perms)
1350 has_repo_permissions(apiuser, repoid, repo, _perms)
1351
1351
1352 if isinstance(userid, Optional):
1352 if isinstance(userid, Optional):
1353 userid = apiuser.user_id
1353 userid = apiuser.user_id
1354
1354
1355 user = get_user_or_error(userid)
1355 user = get_user_or_error(userid)
1356 status = Optional.extract(status)
1356 status = Optional.extract(status)
1357
1357
1358 allowed_statuses = [x[0] for x in ChangesetStatus.STATUSES]
1358 allowed_statuses = [x[0] for x in ChangesetStatus.STATUSES]
1359 if status and status not in allowed_statuses:
1359 if status and status not in allowed_statuses:
1360 raise JSONRPCError('Bad status, must be on '
1360 raise JSONRPCError('Bad status, must be on '
1361 'of %s got %s' % (allowed_statuses, status,))
1361 'of %s got %s' % (allowed_statuses, status,))
1362
1362
1363 try:
1363 try:
1364 rc_config = SettingsModel().get_all_settings()
1364 rc_config = SettingsModel().get_all_settings()
1365 renderer = rc_config.get('rhodecode_markup_renderer', 'rst')
1365 renderer = rc_config.get('rhodecode_markup_renderer', 'rst')
1366 status_change_label = ChangesetStatus.get_status_lbl(status)
1366 status_change_label = ChangesetStatus.get_status_lbl(status)
1367 comm = ChangesetCommentsModel().create(
1367 comm = ChangesetCommentsModel().create(
1368 message, repo, user, revision=commit_id,
1368 message, repo, user, revision=commit_id,
1369 status_change=status_change_label,
1369 status_change=status_change_label,
1370 status_change_type=status,
1370 status_change_type=status,
1371 renderer=renderer)
1371 renderer=renderer)
1372 if status:
1372 if status:
1373 # also do a status change
1373 # also do a status change
1374 try:
1374 try:
1375 ChangesetStatusModel().set_status(
1375 ChangesetStatusModel().set_status(
1376 repo, status, user, comm, revision=commit_id,
1376 repo, status, user, comm, revision=commit_id,
1377 dont_allow_on_closed_pull_request=True
1377 dont_allow_on_closed_pull_request=True
1378 )
1378 )
1379 except StatusChangeOnClosedPullRequestError:
1379 except StatusChangeOnClosedPullRequestError:
1380 log.exception(
1380 log.exception(
1381 "Exception occurred while trying to change repo commit status")
1381 "Exception occurred while trying to change repo commit status")
1382 msg = ('Changing status on a changeset associated with '
1382 msg = ('Changing status on a changeset associated with '
1383 'a closed pull request is not allowed')
1383 'a closed pull request is not allowed')
1384 raise JSONRPCError(msg)
1384 raise JSONRPCError(msg)
1385
1385
1386 Session().commit()
1386 Session().commit()
1387 return {
1387 return {
1388 'msg': (
1388 'msg': (
1389 'Commented on commit `%s` for repository `%s`' % (
1389 'Commented on commit `%s` for repository `%s`' % (
1390 comm.revision, repo.repo_name)),
1390 comm.revision, repo.repo_name)),
1391 'status_change': status,
1391 'status_change': status,
1392 'success': True,
1392 'success': True,
1393 }
1393 }
1394 except JSONRPCError:
1394 except JSONRPCError:
1395 # catch any inside errors, and re-raise them to prevent from
1395 # catch any inside errors, and re-raise them to prevent from
1396 # below global catch to silence them
1396 # below global catch to silence them
1397 raise
1397 raise
1398 except Exception:
1398 except Exception:
1399 log.exception("Exception occurred while trying to comment on commit")
1399 log.exception("Exception occurred while trying to comment on commit")
1400 raise JSONRPCError(
1400 raise JSONRPCError(
1401 'failed to set comment on repository `%s`' % (repo.repo_name,)
1401 'failed to set comment on repository `%s`' % (repo.repo_name,)
1402 )
1402 )
1403
1403
1404
1404
1405 @jsonrpc_method()
1405 @jsonrpc_method()
1406 def grant_user_permission(request, apiuser, repoid, userid, perm):
1406 def grant_user_permission(request, apiuser, repoid, userid, perm):
1407 """
1407 """
1408 Grant permissions for the specified user on the given repository,
1408 Grant permissions for the specified user on the given repository,
1409 or update existing permissions if found.
1409 or update existing permissions if found.
1410
1410
1411 This command can only be run using an |authtoken| with admin
1411 This command can only be run using an |authtoken| with admin
1412 permissions on the |repo|.
1412 permissions on the |repo|.
1413
1413
1414 :param apiuser: This is filled automatically from the |authtoken|.
1414 :param apiuser: This is filled automatically from the |authtoken|.
1415 :type apiuser: AuthUser
1415 :type apiuser: AuthUser
1416 :param repoid: Set the repository name or repository ID.
1416 :param repoid: Set the repository name or repository ID.
1417 :type repoid: str or int
1417 :type repoid: str or int
1418 :param userid: Set the user name.
1418 :param userid: Set the user name.
1419 :type userid: str
1419 :type userid: str
1420 :param perm: Set the user permissions, using the following format
1420 :param perm: Set the user permissions, using the following format
1421 ``(repository.(none|read|write|admin))``
1421 ``(repository.(none|read|write|admin))``
1422 :type perm: str
1422 :type perm: str
1423
1423
1424 Example output:
1424 Example output:
1425
1425
1426 .. code-block:: bash
1426 .. code-block:: bash
1427
1427
1428 id : <id_given_in_input>
1428 id : <id_given_in_input>
1429 result: {
1429 result: {
1430 "msg" : "Granted perm: `<perm>` for user: `<username>` in repo: `<reponame>`",
1430 "msg" : "Granted perm: `<perm>` for user: `<username>` in repo: `<reponame>`",
1431 "success": true
1431 "success": true
1432 }
1432 }
1433 error: null
1433 error: null
1434 """
1434 """
1435
1435
1436 repo = get_repo_or_error(repoid)
1436 repo = get_repo_or_error(repoid)
1437 user = get_user_or_error(userid)
1437 user = get_user_or_error(userid)
1438 perm = get_perm_or_error(perm)
1438 perm = get_perm_or_error(perm)
1439 if not has_superadmin_permission(apiuser):
1439 if not has_superadmin_permission(apiuser):
1440 _perms = ('repository.admin',)
1440 _perms = ('repository.admin',)
1441 has_repo_permissions(apiuser, repoid, repo, _perms)
1441 has_repo_permissions(apiuser, repoid, repo, _perms)
1442
1442
1443 try:
1443 try:
1444
1444
1445 RepoModel().grant_user_permission(repo=repo, user=user, perm=perm)
1445 RepoModel().grant_user_permission(repo=repo, user=user, perm=perm)
1446
1446
1447 Session().commit()
1447 Session().commit()
1448 return {
1448 return {
1449 'msg': 'Granted perm: `%s` for user: `%s` in repo: `%s`' % (
1449 'msg': 'Granted perm: `%s` for user: `%s` in repo: `%s`' % (
1450 perm.permission_name, user.username, repo.repo_name
1450 perm.permission_name, user.username, repo.repo_name
1451 ),
1451 ),
1452 'success': True
1452 'success': True
1453 }
1453 }
1454 except Exception:
1454 except Exception:
1455 log.exception(
1455 log.exception(
1456 "Exception occurred while trying edit permissions for repo")
1456 "Exception occurred while trying edit permissions for repo")
1457 raise JSONRPCError(
1457 raise JSONRPCError(
1458 'failed to edit permission for user: `%s` in repo: `%s`' % (
1458 'failed to edit permission for user: `%s` in repo: `%s`' % (
1459 userid, repoid
1459 userid, repoid
1460 )
1460 )
1461 )
1461 )
1462
1462
1463
1463
1464 @jsonrpc_method()
1464 @jsonrpc_method()
1465 def revoke_user_permission(request, apiuser, repoid, userid):
1465 def revoke_user_permission(request, apiuser, repoid, userid):
1466 """
1466 """
1467 Revoke permission for a user on the specified repository.
1467 Revoke permission for a user on the specified repository.
1468
1468
1469 This command can only be run using an |authtoken| with admin
1469 This command can only be run using an |authtoken| with admin
1470 permissions on the |repo|.
1470 permissions on the |repo|.
1471
1471
1472 :param apiuser: This is filled automatically from the |authtoken|.
1472 :param apiuser: This is filled automatically from the |authtoken|.
1473 :type apiuser: AuthUser
1473 :type apiuser: AuthUser
1474 :param repoid: Set the repository name or repository ID.
1474 :param repoid: Set the repository name or repository ID.
1475 :type repoid: str or int
1475 :type repoid: str or int
1476 :param userid: Set the user name of revoked user.
1476 :param userid: Set the user name of revoked user.
1477 :type userid: str or int
1477 :type userid: str or int
1478
1478
1479 Example error output:
1479 Example error output:
1480
1480
1481 .. code-block:: bash
1481 .. code-block:: bash
1482
1482
1483 id : <id_given_in_input>
1483 id : <id_given_in_input>
1484 result: {
1484 result: {
1485 "msg" : "Revoked perm for user: `<username>` in repo: `<reponame>`",
1485 "msg" : "Revoked perm for user: `<username>` in repo: `<reponame>`",
1486 "success": true
1486 "success": true
1487 }
1487 }
1488 error: null
1488 error: null
1489 """
1489 """
1490
1490
1491 repo = get_repo_or_error(repoid)
1491 repo = get_repo_or_error(repoid)
1492 user = get_user_or_error(userid)
1492 user = get_user_or_error(userid)
1493 if not has_superadmin_permission(apiuser):
1493 if not has_superadmin_permission(apiuser):
1494 _perms = ('repository.admin',)
1494 _perms = ('repository.admin',)
1495 has_repo_permissions(apiuser, repoid, repo, _perms)
1495 has_repo_permissions(apiuser, repoid, repo, _perms)
1496
1496
1497 try:
1497 try:
1498 RepoModel().revoke_user_permission(repo=repo, user=user)
1498 RepoModel().revoke_user_permission(repo=repo, user=user)
1499 Session().commit()
1499 Session().commit()
1500 return {
1500 return {
1501 'msg': 'Revoked perm for user: `%s` in repo: `%s`' % (
1501 'msg': 'Revoked perm for user: `%s` in repo: `%s`' % (
1502 user.username, repo.repo_name
1502 user.username, repo.repo_name
1503 ),
1503 ),
1504 'success': True
1504 'success': True
1505 }
1505 }
1506 except Exception:
1506 except Exception:
1507 log.exception(
1507 log.exception(
1508 "Exception occurred while trying revoke permissions to repo")
1508 "Exception occurred while trying revoke permissions to repo")
1509 raise JSONRPCError(
1509 raise JSONRPCError(
1510 'failed to edit permission for user: `%s` in repo: `%s`' % (
1510 'failed to edit permission for user: `%s` in repo: `%s`' % (
1511 userid, repoid
1511 userid, repoid
1512 )
1512 )
1513 )
1513 )
1514
1514
1515
1515
1516 @jsonrpc_method()
1516 @jsonrpc_method()
1517 def grant_user_group_permission(request, apiuser, repoid, usergroupid, perm):
1517 def grant_user_group_permission(request, apiuser, repoid, usergroupid, perm):
1518 """
1518 """
1519 Grant permission for a user group on the specified repository,
1519 Grant permission for a user group on the specified repository,
1520 or update existing permissions.
1520 or update existing permissions.
1521
1521
1522 This command can only be run using an |authtoken| with admin
1522 This command can only be run using an |authtoken| with admin
1523 permissions on the |repo|.
1523 permissions on the |repo|.
1524
1524
1525 :param apiuser: This is filled automatically from the |authtoken|.
1525 :param apiuser: This is filled automatically from the |authtoken|.
1526 :type apiuser: AuthUser
1526 :type apiuser: AuthUser
1527 :param repoid: Set the repository name or repository ID.
1527 :param repoid: Set the repository name or repository ID.
1528 :type repoid: str or int
1528 :type repoid: str or int
1529 :param usergroupid: Specify the ID of the user group.
1529 :param usergroupid: Specify the ID of the user group.
1530 :type usergroupid: str or int
1530 :type usergroupid: str or int
1531 :param perm: Set the user group permissions using the following
1531 :param perm: Set the user group permissions using the following
1532 format: (repository.(none|read|write|admin))
1532 format: (repository.(none|read|write|admin))
1533 :type perm: str
1533 :type perm: str
1534
1534
1535 Example output:
1535 Example output:
1536
1536
1537 .. code-block:: bash
1537 .. code-block:: bash
1538
1538
1539 id : <id_given_in_input>
1539 id : <id_given_in_input>
1540 result : {
1540 result : {
1541 "msg" : "Granted perm: `<perm>` for group: `<usersgroupname>` in repo: `<reponame>`",
1541 "msg" : "Granted perm: `<perm>` for group: `<usersgroupname>` in repo: `<reponame>`",
1542 "success": true
1542 "success": true
1543
1543
1544 }
1544 }
1545 error : null
1545 error : null
1546
1546
1547 Example error output:
1547 Example error output:
1548
1548
1549 .. code-block:: bash
1549 .. code-block:: bash
1550
1550
1551 id : <id_given_in_input>
1551 id : <id_given_in_input>
1552 result : null
1552 result : null
1553 error : {
1553 error : {
1554 "failed to edit permission for user group: `<usergroup>` in repo `<repo>`'
1554 "failed to edit permission for user group: `<usergroup>` in repo `<repo>`'
1555 }
1555 }
1556
1556
1557 """
1557 """
1558
1558
1559 repo = get_repo_or_error(repoid)
1559 repo = get_repo_or_error(repoid)
1560 perm = get_perm_or_error(perm)
1560 perm = get_perm_or_error(perm)
1561 if not has_superadmin_permission(apiuser):
1561 if not has_superadmin_permission(apiuser):
1562 _perms = ('repository.admin',)
1562 _perms = ('repository.admin',)
1563 has_repo_permissions(apiuser, repoid, repo, _perms)
1563 has_repo_permissions(apiuser, repoid, repo, _perms)
1564
1564
1565 user_group = get_user_group_or_error(usergroupid)
1565 user_group = get_user_group_or_error(usergroupid)
1566 if not has_superadmin_permission(apiuser):
1566 if not has_superadmin_permission(apiuser):
1567 # check if we have at least read permission for this user group !
1567 # check if we have at least read permission for this user group !
1568 _perms = ('usergroup.read', 'usergroup.write', 'usergroup.admin',)
1568 _perms = ('usergroup.read', 'usergroup.write', 'usergroup.admin',)
1569 if not HasUserGroupPermissionAnyApi(*_perms)(
1569 if not HasUserGroupPermissionAnyApi(*_perms)(
1570 user=apiuser, user_group_name=user_group.users_group_name):
1570 user=apiuser, user_group_name=user_group.users_group_name):
1571 raise JSONRPCError(
1571 raise JSONRPCError(
1572 'user group `%s` does not exist' % (usergroupid,))
1572 'user group `%s` does not exist' % (usergroupid,))
1573
1573
1574 try:
1574 try:
1575 RepoModel().grant_user_group_permission(
1575 RepoModel().grant_user_group_permission(
1576 repo=repo, group_name=user_group, perm=perm)
1576 repo=repo, group_name=user_group, perm=perm)
1577
1577
1578 Session().commit()
1578 Session().commit()
1579 return {
1579 return {
1580 'msg': 'Granted perm: `%s` for user group: `%s` in '
1580 'msg': 'Granted perm: `%s` for user group: `%s` in '
1581 'repo: `%s`' % (
1581 'repo: `%s`' % (
1582 perm.permission_name, user_group.users_group_name,
1582 perm.permission_name, user_group.users_group_name,
1583 repo.repo_name
1583 repo.repo_name
1584 ),
1584 ),
1585 'success': True
1585 'success': True
1586 }
1586 }
1587 except Exception:
1587 except Exception:
1588 log.exception(
1588 log.exception(
1589 "Exception occurred while trying change permission on repo")
1589 "Exception occurred while trying change permission on repo")
1590 raise JSONRPCError(
1590 raise JSONRPCError(
1591 'failed to edit permission for user group: `%s` in '
1591 'failed to edit permission for user group: `%s` in '
1592 'repo: `%s`' % (
1592 'repo: `%s`' % (
1593 usergroupid, repo.repo_name
1593 usergroupid, repo.repo_name
1594 )
1594 )
1595 )
1595 )
1596
1596
1597
1597
1598 @jsonrpc_method()
1598 @jsonrpc_method()
1599 def revoke_user_group_permission(request, apiuser, repoid, usergroupid):
1599 def revoke_user_group_permission(request, apiuser, repoid, usergroupid):
1600 """
1600 """
1601 Revoke the permissions of a user group on a given repository.
1601 Revoke the permissions of a user group on a given repository.
1602
1602
1603 This command can only be run using an |authtoken| with admin
1603 This command can only be run using an |authtoken| with admin
1604 permissions on the |repo|.
1604 permissions on the |repo|.
1605
1605
1606 :param apiuser: This is filled automatically from the |authtoken|.
1606 :param apiuser: This is filled automatically from the |authtoken|.
1607 :type apiuser: AuthUser
1607 :type apiuser: AuthUser
1608 :param repoid: Set the repository name or repository ID.
1608 :param repoid: Set the repository name or repository ID.
1609 :type repoid: str or int
1609 :type repoid: str or int
1610 :param usergroupid: Specify the user group ID.
1610 :param usergroupid: Specify the user group ID.
1611 :type usergroupid: str or int
1611 :type usergroupid: str or int
1612
1612
1613 Example output:
1613 Example output:
1614
1614
1615 .. code-block:: bash
1615 .. code-block:: bash
1616
1616
1617 id : <id_given_in_input>
1617 id : <id_given_in_input>
1618 result: {
1618 result: {
1619 "msg" : "Revoked perm for group: `<usersgroupname>` in repo: `<reponame>`",
1619 "msg" : "Revoked perm for group: `<usersgroupname>` in repo: `<reponame>`",
1620 "success": true
1620 "success": true
1621 }
1621 }
1622 error: null
1622 error: null
1623 """
1623 """
1624
1624
1625 repo = get_repo_or_error(repoid)
1625 repo = get_repo_or_error(repoid)
1626 if not has_superadmin_permission(apiuser):
1626 if not has_superadmin_permission(apiuser):
1627 _perms = ('repository.admin',)
1627 _perms = ('repository.admin',)
1628 has_repo_permissions(apiuser, repoid, repo, _perms)
1628 has_repo_permissions(apiuser, repoid, repo, _perms)
1629
1629
1630 user_group = get_user_group_or_error(usergroupid)
1630 user_group = get_user_group_or_error(usergroupid)
1631 if not has_superadmin_permission(apiuser):
1631 if not has_superadmin_permission(apiuser):
1632 # check if we have at least read permission for this user group !
1632 # check if we have at least read permission for this user group !
1633 _perms = ('usergroup.read', 'usergroup.write', 'usergroup.admin',)
1633 _perms = ('usergroup.read', 'usergroup.write', 'usergroup.admin',)
1634 if not HasUserGroupPermissionAnyApi(*_perms)(
1634 if not HasUserGroupPermissionAnyApi(*_perms)(
1635 user=apiuser, user_group_name=user_group.users_group_name):
1635 user=apiuser, user_group_name=user_group.users_group_name):
1636 raise JSONRPCError(
1636 raise JSONRPCError(
1637 'user group `%s` does not exist' % (usergroupid,))
1637 'user group `%s` does not exist' % (usergroupid,))
1638
1638
1639 try:
1639 try:
1640 RepoModel().revoke_user_group_permission(
1640 RepoModel().revoke_user_group_permission(
1641 repo=repo, group_name=user_group)
1641 repo=repo, group_name=user_group)
1642
1642
1643 Session().commit()
1643 Session().commit()
1644 return {
1644 return {
1645 'msg': 'Revoked perm for user group: `%s` in repo: `%s`' % (
1645 'msg': 'Revoked perm for user group: `%s` in repo: `%s`' % (
1646 user_group.users_group_name, repo.repo_name
1646 user_group.users_group_name, repo.repo_name
1647 ),
1647 ),
1648 'success': True
1648 'success': True
1649 }
1649 }
1650 except Exception:
1650 except Exception:
1651 log.exception("Exception occurred while trying revoke "
1651 log.exception("Exception occurred while trying revoke "
1652 "user group permission on repo")
1652 "user group permission on repo")
1653 raise JSONRPCError(
1653 raise JSONRPCError(
1654 'failed to edit permission for user group: `%s` in '
1654 'failed to edit permission for user group: `%s` in '
1655 'repo: `%s`' % (
1655 'repo: `%s`' % (
1656 user_group.users_group_name, repo.repo_name
1656 user_group.users_group_name, repo.repo_name
1657 )
1657 )
1658 )
1658 )
1659
1659
1660
1660
1661 @jsonrpc_method()
1661 @jsonrpc_method()
1662 def pull(request, apiuser, repoid):
1662 def pull(request, apiuser, repoid):
1663 """
1663 """
1664 Triggers a pull on the given repository from a remote location. You
1664 Triggers a pull on the given repository from a remote location. You
1665 can use this to keep remote repositories up-to-date.
1665 can use this to keep remote repositories up-to-date.
1666
1666
1667 This command can only be run using an |authtoken| with admin
1667 This command can only be run using an |authtoken| with admin
1668 rights to the specified repository. For more information,
1668 rights to the specified repository. For more information,
1669 see :ref:`config-token-ref`.
1669 see :ref:`config-token-ref`.
1670
1670
1671 This command takes the following options:
1671 This command takes the following options:
1672
1672
1673 :param apiuser: This is filled automatically from the |authtoken|.
1673 :param apiuser: This is filled automatically from the |authtoken|.
1674 :type apiuser: AuthUser
1674 :type apiuser: AuthUser
1675 :param repoid: The repository name or repository ID.
1675 :param repoid: The repository name or repository ID.
1676 :type repoid: str or int
1676 :type repoid: str or int
1677
1677
1678 Example output:
1678 Example output:
1679
1679
1680 .. code-block:: bash
1680 .. code-block:: bash
1681
1681
1682 id : <id_given_in_input>
1682 id : <id_given_in_input>
1683 result : {
1683 result : {
1684 "msg": "Pulled from `<repository name>`"
1684 "msg": "Pulled from `<repository name>`"
1685 "repository": "<repository name>"
1685 "repository": "<repository name>"
1686 }
1686 }
1687 error : null
1687 error : null
1688
1688
1689 Example error output:
1689 Example error output:
1690
1690
1691 .. code-block:: bash
1691 .. code-block:: bash
1692
1692
1693 id : <id_given_in_input>
1693 id : <id_given_in_input>
1694 result : null
1694 result : null
1695 error : {
1695 error : {
1696 "Unable to pull changes from `<reponame>`"
1696 "Unable to pull changes from `<reponame>`"
1697 }
1697 }
1698
1698
1699 """
1699 """
1700
1700
1701 repo = get_repo_or_error(repoid)
1701 repo = get_repo_or_error(repoid)
1702 if not has_superadmin_permission(apiuser):
1702 if not has_superadmin_permission(apiuser):
1703 _perms = ('repository.admin',)
1703 _perms = ('repository.admin',)
1704 has_repo_permissions(apiuser, repoid, repo, _perms)
1704 has_repo_permissions(apiuser, repoid, repo, _perms)
1705
1705
1706 try:
1706 try:
1707 ScmModel().pull_changes(repo.repo_name, apiuser.username)
1707 ScmModel().pull_changes(repo.repo_name, apiuser.username)
1708 return {
1708 return {
1709 'msg': 'Pulled from `%s`' % repo.repo_name,
1709 'msg': 'Pulled from `%s`' % repo.repo_name,
1710 'repository': repo.repo_name
1710 'repository': repo.repo_name
1711 }
1711 }
1712 except Exception:
1712 except Exception:
1713 log.exception("Exception occurred while trying to "
1713 log.exception("Exception occurred while trying to "
1714 "pull changes from remote location")
1714 "pull changes from remote location")
1715 raise JSONRPCError(
1715 raise JSONRPCError(
1716 'Unable to pull changes from `%s`' % repo.repo_name
1716 'Unable to pull changes from `%s`' % repo.repo_name
1717 )
1717 )
1718
1718
1719
1719
1720 @jsonrpc_method()
1720 @jsonrpc_method()
1721 def strip(request, apiuser, repoid, revision, branch):
1721 def strip(request, apiuser, repoid, revision, branch):
1722 """
1722 """
1723 Strips the given revision from the specified repository.
1723 Strips the given revision from the specified repository.
1724
1724
1725 * This will remove the revision and all of its decendants.
1725 * This will remove the revision and all of its decendants.
1726
1726
1727 This command can only be run using an |authtoken| with admin rights to
1727 This command can only be run using an |authtoken| with admin rights to
1728 the specified repository.
1728 the specified repository.
1729
1729
1730 This command takes the following options:
1730 This command takes the following options:
1731
1731
1732 :param apiuser: This is filled automatically from the |authtoken|.
1732 :param apiuser: This is filled automatically from the |authtoken|.
1733 :type apiuser: AuthUser
1733 :type apiuser: AuthUser
1734 :param repoid: The repository name or repository ID.
1734 :param repoid: The repository name or repository ID.
1735 :type repoid: str or int
1735 :type repoid: str or int
1736 :param revision: The revision you wish to strip.
1736 :param revision: The revision you wish to strip.
1737 :type revision: str
1737 :type revision: str
1738 :param branch: The branch from which to strip the revision.
1738 :param branch: The branch from which to strip the revision.
1739 :type branch: str
1739 :type branch: str
1740
1740
1741 Example output:
1741 Example output:
1742
1742
1743 .. code-block:: bash
1743 .. code-block:: bash
1744
1744
1745 id : <id_given_in_input>
1745 id : <id_given_in_input>
1746 result : {
1746 result : {
1747 "msg": "'Stripped commit <commit_hash> from repo `<repository name>`'"
1747 "msg": "'Stripped commit <commit_hash> from repo `<repository name>`'"
1748 "repository": "<repository name>"
1748 "repository": "<repository name>"
1749 }
1749 }
1750 error : null
1750 error : null
1751
1751
1752 Example error output:
1752 Example error output:
1753
1753
1754 .. code-block:: bash
1754 .. code-block:: bash
1755
1755
1756 id : <id_given_in_input>
1756 id : <id_given_in_input>
1757 result : null
1757 result : null
1758 error : {
1758 error : {
1759 "Unable to strip commit <commit_hash> from repo `<repository name>`"
1759 "Unable to strip commit <commit_hash> from repo `<repository name>`"
1760 }
1760 }
1761
1761
1762 """
1762 """
1763
1763
1764 repo = get_repo_or_error(repoid)
1764 repo = get_repo_or_error(repoid)
1765 if not has_superadmin_permission(apiuser):
1765 if not has_superadmin_permission(apiuser):
1766 _perms = ('repository.admin',)
1766 _perms = ('repository.admin',)
1767 has_repo_permissions(apiuser, repoid, repo, _perms)
1767 has_repo_permissions(apiuser, repoid, repo, _perms)
1768
1768
1769 try:
1769 try:
1770 ScmModel().strip(repo, revision, branch)
1770 ScmModel().strip(repo, revision, branch)
1771 return {
1771 return {
1772 'msg': 'Stripped commit %s from repo `%s`' % (
1772 'msg': 'Stripped commit %s from repo `%s`' % (
1773 revision, repo.repo_name),
1773 revision, repo.repo_name),
1774 'repository': repo.repo_name
1774 'repository': repo.repo_name
1775 }
1775 }
1776 except Exception:
1776 except Exception:
1777 log.exception("Exception while trying to strip")
1777 log.exception("Exception while trying to strip")
1778 raise JSONRPCError(
1778 raise JSONRPCError(
1779 'Unable to strip commit %s from repo `%s`' % (
1779 'Unable to strip commit %s from repo `%s`' % (
1780 revision, repo.repo_name)
1780 revision, repo.repo_name)
1781 )
1781 )
1782
1782
1783
1783
1784 @jsonrpc_method()
1784 @jsonrpc_method()
1785 def get_repo_settings(request, apiuser, repoid, key=Optional(None)):
1785 def get_repo_settings(request, apiuser, repoid, key=Optional(None)):
1786 """
1786 """
1787 Returns all settings for a repository. If key is given it only returns the
1787 Returns all settings for a repository. If key is given it only returns the
1788 setting identified by the key or null.
1788 setting identified by the key or null.
1789
1789
1790 :param apiuser: This is filled automatically from the |authtoken|.
1790 :param apiuser: This is filled automatically from the |authtoken|.
1791 :type apiuser: AuthUser
1791 :type apiuser: AuthUser
1792 :param repoid: The repository name or repository id.
1792 :param repoid: The repository name or repository id.
1793 :type repoid: str or int
1793 :type repoid: str or int
1794 :param key: Key of the setting to return.
1794 :param key: Key of the setting to return.
1795 :type: key: Optional(str)
1795 :type: key: Optional(str)
1796
1796
1797 Example output:
1797 Example output:
1798
1798
1799 .. code-block:: bash
1799 .. code-block:: bash
1800
1800
1801 {
1801 {
1802 "error": null,
1802 "error": null,
1803 "id": 237,
1803 "id": 237,
1804 "result": {
1804 "result": {
1805 "extensions_largefiles": true,
1805 "extensions_largefiles": true,
1806 "hooks_changegroup_push_logger": true,
1806 "hooks_changegroup_push_logger": true,
1807 "hooks_changegroup_repo_size": false,
1807 "hooks_changegroup_repo_size": false,
1808 "hooks_outgoing_pull_logger": true,
1808 "hooks_outgoing_pull_logger": true,
1809 "phases_publish": "True",
1809 "phases_publish": "True",
1810 "rhodecode_hg_use_rebase_for_merging": true,
1810 "rhodecode_hg_use_rebase_for_merging": true,
1811 "rhodecode_pr_merge_enabled": true,
1811 "rhodecode_pr_merge_enabled": true,
1812 "rhodecode_use_outdated_comments": true
1812 "rhodecode_use_outdated_comments": true
1813 }
1813 }
1814 }
1814 }
1815 """
1815 """
1816
1816
1817 # Restrict access to this api method to admins only.
1817 # Restrict access to this api method to admins only.
1818 if not has_superadmin_permission(apiuser):
1818 if not has_superadmin_permission(apiuser):
1819 raise JSONRPCForbidden()
1819 raise JSONRPCForbidden()
1820
1820
1821 try:
1821 try:
1822 repo = get_repo_or_error(repoid)
1822 repo = get_repo_or_error(repoid)
1823 settings_model = VcsSettingsModel(repo=repo)
1823 settings_model = VcsSettingsModel(repo=repo)
1824 settings = settings_model.get_global_settings()
1824 settings = settings_model.get_global_settings()
1825 settings.update(settings_model.get_repo_settings())
1825 settings.update(settings_model.get_repo_settings())
1826
1826
1827 # If only a single setting is requested fetch it from all settings.
1827 # If only a single setting is requested fetch it from all settings.
1828 key = Optional.extract(key)
1828 key = Optional.extract(key)
1829 if key is not None:
1829 if key is not None:
1830 settings = settings.get(key, None)
1830 settings = settings.get(key, None)
1831 except Exception:
1831 except Exception:
1832 msg = 'Failed to fetch settings for repository `{}`'.format(repoid)
1832 msg = 'Failed to fetch settings for repository `{}`'.format(repoid)
1833 log.exception(msg)
1833 log.exception(msg)
1834 raise JSONRPCError(msg)
1834 raise JSONRPCError(msg)
1835
1835
1836 return settings
1836 return settings
1837
1837
1838
1838
1839 @jsonrpc_method()
1839 @jsonrpc_method()
1840 def set_repo_settings(request, apiuser, repoid, settings):
1840 def set_repo_settings(request, apiuser, repoid, settings):
1841 """
1841 """
1842 Update repository settings. Returns true on success.
1842 Update repository settings. Returns true on success.
1843
1843
1844 :param apiuser: This is filled automatically from the |authtoken|.
1844 :param apiuser: This is filled automatically from the |authtoken|.
1845 :type apiuser: AuthUser
1845 :type apiuser: AuthUser
1846 :param repoid: The repository name or repository id.
1846 :param repoid: The repository name or repository id.
1847 :type repoid: str or int
1847 :type repoid: str or int
1848 :param settings: The new settings for the repository.
1848 :param settings: The new settings for the repository.
1849 :type: settings: dict
1849 :type: settings: dict
1850
1850
1851 Example output:
1851 Example output:
1852
1852
1853 .. code-block:: bash
1853 .. code-block:: bash
1854
1854
1855 {
1855 {
1856 "error": null,
1856 "error": null,
1857 "id": 237,
1857 "id": 237,
1858 "result": true
1858 "result": true
1859 }
1859 }
1860 """
1860 """
1861 # Restrict access to this api method to admins only.
1861 # Restrict access to this api method to admins only.
1862 if not has_superadmin_permission(apiuser):
1862 if not has_superadmin_permission(apiuser):
1863 raise JSONRPCForbidden()
1863 raise JSONRPCForbidden()
1864
1864
1865 if type(settings) is not dict:
1865 if type(settings) is not dict:
1866 raise JSONRPCError('Settings have to be a JSON Object.')
1866 raise JSONRPCError('Settings have to be a JSON Object.')
1867
1867
1868 try:
1868 try:
1869 settings_model = VcsSettingsModel(repo=repoid)
1869 settings_model = VcsSettingsModel(repo=repoid)
1870
1870
1871 # Merge global, repo and incoming settings.
1871 # Merge global, repo and incoming settings.
1872 new_settings = settings_model.get_global_settings()
1872 new_settings = settings_model.get_global_settings()
1873 new_settings.update(settings_model.get_repo_settings())
1873 new_settings.update(settings_model.get_repo_settings())
1874 new_settings.update(settings)
1874 new_settings.update(settings)
1875
1875
1876 # Update the settings.
1876 # Update the settings.
1877 inherit_global_settings = new_settings.get(
1877 inherit_global_settings = new_settings.get(
1878 'inherit_global_settings', False)
1878 'inherit_global_settings', False)
1879 settings_model.create_or_update_repo_settings(
1879 settings_model.create_or_update_repo_settings(
1880 new_settings, inherit_global_settings=inherit_global_settings)
1880 new_settings, inherit_global_settings=inherit_global_settings)
1881 Session().commit()
1881 Session().commit()
1882 except Exception:
1882 except Exception:
1883 msg = 'Failed to update settings for repository `{}`'.format(repoid)
1883 msg = 'Failed to update settings for repository `{}`'.format(repoid)
1884 log.exception(msg)
1884 log.exception(msg)
1885 raise JSONRPCError(msg)
1885 raise JSONRPCError(msg)
1886
1886
1887 # Indicate success.
1887 # Indicate success.
1888 return True
1888 return True
@@ -1,699 +1,699 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2
2
3 # Copyright (C) 2011-2016 RhodeCode GmbH
3 # Copyright (C) 2011-2016 RhodeCode GmbH
4 #
4 #
5 # This program is free software: you can redistribute it and/or modify
5 # This program is free software: you can redistribute it and/or modify
6 # it under the terms of the GNU Affero General Public License, version 3
6 # it under the terms of the GNU Affero General Public License, version 3
7 # (only), as published by the Free Software Foundation.
7 # (only), as published by the Free Software Foundation.
8 #
8 #
9 # This program is distributed in the hope that it will be useful,
9 # This program is distributed in the hope that it will be useful,
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 # GNU General Public License for more details.
12 # GNU General Public License for more details.
13 #
13 #
14 # You should have received a copy of the GNU Affero General Public License
14 # You should have received a copy of the GNU Affero General Public License
15 # along with this program. If not, see <http://www.gnu.org/licenses/>.
15 # along with this program. If not, see <http://www.gnu.org/licenses/>.
16 #
16 #
17 # This program is dual-licensed. If you wish to learn more about the
17 # This program is dual-licensed. If you wish to learn more about the
18 # RhodeCode Enterprise Edition, including its added features, Support services,
18 # RhodeCode Enterprise Edition, including its added features, Support services,
19 # and proprietary license terms, please see https://rhodecode.com/licenses/
19 # and proprietary license terms, please see https://rhodecode.com/licenses/
20
20
21
21
22 import logging
22 import logging
23
23
24 import colander
24 import colander
25
25
26 from rhodecode.api import jsonrpc_method, JSONRPCError, JSONRPCForbidden
26 from rhodecode.api import jsonrpc_method, JSONRPCError, JSONRPCForbidden
27 from rhodecode.api.utils import (
27 from rhodecode.api.utils import (
28 has_superadmin_permission, Optional, OAttr, get_user_or_error,
28 has_superadmin_permission, Optional, OAttr, get_user_or_error,
29 store_update, get_repo_group_or_error,
29 store_update, get_repo_group_or_error,
30 get_perm_or_error, get_user_group_or_error, get_origin)
30 get_perm_or_error, get_user_group_or_error, get_origin)
31 from rhodecode.lib.auth import (
31 from rhodecode.lib.auth import (
32 HasPermissionAnyApi, HasRepoGroupPermissionAnyApi,
32 HasPermissionAnyApi, HasRepoGroupPermissionAnyApi,
33 HasUserGroupPermissionAnyApi)
33 HasUserGroupPermissionAnyApi)
34 from rhodecode.model.db import Session, RepoGroup
34 from rhodecode.model.db import Session, RepoGroup
35 from rhodecode.model.repo_group import RepoGroupModel
35 from rhodecode.model.repo_group import RepoGroupModel
36 from rhodecode.model.scm import RepoGroupList
36 from rhodecode.model.scm import RepoGroupList
37 from rhodecode.model.validation_schema.schemas import repo_group_schema
37 from rhodecode.model.validation_schema.schemas import repo_group_schema
38
38
39
39
40 log = logging.getLogger(__name__)
40 log = logging.getLogger(__name__)
41
41
42
42
43 @jsonrpc_method()
43 @jsonrpc_method()
44 def get_repo_group(request, apiuser, repogroupid):
44 def get_repo_group(request, apiuser, repogroupid):
45 """
45 """
46 Return the specified |repo| group, along with permissions,
46 Return the specified |repo| group, along with permissions,
47 and repositories inside the group
47 and repositories inside the group
48
48
49 :param apiuser: This is filled automatically from the |authtoken|.
49 :param apiuser: This is filled automatically from the |authtoken|.
50 :type apiuser: AuthUser
50 :type apiuser: AuthUser
51 :param repogroupid: Specify the name of ID of the repository group.
51 :param repogroupid: Specify the name of ID of the repository group.
52 :type repogroupid: str or int
52 :type repogroupid: str or int
53
53
54
54
55 Example output:
55 Example output:
56
56
57 .. code-block:: bash
57 .. code-block:: bash
58
58
59 {
59 {
60 "error": null,
60 "error": null,
61 "id": repo-group-id,
61 "id": repo-group-id,
62 "result": {
62 "result": {
63 "group_description": "repo group description",
63 "group_description": "repo group description",
64 "group_id": 14,
64 "group_id": 14,
65 "group_name": "group name",
65 "group_name": "group name",
66 "members": [
66 "members": [
67 {
67 {
68 "name": "super-admin-username",
68 "name": "super-admin-username",
69 "origin": "super-admin",
69 "origin": "super-admin",
70 "permission": "group.admin",
70 "permission": "group.admin",
71 "type": "user"
71 "type": "user"
72 },
72 },
73 {
73 {
74 "name": "owner-name",
74 "name": "owner-name",
75 "origin": "owner",
75 "origin": "owner",
76 "permission": "group.admin",
76 "permission": "group.admin",
77 "type": "user"
77 "type": "user"
78 },
78 },
79 {
79 {
80 "name": "user-group-name",
80 "name": "user-group-name",
81 "origin": "permission",
81 "origin": "permission",
82 "permission": "group.write",
82 "permission": "group.write",
83 "type": "user_group"
83 "type": "user_group"
84 }
84 }
85 ],
85 ],
86 "owner": "owner-name",
86 "owner": "owner-name",
87 "parent_group": null,
87 "parent_group": null,
88 "repositories": [ repo-list ]
88 "repositories": [ repo-list ]
89 }
89 }
90 }
90 }
91 """
91 """
92
92
93 repo_group = get_repo_group_or_error(repogroupid)
93 repo_group = get_repo_group_or_error(repogroupid)
94 if not has_superadmin_permission(apiuser):
94 if not has_superadmin_permission(apiuser):
95 # check if we have at least read permission for this repo group !
95 # check if we have at least read permission for this repo group !
96 _perms = ('group.admin', 'group.write', 'group.read',)
96 _perms = ('group.admin', 'group.write', 'group.read',)
97 if not HasRepoGroupPermissionAnyApi(*_perms)(
97 if not HasRepoGroupPermissionAnyApi(*_perms)(
98 user=apiuser, group_name=repo_group.group_name):
98 user=apiuser, group_name=repo_group.group_name):
99 raise JSONRPCError(
99 raise JSONRPCError(
100 'repository group `%s` does not exist' % (repogroupid,))
100 'repository group `%s` does not exist' % (repogroupid,))
101
101
102 permissions = []
102 permissions = []
103 for _user in repo_group.permissions():
103 for _user in repo_group.permissions():
104 user_data = {
104 user_data = {
105 'name': _user.username,
105 'name': _user.username,
106 'permission': _user.permission,
106 'permission': _user.permission,
107 'origin': get_origin(_user),
107 'origin': get_origin(_user),
108 'type': "user",
108 'type': "user",
109 }
109 }
110 permissions.append(user_data)
110 permissions.append(user_data)
111
111
112 for _user_group in repo_group.permission_user_groups():
112 for _user_group in repo_group.permission_user_groups():
113 user_group_data = {
113 user_group_data = {
114 'name': _user_group.users_group_name,
114 'name': _user_group.users_group_name,
115 'permission': _user_group.permission,
115 'permission': _user_group.permission,
116 'origin': get_origin(_user_group),
116 'origin': get_origin(_user_group),
117 'type': "user_group",
117 'type': "user_group",
118 }
118 }
119 permissions.append(user_group_data)
119 permissions.append(user_group_data)
120
120
121 data = repo_group.get_api_data()
121 data = repo_group.get_api_data()
122 data["members"] = permissions # TODO: this should be named permissions
122 data["members"] = permissions # TODO: this should be named permissions
123 return data
123 return data
124
124
125
125
126 @jsonrpc_method()
126 @jsonrpc_method()
127 def get_repo_groups(request, apiuser):
127 def get_repo_groups(request, apiuser):
128 """
128 """
129 Returns all repository groups.
129 Returns all repository groups.
130
130
131 :param apiuser: This is filled automatically from the |authtoken|.
131 :param apiuser: This is filled automatically from the |authtoken|.
132 :type apiuser: AuthUser
132 :type apiuser: AuthUser
133 """
133 """
134
134
135 result = []
135 result = []
136 _perms = ('group.read', 'group.write', 'group.admin',)
136 _perms = ('group.read', 'group.write', 'group.admin',)
137 extras = {'user': apiuser}
137 extras = {'user': apiuser}
138 for repo_group in RepoGroupList(RepoGroupModel().get_all(),
138 for repo_group in RepoGroupList(RepoGroupModel().get_all(),
139 perm_set=_perms, extra_kwargs=extras):
139 perm_set=_perms, extra_kwargs=extras):
140 result.append(repo_group.get_api_data())
140 result.append(repo_group.get_api_data())
141 return result
141 return result
142
142
143
143
144 @jsonrpc_method()
144 @jsonrpc_method()
145 def create_repo_group(request, apiuser, group_name, description=Optional(''),
145 def create_repo_group(request, apiuser, group_name, description=Optional(''),
146 owner=Optional(OAttr('apiuser')),
146 owner=Optional(OAttr('apiuser')),
147 copy_permissions=Optional(False)):
147 copy_permissions=Optional(False)):
148 """
148 """
149 Creates a repository group.
149 Creates a repository group.
150
150
151 * If the repository group name contains "/", all the required repository
151 * If the repository group name contains "/", all the required repository
152 groups will be created.
152 groups will be created.
153
153
154 For example "foo/bar/baz" will create |repo| groups "foo" and "bar"
154 For example "foo/bar/baz" will create |repo| groups "foo" and "bar"
155 (with "foo" as parent). It will also create the "baz" repository
155 (with "foo" as parent). It will also create the "baz" repository
156 with "bar" as |repo| group.
156 with "bar" as |repo| group.
157
157
158 This command can only be run using an |authtoken| with admin
158 This command can only be run using an |authtoken| with admin
159 permissions.
159 permissions.
160
160
161 :param apiuser: This is filled automatically from the |authtoken|.
161 :param apiuser: This is filled automatically from the |authtoken|.
162 :type apiuser: AuthUser
162 :type apiuser: AuthUser
163 :param group_name: Set the repository group name.
163 :param group_name: Set the repository group name.
164 :type group_name: str
164 :type group_name: str
165 :param description: Set the |repo| group description.
165 :param description: Set the |repo| group description.
166 :type description: str
166 :type description: str
167 :param owner: Set the |repo| group owner.
167 :param owner: Set the |repo| group owner.
168 :type owner: str
168 :type owner: str
169 :param copy_permissions:
169 :param copy_permissions:
170 :type copy_permissions:
170 :type copy_permissions:
171
171
172 Example output:
172 Example output:
173
173
174 .. code-block:: bash
174 .. code-block:: bash
175
175
176 id : <id_given_in_input>
176 id : <id_given_in_input>
177 result : {
177 result : {
178 "msg": "Created new repo group `<repo_group_name>`"
178 "msg": "Created new repo group `<repo_group_name>`"
179 "repo_group": <repogroup_object>
179 "repo_group": <repogroup_object>
180 }
180 }
181 error : null
181 error : null
182
182
183
183
184 Example error output:
184 Example error output:
185
185
186 .. code-block:: bash
186 .. code-block:: bash
187
187
188 id : <id_given_in_input>
188 id : <id_given_in_input>
189 result : null
189 result : null
190 error : {
190 error : {
191 failed to create repo group `<repogroupid>`
191 failed to create repo group `<repogroupid>`
192 }
192 }
193
193
194 """
194 """
195
195
196 schema = repo_group_schema.RepoGroupSchema()
196 schema = repo_group_schema.RepoGroupSchema()
197 try:
197 try:
198 data = schema.deserialize({
198 data = schema.deserialize({
199 'group_name': group_name
199 'group_name': group_name
200 })
200 })
201 except colander.Invalid as e:
201 except colander.Invalid as e:
202 raise JSONRPCError("Validation failed: %s" % (e.asdict(),))
202 raise JSONRPCError("Validation failed: %s" % (e.asdict(),))
203 group_name = data['group_name']
203 group_name = data['group_name']
204
204
205 if isinstance(owner, Optional):
205 if isinstance(owner, Optional):
206 owner = apiuser.user_id
206 owner = apiuser.user_id
207
207
208 group_description = Optional.extract(description)
208 group_description = Optional.extract(description)
209 copy_permissions = Optional.extract(copy_permissions)
209 copy_permissions = Optional.extract(copy_permissions)
210
210
211 # get by full name with parents, check if it already exist
211 # get by full name with parents, check if it already exist
212 if RepoGroup.get_by_group_name(group_name):
212 if RepoGroup.get_by_group_name(group_name):
213 raise JSONRPCError("repo group `%s` already exist" % (group_name,))
213 raise JSONRPCError("repo group `%s` already exist" % (group_name,))
214
214
215 (group_name_cleaned,
215 (group_name_cleaned,
216 parent_group_name) = RepoGroupModel()._get_group_name_and_parent(
216 parent_group_name) = RepoGroupModel()._get_group_name_and_parent(
217 group_name)
217 group_name)
218
218
219 parent_group = None
219 parent_group = None
220 if parent_group_name:
220 if parent_group_name:
221 parent_group = get_repo_group_or_error(parent_group_name)
221 parent_group = get_repo_group_or_error(parent_group_name)
222
222
223 if not HasPermissionAnyApi(
223 if not HasPermissionAnyApi(
224 'hg.admin', 'hg.repogroup.create.true')(user=apiuser):
224 'hg.admin', 'hg.repogroup.create.true')(user=apiuser):
225 # check if we have admin permission for this parent repo group !
225 # check if we have admin permission for this parent repo group !
226 # users without admin or hg.repogroup.create can only create other
226 # users without admin or hg.repogroup.create can only create other
227 # groups in groups they own so this is a required, but can be empty
227 # groups in groups they own so this is a required, but can be empty
228 parent_group = getattr(parent_group, 'group_name', '')
228 parent_group = getattr(parent_group, 'group_name', '')
229 _perms = ('group.admin',)
229 _perms = ('group.admin',)
230 if not HasRepoGroupPermissionAnyApi(*_perms)(
230 if not HasRepoGroupPermissionAnyApi(*_perms)(
231 user=apiuser, group_name=parent_group):
231 user=apiuser, group_name=parent_group):
232 raise JSONRPCForbidden()
232 raise JSONRPCForbidden()
233
233
234 try:
234 try:
235 repo_group = RepoGroupModel().create(
235 repo_group = RepoGroupModel().create(
236 group_name=group_name,
236 group_name=group_name,
237 group_description=group_description,
237 group_description=group_description,
238 owner=owner,
238 owner=owner,
239 copy_permissions=copy_permissions)
239 copy_permissions=copy_permissions)
240 Session().commit()
240 Session().commit()
241 return {
241 return {
242 'msg': 'Created new repo group `%s`' % group_name,
242 'msg': 'Created new repo group `%s`' % group_name,
243 'repo_group': repo_group.get_api_data()
243 'repo_group': repo_group.get_api_data()
244 }
244 }
245 except Exception:
245 except Exception:
246 log.exception("Exception occurred while trying create repo group")
246 log.exception("Exception occurred while trying create repo group")
247 raise JSONRPCError(
247 raise JSONRPCError(
248 'failed to create repo group `%s`' % (group_name,))
248 'failed to create repo group `%s`' % (group_name,))
249
249
250
250
251 @jsonrpc_method()
251 @jsonrpc_method()
252 def update_repo_group(
252 def update_repo_group(
253 request, apiuser, repogroupid, group_name=Optional(''),
253 request, apiuser, repogroupid, group_name=Optional(''),
254 description=Optional(''), owner=Optional(OAttr('apiuser')),
254 description=Optional(''), owner=Optional(OAttr('apiuser')),
255 parent=Optional(None), enable_locking=Optional(False)):
255 parent=Optional(None), enable_locking=Optional(False)):
256 """
256 """
257 Updates repository group with the details given.
257 Updates repository group with the details given.
258
258
259 This command can only be run using an |authtoken| with admin
259 This command can only be run using an |authtoken| with admin
260 permissions.
260 permissions.
261
261
262 :param apiuser: This is filled automatically from the |authtoken|.
262 :param apiuser: This is filled automatically from the |authtoken|.
263 :type apiuser: AuthUser
263 :type apiuser: AuthUser
264 :param repogroupid: Set the ID of repository group.
264 :param repogroupid: Set the ID of repository group.
265 :type repogroupid: str or int
265 :type repogroupid: str or int
266 :param group_name: Set the name of the |repo| group.
266 :param group_name: Set the name of the |repo| group.
267 :type group_name: str
267 :type group_name: str
268 :param description: Set a description for the group.
268 :param description: Set a description for the group.
269 :type description: str
269 :type description: str
270 :param owner: Set the |repo| group owner.
270 :param owner: Set the |repo| group owner.
271 :type owner: str
271 :type owner: str
272 :param parent: Set the |repo| group parent.
272 :param parent: Set the |repo| group parent.
273 :type parent: str or int
273 :type parent: str or int
274 :param enable_locking: Enable |repo| locking. The default is false.
274 :param enable_locking: Enable |repo| locking. The default is false.
275 :type enable_locking: bool
275 :type enable_locking: bool
276 """
276 """
277
277
278 repo_group = get_repo_group_or_error(repogroupid)
278 repo_group = get_repo_group_or_error(repogroupid)
279 if not has_superadmin_permission(apiuser):
279 if not has_superadmin_permission(apiuser):
280 # check if we have admin permission for this repo group !
280 # check if we have admin permission for this repo group !
281 _perms = ('group.admin',)
281 _perms = ('group.admin',)
282 if not HasRepoGroupPermissionAnyApi(*_perms)(
282 if not HasRepoGroupPermissionAnyApi(*_perms)(
283 user=apiuser, group_name=repo_group.group_name):
283 user=apiuser, group_name=repo_group.group_name):
284 raise JSONRPCError(
284 raise JSONRPCError(
285 'repository group `%s` does not exist' % (repogroupid,))
285 'repository group `%s` does not exist' % (repogroupid,))
286
286
287 updates = {}
287 updates = {}
288 try:
288 try:
289 store_update(updates, group_name, 'group_name')
289 store_update(updates, group_name, 'group_name')
290 store_update(updates, description, 'group_description')
290 store_update(updates, description, 'group_description')
291 store_update(updates, owner, 'user')
291 store_update(updates, owner, 'user')
292 store_update(updates, parent, 'group_parent_id')
292 store_update(updates, parent, 'group_parent_id')
293 store_update(updates, enable_locking, 'enable_locking')
293 store_update(updates, enable_locking, 'enable_locking')
294 repo_group = RepoGroupModel().update(repo_group, updates)
294 repo_group = RepoGroupModel().update(repo_group, updates)
295 Session().commit()
295 Session().commit()
296 return {
296 return {
297 'msg': 'updated repository group ID:%s %s' % (
297 'msg': 'updated repository group ID:%s %s' % (
298 repo_group.group_id, repo_group.group_name),
298 repo_group.group_id, repo_group.group_name),
299 'repo_group': repo_group.get_api_data()
299 'repo_group': repo_group.get_api_data()
300 }
300 }
301 except Exception:
301 except Exception:
302 log.exception("Exception occurred while trying update repo group")
302 log.exception("Exception occurred while trying update repo group")
303 raise JSONRPCError('failed to update repository group `%s`'
303 raise JSONRPCError('failed to update repository group `%s`'
304 % (repogroupid,))
304 % (repogroupid,))
305
305
306
306
307 @jsonrpc_method()
307 @jsonrpc_method()
308 def delete_repo_group(request, apiuser, repogroupid):
308 def delete_repo_group(request, apiuser, repogroupid):
309 """
309 """
310 Deletes a |repo| group.
310 Deletes a |repo| group.
311
311
312 :param apiuser: This is filled automatically from the |authtoken|.
312 :param apiuser: This is filled automatically from the |authtoken|.
313 :type apiuser: AuthUser
313 :type apiuser: AuthUser
314 :param repogroupid: Set the name or ID of repository group to be
314 :param repogroupid: Set the name or ID of repository group to be
315 deleted.
315 deleted.
316 :type repogroupid: str or int
316 :type repogroupid: str or int
317
317
318 Example output:
318 Example output:
319
319
320 .. code-block:: bash
320 .. code-block:: bash
321
321
322 id : <id_given_in_input>
322 id : <id_given_in_input>
323 result : {
323 result : {
324 'msg': 'deleted repo group ID:<repogroupid> <repogroupname>
324 'msg': 'deleted repo group ID:<repogroupid> <repogroupname>'
325 'repo_group': null
325 'repo_group': null
326 }
326 }
327 error : null
327 error : null
328
328
329 Example error output:
329 Example error output:
330
330
331 .. code-block:: bash
331 .. code-block:: bash
332
332
333 id : <id_given_in_input>
333 id : <id_given_in_input>
334 result : null
334 result : null
335 error : {
335 error : {
336 "failed to delete repo group ID:<repogroupid> <repogroupname>"
336 "failed to delete repo group ID:<repogroupid> <repogroupname>"
337 }
337 }
338
338
339 """
339 """
340
340
341 repo_group = get_repo_group_or_error(repogroupid)
341 repo_group = get_repo_group_or_error(repogroupid)
342 if not has_superadmin_permission(apiuser):
342 if not has_superadmin_permission(apiuser):
343 # check if we have admin permission for this repo group !
343 # check if we have admin permission for this repo group !
344 _perms = ('group.admin',)
344 _perms = ('group.admin',)
345 if not HasRepoGroupPermissionAnyApi(*_perms)(
345 if not HasRepoGroupPermissionAnyApi(*_perms)(
346 user=apiuser, group_name=repo_group.group_name):
346 user=apiuser, group_name=repo_group.group_name):
347 raise JSONRPCError(
347 raise JSONRPCError(
348 'repository group `%s` does not exist' % (repogroupid,))
348 'repository group `%s` does not exist' % (repogroupid,))
349 try:
349 try:
350 RepoGroupModel().delete(repo_group)
350 RepoGroupModel().delete(repo_group)
351 Session().commit()
351 Session().commit()
352 return {
352 return {
353 'msg': 'deleted repo group ID:%s %s' %
353 'msg': 'deleted repo group ID:%s %s' %
354 (repo_group.group_id, repo_group.group_name),
354 (repo_group.group_id, repo_group.group_name),
355 'repo_group': None
355 'repo_group': None
356 }
356 }
357 except Exception:
357 except Exception:
358 log.exception("Exception occurred while trying to delete repo group")
358 log.exception("Exception occurred while trying to delete repo group")
359 raise JSONRPCError('failed to delete repo group ID:%s %s' %
359 raise JSONRPCError('failed to delete repo group ID:%s %s' %
360 (repo_group.group_id, repo_group.group_name))
360 (repo_group.group_id, repo_group.group_name))
361
361
362
362
363 @jsonrpc_method()
363 @jsonrpc_method()
364 def grant_user_permission_to_repo_group(
364 def grant_user_permission_to_repo_group(
365 request, apiuser, repogroupid, userid, perm,
365 request, apiuser, repogroupid, userid, perm,
366 apply_to_children=Optional('none')):
366 apply_to_children=Optional('none')):
367 """
367 """
368 Grant permission for a user on the given repository group, or update
368 Grant permission for a user on the given repository group, or update
369 existing permissions if found.
369 existing permissions if found.
370
370
371 This command can only be run using an |authtoken| with admin
371 This command can only be run using an |authtoken| with admin
372 permissions.
372 permissions.
373
373
374 :param apiuser: This is filled automatically from the |authtoken|.
374 :param apiuser: This is filled automatically from the |authtoken|.
375 :type apiuser: AuthUser
375 :type apiuser: AuthUser
376 :param repogroupid: Set the name or ID of repository group.
376 :param repogroupid: Set the name or ID of repository group.
377 :type repogroupid: str or int
377 :type repogroupid: str or int
378 :param userid: Set the user name.
378 :param userid: Set the user name.
379 :type userid: str
379 :type userid: str
380 :param perm: (group.(none|read|write|admin))
380 :param perm: (group.(none|read|write|admin))
381 :type perm: str
381 :type perm: str
382 :param apply_to_children: 'none', 'repos', 'groups', 'all'
382 :param apply_to_children: 'none', 'repos', 'groups', 'all'
383 :type apply_to_children: str
383 :type apply_to_children: str
384
384
385 Example output:
385 Example output:
386
386
387 .. code-block:: bash
387 .. code-block:: bash
388
388
389 id : <id_given_in_input>
389 id : <id_given_in_input>
390 result: {
390 result: {
391 "msg" : "Granted perm: `<perm>` (recursive:<apply_to_children>) for user: `<username>` in repo group: `<repo_group_name>`",
391 "msg" : "Granted perm: `<perm>` (recursive:<apply_to_children>) for user: `<username>` in repo group: `<repo_group_name>`",
392 "success": true
392 "success": true
393 }
393 }
394 error: null
394 error: null
395
395
396 Example error output:
396 Example error output:
397
397
398 .. code-block:: bash
398 .. code-block:: bash
399
399
400 id : <id_given_in_input>
400 id : <id_given_in_input>
401 result : null
401 result : null
402 error : {
402 error : {
403 "failed to edit permission for user: `<userid>` in repo group: `<repo_group_name>`"
403 "failed to edit permission for user: `<userid>` in repo group: `<repo_group_name>`"
404 }
404 }
405
405
406 """
406 """
407
407
408 repo_group = get_repo_group_or_error(repogroupid)
408 repo_group = get_repo_group_or_error(repogroupid)
409
409
410 if not has_superadmin_permission(apiuser):
410 if not has_superadmin_permission(apiuser):
411 # check if we have admin permission for this repo group !
411 # check if we have admin permission for this repo group !
412 _perms = ('group.admin',)
412 _perms = ('group.admin',)
413 if not HasRepoGroupPermissionAnyApi(*_perms)(
413 if not HasRepoGroupPermissionAnyApi(*_perms)(
414 user=apiuser, group_name=repo_group.group_name):
414 user=apiuser, group_name=repo_group.group_name):
415 raise JSONRPCError(
415 raise JSONRPCError(
416 'repository group `%s` does not exist' % (repogroupid,))
416 'repository group `%s` does not exist' % (repogroupid,))
417
417
418 user = get_user_or_error(userid)
418 user = get_user_or_error(userid)
419 perm = get_perm_or_error(perm, prefix='group.')
419 perm = get_perm_or_error(perm, prefix='group.')
420 apply_to_children = Optional.extract(apply_to_children)
420 apply_to_children = Optional.extract(apply_to_children)
421
421
422 perm_additions = [[user.user_id, perm, "user"]]
422 perm_additions = [[user.user_id, perm, "user"]]
423 try:
423 try:
424 RepoGroupModel().update_permissions(repo_group=repo_group,
424 RepoGroupModel().update_permissions(repo_group=repo_group,
425 perm_additions=perm_additions,
425 perm_additions=perm_additions,
426 recursive=apply_to_children,
426 recursive=apply_to_children,
427 cur_user=apiuser)
427 cur_user=apiuser)
428 Session().commit()
428 Session().commit()
429 return {
429 return {
430 'msg': 'Granted perm: `%s` (recursive:%s) for user: '
430 'msg': 'Granted perm: `%s` (recursive:%s) for user: '
431 '`%s` in repo group: `%s`' % (
431 '`%s` in repo group: `%s`' % (
432 perm.permission_name, apply_to_children, user.username,
432 perm.permission_name, apply_to_children, user.username,
433 repo_group.name
433 repo_group.name
434 ),
434 ),
435 'success': True
435 'success': True
436 }
436 }
437 except Exception:
437 except Exception:
438 log.exception("Exception occurred while trying to grant "
438 log.exception("Exception occurred while trying to grant "
439 "user permissions to repo group")
439 "user permissions to repo group")
440 raise JSONRPCError(
440 raise JSONRPCError(
441 'failed to edit permission for user: '
441 'failed to edit permission for user: '
442 '`%s` in repo group: `%s`' % (userid, repo_group.name))
442 '`%s` in repo group: `%s`' % (userid, repo_group.name))
443
443
444
444
445 @jsonrpc_method()
445 @jsonrpc_method()
446 def revoke_user_permission_from_repo_group(
446 def revoke_user_permission_from_repo_group(
447 request, apiuser, repogroupid, userid,
447 request, apiuser, repogroupid, userid,
448 apply_to_children=Optional('none')):
448 apply_to_children=Optional('none')):
449 """
449 """
450 Revoke permission for a user in a given repository group.
450 Revoke permission for a user in a given repository group.
451
451
452 This command can only be run using an |authtoken| with admin
452 This command can only be run using an |authtoken| with admin
453 permissions on the |repo| group.
453 permissions on the |repo| group.
454
454
455 :param apiuser: This is filled automatically from the |authtoken|.
455 :param apiuser: This is filled automatically from the |authtoken|.
456 :type apiuser: AuthUser
456 :type apiuser: AuthUser
457 :param repogroupid: Set the name or ID of the repository group.
457 :param repogroupid: Set the name or ID of the repository group.
458 :type repogroupid: str or int
458 :type repogroupid: str or int
459 :param userid: Set the user name to revoke.
459 :param userid: Set the user name to revoke.
460 :type userid: str
460 :type userid: str
461 :param apply_to_children: 'none', 'repos', 'groups', 'all'
461 :param apply_to_children: 'none', 'repos', 'groups', 'all'
462 :type apply_to_children: str
462 :type apply_to_children: str
463
463
464 Example output:
464 Example output:
465
465
466 .. code-block:: bash
466 .. code-block:: bash
467
467
468 id : <id_given_in_input>
468 id : <id_given_in_input>
469 result: {
469 result: {
470 "msg" : "Revoked perm (recursive:<apply_to_children>) for user: `<username>` in repo group: `<repo_group_name>`",
470 "msg" : "Revoked perm (recursive:<apply_to_children>) for user: `<username>` in repo group: `<repo_group_name>`",
471 "success": true
471 "success": true
472 }
472 }
473 error: null
473 error: null
474
474
475 Example error output:
475 Example error output:
476
476
477 .. code-block:: bash
477 .. code-block:: bash
478
478
479 id : <id_given_in_input>
479 id : <id_given_in_input>
480 result : null
480 result : null
481 error : {
481 error : {
482 "failed to edit permission for user: `<userid>` in repo group: `<repo_group_name>`"
482 "failed to edit permission for user: `<userid>` in repo group: `<repo_group_name>`"
483 }
483 }
484
484
485 """
485 """
486
486
487 repo_group = get_repo_group_or_error(repogroupid)
487 repo_group = get_repo_group_or_error(repogroupid)
488
488
489 if not has_superadmin_permission(apiuser):
489 if not has_superadmin_permission(apiuser):
490 # check if we have admin permission for this repo group !
490 # check if we have admin permission for this repo group !
491 _perms = ('group.admin',)
491 _perms = ('group.admin',)
492 if not HasRepoGroupPermissionAnyApi(*_perms)(
492 if not HasRepoGroupPermissionAnyApi(*_perms)(
493 user=apiuser, group_name=repo_group.group_name):
493 user=apiuser, group_name=repo_group.group_name):
494 raise JSONRPCError(
494 raise JSONRPCError(
495 'repository group `%s` does not exist' % (repogroupid,))
495 'repository group `%s` does not exist' % (repogroupid,))
496
496
497 user = get_user_or_error(userid)
497 user = get_user_or_error(userid)
498 apply_to_children = Optional.extract(apply_to_children)
498 apply_to_children = Optional.extract(apply_to_children)
499
499
500 perm_deletions = [[user.user_id, None, "user"]]
500 perm_deletions = [[user.user_id, None, "user"]]
501 try:
501 try:
502 RepoGroupModel().update_permissions(repo_group=repo_group,
502 RepoGroupModel().update_permissions(repo_group=repo_group,
503 perm_deletions=perm_deletions,
503 perm_deletions=perm_deletions,
504 recursive=apply_to_children,
504 recursive=apply_to_children,
505 cur_user=apiuser)
505 cur_user=apiuser)
506 Session().commit()
506 Session().commit()
507 return {
507 return {
508 'msg': 'Revoked perm (recursive:%s) for user: '
508 'msg': 'Revoked perm (recursive:%s) for user: '
509 '`%s` in repo group: `%s`' % (
509 '`%s` in repo group: `%s`' % (
510 apply_to_children, user.username, repo_group.name
510 apply_to_children, user.username, repo_group.name
511 ),
511 ),
512 'success': True
512 'success': True
513 }
513 }
514 except Exception:
514 except Exception:
515 log.exception("Exception occurred while trying revoke user "
515 log.exception("Exception occurred while trying revoke user "
516 "permission from repo group")
516 "permission from repo group")
517 raise JSONRPCError(
517 raise JSONRPCError(
518 'failed to edit permission for user: '
518 'failed to edit permission for user: '
519 '`%s` in repo group: `%s`' % (userid, repo_group.name))
519 '`%s` in repo group: `%s`' % (userid, repo_group.name))
520
520
521
521
522 @jsonrpc_method()
522 @jsonrpc_method()
523 def grant_user_group_permission_to_repo_group(
523 def grant_user_group_permission_to_repo_group(
524 request, apiuser, repogroupid, usergroupid, perm,
524 request, apiuser, repogroupid, usergroupid, perm,
525 apply_to_children=Optional('none'), ):
525 apply_to_children=Optional('none'), ):
526 """
526 """
527 Grant permission for a user group on given repository group, or update
527 Grant permission for a user group on given repository group, or update
528 existing permissions if found.
528 existing permissions if found.
529
529
530 This command can only be run using an |authtoken| with admin
530 This command can only be run using an |authtoken| with admin
531 permissions on the |repo| group.
531 permissions on the |repo| group.
532
532
533 :param apiuser: This is filled automatically from the |authtoken|.
533 :param apiuser: This is filled automatically from the |authtoken|.
534 :type apiuser: AuthUser
534 :type apiuser: AuthUser
535 :param repogroupid: Set the name or id of repository group
535 :param repogroupid: Set the name or id of repository group
536 :type repogroupid: str or int
536 :type repogroupid: str or int
537 :param usergroupid: id of usergroup
537 :param usergroupid: id of usergroup
538 :type usergroupid: str or int
538 :type usergroupid: str or int
539 :param perm: (group.(none|read|write|admin))
539 :param perm: (group.(none|read|write|admin))
540 :type perm: str
540 :type perm: str
541 :param apply_to_children: 'none', 'repos', 'groups', 'all'
541 :param apply_to_children: 'none', 'repos', 'groups', 'all'
542 :type apply_to_children: str
542 :type apply_to_children: str
543
543
544 Example output:
544 Example output:
545
545
546 .. code-block:: bash
546 .. code-block:: bash
547
547
548 id : <id_given_in_input>
548 id : <id_given_in_input>
549 result : {
549 result : {
550 "msg" : "Granted perm: `<perm>` (recursive:<apply_to_children>) for user group: `<usersgroupname>` in repo group: `<repo_group_name>`",
550 "msg" : "Granted perm: `<perm>` (recursive:<apply_to_children>) for user group: `<usersgroupname>` in repo group: `<repo_group_name>`",
551 "success": true
551 "success": true
552
552
553 }
553 }
554 error : null
554 error : null
555
555
556 Example error output:
556 Example error output:
557
557
558 .. code-block:: bash
558 .. code-block:: bash
559
559
560 id : <id_given_in_input>
560 id : <id_given_in_input>
561 result : null
561 result : null
562 error : {
562 error : {
563 "failed to edit permission for user group: `<usergroup>` in repo group: `<repo_group_name>`"
563 "failed to edit permission for user group: `<usergroup>` in repo group: `<repo_group_name>`"
564 }
564 }
565
565
566 """
566 """
567
567
568 repo_group = get_repo_group_or_error(repogroupid)
568 repo_group = get_repo_group_or_error(repogroupid)
569 perm = get_perm_or_error(perm, prefix='group.')
569 perm = get_perm_or_error(perm, prefix='group.')
570 user_group = get_user_group_or_error(usergroupid)
570 user_group = get_user_group_or_error(usergroupid)
571 if not has_superadmin_permission(apiuser):
571 if not has_superadmin_permission(apiuser):
572 # check if we have admin permission for this repo group !
572 # check if we have admin permission for this repo group !
573 _perms = ('group.admin',)
573 _perms = ('group.admin',)
574 if not HasRepoGroupPermissionAnyApi(*_perms)(
574 if not HasRepoGroupPermissionAnyApi(*_perms)(
575 user=apiuser, group_name=repo_group.group_name):
575 user=apiuser, group_name=repo_group.group_name):
576 raise JSONRPCError(
576 raise JSONRPCError(
577 'repository group `%s` does not exist' % (repogroupid,))
577 'repository group `%s` does not exist' % (repogroupid,))
578
578
579 # check if we have at least read permission for this user group !
579 # check if we have at least read permission for this user group !
580 _perms = ('usergroup.read', 'usergroup.write', 'usergroup.admin',)
580 _perms = ('usergroup.read', 'usergroup.write', 'usergroup.admin',)
581 if not HasUserGroupPermissionAnyApi(*_perms)(
581 if not HasUserGroupPermissionAnyApi(*_perms)(
582 user=apiuser, user_group_name=user_group.users_group_name):
582 user=apiuser, user_group_name=user_group.users_group_name):
583 raise JSONRPCError(
583 raise JSONRPCError(
584 'user group `%s` does not exist' % (usergroupid,))
584 'user group `%s` does not exist' % (usergroupid,))
585
585
586 apply_to_children = Optional.extract(apply_to_children)
586 apply_to_children = Optional.extract(apply_to_children)
587
587
588 perm_additions = [[user_group.users_group_id, perm, "user_group"]]
588 perm_additions = [[user_group.users_group_id, perm, "user_group"]]
589 try:
589 try:
590 RepoGroupModel().update_permissions(repo_group=repo_group,
590 RepoGroupModel().update_permissions(repo_group=repo_group,
591 perm_additions=perm_additions,
591 perm_additions=perm_additions,
592 recursive=apply_to_children,
592 recursive=apply_to_children,
593 cur_user=apiuser)
593 cur_user=apiuser)
594 Session().commit()
594 Session().commit()
595 return {
595 return {
596 'msg': 'Granted perm: `%s` (recursive:%s) '
596 'msg': 'Granted perm: `%s` (recursive:%s) '
597 'for user group: `%s` in repo group: `%s`' % (
597 'for user group: `%s` in repo group: `%s`' % (
598 perm.permission_name, apply_to_children,
598 perm.permission_name, apply_to_children,
599 user_group.users_group_name, repo_group.name
599 user_group.users_group_name, repo_group.name
600 ),
600 ),
601 'success': True
601 'success': True
602 }
602 }
603 except Exception:
603 except Exception:
604 log.exception("Exception occurred while trying to grant user "
604 log.exception("Exception occurred while trying to grant user "
605 "group permissions to repo group")
605 "group permissions to repo group")
606 raise JSONRPCError(
606 raise JSONRPCError(
607 'failed to edit permission for user group: `%s` in '
607 'failed to edit permission for user group: `%s` in '
608 'repo group: `%s`' % (
608 'repo group: `%s`' % (
609 usergroupid, repo_group.name
609 usergroupid, repo_group.name
610 )
610 )
611 )
611 )
612
612
613
613
614 @jsonrpc_method()
614 @jsonrpc_method()
615 def revoke_user_group_permission_from_repo_group(
615 def revoke_user_group_permission_from_repo_group(
616 request, apiuser, repogroupid, usergroupid,
616 request, apiuser, repogroupid, usergroupid,
617 apply_to_children=Optional('none')):
617 apply_to_children=Optional('none')):
618 """
618 """
619 Revoke permission for user group on given repository.
619 Revoke permission for user group on given repository.
620
620
621 This command can only be run using an |authtoken| with admin
621 This command can only be run using an |authtoken| with admin
622 permissions on the |repo| group.
622 permissions on the |repo| group.
623
623
624 :param apiuser: This is filled automatically from the |authtoken|.
624 :param apiuser: This is filled automatically from the |authtoken|.
625 :type apiuser: AuthUser
625 :type apiuser: AuthUser
626 :param repogroupid: name or id of repository group
626 :param repogroupid: name or id of repository group
627 :type repogroupid: str or int
627 :type repogroupid: str or int
628 :param usergroupid:
628 :param usergroupid:
629 :param apply_to_children: 'none', 'repos', 'groups', 'all'
629 :param apply_to_children: 'none', 'repos', 'groups', 'all'
630 :type apply_to_children: str
630 :type apply_to_children: str
631
631
632 Example output:
632 Example output:
633
633
634 .. code-block:: bash
634 .. code-block:: bash
635
635
636 id : <id_given_in_input>
636 id : <id_given_in_input>
637 result: {
637 result: {
638 "msg" : "Revoked perm (recursive:<apply_to_children>) for user group: `<usersgroupname>` in repo group: `<repo_group_name>`",
638 "msg" : "Revoked perm (recursive:<apply_to_children>) for user group: `<usersgroupname>` in repo group: `<repo_group_name>`",
639 "success": true
639 "success": true
640 }
640 }
641 error: null
641 error: null
642
642
643 Example error output:
643 Example error output:
644
644
645 .. code-block:: bash
645 .. code-block:: bash
646
646
647 id : <id_given_in_input>
647 id : <id_given_in_input>
648 result : null
648 result : null
649 error : {
649 error : {
650 "failed to edit permission for user group: `<usergroup>` in repo group: `<repo_group_name>`"
650 "failed to edit permission for user group: `<usergroup>` in repo group: `<repo_group_name>`"
651 }
651 }
652
652
653
653
654 """
654 """
655
655
656 repo_group = get_repo_group_or_error(repogroupid)
656 repo_group = get_repo_group_or_error(repogroupid)
657 user_group = get_user_group_or_error(usergroupid)
657 user_group = get_user_group_or_error(usergroupid)
658 if not has_superadmin_permission(apiuser):
658 if not has_superadmin_permission(apiuser):
659 # check if we have admin permission for this repo group !
659 # check if we have admin permission for this repo group !
660 _perms = ('group.admin',)
660 _perms = ('group.admin',)
661 if not HasRepoGroupPermissionAnyApi(*_perms)(
661 if not HasRepoGroupPermissionAnyApi(*_perms)(
662 user=apiuser, group_name=repo_group.group_name):
662 user=apiuser, group_name=repo_group.group_name):
663 raise JSONRPCError(
663 raise JSONRPCError(
664 'repository group `%s` does not exist' % (repogroupid,))
664 'repository group `%s` does not exist' % (repogroupid,))
665
665
666 # check if we have at least read permission for this user group !
666 # check if we have at least read permission for this user group !
667 _perms = ('usergroup.read', 'usergroup.write', 'usergroup.admin',)
667 _perms = ('usergroup.read', 'usergroup.write', 'usergroup.admin',)
668 if not HasUserGroupPermissionAnyApi(*_perms)(
668 if not HasUserGroupPermissionAnyApi(*_perms)(
669 user=apiuser, user_group_name=user_group.users_group_name):
669 user=apiuser, user_group_name=user_group.users_group_name):
670 raise JSONRPCError(
670 raise JSONRPCError(
671 'user group `%s` does not exist' % (usergroupid,))
671 'user group `%s` does not exist' % (usergroupid,))
672
672
673 apply_to_children = Optional.extract(apply_to_children)
673 apply_to_children = Optional.extract(apply_to_children)
674
674
675 perm_deletions = [[user_group.users_group_id, None, "user_group"]]
675 perm_deletions = [[user_group.users_group_id, None, "user_group"]]
676 try:
676 try:
677 RepoGroupModel().update_permissions(repo_group=repo_group,
677 RepoGroupModel().update_permissions(repo_group=repo_group,
678 perm_deletions=perm_deletions,
678 perm_deletions=perm_deletions,
679 recursive=apply_to_children,
679 recursive=apply_to_children,
680 cur_user=apiuser)
680 cur_user=apiuser)
681 Session().commit()
681 Session().commit()
682 return {
682 return {
683 'msg': 'Revoked perm (recursive:%s) for user group: '
683 'msg': 'Revoked perm (recursive:%s) for user group: '
684 '`%s` in repo group: `%s`' % (
684 '`%s` in repo group: `%s`' % (
685 apply_to_children, user_group.users_group_name,
685 apply_to_children, user_group.users_group_name,
686 repo_group.name
686 repo_group.name
687 ),
687 ),
688 'success': True
688 'success': True
689 }
689 }
690 except Exception:
690 except Exception:
691 log.exception("Exception occurred while trying revoke user group "
691 log.exception("Exception occurred while trying revoke user group "
692 "permissions from repo group")
692 "permissions from repo group")
693 raise JSONRPCError(
693 raise JSONRPCError(
694 'failed to edit permission for user group: '
694 'failed to edit permission for user group: '
695 '`%s` in repo group: `%s`' % (
695 '`%s` in repo group: `%s`' % (
696 user_group.users_group_name, repo_group.name
696 user_group.users_group_name, repo_group.name
697 )
697 )
698 )
698 )
699
699
General Comments 0
You need to be logged in to leave comments. Login now